Browse Source

11/25完整业务功能代码

25057 4 tháng trước cách đây
mục cha
commit
fafdd3c33d
100 tập tin đã thay đổi với 3819 bổ sung1374 xóa
  1. 9 0
      Dockerfile
  2. 3 0
      src/main/java/com/loan/system/LoanSystemApplication.java
  3. 4 2
      src/main/java/com/loan/system/config/WebMvcConfiguration.java
  4. 2 0
      src/main/java/com/loan/system/constant/JwtClaimsConstant.java
  5. 1 1
      src/main/java/com/loan/system/constant/PasswordConstant.java
  6. 26 48
      src/main/java/com/loan/system/controller/admin/AdminController.java
  7. 30 0
      src/main/java/com/loan/system/controller/admin/CustomerController.java
  8. 398 0
      src/main/java/com/loan/system/controller/admin/DetailsController.java
  9. 68 0
      src/main/java/com/loan/system/controller/admin/DictionaryController.java
  10. 11 0
      src/main/java/com/loan/system/controller/admin/MaterialsController.java
  11. 24 1
      src/main/java/com/loan/system/controller/admin/RecommenderController.java
  12. 159 224
      src/main/java/com/loan/system/controller/wechat/ApprovalController.java
  13. 241 123
      src/main/java/com/loan/system/controller/wechat/CollateralController.java
  14. 64 46
      src/main/java/com/loan/system/controller/wechat/ContractController.java
  15. 19 4
      src/main/java/com/loan/system/controller/wechat/CustomerController.java
  16. 24 10
      src/main/java/com/loan/system/controller/wechat/DictionaryController.java
  17. 183 152
      src/main/java/com/loan/system/controller/wechat/DisbursementController.java
  18. 285 105
      src/main/java/com/loan/system/controller/wechat/LoanController.java
  19. 345 0
      src/main/java/com/loan/system/controller/wechat/LoanController_copy.java
  20. 298 145
      src/main/java/com/loan/system/controller/wechat/RepaymentController.java
  21. 238 24
      src/main/java/com/loan/system/controller/wechat/StatisticsController.java
  22. 26 4
      src/main/java/com/loan/system/controller/wechat/StepController.java
  23. 30 44
      src/main/java/com/loan/system/controller/wechat/UploadController.java
  24. 147 146
      src/main/java/com/loan/system/controller/wechat/UserController.java
  25. 2 1
      src/main/java/com/loan/system/domain/dto/CollateralDTO.java
  26. 3 3
      src/main/java/com/loan/system/domain/dto/CollateralPlanApprovalDTO.java
  27. 2 1
      src/main/java/com/loan/system/domain/dto/CollateralPlanDTO.java
  28. 1 1
      src/main/java/com/loan/system/domain/dto/ContractDTO.java
  29. 25 0
      src/main/java/com/loan/system/domain/dto/CustomerDTO.java
  30. 1 0
      src/main/java/com/loan/system/domain/dto/CustomersOtherDTO.java
  31. 21 0
      src/main/java/com/loan/system/domain/dto/DictDataDTO.java
  32. 23 0
      src/main/java/com/loan/system/domain/dto/DictTypeDTO.java
  33. 4 2
      src/main/java/com/loan/system/domain/dto/DisbursementDTO.java
  34. 1 0
      src/main/java/com/loan/system/domain/dto/DisbursementRecordDTO.java
  35. 15 0
      src/main/java/com/loan/system/domain/dto/DisbursementRecordListWrapper.java
  36. 17 0
      src/main/java/com/loan/system/domain/dto/DisbursementStartDTO.java
  37. 2 2
      src/main/java/com/loan/system/domain/dto/LoanCaseDTO.java
  38. 15 0
      src/main/java/com/loan/system/domain/dto/RepaymentApprovalDTO.java
  39. 5 1
      src/main/java/com/loan/system/domain/dto/RepaymentRecordDTO.java
  40. 4 2
      src/main/java/com/loan/system/domain/dto/UserLoginDTO.java
  41. 2 2
      src/main/java/com/loan/system/domain/dto/WeChatLoginDTO.java
  42. 3 0
      src/main/java/com/loan/system/domain/entity/ApprovalRecord.java
  43. 2 2
      src/main/java/com/loan/system/domain/entity/Collateral.java
  44. 14 10
      src/main/java/com/loan/system/domain/entity/CollateralPlan.java
  45. 11 2
      src/main/java/com/loan/system/domain/entity/Contract.java
  46. 43 0
      src/main/java/com/loan/system/domain/entity/ContractRepayment.java
  47. 1 3
      src/main/java/com/loan/system/domain/entity/ContractSeq.java
  48. 6 0
      src/main/java/com/loan/system/domain/entity/Customer.java
  49. 47 0
      src/main/java/com/loan/system/domain/entity/DictData.java
  50. 18 19
      src/main/java/com/loan/system/domain/entity/DictType.java
  51. 10 4
      src/main/java/com/loan/system/domain/entity/Disbursement.java
  52. 3 1
      src/main/java/com/loan/system/domain/entity/DisbursementRecord.java
  53. 135 110
      src/main/java/com/loan/system/domain/entity/ExceptionLog.java
  54. 4 4
      src/main/java/com/loan/system/domain/entity/LoanCase.java
  55. 40 0
      src/main/java/com/loan/system/domain/entity/PawnTicketInfo.java
  56. 3 0
      src/main/java/com/loan/system/domain/entity/Repayment.java
  57. 8 2
      src/main/java/com/loan/system/domain/entity/RepaymentRecord.java
  58. 12 0
      src/main/java/com/loan/system/domain/entity/Step.java
  59. 22 1
      src/main/java/com/loan/system/domain/enums/DecisionEnum.java
  60. 26 7
      src/main/java/com/loan/system/domain/enums/ExceptionEnum.java
  61. 2 1
      src/main/java/com/loan/system/domain/enums/RoleEnum.java
  62. 68 27
      src/main/java/com/loan/system/domain/enums/StepPropertyEnum.java
  63. 2 2
      src/main/java/com/loan/system/domain/pojo/ContractInformation.java
  64. 2 2
      src/main/java/com/loan/system/domain/vo/ApprovalRecordVO.java
  65. 17 0
      src/main/java/com/loan/system/domain/vo/CaseAndUserVO.java
  66. 11 7
      src/main/java/com/loan/system/domain/vo/CollateralPlanVO.java
  67. 5 1
      src/main/java/com/loan/system/domain/vo/ContractVO.java
  68. 2 1
      src/main/java/com/loan/system/domain/vo/CustomerLoginVO.java
  69. 2 0
      src/main/java/com/loan/system/domain/vo/CustomerVO.java
  70. 33 0
      src/main/java/com/loan/system/domain/vo/DailyReport.java
  71. 3 4
      src/main/java/com/loan/system/domain/vo/DictionarysVO.java
  72. 15 2
      src/main/java/com/loan/system/domain/vo/DisbursementDetailVO.java
  73. 24 0
      src/main/java/com/loan/system/domain/vo/DisbursementDetails.java
  74. 3 1
      src/main/java/com/loan/system/domain/vo/DisbursementRecordVO.java
  75. 5 3
      src/main/java/com/loan/system/domain/vo/DisbursementVO.java
  76. 35 0
      src/main/java/com/loan/system/domain/vo/LoanCaseDetails.java
  77. 4 2
      src/main/java/com/loan/system/domain/vo/LoanCaseSimpleVO.java
  78. 21 0
      src/main/java/com/loan/system/domain/vo/LoanCaseStatistic.java
  79. 8 2
      src/main/java/com/loan/system/domain/vo/LoanCaseVO.java
  80. 8 4
      src/main/java/com/loan/system/domain/vo/RepaymentDetailVO.java
  81. 29 0
      src/main/java/com/loan/system/domain/vo/RepaymentDetails.java
  82. 6 2
      src/main/java/com/loan/system/domain/vo/RepaymentRecordVO.java
  83. 3 1
      src/main/java/com/loan/system/domain/vo/StepVO.java
  84. 1 1
      src/main/java/com/loan/system/domain/vo/UserLoginVO.java
  85. 25 1
      src/main/java/com/loan/system/exception/GlobalExceptionHandler.java
  86. 10 0
      src/main/java/com/loan/system/interceptor/JwtTokenAdminInterceptor.java
  87. 43 19
      src/main/java/com/loan/system/interceptor/JwtTokenUserInterceptor.java
  88. 18 2
      src/main/java/com/loan/system/repository/ApproveRecordRepository.java
  89. 24 12
      src/main/java/com/loan/system/repository/CollateralPlanRepository.java
  90. 15 3
      src/main/java/com/loan/system/repository/CollateralRepository.java
  91. 2 0
      src/main/java/com/loan/system/repository/ContractAndCollateralRepository.java
  92. 35 0
      src/main/java/com/loan/system/repository/ContractRepaymentRepository.java
  93. 30 4
      src/main/java/com/loan/system/repository/ContractRepository.java
  94. 3 2
      src/main/java/com/loan/system/repository/CustomerOtherRepository.java
  95. 31 2
      src/main/java/com/loan/system/repository/CustomerRepository.java
  96. 15 0
      src/main/java/com/loan/system/repository/DictBusinessTypeRepository.java
  97. 34 0
      src/main/java/com/loan/system/repository/DictDataRepository.java
  98. 0 1
      src/main/java/com/loan/system/repository/DictStepRepository.java
  99. 16 5
      src/main/java/com/loan/system/repository/DictTypeRepository.java
  100. 23 1
      src/main/java/com/loan/system/repository/DisbursementRepository.java

+ 9 - 0
Dockerfile

@@ -0,0 +1,9 @@
+# 基础镜像
+FROM openjdk:11.0-jre-buster
+# 设定时区
+ENV TZ=Asia/Shanghai
+RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
+# 拷贝jar包
+COPY loan-system.jar /app.jar
+# 入口
+ENTRYPOINT ["java", "-jar", "/app.jar"]

+ 3 - 0
src/main/java/com/loan/system/LoanSystemApplication.java

@@ -9,13 +9,16 @@ import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfi
 import org.springframework.cache.annotation.EnableCaching;
 import org.springframework.context.ApplicationContext;
 import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
+import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
 
 //@MapperScan(value = {"com/hdu/maintenance/mapper"})
 @SpringBootApplication(exclude = SecurityAutoConfiguration.class)
 @EnableCaching
 @EnableJpaAuditing
 @Slf4j
+@EnableGlobalMethodSecurity(prePostEnabled = true)
 public class LoanSystemApplication {
+
     public static void main(String[] args) {
         SpringApplication.run(LoanSystemApplication.class, args);
 

+ 4 - 2
src/main/java/com/loan/system/config/WebMvcConfiguration.java

@@ -45,7 +45,8 @@ public class WebMvcConfiguration extends WebMvcConfigurationSupport {
 
         registry.addInterceptor(jwtTokenUserInterceptor)
                 .addPathPatterns("/wechat/**")
-                .excludePathPatterns("/wechat/login");
+                .excludePathPatterns("/wechat/login")
+                .excludePathPatterns("/wechat/loginTest");
     }
 
     /*
@@ -100,7 +101,8 @@ public class WebMvcConfiguration extends WebMvcConfigurationSupport {
     protected void addResourceHandlers(ResourceHandlerRegistry registry) {
         log.info("设置静态资源映射");
         registry.addResourceHandler("/doc.html").addResourceLocations("classpath:/META-INF/resources/");
-        registry.addResourceHandler("/wechat/files/**").addResourceLocations("classpath:/META-INF/resources/file_store/");
+        registry.addResourceHandler("/wechat/files/**").addResourceLocations("file:/app/upload/");
+        //registry.addResourceHandler("/wechat/files/**").addResourceLocations("classpath:/file_store");
         registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
     }
 

+ 2 - 0
src/main/java/com/loan/system/constant/JwtClaimsConstant.java

@@ -5,6 +5,8 @@ public class JwtClaimsConstant {
     public static final String EMP_ID = "empId";
     public static final String USER_ID = "userId";
     public static final String PHONE = "phone";
+    public static final String OPENID = "openid";
+    public static final String isCustomer = "isCustomer";
     public static final String USERNAME = "username";
     public static final String NAME = "name";
 

+ 1 - 1
src/main/java/com/loan/system/constant/PasswordConstant.java

@@ -5,6 +5,6 @@ package com.loan.system.constant;
  */
 public class PasswordConstant {
 
-    public static final String DEFAULT_PASSWORD = "123456";
+    public static final String DEFAULT_PASSWORD = "baolutong123456";
 
 }

+ 26 - 48
src/main/java/com/loan/system/controller/admin/AdminController.java

@@ -8,6 +8,7 @@ import com.loan.system.domain.entity.User;
 import com.loan.system.domain.enums.ExceptionEnum;
 import com.loan.system.domain.pojo.Result;
 import com.loan.system.domain.vo.UserLoginVO;
+import com.loan.system.exception.DescribeException;
 import com.loan.system.properties.JwtProperties;
 import com.loan.system.repository.RoleRepository;
 import com.loan.system.service.CustomerService;
@@ -38,8 +39,6 @@ import java.util.Map;
 public class AdminController {//包含内部人员、外部人员
     @Autowired
     private UserService userService;
-    @Autowired
-    private JwtProperties jwtProperties;
 
     @Autowired
     private RoleRepository roleRepository;
@@ -47,11 +46,6 @@ public class AdminController {//包含内部人员、外部人员
     @Autowired
     private CustomerService customerService;
 
-    @Autowired
-    private WxService wxService;
-
-    private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);
-
     /*
     1.先查询user查看是否为内部人员
     2.若不是内部人员,查询外部人员
@@ -60,50 +54,24 @@ public class AdminController {//包含内部人员、外部人员
     @PostMapping("/login")
     @ApiOperation("管理端登陆")
     public Result login(@RequestBody UserLoginDTO userLoginDTO){
-
         //账号密码验证
         User user = userService.getUserByMobile(userLoginDTO.getTel());
-        UserLoginVO userLoginVO = new UserLoginVO();
-
-        //为微信用户生成jwt令牌
-        Map<String ,Object> claims=new HashMap<>();
-        Long userId = null;
-
-        if (!ObjectUtils.isEmpty(user)){
-            userLoginVO.setId(user.getId());
-            userLoginVO.setRole(user.getRole());
-        }else{
+        if(ObjectUtils.isEmpty(user)){
             return ResultUtil.error(ExceptionEnum.USER_NOT_EXIST);
         }
-
-        claims.put(JwtClaimsConstant.USER_ID,userLoginVO.getId());
-        String token = JwtUtil.createJWT(jwtProperties.getUserSecretKey(), jwtProperties.getUserTtl(), claims);
-        userLoginVO.setToken(token);
+        UserLoginVO userLoginVO ;
+        if(userLoginDTO.getIsPassword())
+            userLoginVO=userService.passwordLogin(userLoginDTO.getTel(),userLoginDTO.getPassword());
+        else
+            userLoginVO=userService.codeLogin(userLoginDTO.getTel(),userLoginDTO.getValidCode());
 
         return ResultUtil.success("success", userLoginVO);
     }
 
-//    @PostMapping("/login")
-//    @ApiOperation("账号登陆")
-//    public Result login(@RequestBody UserLoginDTO userLoginDTO){
-//        String phoneNumber=userLoginDTO.getTel();
-//        boolean user_is_exist = userService.existsByMobileAndIsDelete(phoneNumber);
-//        boolean customer_is_exist=customerService.existsBymobileAndIsDelete(phoneNumber);
-//        if(!customer_is_exist&&!user_is_exist){
-//            Customer customer = new Customer();
-//            customer.setMobile(phoneNumber);
-//            customer.setOpenid(userLoginDTO.getOpenid());
-//            return this.register(customer);
-//        }else if(customer_is_exist){
-//            Customer customer=customerService.findBymobileAndIsDelete(phoneNumber);
-//            return this.customer_login(customer);
-//        }else{
-//            return this.user_login(userLoginDTO);
-//        }
-//    }
 
-    @PutMapping("/{id}")
+    @PutMapping("/role/{id}")
     @ApiOperation("更新用户角色")
+    @PreAuthorize("@pms.hasRole('SYSTEM_ADMIN')")
     public Result updateRole(@PathVariable("id") Long id,@RequestBody String role){
         User user1 = userService.findByIdAndIsDelete(id);
         if(ObjectUtils.isEmpty(user1)){
@@ -136,8 +104,18 @@ public class AdminController {//包含内部人员、外部人员
         return ResultUtil.success("success");
     }
 
+    @PutMapping("/{id}")
+    @ApiOperation("更新用户信息")
+    @PreAuthorize("@pms.hasRole('SYSTEM_ADMIN')")
+    public Result updateUser(@PathVariable("id") Long id,@RequestBody UserDTO user){
+        userService.updateUserById(id,user);
+        return ResultUtil.success("success");
+    }
+
+
     @PostMapping("/role")
     @ApiOperation("添加用户角色")
+    @PreAuthorize("@pms.hasRole('SYSTEM_ADMIN')")
     public Result addRole(@RequestParam Long userId, @RequestBody Role role){
         roleRepository.save(role);
         return ResultUtil.success("success");
@@ -164,16 +142,16 @@ public class AdminController {//包含内部人员、外部人员
 
     @GetMapping("/users")
     @ApiOperation("查询所有用户")
-    public Result findAllUsers(Integer pageNum,Integer pageSize,Boolean isDelete){
+    public Result findAllUsers(@RequestParam(defaultValue = "1") Integer pageNum,@RequestParam(defaultValue = "10") Integer pageSize,@RequestParam(required = false) Boolean isDelete){
         return ResultUtil.success("success", userService.getAllUsers(pageNum,pageSize,isDelete));
     }
 
-    @GetMapping("/users/sales")
-    @ApiOperation("查询所有业务员")
-    @PreAuthorize("@pms.hasAnyRoles('SYSTEM_ADMIN','APPROVER')")
-    public Result findAllSales(){
-        return ResultUtil.success("success", userService.getAllSalesByIsDelete(false));
-    }
+//    @GetMapping("/users/sales")
+//    @ApiOperation("查询所有业务员")
+//    @PreAuthorize("@pms.hasAnyRoles('SYSTEM_ADMIN','APPROVER')")
+//    public Result findAllSales(){
+//        return ResultUtil.success("success", userService.getAllSalesByIsDelete(false));
+//    }
 
 
 }

+ 30 - 0
src/main/java/com/loan/system/controller/admin/CustomerController.java

@@ -0,0 +1,30 @@
+package com.loan.system.controller.admin;
+
+import com.loan.system.domain.entity.Customer;
+import com.loan.system.service.CustomerService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+@RestController
+@RequestMapping("/admin/customer")
+@Api(tags = "客户管理")
+public class CustomerController {
+    @Autowired
+    private CustomerService customerService;
+
+    @GetMapping
+    @ApiOperation("获取所有客户信息")
+    public List<Customer> getAllCustomer(Integer pageNum, Integer pageSize) {
+        return customerService.getAllCustomersByAdmin(pageNum, pageSize);
+    }
+
+    @PutMapping("{id}")
+    @ApiOperation("删除客户")
+    public void deleteCustomer(@PathVariable Long id) {
+        customerService.deleteCustomerByLogic(id);
+    }
+}

+ 398 - 0
src/main/java/com/loan/system/controller/admin/DetailsController.java

@@ -0,0 +1,398 @@
+package com.loan.system.controller.admin;
+
+import com.loan.system.config.FileUploadConfig;
+import com.loan.system.domain.entity.*;
+import com.loan.system.domain.enums.StepEnum;
+import com.loan.system.domain.enums.StepPropertyEnum;
+import com.loan.system.domain.pojo.Result;
+import com.loan.system.domain.vo.*;
+import com.loan.system.service.*;
+import com.loan.system.utils.ResultUtil;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.apache.poi.xssf.usermodel.XSSFRow;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@RestController
+@RequestMapping("/admin/details")
+@Api(tags = "业务明细")
+public class DetailsController {
+    @Autowired
+    private LoanService loanService;
+    @Autowired
+    private RepaymentService repaymentService;
+    @Autowired
+    private RepaymentRecordService repaymentRecordService;
+    @Autowired
+    private FileUploadConfig fileUploadConfig;
+    @Autowired
+    private ContractService contractService;
+    @Autowired
+    private ContractRepaymentService contractRepaymentService;
+    @Autowired
+    private CustomerService customerService;
+    @Autowired
+    private CustomerOtherService customerOtherService;
+    @Autowired
+    private RecommenderService recommenderService;
+    @Autowired
+    private StepService stepService;
+    @Autowired
+    private UserService userService;
+    @Autowired
+    private PawnTicketService pawnTicketService;
+    @Autowired
+    private DisbursementService disbursementService;
+    @Autowired
+    private CollateralService collateralService;
+    @Autowired
+    private ContractAndCollateralService contractAndCollateralService;
+
+    @GetMapping("/accountReport")
+    @ApiOperation("获取台账")
+    public Result accountReport(@RequestParam Long caseId, @RequestParam(defaultValue = "0") Integer pageNum, @RequestParam(defaultValue = "10") Integer pageSize) {
+        int begin = pageNum * pageSize;
+        List<LoanCaseDetails> loanCaseDetails = new ArrayList<>();
+        //获取业务信息
+        LoanCaseSimpleVO loanCase = loanService.findLoanCaseSimpleByIdAndIsDelete(caseId, false);
+
+        //获取客户与其它客户信息
+        Customer customer = customerService.findByIdAndIsDelete(loanCase.getCustomerId());
+        List<CustomersOtherVO> customersOtherVOS = customerOtherService.findByCaseId(caseId);
+
+        //获取回款记录信息(核心)
+        List<RepaymentRecord> repaymentRecords = repaymentRecordService.findByRepaymentIdAndIsInterestAndIsDelete(repaymentService.findByCaseIdAndIsDelete(caseId, false).getId(), false);
+        List<Long> recordIds = repaymentRecords.stream().map(RepaymentRecord::getId).collect(Collectors.toList());
+        List<ContractRepayment> contractRepayments = contractRepaymentService.findByRepaymentRecordIdsAndIsDelete(recordIds);
+
+        List<Long> contractIds = contractRepayments.stream().map(ContractRepayment::getContractId).collect(Collectors.toList());
+        for (Long contractId : contractIds) {
+            double amount = 0.0;//累计回款
+            Contract contract = contractService.findContractById(contractId);
+            for (ContractRepayment contractRepayment : contractRepayments) {
+                if (contractRepayment.getContractId().equals(contractId)) {
+                    LoanCaseDetails loanCaseDetail = new LoanCaseDetails();
+
+                    loanCaseDetail.setContractNo(contract.getContractNo());//1
+                    PawnTicketInfo pawnTicketInfo = pawnTicketService.findByContractIdAndIsDelete(contractId);
+                    if(pawnTicketInfo!=null){
+                        loanCaseDetail.setPawnTicketNo(pawnTicketInfo.getPawnTicketNo());//2.
+                        loanCaseDetail.setRedeemTime(pawnTicketInfo.getEndTime());//16.
+                        loanCaseDetail.setRedeemTicketNo(pawnTicketInfo.getRedeemTicketNo());//17.
+                    }
+                    loanCaseDetail.setLoanTime(disbursementService.getLoanTime(caseId));//3.
+                    loanCaseDetail.setCustomerName(customer.getName());//4.
+                    loanCaseDetail.setCustomerName2(customersOtherVOS.get(0).getName());//5.
+                    loanCaseDetail.setPhoneNumber(customer.getMobile());//6.
+                    loanCaseDetail.setPawnAmount(loanCase.getTotalLoanAmount());//7.
+                    List<String> attributes = new ArrayList<>();
+                    List<String> locations = new ArrayList<>();
+                    List<ContractAndCollateral> contractAndCollaterals = contractAndCollateralService.listByContractId(contractId);
+                    for (ContractAndCollateral contractAndCollateral : contractAndCollaterals) {
+                        if (contractAndCollateral.getContractId().equals(contractId)){
+                            Collateral collateral = collateralService.findCollateralById(contractAndCollateral.getCollateralId());
+                            attributes.add(contract.getBusinessAttr());
+                            locations.add(collateral.getAddress());
+                        }
+                    }
+                    loanCaseDetail.setLocations( locations);
+                    loanCaseDetail.setAttributes(attributes);
+
+                    loanCaseDetail.setChannelName(loanCase.getChannelName());//9.
+                    List<String> userNames=new ArrayList<>();
+                    StepVO stepVO = stepService.findByStepNameAndCaseId(StepPropertyEnum.BUSINESS_ACCEPT.getLabel(), caseId);
+                    StepVO stepVO1 = stepService.findByStepNameAndCaseId(StepPropertyEnum.PRE_TRIAL.getLabel(), caseId);
+                    if(stepVO!=null){
+                        userNames.add(userService.findByIdAndIsDelete(stepVO.getUserId1()).getRealName());
+                    }
+                    if(stepVO1!=null){
+                        userNames.add(userService.findByIdAndIsDelete(stepVO1.getUserId1()).getRealName());
+                    }
+                    loanCaseDetail.setUserName(userNames);//10.
+
+                    amount += contractRepayment.getAmount();
+                    loanCaseDetail.setRepayTime(contractRepayment.getCreateTime());//11.
+                    loanCaseDetail.setRepayTotalAmount(amount);//12
+                    loanCaseDetail.setLastRepayAmount(contractRepayment.getAmount());//13.
+                    loanCaseDetail.setBalance(loanCase.getTotalLoanAmount() - amount);//14.
+                    if(Math.abs(loanCase.getTotalLoanAmount() - amount)<Double.MIN_VALUE)
+                        loanCaseDetail.setInterestAmount(contract.getInterestAmount());//15.
+
+                    loanCaseDetails.add(loanCaseDetail);
+                }
+
+            }
+        }
+
+        return ResultUtil.success("success", loanCaseDetails.stream().skip( begin).limit(pageSize).collect(Collectors.toList()));
+    }
+
+    @GetMapping("/accountReport/export")
+    @ApiOperation("导出台账")//begin从1开始
+    public void exportAccountReport(@RequestBody List<LoanCaseDetails> loanCaseDetails, @RequestParam Integer begin, @RequestParam Integer end, HttpServletResponse response) {
+        //查询概览运营数据,提供给Excel模板文件
+        InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(fileUploadConfig.getUploadDir() + "业务台账.xlsx");
+        try {
+            //基于提供好的模板文件创建一个新的Excel表格对象
+            XSSFWorkbook excel = new XSSFWorkbook(inputStream);
+
+            //获得Excel文件中的一个Sheet页
+            XSSFSheet sheet = excel.getSheet("Sheet1");
+            //TODO:row(从0开始)行,cell(从0开始)获取单元格
+            //获得第1行
+            XSSFRow row = sheet.getRow(1);
+            //获取单元格
+            for (int i = begin; i < end; i++) {
+                LoanCaseDetails loanCaseDetail = loanCaseDetails.get(i);
+                row = sheet.getRow(i);
+                row.getCell(0).setCellValue(loanCaseDetail.getContractNo());
+                row.getCell(1).setCellValue(loanCaseDetail.getPawnTicketNo());
+                row.getCell(2).setCellValue(loanCaseDetail.getLoanTime());
+                row.getCell(3).setCellValue(loanCaseDetail.getCustomerName());
+                row.getCell(4).setCellValue(loanCaseDetail.getCustomerName2());
+                row.getCell(5).setCellValue(loanCaseDetail.getPhoneNumber());
+                row.getCell(6).setCellValue(loanCaseDetail.getPawnAmount());
+                row.getCell(7).setCellValue(loanCaseDetail.getLocations().toString());
+                row.getCell(8).setCellValue(loanCaseDetail.getAttributes().toString());
+                row.getCell(9).setCellValue(loanCaseDetail.getChannelName());
+                row.getCell(10).setCellValue(loanCaseDetail.getUserName().toString());
+                row.getCell(11).setCellValue(loanCaseDetail.getRepayTime());
+                row.getCell(12).setCellValue(loanCaseDetail.getRepayTotalAmount());
+                row.getCell(13).setCellValue(loanCaseDetail.getLastRepayAmount());
+                row.getCell(14).setCellValue(loanCaseDetail.getBalance());
+                row.getCell(15).setCellValue(loanCaseDetail.getInterestAmount());
+                row.getCell(16).setCellValue(loanCaseDetail.getRedeemTime());
+                row.getCell(17).setCellValue(loanCaseDetail.getRedeemTicketNo());
+                row.getCell(18).setCellValue(loanCaseDetail.getComment());
+
+            }
+
+            //通过输出流将文件下载到客户端浏览器中
+            ServletOutputStream out = response.getOutputStream();
+            excel.write(out);
+
+            //关闭资源
+            out.flush();
+            out.close();
+            excel.close();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    @GetMapping("/disbursementReport")
+    @ApiOperation("获取出款报表")
+    public Result disbursementReport(@RequestParam Long caseId,@RequestParam(defaultValue = "0") Integer pageNum,@RequestParam(defaultValue = "10") Integer pageSize) {
+        int begin = pageNum * pageSize;
+        List<DisbursementDetails> disbursementDetails = new ArrayList<>();
+
+        //获取业务信息
+        LoanCaseSimpleVO loanCase = loanService.findLoanCaseSimpleByIdAndIsDelete(caseId, false);
+        //获取合同信息
+        List<ContractVO> contractVOS = contractService.findContractByCaseId(caseId);
+        for(ContractVO contractVO : contractVOS){
+            DisbursementDetails disbursementDetail = new DisbursementDetails();
+
+            disbursementDetail.setContractNo(contractVO.getContractNo());//1.
+            PawnTicketInfo pawnTicketInfo = pawnTicketService.findByContractIdAndIsDelete(contractVO.getId());
+            if(pawnTicketInfo!=null){
+                disbursementDetail.setPawnTicketNo(pawnTicketInfo.getPawnTicketNo());//2.
+                disbursementDetail.setRedeemTime(pawnTicketInfo.getEndTime());//9.
+                disbursementDetail.setRedeemTicketNo(pawnTicketInfo.getRedeemTicketNo());//10.
+            }
+            disbursementDetail.setLoanTime(disbursementService.getLoanTime(caseId));//3.
+
+            disbursementDetail.setCustomerName(customerService.findByCustomerIdAndIsDelete(loanCase.getCustomerId(), false).getName());//4.
+            disbursementDetail.setPawnAmount(contractVO.getContractAmount());//5.
+            List<String> userNames=new ArrayList<>();
+            StepVO stepVO = stepService.findByStepNameAndCaseId(StepPropertyEnum.BUSINESS_ACCEPT.getLabel(), caseId);
+            StepVO stepVO1 = stepService.findByStepNameAndCaseId(StepPropertyEnum.PRE_TRIAL.getLabel(), caseId);
+            if(stepVO!=null){
+                userNames.add(userService.findByIdAndIsDelete(stepVO.getUserId1()).getRealName());
+            }
+            if(stepVO1!=null){
+                userNames.add(userService.findByIdAndIsDelete(stepVO1.getUserId1()).getRealName());
+            }
+            disbursementDetail.setUserName(userNames);//6.
+            disbursementDetail.setRecommenderName(recommenderService.getRecommenderById(loanCase.getRecommenderId()).getRecommenderName());//7.
+            disbursementDetail.setChannelName(loanCase.getChannelName());//8.
+
+            disbursementDetails.add(disbursementDetail);
+        }
+
+        //获取当票
+        return ResultUtil.success("success", disbursementDetails.stream().skip( begin).limit(pageSize).collect(Collectors.toList()));
+    }
+
+    @GetMapping("/disbursementReport/export")
+    @ApiOperation("导出出款报表")
+    public void exportDisbursementReport(@RequestBody List<DisbursementDetails> disbursementDetails, @RequestParam Integer begin, @RequestParam Integer end, HttpServletResponse response) {
+        //查询概览运营数据,提供给Excel模板文件
+        InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(fileUploadConfig.getUploadDir() + "出账明细.xlsx");
+        try {
+            //基于提供好的模板文件创建一个新的Excel表格对象
+            XSSFWorkbook excel = new XSSFWorkbook(inputStream);
+
+            //获得Excel文件中的一个Sheet页
+            XSSFSheet sheet = excel.getSheet("Sheet1");
+            //TODO:row(从0开始)行,cell(从0开始)获取单元格
+            //获得第1行
+            XSSFRow row = sheet.getRow(1);
+            //获取单元格
+            for (int i = begin; i < end; i++) {
+                DisbursementDetails disbursementDetail = disbursementDetails.get(i);
+                row = sheet.getRow(i);
+                row.getCell(0).setCellValue(disbursementDetail.getContractNo());
+                row.getCell(1).setCellValue(disbursementDetail.getLoanTime());
+                row.getCell(2).setCellValue(disbursementDetail.getPawnTicketNo());
+                row.getCell(3).setCellValue(disbursementDetail.getCustomerName());
+                row.getCell(4).setCellValue(disbursementDetail.getPawnAmount());
+                row.getCell(5).setCellValue(disbursementDetail.getUserName().toString());
+                row.getCell(6).setCellValue(disbursementDetail.getRecommenderName());
+                row.getCell(7).setCellValue(disbursementDetail.getChannelName());
+                row.getCell(8).setCellValue(disbursementDetail.getRedeemTime());
+                row.getCell(9).setCellValue(disbursementDetail.getRedeemTicketNo());
+
+            }
+
+            //通过输出流将文件下载到客户端浏览器中
+            ServletOutputStream out = response.getOutputStream();
+            excel.write(out);
+
+            //关闭资源
+            out.flush();
+            out.close();
+            excel.close();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    @GetMapping("/repaymentReport")
+    @ApiOperation("获取回款报表")
+    public Result repaymentReport(@RequestParam Long caseId,@RequestParam(defaultValue = "0") Integer pageNum,@RequestParam(defaultValue = "10") Integer pageSize) {
+        int begin = pageNum * pageSize;
+        List<RepaymentDetails> repaymentDetails = new ArrayList<>();
+        //获取当票信息
+
+        //获取业务信息
+        LoanCaseSimpleVO loanCase = loanService.findLoanCaseSimpleByIdAndIsDelete(caseId, false);
+
+        //获取客户与其它客户信息
+        Customer customer = customerService.findByIdAndIsDelete(loanCase.getCustomerId());
+
+        //获取回款记录信息(核心)
+        List<RepaymentRecord> repaymentRecords = repaymentRecordService.findByRepaymentIdAndIsInterestAndIsDelete(repaymentService.findByCaseIdAndIsDelete(caseId, false).getId(), false);
+        List<Long> recordIds = repaymentRecords.stream().map(RepaymentRecord::getId).collect(Collectors.toList());
+        List<ContractRepayment> contractRepayments = contractRepaymentService.findByRepaymentRecordIdsAndIsDelete(recordIds);
+
+        List<Long> contractIds = contractRepayments.stream().map(ContractRepayment::getContractId).collect(Collectors.toList());
+        for (Long contractId : contractIds) {
+            double amount = 0.0;//累计回款
+            Contract contract = contractService.findContractById(contractId);
+            for (ContractRepayment contractRepayment : contractRepayments) {
+                if (contractRepayment.getContractId().equals(contractId)) {
+                    RepaymentDetails repaymentDetail = new RepaymentDetails();
+
+                    repaymentDetail.setContractNo(contract.getContractNo());//1
+                    PawnTicketInfo pawnTicketInfo = pawnTicketService.findByContractIdAndIsDelete(contractId);
+                    if(pawnTicketInfo!=null){
+                        repaymentDetail.setPawnTicketNo(pawnTicketInfo.getPawnTicketNo());//2.
+                        repaymentDetail.setRedeemTicketNo(pawnTicketInfo.getRedeemTicketNo());//10.
+                    }
+                    repaymentDetail.setLoanTime(disbursementService.getLoanTime(caseId));//3.
+                    repaymentDetail.setCustomerName(customer.getName());//4.
+                    repaymentDetail.setPawnAmount(loanCase.getTotalLoanAmount());//5.
+                    repaymentDetail.setRepayTime(contractRepayment.getCreateTime());//6.
+                    repaymentDetail.setRepayAmount(contractRepayment.getAmount());//7.
+                    amount += contractRepayment.getAmount();
+                    repaymentDetail.setBalance(loanCase.getTotalLoanAmount() - amount);//8.
+                    if(Math.abs(loanCase.getTotalLoanAmount() - amount)<Double.MIN_VALUE)
+                        repaymentDetail.setInterestAmount(contract.getInterestAmount());//9.
+                    List<String> userNames=new ArrayList<>();
+                    StepVO stepVO = stepService.findByStepNameAndCaseId(StepPropertyEnum.BUSINESS_ACCEPT.getLabel(), caseId);
+                    StepVO stepVO1 = stepService.findByStepNameAndCaseId(StepPropertyEnum.PRE_TRIAL.getLabel(), caseId);
+                    if(stepVO!=null){
+                        userNames.add(userService.findByIdAndIsDelete(stepVO.getUserId1()).getRealName());
+                    }
+                    if(stepVO1!=null){
+                        userNames.add(userService.findByIdAndIsDelete(stepVO1.getUserId1()).getRealName());
+                    }
+                    repaymentDetail.setUserName(userNames);//11.
+                    repaymentDetail.setRecommenderName(recommenderService.getRecommenderById(loanCase.getRecommenderId()).getRecommenderName());//12.
+                    repaymentDetail.setChannelName(loanCase.getChannelName());//13.
+
+                    repaymentDetails.add(repaymentDetail);
+                }
+
+            }
+        }
+
+        return ResultUtil.success("success", repaymentDetails.stream().skip( begin).limit(pageSize).collect(Collectors.toList()));
+    }
+
+    @GetMapping("/repaymentReport/export")
+    @ApiOperation("导出回款报表")
+    public void exportRepaymentReport(@RequestBody List<RepaymentDetails> repaymentDetails, @RequestParam Integer begin, @RequestParam Integer end, HttpServletResponse response) {
+        //查询概览运营数据,提供给Excel模板文件
+        InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(fileUploadConfig.getUploadDir() + "出账明细.xlsx");
+        try {
+            //基于提供好的模板文件创建一个新的Excel表格对象
+            XSSFWorkbook excel = new XSSFWorkbook(inputStream);
+
+            //获得Excel文件中的一个Sheet页
+            XSSFSheet sheet = excel.getSheet("Sheet1");
+            //TODO:row(从0开始)行,cell(从0开始)获取单元格
+            //获得第1行
+            XSSFRow row = sheet.getRow(1);
+            int index=1;
+            //获取单元格
+            for (int i = begin; i < end; i++) {
+                RepaymentDetails repaymentDetail = repaymentDetails.get(i);
+                row = sheet.getRow(index);
+                row.getCell(0).setCellValue(repaymentDetail.getContractNo());
+                row.getCell(1).setCellValue(repaymentDetail.getPawnTicketNo());
+                row.getCell(2).setCellValue(repaymentDetail.getLoanTime());
+                row.getCell(3).setCellValue(repaymentDetail.getCustomerName());
+                row.getCell(4).setCellValue(repaymentDetail.getPawnAmount());
+                row.getCell(5).setCellValue(repaymentDetail.getRepayTime());
+                row.getCell(6).setCellValue(repaymentDetail.getRepayAmount());
+                row.getCell(7).setCellValue(repaymentDetail.getBalance());
+                row.getCell(8).setCellValue(repaymentDetail.getInterestAmount());
+                row.getCell(9).setCellValue(repaymentDetail.getRedeemTicketNo());
+                row.getCell(10).setCellValue(repaymentDetail.getUserName().toString());
+                row.getCell(11).setCellValue(repaymentDetail.getRecommenderName());
+                row.getCell(12).setCellValue(repaymentDetail.getChannelName());
+                row.getCell(13).setCellValue(repaymentDetail.getComment());
+
+                index++;
+            }
+
+            //通过输出流将文件下载到客户端浏览器中
+            ServletOutputStream out = response.getOutputStream();
+            excel.write(out);
+
+            //关闭资源
+            out.flush();
+            out.close();
+            excel.close();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+
+}

+ 68 - 0
src/main/java/com/loan/system/controller/admin/DictionaryController.java

@@ -0,0 +1,68 @@
+package com.loan.system.controller.admin;
+
+import com.loan.system.domain.dto.DictDataDTO;
+import com.loan.system.domain.dto.DictTypeDTO;
+import com.loan.system.domain.enums.ExceptionEnum;
+import com.loan.system.domain.pojo.Result;
+import com.loan.system.domain.vo.DictionarysVO;
+import com.loan.system.exception.DescribeException;
+import com.loan.system.service.DictionaryService;
+import com.loan.system.utils.ResultUtil;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+@RestController("AdminDictionaryController")
+@RequestMapping("/admin/dictionary")
+@Api(tags = "字典表接口")
+public class DictionaryController {
+    @Autowired
+    private DictionaryService dictionaryService;
+
+    @GetMapping
+    @ApiOperation("查询所有字典数据")
+    public Result getDictionarys(){
+        return ResultUtil.success("success",dictionaryService.listDictData());
+    }
+
+    @PostMapping
+    @ApiOperation("添加字典数据")
+    public Result addDictionary(@RequestBody DictDataDTO dataDTO){
+        if (dataDTO==null || dataDTO.getDictLabel()==null || dataDTO.getDictValue()==null || dataDTO.getDictType()==null)
+            throw  new DescribeException(ExceptionEnum.INPUT_ERROR);
+        dictionaryService.addDictData(dataDTO);
+        return ResultUtil.success("success");
+    }
+
+    @PutMapping("/{id}")
+    @ApiOperation("修改字典数据")
+    public Result updateDictionary(@PathVariable Long id,@RequestBody DictDataDTO dataDTO){
+        dictionaryService.updateDictData(dataDTO,id);
+        return ResultUtil.success("success");
+    }
+
+    @GetMapping("/types")
+    @ApiOperation("查询所有字典类型")
+    public Result getAllTypes(){
+        return ResultUtil.success("success",dictionaryService.listDictType());
+    }
+
+    @PutMapping("/types/{id}")
+    @ApiOperation("修改字典类型")
+    public Result updateType(@PathVariable Long id, @RequestBody DictTypeDTO dictTypeDTO){
+        dictionaryService.updateDictType(dictTypeDTO,id);
+        return ResultUtil.success("success");
+    }
+
+    @PostMapping("/types")
+    @ApiOperation("添加字典类型")
+    public Result addType(@RequestBody DictTypeDTO dictTypeDTO){
+        if (dictTypeDTO==null || dictTypeDTO.getDictName()==null || dictTypeDTO.getDictType()==null)
+            throw  new DescribeException(ExceptionEnum.INPUT_ERROR);
+        dictionaryService.addDictType(dictTypeDTO);
+        return ResultUtil.success("success");
+    }
+
+
+}

+ 11 - 0
src/main/java/com/loan/system/controller/admin/MaterialsController.java

@@ -0,0 +1,11 @@
+package com.loan.system.controller.admin;
+
+import io.swagger.annotations.Api;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/admin/materials")
+@Api(tags = "资料归档管理")
+public class MaterialsController {
+}

+ 24 - 1
src/main/java/com/loan/system/controller/admin/RecommenderController.java

@@ -1,26 +1,47 @@
 package com.loan.system.controller.admin;
 
 import com.loan.system.domain.dto.BizRecommenderDTO;
+import com.loan.system.domain.entity.BizRecommender;
 import com.loan.system.domain.pojo.Result;
 import com.loan.system.service.RecommenderService;
+import com.loan.system.service.UserService;
 import com.loan.system.utils.ResultUtil;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
+import java.util.List;
+import java.util.stream.Collectors;
+
 @RestController
 @RequestMapping("/admin/recommender")
 @Api(tags = "推荐人管理")
 public class RecommenderController {
     @Autowired
     private RecommenderService recommenderService;
+    @Autowired
+    private UserService userService;
 
     @GetMapping
-    @ApiOperation("查询推荐人")
+    @ApiOperation("查询所有推荐人")
     public Result getRecommenders(Integer pageNum, Integer pageSize){
         return ResultUtil.success("success",recommenderService.getRecommenders(pageNum, pageSize));
     }
+    @GetMapping("/group")
+    @ApiOperation("按组别查询所有推荐人")
+    public Result findAllRecommenders(){
+        List<BizRecommender> allRecommenders = userService.getAllRecommenders(false);
+
+        return ResultUtil.success("success", allRecommenders.stream()
+                .collect(Collectors.groupingBy(
+                                BizRecommender::getChannelName,         // 第一层 key:channel
+                                Collectors.groupingBy(
+                                        BizRecommender::getGroup,   // 第二层 key:group
+                                        Collectors.toList()) // 第三层
+                        )
+                ));
+    }
 
     @PostMapping
     @ApiOperation("添加推荐人")
@@ -39,4 +60,6 @@ public class RecommenderController {
     }
 
 
+
+
 }

+ 159 - 224
src/main/java/com/loan/system/controller/wechat/ApprovalController.java

@@ -1,6 +1,7 @@
 package com.loan.system.controller.wechat;
 
 import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.util.ObjectUtil;
 import com.loan.system.context.BaseContext;
 import com.loan.system.domain.dto.ApprovalDTO;
 import com.loan.system.domain.dto.PreApprovalDTO;
@@ -10,10 +11,12 @@ import com.loan.system.domain.enums.StepEnum;
 import com.loan.system.domain.enums.StepPropertyEnum;
 import com.loan.system.domain.pojo.Result;
 import com.loan.system.domain.vo.*;
+import com.loan.system.exception.DescribeException;
 import com.loan.system.properties.JwtProperties;
 import com.loan.system.service.*;
 import com.loan.system.service.Impl.UserServiceImpl;
 import com.loan.system.utils.JwtUtil;
+import com.loan.system.utils.RedisData;
 import com.loan.system.utils.ResultUtil;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
@@ -21,9 +24,12 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Bean;
+import org.springframework.data.redis.core.StringRedisTemplate;
 import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.util.ObjectUtils;
 import org.springframework.web.bind.annotation.*;
 
+import javax.annotation.Resource;
 import javax.servlet.http.HttpServletRequest;
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
@@ -40,87 +46,54 @@ import static com.loan.system.domain.enums.ExceptionEnum.*;
 public class ApprovalController {
     private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);
     @Autowired
-    private UserService userService;
-    @Autowired
-    private CustomerService customerService;
-    @Autowired
     private LoanService loanCaseService;
     @Autowired
     private ApprovalService approvalService;
     @Autowired
-    private DocumentService documentService;
-    @Autowired
     private StepService stepService;
     @Autowired
-    private JwtProperties jwtProperties;
-    @Autowired
-    private MessageService messageService;
-//    @Autowired
-//    private WxService wxService;
+    private StringRedisTemplate stringRedisTemplate;
 
     @GetMapping("preApproval/detail")
     @ApiOperation("获取预审审详情")
     @PreAuthorize("@pms.hasAnyRoles('SYSTEM_ADMIN','APPROVER','LEAD_SALES', 'ASSIST_SALES', 'FINANCE', 'BACK_OFFICE')")
     public Result getPreApprovalDetail(@RequestParam Long caseId) {
-        ApprovalVO approvalVO = new ApprovalVO();
-        StepVO stepVO = stepService.findByStepNameAndCaseId(StepPropertyEnum.PRE_TRIAL.getLabel(), caseId);
-        Map<UserVO,String> decision=new HashMap<>();
-        Map<UserVO,String> comment=new HashMap<>();
-
-        if (stepVO.getUserId2()!=null){
-            User user=userService.findByIdAndIsDelete(stepVO.getUserId2());
-            ApprovalRecordVO approvalRecordVO = approvalService.findByCaseIdAndIsDeleteAndStepName(caseId, StepPropertyEnum.APPROVAL.getLabel(), user.getId());
-            decision.put(BeanUtil.copyProperties(user,UserVO.class),approvalRecordVO.getDecision());
-            comment.put(BeanUtil.copyProperties(user,UserVO.class),approvalRecordVO.getComments());
-        }
+        if (ObjectUtils.isEmpty(caseId) || !loanCaseService.existsByIdAndIsDelete(caseId))
+            throw new DescribeException(PROJECT_NOT_EXIST);
 
-        return ResultUtil.success("success",approvalVO);
+        return ResultUtil.success("success",approvalService.findByCaseIdAndStepNameAndIsDelete(caseId,StepPropertyEnum.PRE_TRIAL.getLabel()));
     }
 
     @PostMapping("/preapproval-assist/pass")
     @PreAuthorize("@pms.hasRole('ASSIST_SALES')")
     @ApiOperation("副业务员审核")
     public Result pre_approval_save_primary(@RequestBody PreApprovalDTO preApprovalDTO) {
+        if(ObjectUtils.isEmpty(preApprovalDTO)||ObjectUtils.isEmpty(preApprovalDTO.getCaseId()))
+            throw new DescribeException(INPUT_ERROR);
+
         Long userId= BaseContext.getCurrentId();
-        log.info("用户id: {}", userId);
-        User user = userService.findByIdAndIsDelete(userId);
-        log.info("用户: {}", user.getMobile());
-        LoanCase loanCase = loanCaseService.findLoanCaseByIdAndIsDelete(preApprovalDTO.getCaseId(),false);
+        Long caseId=preApprovalDTO.getCaseId();
+        LoanCase loanCase = loanCaseService.findLoanCaseByIdAndIsDelete(caseId,false);
         if(loanCase == null||loanCase.getIsDelete()){
             return ResultUtil.error(PROJECT_NOT_EXIST.getCode(), PROJECT_NOT_EXIST.getMsg());
         }
-        StepVO step = stepService.findByStepNameAndCaseId(StepPropertyEnum.PRE_TRIAL.getLabel(), preApprovalDTO.getCaseId());
-        if(step.getUserId2()!=null&&userId!=step.getUserId2()){
-            return ResultUtil.error(STEP_USER_NOT_EXPECTED.getCode(), "环节处理人不是预期用户");
-        }
-        if(step.getStatus()==StepEnum.COMPLETED.getMsg()){
-            return ResultUtil.error(STEP_HAS_COMPLETEED.getCode(), "环节已完成,无法重复审批");
-        }
-        ApprovalRecordVO approvalRecord_origin = approvalService.findByCaseIdAndIsDeleteAndStepName(preApprovalDTO.getCaseId(),StepPropertyEnum.PRE_TRIAL.getLabel(),userId);
-        if (approvalRecord_origin == null) {
-            // 创建审批记录
-            ApprovalRecord approvalRecord = new ApprovalRecord();
-            approvalRecord.setCaseId(preApprovalDTO.getCaseId());
-            approvalRecord.setStepName(StepPropertyEnum.PRE_TRIAL.getLabel());
-            approvalRecord.setApproverId(user.getId());
-            approvalRecord.setDecision(DecisionEnum.PASS.getMsg());
-            approvalRecord.setComments(preApprovalDTO.getComments());
-            approvalRecord.setCreateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
-            approvalRecord.setUpdateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
-            approvalRecord.setIsDelete(false);
-            // 保存到数据库
-            approvalService.save(approvalRecord);
-            stepService.updateUserId2ByCaseIdAndStepName(StepPropertyEnum.PRE_TRIAL.getLabel(), user.getId(), preApprovalDTO.getCaseId());
-        }else {
-            approvalService.updateDecisionByCaseIdAndStepNameAndIsDelete(DecisionEnum.PASS.getMsg(), preApprovalDTO.getCaseId(), StepPropertyEnum.PRE_TRIAL.getLabel(), preApprovalDTO.getComments(), userId);
-        }
-        stepService.updateUserId2ByCaseIdAndStepName(StepPropertyEnum.PRE_TRIAL.getLabel(),userId,preApprovalDTO.getCaseId());
+        StepVO step = stepService.findByStepNameAndCaseId(StepPropertyEnum.PRE_TRIAL.getLabel(), caseId);
+        if(ObjectUtils.isEmpty(step)||!step.getStatus().equals(StepEnum.PROCESS.getMsg()))
+            throw new DescribeException(STEP_HAS_NOT_PROCESS);
+
+        //如果当前业务员与第一个业务员相同 或 当前业务员与第二个业务员不同 则报错
+        if((step.getUserId1()!=null && step.getUserId1().equals(userId)) || (step.getUserId2()!=null&&userId!=step.getUserId2()))
+            throw new DescribeException(STEP_USER_NOT_EXPECTED);
+
+        //添加记录
+        approvalService.addApprovalRecord(caseId,StepPropertyEnum.PRE_TRIAL.getLabel(),DecisionEnum.PASS.getMsg(),preApprovalDTO.getComments());
+
+        stepService.updateUserId1ByCaseIdAndStepName(StepPropertyEnum.PRE_TRIAL.getLabel(),userId,caseId);
         //更新步骤状态
-        stepService.updateStatusByCaseId(StepEnum.COMPLETED.getMsg(), StepPropertyEnum.PRE_TRIAL_PARENT.getLabel(), preApprovalDTO.getCaseId());
-        stepService.updateStatusByCaseId(StepEnum.COMPLETED.getMsg(), StepPropertyEnum.PRE_TRIAL.getLabel(), preApprovalDTO.getCaseId());
-        stepService.updateStatusByCaseId(StepEnum.PROCESS.getMsg(), StepPropertyEnum.APPROVAL_PARENT.getLabel(), preApprovalDTO.getCaseId());
-        stepService.updateStatusByCaseId(StepEnum.PROCESS.getMsg(), StepPropertyEnum.APPROVAL.getLabel(), preApprovalDTO.getCaseId());
-        loanCaseService.updateUpdatetimeByIdAndIsDeleted(preApprovalDTO.getCaseId(),false);
+        stepService.updateStatusByCaseId(StepEnum.COMPLETED.getMsg(), StepPropertyEnum.PRE_TRIAL_PARENT.getLabel(),caseId);
+        stepService.updateStatusByCaseId(StepEnum.COMPLETED.getMsg(), StepPropertyEnum.PRE_TRIAL.getLabel(), caseId);
+        stepService.tryStartStep(StepPropertyEnum.PRE_TRIAL.getLabel(),caseId);
+        loanCaseService.updateUpdatetimeByIdAndIsDeleted(caseId,false);
         //TODO:微信推送预审通过消息和通知下一环节
 //        SysMessage message = new SysMessage();
 //        message.setMobile(null);
@@ -182,47 +155,35 @@ public class ApprovalController {
     @PreAuthorize("@pms.hasAnyRoles('LEAD_SALES','ASSIST_SALES')")
     @ApiOperation("业务预审拒绝")
     public Result pre_approval_reject(@RequestBody PreApprovalDTO preApprovalDTO) {
+        if(ObjectUtils.isEmpty(preApprovalDTO)||ObjectUtils.isEmpty(preApprovalDTO.getCaseId()))
+            throw new DescribeException(INPUT_ERROR);
+
         Long userId= BaseContext.getCurrentId();
-        log.info("用户id: {}", userId);
-        User user = userService.findByIdAndIsDelete(userId);
-        log.info("用户: {}", user.getMobile());
-        LoanCase loanCase = loanCaseService.findLoanCaseByIdAndIsDelete(preApprovalDTO.getCaseId(),false);
-        StepVO step = stepService.findByStepNameAndCaseId(StepPropertyEnum.PRE_TRIAL.getLabel(), preApprovalDTO.getCaseId());
+        Long caseId = preApprovalDTO.getCaseId();
+
+        LoanCase loanCase = loanCaseService.findLoanCaseByIdAndIsDelete(caseId,false);
+        StepVO step = stepService.findByStepNameAndCaseId(StepPropertyEnum.PRE_TRIAL.getLabel(),caseId);
+        if(ObjectUtils.isEmpty(step)||!step.getStatus().equals(StepEnum.PROCESS.getMsg()))
+            throw new DescribeException(STEP_HAS_NOT_PROCESS);
+
         //判断过去处理人与目前处理人是否一致
-        if(step.getUserId2()!=null&&userId!=step.getUserId2()){
-            return ResultUtil.error(STEP_USER_NOT_EXPECTED.getCode(), "环节处理人不是预期用户");
-        }
-        if(step.getStatus()==StepEnum.COMPLETED.getMsg()){
-            return ResultUtil.error(STEP_HAS_COMPLETEED.getCode(), "环节已完成,无法重复审批");
-        }
+        if(step.getUserId2()!=null&&userId!=step.getUserId2())
+            throw new DescribeException(STEP_USER_NOT_EXPECTED);
+
         if(loanCase == null||loanCase.getIsDelete()){
             return ResultUtil.error(PROJECT_NOT_EXIST.getCode(), PROJECT_NOT_EXIST.getMsg());
         }
-        ApprovalRecordVO approvalRecord_origin = approvalService.findByCaseIdAndIsDeleteAndStepName(preApprovalDTO.getCaseId(),StepPropertyEnum.PRE_TRIAL.getLabel(),userId);
-        if(approvalRecord_origin == null) {
-            log.info("没找到对应以前审批记录");
-            // 创建审批记录
-            ApprovalRecord approvalRecord = new ApprovalRecord();
-            approvalRecord.setCaseId(preApprovalDTO.getCaseId());
-            approvalRecord.setStepName(StepPropertyEnum.PRE_TRIAL.getLabel());
-            approvalRecord.setApproverId(userId);
-            approvalRecord.setDecision(DecisionEnum.REJECT.getMsg());
-            approvalRecord.setComments(preApprovalDTO.getComments());
-            approvalRecord.setCreateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
-            approvalRecord.setUpdateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
-            approvalRecord.setIsDelete(false);
-            // 保存到数据库
-            approvalService.save(approvalRecord);
-        }else{
-            log.info("找到对应以前审批记录");
-            approvalService.updateDecisionByCaseIdAndStepNameAndIsDelete(DecisionEnum.REJECT.getMsg(),preApprovalDTO.getCaseId(),StepPropertyEnum.PRE_TRIAL.getLabel(),preApprovalDTO.getComments(),userId);
-        }
-        stepService.updateUserId2ByCaseIdAndStepName(StepPropertyEnum.PRE_TRIAL.getLabel(),userId,preApprovalDTO.getCaseId());
-        stepService.updateStatusByCaseId(StepEnum.PROCESS.getMsg(),StepPropertyEnum.BUSINESS_ACCEPT.getLabel(),preApprovalDTO.getCaseId());
-        stepService.updateStatusByCaseId(StepEnum.PROCESS.getMsg(),StepPropertyEnum.BUSINESS_ACCEPT_PARENT.getLabel(),preApprovalDTO.getCaseId());
-        stepService.updateStatusByCaseId(StepEnum.UNSTART.getMsg(),StepPropertyEnum.PRE_TRIAL_PARENT.getLabel(),preApprovalDTO.getCaseId());
-        stepService.updateStatusByCaseId(StepEnum.UNSTART.getMsg(),StepPropertyEnum.PRE_TRIAL.getLabel(),preApprovalDTO.getCaseId());
-        loanCaseService.updateUpdatetimeByIdAndIsDeleted(preApprovalDTO.getCaseId(),false);
+        //添加记录
+        approvalService.addApprovalRecord(caseId,StepPropertyEnum.PRE_TRIAL.getLabel(),DecisionEnum.REJECT.getMsg(),preApprovalDTO.getComments());
+        RedisData redisData = new RedisData(stringRedisTemplate);
+        redisData.setRejectApprovalRecord(caseId,StepPropertyEnum.BUSINESS_ACCEPT.getLabel(),preApprovalDTO.getComments());
+
+        stepService.updateUserId2ByCaseIdAndStepName(StepPropertyEnum.PRE_TRIAL.getLabel(),userId,caseId);
+        stepService.updateStatusByCaseId(StepEnum.PROCESS.getMsg(),StepPropertyEnum.BUSINESS_ACCEPT.getLabel(),caseId);
+        stepService.updateStatusByCaseId(StepEnum.PROCESS.getMsg(),StepPropertyEnum.BUSINESS_ACCEPT_PARENT.getLabel(),caseId);
+        stepService.updateStatusByCaseId(StepEnum.UNSTART.getMsg(),StepPropertyEnum.PRE_TRIAL_PARENT.getLabel(),caseId);
+        stepService.updateStatusByCaseId(StepEnum.UNSTART.getMsg(),StepPropertyEnum.PRE_TRIAL.getLabel(),caseId);
+        loanCaseService.updateUpdatetimeByIdAndIsDeleted(caseId,false);
         //TODO:微信推送预审拒绝消息和通知下一环节
 //        SysMessage message = new SysMessage();
 //        message.setMobile(null);
@@ -242,79 +203,74 @@ public class ApprovalController {
     @ApiOperation("获取审批详情")
     @PreAuthorize("@pms.hasAnyRoles('SYSTEM_ADMIN','APPROVER','LEAD_SALES', 'ASSIST_SALES', 'FINANCE', 'BACK_OFFICE')")
     public Result getApprovalDetail(@RequestParam Long caseId) {
-        ApprovalVO approvalVO = new ApprovalVO();
-        StepVO stepVO = stepService.findByStepNameAndCaseId(StepPropertyEnum.APPROVAL.getLabel(), caseId);
-        Map<UserVO,String> decision=new HashMap<>();
-        Map<UserVO,String> comment=new HashMap<>();
-
-        if (stepVO.getUserId1()!=null){
-            User user=userService.findByIdAndIsDelete(stepVO.getUserId1());
-            ApprovalRecordVO approvalRecordVO = approvalService.findByCaseIdAndIsDeleteAndStepName(caseId, StepPropertyEnum.APPROVAL.getLabel(), user.getId());
-            decision.put(BeanUtil.copyProperties(user,UserVO.class),approvalRecordVO.getDecision());
-            comment.put(BeanUtil.copyProperties(user,UserVO.class),approvalRecordVO.getComments());
-        }
-
-        if (stepVO.getUserId2()!=null){
-            User user=userService.findByIdAndIsDelete(stepVO.getUserId2());
-            ApprovalRecordVO approvalRecordVO = approvalService.findByCaseIdAndIsDeleteAndStepName(caseId, StepPropertyEnum.APPROVAL.getLabel(), user.getId());
-            decision.put(BeanUtil.copyProperties(user,UserVO.class),approvalRecordVO.getDecision());
-            comment.put(BeanUtil.copyProperties(user,UserVO.class),approvalRecordVO.getComments());
-        }
+        if (ObjectUtils.isEmpty(caseId) || !loanCaseService.existsByIdAndIsDelete(caseId))
+            throw new DescribeException(PROJECT_NOT_EXIST);
 
-        return ResultUtil.success("success",approvalVO);
+        return ResultUtil.success("success",approvalService.findByCaseIdAndStepNameAndIsDelete(caseId,StepPropertyEnum.APPROVAL.getLabel()));
     }
 
     @PostMapping("/approval/pass")
     @PreAuthorize("@pms.hasRole('APPROVER')")
     @ApiOperation("业务审批通过")
     public Result approval_pass(@RequestBody ApprovalDTO approvalDTO) {
+        if(ObjectUtils.isEmpty(approvalDTO)||approvalDTO.getCaseId() == null)
+            throw new DescribeException(INPUT_ERROR);
+
         Long userId= BaseContext.getCurrentId();
-        log.info("用户id: {}", userId);
+        Long caseId = approvalDTO.getCaseId();
         //审批业务逻辑
-        LoanCase loanCase = loanCaseService.findLoanCaseByIdAndIsDelete(approvalDTO.getCaseId(), false);
-        StepVO step = stepService.findByStepNameAndCaseId(StepPropertyEnum.APPROVAL.getLabel(), approvalDTO.getCaseId());
+        LoanCase loanCase = loanCaseService.findLoanCaseByIdAndIsDelete(caseId, false);
+        StepVO step = stepService.findByStepNameAndCaseId(StepPropertyEnum.APPROVAL.getLabel(),caseId);
         //判断过去处理人与目前处理人是否一致
-        if(step.getUserId1()!=null&&step.getUserId2()!=null&&userId != step.getUserId2()&&userId!=step.getUserId1()){
-            return ResultUtil.error(STEP_USER_NOT_EXPECTED.getCode(), "环节处理人不是预期用户");
-        }
-        if(step.getStatus()==StepEnum.COMPLETED.getMsg()){
-            return ResultUtil.error(STEP_HAS_COMPLETEED.getCode(), "环节已完成,无法重复审批");
-        }
+        if(ObjectUtils.isEmpty(step)||!step.getStatus().equals(StepEnum.PROCESS.getMsg()))
+            throw new DescribeException(STEP_HAS_NOT_PROCESS);
+
+        if(step.getUserId1()!=null&&step.getUserId2()!=null&&userId != step.getUserId2()&&userId!=step.getUserId1())
+            throw new DescribeException(STEP_USER_NOT_EXPECTED);
+
         if(loanCase == null || loanCase.getIsDelete()){
-            return ResultUtil.error(PROJECT_NOT_EXIST.getCode(), PROJECT_NOT_EXIST.getMsg());
-        }
-        ApprovalRecordVO approvalRecord_origin = approvalService.findByCaseIdAndIsDeleteAndStepName(approvalDTO.getCaseId(),StepPropertyEnum.APPROVAL.getLabel(),userId);
-        if(approvalRecord_origin == null) {
-            log.info("没找到对应以前审批记录");
-            // 创建审批记录
-            ApprovalRecord approvalRecord = new ApprovalRecord();
-            approvalRecord.setCaseId(approvalDTO.getCaseId());
-            approvalRecord.setStepName(StepPropertyEnum.APPROVAL.getLabel());
-            approvalRecord.setApproverId(userId);
-            approvalRecord.setDecision(DecisionEnum.PASS.getMsg());
-            approvalRecord.setComments(approvalDTO.getComments());
-            approvalRecord.setCreateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
-            approvalRecord.setUpdateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
-            approvalRecord.setIsDelete(false);
-            // 保存到数据库
-            approvalService.save(approvalRecord);
-        }else{
-            log.info("找到对应以前审批记录");
-            approvalService.updateDecisionByCaseIdAndStepNameAndIsDelete(DecisionEnum.PASS.getMsg(),approvalDTO.getCaseId(),StepPropertyEnum.APPROVAL.getLabel(),approvalDTO.getComments(),userId);
+            throw  new DescribeException(PROJECT_NOT_EXIST);
         }
+
+        List<ApprovalRecordVO> records = approvalService.findByCaseIdAndStepNameAndApproverIdAndIsDelete(caseId, StepPropertyEnum.APPROVAL.getLabel(), userId);
+        ApprovalRecordVO record = ObjectUtils.isEmpty(records)?null:records.get(records.size()-1);//获取当前审批人上次的记录
         if(step.getUserId1()== null){
-            stepService.updateUserId1ByCaseIdAndStepName(StepPropertyEnum.APPROVAL.getLabel(),userId,approvalDTO.getCaseId());
-        }else if(step.getUserId2()== null){
-            stepService.updateUserId2ByCaseIdAndStepName(StepPropertyEnum.APPROVAL.getLabel(),userId,approvalDTO.getCaseId());
+            stepService.updateUserId1ByCaseIdAndStepName(StepPropertyEnum.APPROVAL.getLabel(),userId,caseId);
+        }else if(step.getUserId2()== null ){
+            //如果用户1审批过且通过,无法重复审批
+            if(step.getUserId1() == userId && record!=null && record.getDecision().equals(DecisionEnum.PASS.getMsg()))
+                throw new DescribeException(APPROVAL_USER_IS_COMPLETED);
+            else if(step.getUserId1()!= userId)
+                stepService.updateUserId2ByCaseIdAndStepName(StepPropertyEnum.APPROVAL.getLabel(),userId,caseId);
+        }else {
+            List<ApprovalRecordVO> approvalRecords1 = approvalService.findByCaseIdAndStepNameAndApproverIdAndIsDelete(caseId, StepPropertyEnum.APPROVAL.getLabel(), step.getUserId1());
+            ApprovalRecordVO approvalRecord1 = approvalRecords1.get(approvalRecords1.size()-1);
+            List<ApprovalRecordVO> approvalRecords2 = approvalService.findByCaseIdAndStepNameAndApproverIdAndIsDelete(caseId, StepPropertyEnum.APPROVAL.getLabel(), step.getUserId2());
+            ApprovalRecordVO approvalRecord2 = approvalRecords2.get(approvalRecords2.size()-1);
+            if(step.getUserId1()== userId){//仅版本一样或版本小于可新增
+              if(approvalRecord1.getVersion()> approvalRecord2.getVersion() && approvalRecord1.getDecision().equals(DecisionEnum.PASS.getMsg()))
+                  throw new DescribeException(APPROVAL_USER_IS_COMPLETED);
+            }else{
+                if(approvalRecord1.getVersion()< approvalRecord2.getVersion() && approvalRecord2.getDecision().equals(DecisionEnum.PASS.getMsg()))
+                    throw new DescribeException(APPROVAL_USER_IS_COMPLETED);
+            }
         }
+
+        approvalService.addApprovalRecord(caseId,StepPropertyEnum.APPROVAL.getLabel(),DecisionEnum.PASS.getMsg(),approvalDTO.getComments());
+
+        step=stepService.findByStepNameAndCaseId(StepPropertyEnum.APPROVAL.getLabel(), caseId);
         if(step.getUserId1()!=null&&step.getUserId2()!=null){
-            ApprovalRecordVO approvalRecord_user1 = approvalService.findByCaseIdAndIsDeleteAndStepName(approvalDTO.getCaseId(),StepPropertyEnum.APPROVAL.getLabel(),step.getUserId1());
-            ApprovalRecordVO approvalRecord_user2 = approvalService.findByCaseIdAndIsDeleteAndStepName(approvalDTO.getCaseId(),StepPropertyEnum.APPROVAL.getLabel(),step.getUserId2());
-            if(approvalRecord_user1.getDecision() == DecisionEnum.PASS.getMsg()&&approvalRecord_user2.getDecision() == DecisionEnum.PASS.getMsg()){
-                stepService.updateStatusByCaseId(StepEnum.COMPLETED.getMsg(),StepPropertyEnum.APPROVAL_PARENT.getLabel(),approvalDTO.getCaseId());
-                stepService.updateStatusByCaseId(StepEnum.COMPLETED.getMsg(),StepPropertyEnum.APPROVAL.getLabel(),approvalDTO.getCaseId());
-                stepService.updateStatusByCaseId(StepEnum.PROCESS.getMsg(),StepPropertyEnum.CONTRACT_SIGN_PARENT.getLabel(),approvalDTO.getCaseId());
-                stepService.updateStatusByCaseId(StepEnum.PROCESS.getMsg(),StepPropertyEnum.CONTRACT_SIGN.getLabel(),approvalDTO.getCaseId());
+            List<ApprovalRecordVO> records1 = approvalService.findByCaseIdAndStepNameAndApproverIdAndIsDelete(caseId, StepPropertyEnum.APPROVAL.getLabel(), step.getUserId1());
+            ApprovalRecordVO record1 = records1.get(records1.size()-1);//获取当前审批人上次的记录
+            List<ApprovalRecordVO> records2 = approvalService.findByCaseIdAndStepNameAndApproverIdAndIsDelete(caseId, StepPropertyEnum.APPROVAL.getLabel(), step.getUserId2());
+            ApprovalRecordVO record2 = records2.get(records2.size()-1);//获取当前审批人上次的记录
+
+            //TODO:同一阶段双人审批通过,才结束
+            if(record1.getVersion()==record2.getVersion() && record1.getDecision().equals(DecisionEnum.PASS.getMsg()) && record2.getDecision().equals(DecisionEnum.PASS.getMsg())){
+                stepService.updateStatusByCaseId(StepEnum.COMPLETED.getMsg(),StepPropertyEnum.APPROVAL_PARENT.getLabel(),caseId);
+                stepService.updateStatusByCaseId(StepEnum.COMPLETED.getMsg(),StepPropertyEnum.APPROVAL.getLabel(),caseId);
+
+                stepService.tryStartStep(StepPropertyEnum.APPROVAL.getLabel(), caseId);
                 //TODO微信推送审批通过消息和通知下一环节
             }
         }else{
@@ -329,53 +285,45 @@ public class ApprovalController {
     @PreAuthorize("@pms.hasRole('APPROVER')")
     @ApiOperation("业务审批拒绝")
     public Result approval_reject(@RequestBody ApprovalDTO approvalDTO) {
+        if(ObjectUtils.isEmpty(approvalDTO)||approvalDTO.getCaseId() == null)
+            throw new DescribeException(INPUT_ERROR);
         Long userId= BaseContext.getCurrentId();
-        log.info("用户id: {}", userId);
+        Long caseId = approvalDTO.getCaseId();
         //审批业务逻辑
         LoanCase loanCase = loanCaseService.findLoanCaseByIdAndIsDelete(approvalDTO.getCaseId(),false);
         if(loanCase == null||loanCase.getIsDelete()){
             return ResultUtil.error(PROJECT_NOT_EXIST.getCode(), PROJECT_NOT_EXIST.getMsg());
         }
         StepVO step = stepService.findByStepNameAndCaseId(StepPropertyEnum.APPROVAL.getLabel(), approvalDTO.getCaseId());
+        if(ObjectUtils.isEmpty(step)||!step.getStatus().equals(StepEnum.PROCESS.getMsg()))
+            throw new DescribeException(STEP_HAS_NOT_PROCESS);
+
         //判断过去处理人与目前处理人是否一致
-        if(step.getUserId1()!=null&&step.getUserId2()!=null&&userId!=step.getUserId2()&&userId!=step.getUserId1()){
-            return ResultUtil.error(STEP_USER_NOT_EXPECTED.getCode(), "环节处理人不是预期用户");
-        }
-        if(step.getStatus()==StepEnum.COMPLETED.getMsg()){
-            return ResultUtil.error(STEP_HAS_COMPLETEED.getCode(), "环节已完成,无法重复审批");
-        }
-        //审批记录处理
-        ApprovalRecordVO approvalRecord_origin = approvalService.findByCaseIdAndIsDeleteAndStepName(approvalDTO.getCaseId(),StepPropertyEnum.APPROVAL.getLabel(),userId);
-        if(approvalRecord_origin == null) {
-            log.info("没找到对应以前审批记录");
-            // 创建审批记录
-            ApprovalRecord approvalRecord = new ApprovalRecord();
-            approvalRecord.setCaseId(approvalDTO.getCaseId());
-            approvalRecord.setStepName(StepPropertyEnum.APPROVAL.getLabel());
-            approvalRecord.setApproverId(userId);
-            approvalRecord.setDecision(DecisionEnum.REJECT.getMsg());
-            approvalRecord.setComments(approvalDTO.getComments());
-            approvalRecord.setCreateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
-            approvalRecord.setUpdateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
-            approvalRecord.setIsDelete(false);
-            // 保存到数据库
-            approvalService.save(approvalRecord);
-        }else{
-            log.info("找到对应以前审批记录");
-            approvalService.updateDecisionByCaseIdAndStepNameAndIsDelete(DecisionEnum.REJECT.getMsg(),approvalDTO.getCaseId(),StepPropertyEnum.APPROVAL.getLabel(),approvalDTO.getComments(),userId);
-        }
+        if(step.getUserId1()!=null&&step.getUserId2()!=null&&userId!=step.getUserId2()&&userId!=step.getUserId1())
+            throw new DescribeException(STEP_USER_NOT_EXPECTED);
+
+        List<ApprovalRecordVO> records = approvalService.findByCaseIdAndStepNameAndApproverIdAndIsDelete(caseId, StepPropertyEnum.APPROVAL.getLabel(), userId);
+        ApprovalRecordVO record = ObjectUtils.isEmpty(records)?null:records.get(records.size()-1);//获取当前审批人上次的记录
         if(step.getUserId1()== null){
-            stepService.updateUserId1ByCaseIdAndStepName(StepPropertyEnum.APPROVAL.getLabel(),userId,approvalDTO.getCaseId());
-        }else if(step.getUserId2()== null){
-            stepService.updateUserId2ByCaseIdAndStepName(StepPropertyEnum.APPROVAL.getLabel(),userId,approvalDTO.getCaseId());
+            stepService.updateUserId1ByCaseIdAndStepName(StepPropertyEnum.APPROVAL.getLabel(),userId,caseId);
+        }else if(step.getUserId2()== null ){
+            //如果用户1审批过且通过,无法重复审批
+            if(step.getUserId1() == userId && record!=null && record.getDecision().equals(DecisionEnum.PASS.getMsg()))
+                throw new DescribeException(APPROVAL_USER_IS_COMPLETED);
+            else if(step.getUserId1()!= userId)
+                stepService.updateUserId2ByCaseIdAndStepName(StepPropertyEnum.APPROVAL.getLabel(),userId,caseId);
         }
+        approvalService.addApprovalRecord(caseId,StepPropertyEnum.APPROVAL.getLabel(),DecisionEnum.REJECT.getMsg(),approvalDTO.getComments());
+        RedisData redisData = new RedisData(stringRedisTemplate);
+        redisData.setRejectApprovalRecord(caseId,StepPropertyEnum.BUSINESS_ACCEPT.getLabel(),approvalDTO.getComments());
+
         //更新环节状态
-        stepService.updateStatusByCaseId(StepEnum.PROCESS.getMsg(),StepPropertyEnum.BUSINESS_ACCEPT_PARENT.getLabel(),approvalDTO.getCaseId());
-        stepService.updateStatusByCaseId(StepEnum.PROCESS.getMsg(),StepPropertyEnum.BUSINESS_ACCEPT.getLabel(),approvalDTO.getCaseId());
-        stepService.updateStatusByCaseId(StepEnum.UNSTART.getMsg(),StepPropertyEnum.PRE_TRIAL_PARENT.getLabel(),approvalDTO.getCaseId());
-        stepService.updateStatusByCaseId(StepEnum.UNSTART.getMsg(),StepPropertyEnum.PRE_TRIAL.getLabel(),approvalDTO.getCaseId());
-        stepService.updateStatusByCaseId(StepEnum.UNSTART.getMsg(),StepPropertyEnum.APPROVAL_PARENT.getLabel(),approvalDTO.getCaseId());
-        stepService.updateStatusByCaseId(StepEnum.UNSTART.getMsg(),StepPropertyEnum.APPROVAL.getLabel(),approvalDTO.getCaseId());
+        stepService.updateStatusByCaseId(StepEnum.PROCESS.getMsg(),StepPropertyEnum.BUSINESS_ACCEPT_PARENT.getLabel(),caseId);
+        stepService.updateStatusByCaseId(StepEnum.PROCESS.getMsg(),StepPropertyEnum.BUSINESS_ACCEPT.getLabel(),caseId);
+        stepService.updateStatusByCaseId(StepEnum.UNSTART.getMsg(),StepPropertyEnum.PRE_TRIAL_PARENT.getLabel(),caseId);
+        stepService.updateStatusByCaseId(StepEnum.UNSTART.getMsg(),StepPropertyEnum.PRE_TRIAL.getLabel(),caseId);
+        stepService.updateStatusByCaseId(StepEnum.UNSTART.getMsg(),StepPropertyEnum.APPROVAL_PARENT.getLabel(),caseId);
+        stepService.updateStatusByCaseId(StepEnum.UNSTART.getMsg(),StepPropertyEnum.APPROVAL.getLabel(),caseId);
         //TODO微信推送审批驳回消息和通知重新受理(到业务受理)
 
         return ResultUtil.success("success","审批驳回");
@@ -384,55 +332,42 @@ public class ApprovalController {
     @PreAuthorize("@pms.hasRole('APPROVER')")
     @ApiOperation("业务审批终结")
     public Result approval_end(@RequestBody ApprovalDTO approvalDTO) {
+        if (ObjectUtils.isEmpty(approvalDTO)||approvalDTO.getCaseId() == null)
+            throw new DescribeException(INPUT_ERROR);
         Long userId= BaseContext.getCurrentId();
-        log.info("用户id: {}", userId);
+        Long caseId = approvalDTO.getCaseId();
         //审批业务逻辑
         LoanCase loanCase = loanCaseService.findLoanCaseByIdAndIsDelete(approvalDTO.getCaseId(),false);
         if(loanCase == null||loanCase.getIsDelete()){
             return ResultUtil.error(PROJECT_NOT_EXIST.getCode(), PROJECT_NOT_EXIST.getMsg());
         }
         StepVO step = stepService.findByStepNameAndCaseId(StepPropertyEnum.APPROVAL.getLabel(), approvalDTO.getCaseId());
+        if(ObjectUtils.isEmpty(step)||!step.getStatus().equals(StepEnum.PROCESS.getMsg()))
+            throw new DescribeException(STEP_HAS_NOT_PROCESS);
         //判断过去处理人与目前处理人是否一致
-        if(step.getUserId1()!=null&&step.getUserId2()!=null&&userId!=step.getUserId2()&&userId!=step.getUserId1()){
-            return ResultUtil.error(STEP_USER_NOT_EXPECTED.getCode(), "环节处理人不是预期用户");
-        }
-        if(step.getStatus()==StepEnum.COMPLETED.getMsg()){
-            return ResultUtil.error(STEP_HAS_COMPLETEED.getCode(), "环节已完成,无法重复审批");
-        }
+        if(step.getUserId1()!=null&&step.getUserId2()!=null&&userId!=step.getUserId2()&&userId!=step.getUserId1())
+            throw new DescribeException(STEP_USER_NOT_EXPECTED);
+
         //审批记录处理
-        ApprovalRecordVO approvalRecord_origin = approvalService.findByCaseIdAndIsDeleteAndStepName(approvalDTO.getCaseId(),StepPropertyEnum.APPROVAL.getLabel(),userId);
-        if(approvalRecord_origin == null) {
-            log.info("没找到对应以前审批记录");
-            // 创建审批记录
-            ApprovalRecord approvalRecord = new ApprovalRecord();
-            approvalRecord.setCaseId(approvalDTO.getCaseId());
-            approvalRecord.setStepName(StepPropertyEnum.APPROVAL.getLabel());
-            approvalRecord.setApproverId(userId);
-            approvalRecord.setDecision(DecisionEnum.TERMINATE.getMsg());
-            approvalRecord.setComments(approvalDTO.getComments());
-            approvalRecord.setCreateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
-            approvalRecord.setUpdateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
-            approvalRecord.setIsDelete(false);
-            // 保存到数据库
-            approvalService.save(approvalRecord);
-        }else{
-            log.info("找到对应以前审批记录");
-            approvalService.updateDecisionByCaseIdAndStepNameAndIsDelete(DecisionEnum.TERMINATE.getMsg(),approvalDTO.getCaseId(),StepPropertyEnum.APPROVAL.getLabel(),approvalDTO.getComments(),userId);
-        }
+        List<ApprovalRecordVO> records = approvalService.findByCaseIdAndStepNameAndApproverIdAndIsDelete(caseId, StepPropertyEnum.APPROVAL.getLabel(), userId);
+        ApprovalRecordVO record = ObjectUtils.isEmpty(records)?null:records.get(records.size()-1);//获取当前审批人上次的记录
         if(step.getUserId1()== null){
-            stepService.updateUserId1ByCaseIdAndStepName(StepPropertyEnum.APPROVAL.getLabel(),userId,approvalDTO.getCaseId());
-        }else if(step.getUserId2()== null){
-            stepService.updateUserId2ByCaseIdAndStepName(StepPropertyEnum.APPROVAL.getLabel(),userId,approvalDTO.getCaseId());
-        }
-        //更新项目和环节状态 作逻辑删除
-        loanCaseService.logic_delete(approvalDTO.getCaseId());
-        List<StepVO> steps = stepService.getStepByCaseId(approvalDTO.getCaseId());
-        for (StepVO step_each : steps){
-            stepService.logic_delete(step_each.getId());
+            stepService.updateUserId1ByCaseIdAndStepName(StepPropertyEnum.APPROVAL.getLabel(),userId,caseId);
+        }else if(step.getUserId2()== null ){
+            //如果用户1审批过且通过,无法重复审批
+            if(step.getUserId1() == userId && record!=null && record.getDecision().equals(DecisionEnum.PASS.getMsg()))
+                throw new DescribeException(APPROVAL_USER_IS_COMPLETED);
+            else if(step.getUserId1()!= userId)
+                stepService.updateUserId2ByCaseIdAndStepName(StepPropertyEnum.APPROVAL.getLabel(),userId,caseId);
         }
+        approvalService.addApprovalRecord(caseId,StepPropertyEnum.APPROVAL.getLabel(),DecisionEnum.TERMINATE.getMsg(),approvalDTO.getComments());
+
+        //项目终结
+        loanCaseService.updateIsCompleteByCaseId(DecisionEnum.TERMINATE.getMsg(),caseId);
+
         //TODO微信推送审批驳回消息和通知重新受理(到业务受理)
 
-        return ResultUtil.success("success","审批驳回");
+        return ResultUtil.success("success","审批终结");
     }
 }
 

+ 241 - 123
src/main/java/com/loan/system/controller/wechat/CollateralController.java

@@ -8,30 +8,28 @@ import com.loan.system.domain.entity.ApprovalRecord;
 import com.loan.system.domain.entity.Collateral;
 import com.loan.system.domain.entity.CollateralPlan;
 import com.loan.system.domain.entity.User;
-import com.loan.system.domain.enums.ExceptionEnum;
-import com.loan.system.domain.enums.RoleEnum;
+import com.loan.system.domain.enums.*;
 import com.loan.system.domain.pojo.Result;
-import com.loan.system.domain.vo.CollateralPlanVO;
-import com.loan.system.domain.vo.CollateralSalesVO;
-import com.loan.system.domain.vo.CollateralVO;
-import com.loan.system.service.ApprovalService;
-import com.loan.system.service.CollateralPlanService;
-import com.loan.system.service.CollateralService;
+import com.loan.system.domain.vo.*;
+import com.loan.system.exception.DescribeException;
+import com.loan.system.service.*;
 import com.loan.system.service.Impl.UserServiceImpl;
-import com.loan.system.service.UserService;
 import com.loan.system.utils.ResultUtil;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.StringRedisTemplate;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.util.Base64Utils;
+import org.springframework.util.ObjectUtils;
 import org.springframework.web.bind.annotation.*;
 
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
 import static com.loan.system.domain.enums.DecisionEnum.*;
@@ -50,46 +48,27 @@ public class CollateralController {
     private ApprovalService approvalService;
     @Autowired
     private UserService userService;
-    private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);
-
-    //显示业务相关抵押物状态
-    @GetMapping("/{id}")
-    @ApiOperation("查看业务相关抵押物状态")
-    public Result findCollateral(@PathVariable("id") Long id){
-        List<CollateralVO> collaterals = collateralService.findByCaseId(id);
-        return ResultUtil.success("success",collaterals);
-    }
+    @Autowired
+    private LoanService loanService;
+    @Autowired
+    private StepService stepService;
+    @Autowired
+    private DisbursementService disbursementService;
+    @Autowired
+    private StringRedisTemplate redisTemplate;
 
-    @GetMapping("/user")
-    @ApiOperation("获取可选用户")
-    public Result findUser(){
-        List<String> Roles=new ArrayList<>();
-        Roles.add("LEAD_SALES");
-        Roles.add("ASSIST_SALES");
-        List<User> users = userService.findByRoleAndIsDelete(Roles,false);
-        if(users == null || users.isEmpty()){
-            return ResultUtil.error(USER_NOT_EXIST.getCode(),"用户不存在");
-        }
-        List<CollateralSalesVO> salesVOS=new ArrayList<>();
-        for (User user : users){
-            CollateralSalesVO salesVO = new CollateralSalesVO();
-            BeanUtil.copyProperties(user, salesVO);
-            salesVOS.add(salesVO);
-        }
-        return ResultUtil.success("success",salesVOS);
+    @GetMapping("/caseInfo")
+    @ApiOperation("查看客户与业务信息")
+    @PreAuthorize("@pms.hasAnyRoles('SYSTEM_ADMIN','APPROVER','LEAD_SALES', 'ASSIST_SALES', 'FINANCE', 'BACK_OFFICE')")
+    public Result findCaseInfo(@RequestParam Long caseId){
+        return ResultUtil.success("success",disbursementService.getLoanCaseAndCustomerByCaseId(caseId));
     }
-    /**
-     * 查看项目抵押物计划
-     * @param id
-     * @return 响应
-     */
-    @GetMapping("/plan/{id}")
+
+    @GetMapping("/plan/{caseId}")
     @ApiOperation("查看项目抵押物计划")
-    public Result findCollateralPlan(@PathVariable("id") Long id){
-        List<CollateralPlan> collateralPlans = collateralPlanService.findByCaseIdAndIsDelete(id,false);
-        if(collateralPlans == null || collateralPlans.isEmpty()){
-            return ResultUtil.error(COLLATERAL_PLAN_NOT_EXIST.getCode(),"计划不存在");
-        }
+    @PreAuthorize("@pms.hasAnyRoles('SYSTEM_ADMIN','APPROVER','LEAD_SALES', 'ASSIST_SALES', 'FINANCE', 'BACK_OFFICE')")
+    public Result findCollateralPlan(@PathVariable("caseId") Long caseId,@RequestParam String  flag){
+        List<CollateralPlan> collateralPlans = collateralPlanService.findByCaseIdAndFlagAndIsDelete(caseId,flag,false);
 
         List<String> Roles=new ArrayList<>();
         Roles.add(RoleEnum.LEAD_SALES.getMsg());
@@ -100,39 +79,55 @@ public class CollateralController {
         for(CollateralPlan plan : collateralPlans){
             CollateralPlanVO vo = new CollateralPlanVO();
             BeanUtil.copyProperties(plan, vo);
-            vo.setOperatorId(plan.getOperatorId());
-            vo.setOperatorName(plan.getOperatorName());
+            vo.setPlanUser(BeanUtil.copyProperties(userService.findByIdAndIsDelete(plan.getUserId()), UserVO.class));
+            vo.setCollaterals(collateralService.findByIds(getCollateralIds(plan.getCollateralIds())));
+
+            ApprovalRecord approvalRecord = approvalService.findByIdAndIsDelete(plan.getApprovalRecordId());
+            if (approvalRecord != null){
+                vo.setApprovalRecord(BeanUtil.copyProperties(approvalService.findByIdAndIsDelete(approvalRecord.getId()), ApprovalRecordVO.class));
+                vo.setApprovalUser(BeanUtil.copyProperties(userService.findByIdAndIsDelete(approvalRecord.getApproverId()), UserVO.class));
+            }
+            vo.setExecuteComments(plan.getOperatorComments());
+            vo.setExecuteUser(BeanUtil.copyProperties(userService.findByIdAndIsDelete(plan.getOperatorId()), UserVO.class));
+
+
             collateralPlanVOs.add(vo);
         }
 
         return ResultUtil.success("success",collateralPlanVOs);
     }
 
-    /**
-     * 上报计划
-     * @return 响应
-     */
-    @PostMapping("/plan")
+    @PostMapping("/plan/{planId}")
     @PreAuthorize("@pms.hasAnyRoles('LEAD_SALES','ASSIST_SALES')")
-    @ApiOperation("上报计划")
-    public Result createCollateralPlan(@RequestBody CollateralPlanDTO collateralPlanDTO){
-        Collateral collaterals = collateralService.findCollateralById(collateralPlanDTO.getCollateralId());
-        if (collaterals == null){
-            return ResultUtil.error(COLLATERAL_NOT_EXIST.getCode(), "抵押物不存在");
+    @ApiOperation("上报计划") //TODO:驳回时无法新增,通过时无法修改   TODO:上报与审批人可能不为同一个人
+    public Result createCollateralPlan(@RequestBody CollateralPlanDTO collateralPlanDTO,@PathVariable("planId") Long planId,@RequestParam(defaultValue = "false") Boolean isComplete){
+        if (ObjectUtils.isEmpty(collateralPlanDTO) || collateralPlanDTO.getCaseId()== null)
+            throw new DescribeException(INPUT_ERROR);
+
+        Long caseId = collateralPlanDTO.getCaseId();
+        if(!loanService.existsByIdAndIsDelete(caseId))
+            throw new DescribeException(PROJECT_NOT_EXIST);
+
+        StepVO stepVO = stepService.findByStepNameAndCaseId(StepPropertyEnum.PLAN_SUBMISSION.getLabel(), caseId);
+        if(ObjectUtils.isEmpty(stepVO)){
+            if(ObjectUtils.isEmpty(stepVO)||!stepVO.getStatus().equals(StepEnum.PROCESS.getMsg()))
+                throw new DescribeException(STEP_HAS_NOT_PROCESS);
         }
-        List<CollateralPlan> collateralPlans=collateralPlanService.findByCollateralIdAndIsDelete(collateralPlanDTO.getCollateralId());
-        // 修改后的代码
-        for(CollateralPlan plan : collateralPlans){
-            // 如果状态既不是拒绝也不是执行完成,则返回错误
-            if(!plan.getStatus().equals(REJECTION.getMsg()) && !plan.getStatus().equals(EXECUTION_COMPLETE.getMsg())){
-                return ResultUtil.error(COLLATERAL_PLAN_ALREADY_EXIST.getCode(), COLLATERAL_PLAN_ALREADY_EXIST.getMsg());
-            }
+
+        List<Long> collateralIds = getCollateralIds(collateralPlanDTO.getCollateralIds());
+        String info="";
+        for (Long id : collateralIds){
+            Collateral collateral = collateralService.findCollateralByIdAndCaseId(id,caseId);
+            if(collateral == null)
+                info = info + id+" ";
         }
+        if (!info.isEmpty())
+            throw new DescribeException(COLLATERAL_NOT_EXIST.getCode(),COLLATERAL_NOT_EXIST.getMsg()+ "{"+info+"}");
 
         Long userid = BaseContext.getCurrentId();
         CollateralPlan collateralPlan = CollateralPlan.builder()
-                .collateralId(collateralPlanDTO.getCollateralId())
-                .caseId(collateralPlanDTO.getCaseId())
+                .collateralIds(collateralPlanDTO.getCollateralIds())
+                .caseId(caseId)
                 .time(collateralPlanDTO.getCollateralTime())
                 .place(collateralPlanDTO.getCollateralPlace())
                 .flag(collateralPlanDTO.getFlag())
@@ -143,30 +138,70 @@ public class CollateralController {
                 .status(WAITING_APPROVAL.getMsg())
                 .isDelete(false)
                 .build();
-        collateralPlanService.save(collateralPlan);
-        return ResultUtil.success("success", "计划上报成功");
+
+        if(planId  <= 0){
+            //TODO:若为驳回或未审批,则无法新增
+            List<CollateralPlan> plans = collateralPlanService.findByCaseIdAndFlagAndIsDelete(caseId,collateralPlanDTO.getFlag(),false);
+            if (!plans.isEmpty()) {
+                ApprovalRecord approvalRecord = approvalService.findByIdAndIsDelete(plans.get(plans.size() - 1).getApprovalRecordId());
+                if ((ObjectUtils.isEmpty(approvalRecord)||!approvalRecord.getDecision().equals(PASS.getMsg()))||(!plans.get(plans.size() - 1).getStatus().equals(WAITING_EXECUTION.getMsg())))
+                    throw new DescribeException(PLAN_HAS_NOT_PASSED);
+            }
+
+            collateralPlanService.save(collateralPlan);
+        }
+        else{
+            CollateralPlan plan=collateralPlanService.findById(planId);
+            if (ObjectUtils.isEmpty( plan))
+                throw new DescribeException(COLLATERAL_PLAN_NOT_EXIST);
+            ApprovalRecord approvalRecord = approvalService.findByIdAndIsDelete(plan.getApprovalRecordId());//获取上一次计划的审批记录
+            //若为通过或未审批,则无法修改
+            if(ObjectUtils.isEmpty(approvalRecord)||approvalRecord.getDecision().equals(PASS.getMsg()))
+                throw new DescribeException(PLAN_HAS_BEEN_PASSED);
+
+            collateralPlanService.updatePlanById(collateralPlan,planId);
+        }
+
+        //更新状态
+        String stepName = collateralPlanDTO.getFlag().equals(ENTER_WAREHOUSE.getMsg()) ? StepPropertyEnum.PLAN_SUBMISSION.getLabel() : StepPropertyEnum.PLAN_SUBMISSION_2.getLabel();
+        //String stepName2 = collateralPlanDTO.getFlag().equals("入库") ? StepPropertyEnum.APPROVAL_ASSIGNMENT.getLabel() : StepPropertyEnum.APPROVAL_ASSIGNMENT_2.getLabel();
+
+        stepService.updateUserId1ByCaseIdAndStepName(stepName,userid,caseId);
+        if (isComplete){
+            stepService.updateStatusByCaseId(StepEnum.COMPLETED.getMsg(), stepName,caseId);
+
+        }
+        stepService.tryStartStep(stepName,caseId);
+
+        return ResultUtil.success( "计划上报成功");
     }
 
-    /**
-     * 审批计划
-     * @param collateralPlanApprovalDTO
-     * @return 响应
-     */
-    @PostMapping("/plan/approval")
+    @PostMapping("/plan/approval/{recordId}")
     @PreAuthorize("@pms.hasRole('APPROVER')")
     @ApiOperation("审批计划")
-    public Result refuseCollateralPlan(@RequestBody CollateralPlanApprovalDTO collateralPlanApprovalDTO){
-        CollateralPlan collateralPlan = collateralPlanService.findById(collateralPlanApprovalDTO.getId());
-        if(collateralPlan == null){
-            return ResultUtil.error(COLLATERAL_PLAN_NOT_EXIST.getCode(),"计划不存在");
+    public Result refuseCollateralPlan(@RequestBody CollateralPlanApprovalDTO collateralPlanApprovalDTO,@PathVariable("recordId") Long recordId){
+        if(ObjectUtils.isEmpty(collateralPlanApprovalDTO)||collateralPlanApprovalDTO.getPlanId()== null||collateralPlanApprovalDTO.getCaseId()== null)
+            throw new DescribeException(INPUT_ERROR);
+        CollateralPlan collateralPlan = collateralPlanService.findById(collateralPlanApprovalDTO.getPlanId());
+        if(ObjectUtils.isEmpty(collateralPlan)){
+            throw new DescribeException(COLLATERAL_PLAN_NOT_EXIST);
         }
-        log.info("collaterralplanid: " + collateralPlan.getId());
+
         if(!collateralPlan.getStatus().equals(WAITING_APPROVAL.getMsg())){
-            return ResultUtil.error(COLLATERAL_PLAN_NOT_ALREADY_APPROVED.getCode(),COLLATERAL_PLAN_NOT_ALREADY_APPROVED.getMsg());
+            throw new DescribeException(COLLATERAL_PLAN_NOT_ALREADY_APPROVED);
         }
+
+        Long caseId = collateralPlanApprovalDTO.getCaseId();
+        StepVO stepVO = stepService.findByStepNameAndCaseId(StepPropertyEnum.PLAN_SUBMISSION.getLabel(), caseId);
+        if(ObjectUtils.isEmpty(stepVO)){
+            if(ObjectUtils.isEmpty(stepVO)||!stepVO.getStatus().equals(StepEnum.PROCESS.getMsg()))
+                throw new DescribeException(STEP_HAS_NOT_PROCESS);
+        }
+
+        String stepName = collateralPlan.getFlag().equals(ENTER_WAREHOUSE.getMsg()) ? StepPropertyEnum.APPROVAL_ASSIGNMENT.getLabel() : StepPropertyEnum.APPROVAL_ASSIGNMENT_2.getLabel();
         ApprovalRecord approvalRecord = ApprovalRecord.builder()
-                .caseId(collateralPlanApprovalDTO.getCaseId())
-                .stepName("押品管控环节")
+                .caseId(caseId)
+                .stepName(stepName)
                 .approverId(BaseContext.getCurrentId())
                 .decision(collateralPlanApprovalDTO.getDecision())
                 .comments(collateralPlanApprovalDTO.getComments())
@@ -174,22 +209,51 @@ public class CollateralController {
                 .updateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")))
                 .isDelete( false)
                 .build();
-        approvalService.save(approvalRecord);
-        log.info(collateralPlanApprovalDTO.getDecision());
-        log.info("操作者id"+collateralPlanApprovalDTO.getOperator().getId());
-        if("拒绝".equals(collateralPlanApprovalDTO.getDecision())){
-            collateralPlanService.updateCollateralStatusByid(collateralPlan.getId(), REJECTION.getMsg());
-            //collateralPlanService.logic_delete(collateralPlanApprovalDTO.getId());
+
+        //TODO:如果存在则修改,不存在则保持
+        if (recordId <= 0)
+            approvalRecord = approvalService.save(approvalRecord);
+        else
+            approvalService.updateByIdAndIsDelete(approvalRecord,recordId);
+
+        //TODO:绑定审批计划与押品计划、下环节负责人
+        collateralPlanService.updateApprovalRecordAndOperatorById(approvalRecord.getId(),collateralPlanApprovalDTO.getUserId(),collateralPlan.getId());
+
+        Long userId = BaseContext.getCurrentId();
+        String stepName2 = collateralPlan.getFlag().equals(ENTER_WAREHOUSE.getMsg()) ? StepPropertyEnum.PLAN_SUBMISSION.getLabel() : StepPropertyEnum.PLAN_SUBMISSION_2.getLabel();
+
+        stepService.updateUserId1ByCaseIdAndStepName(stepName,userId,caseId);
+        //拒绝计划
+        if(REJECTION.getMsg().equals(collateralPlanApprovalDTO.getDecision())){
+            collateralPlanService.updateCollateralStatusById(collateralPlan.getId(), REJECTION.getMsg());
+
+            stepService.updateStatusByCaseId(StepEnum.UNSTART.getMsg(), stepName,caseId);
+            stepService.updateStatusByCaseId(StepEnum.PROCESS.getMsg(), stepName2,caseId);
+
             return ResultUtil.success("success","计划已拒绝");
-        }else if("通过".equals(collateralPlanApprovalDTO.getDecision())){
-//            collateralPlanService.updateCollateraluserIdByid(collateralPlanApprovalDTO.getId(),collateralPlanApprovalDTO.getUserId());
-            collateralPlanService.updateCollateralStatusByid(collateralPlanApprovalDTO.getId(),WAITING_EXECUTION.getMsg());
-            // 修改 Controller 中的调用
-            collateralPlanService.updateCollateraloperatorIdByid(
-                    collateralPlan.getId(),
-                    collateralPlanApprovalDTO.getOperator().getId(),
-                    collateralPlanApprovalDTO.getOperator().getRealName()
-            );
+            //同意计划
+        }else if(PASS.getMsg().equals(collateralPlanApprovalDTO.getDecision())){
+            collateralPlanService.updateCollateralStatusById(collateralPlanApprovalDTO.getPlanId(),WAITING_EXECUTION.getMsg());
+
+            //若上报计划全部完成且审批通过,则此次审批阶段完成
+            boolean flag = true;
+            List<CollateralPlan> collateralPlans = collateralPlanService.findByCaseIdAndFlagAndIsDelete(caseId,collateralPlan.getFlag(),false);
+            List<ApprovalRecordVO> approvalRecords = approvalService.findByCollateralAndCaseIdAndIsDelete(stepName,caseId, false);
+            if (collateralPlans.size()==approvalRecords.size()){
+                for(ApprovalRecordVO approvalRecordVO:approvalRecords){
+                    if(!approvalRecordVO.getDecision().equals(PASS.getMsg())){
+                        flag = false;
+                        break;
+                    }
+                }
+                if(flag && stepService.findByStepNameAndCaseId(stepName2, caseId).getStatus().equals(StepEnum.COMPLETED.getMsg())){
+                    stepService.updateStatusByCaseId(StepEnum.COMPLETED.getMsg(), stepName,caseId);
+
+                }
+            }
+
+            stepService.tryStartStep(stepName,caseId);
+
 //TODO 改状态+微信推送下一个节点业务员
             return ResultUtil.success("success","计划已通过");
         }else{
@@ -197,57 +261,101 @@ public class CollateralController {
         }
     }
 
-
-
     /**确认抵押物入库,完成任务
      *ID:计划id
      */
-    @PostMapping("/warehouse/{id}")
+    @PostMapping("/warehouse/{planId}")
     @PreAuthorize("@pms.hasAnyRoles('LEAD_SALES','ASSIST_SALES')")
     @ApiOperation("确认抵押物入库")
-    public Result warehouseCollateral(@PathVariable("id") Long id){
+    public Result warehouseCollateral(@PathVariable("planId") Long id,String comments){
         CollateralPlan collateralPlan = collateralPlanService.findByCollateralPlanId(id);
         if(collateralPlan == null){
-            return ResultUtil.error(COLLATERAL_PLAN_NOT_EXIST.getCode(),"计划不存在");
+            throw new DescribeException(COLLATERAL_PLAN_NOT_EXIST);
         }
         if(!collateralPlan.getStatus().equals(WAITING_EXECUTION.getMsg())){
-            return ResultUtil.error(COLLATERAL_PLAN_NOT_ALREADY_EXECUTION.getCode(),COLLATERAL_PLAN_NOT_ALREADY_EXECUTION.getMsg());
+            throw new DescribeException(COLLATERAL_PLAN_NOT_ALREADY_EXECUTION);
         }
-        if(!collateralPlan.getFlag().equals("入库")){
-            return ResultUtil.error(COLLATERAL_PLAN_NOT_EQUAL_WAREHOUSE.getCode(),COLLATERAL_PLAN_NOT_EQUAL_WAREHOUSE.getMsg());
+        if(!collateralPlan.getFlag().equals(ENTER_WAREHOUSE.getMsg())){
+            throw new DescribeException(COLLATERAL_PLAN_NOT_EQUAL_WAREHOUSE);
         }
-        Collateral collateral = collateralService.findCollateralById(collateralPlan.getCollateralId());
-        if(collateral == null){
-            return ResultUtil.error(COLLATERAL_NOT_EXIST.getCode(),"抵押物不存在");
+        if(collateralPlan.getOperatorId()!= BaseContext.getCurrentId())
+            throw new DescribeException(STEP_USER_NOT_EXPECTED);
+
+        Long caseId = collateralPlan.getCaseId();
+        Long userId= BaseContext.getCurrentId();
+
+        collateralService.updateCollateralStatusByIds(getCollateralIds(collateralPlan.getCollateralIds()),ENTER_WAREHOUSE.getMsg());
+        collateralPlanService.updateCollateralStatusById(id,EXECUTION_COMPLETE.getMsg());
+        collateralPlanService.updateOperatorIdAndCommentsById(userId,comments,id);
+
+        stepService.updateUserId1ByCaseIdAndStepName(StepPropertyEnum.EVIDENCE_CONFIRMATION.getLabel(),userId,caseId);
+
+        //若所有押品入库,则完成
+        boolean flag = true;
+        List<CollateralVO> collateralVOS = collateralService.findByCaseId(caseId);
+        for(CollateralVO collateralVO:collateralVOS){
+            if(!collateralVO.getStaus().equals(ENTER_WAREHOUSE.getMsg())){
+                flag = false;
+                break;
+            }
+        }
+        if(flag){
+            stepService.updateStatusByCaseId(StepEnum.COMPLETED.getMsg(), StepPropertyEnum.COLLATERAL_RECEIVE.getLabel(), caseId);
+            stepService.updateStatusByCaseId(StepEnum.COMPLETED.getMsg(), StepPropertyEnum.EVIDENCE_CONFIRMATION.getLabel(),caseId);
+            stepService.tryStartStep(StepPropertyEnum.EVIDENCE_CONFIRMATION.getLabel(),caseId);
         }
 
-        collateralService.updateCollateralStatusByid(collateral.getId(),"入库");
-        collateralPlanService.updateCollateralStatusByid(id,EXECUTION_COMPLETE.getMsg());
         return ResultUtil.success("success","抵押物入库成功");
     }
     /**确认抵押物出库,完成任务
      *ID:计划id
      */
-    @PostMapping("/outbound/{id}")
+    @PostMapping("/outbound/{planId}")
     @PreAuthorize("@pms.hasAnyRoles('LEAD_SALES','ASSIST_SALES')")
     @ApiOperation("确认抵押物出库")
-    public Result outboundCollateral(@PathVariable("id") Long id){
+    public Result outboundCollateral(@PathVariable("planId") Long id,String comments){
         CollateralPlan collateralPlan = collateralPlanService.findByCollateralPlanId(id);
         if(collateralPlan == null){
-            return ResultUtil.error(COLLATERAL_PLAN_NOT_EXIST.getCode(),"计划不存在");
+            throw new DescribeException(COLLATERAL_PLAN_NOT_EXIST);
         }
         if(!collateralPlan.getStatus().equals(WAITING_EXECUTION.getMsg())){
-            return ResultUtil.error(COLLATERAL_PLAN_NOT_ALREADY_EXECUTION.getCode(),COLLATERAL_PLAN_NOT_ALREADY_EXECUTION.getMsg());
+            throw new DescribeException(COLLATERAL_PLAN_NOT_ALREADY_EXECUTION);
         }
-        if(!collateralPlan.getFlag().equals("出库")){
-            return ResultUtil.error(COLLATERAL_PLAN_NOT_EQUAL_OUTBOUND.getCode(),COLLATERAL_PLAN_NOT_EQUAL_OUTBOUND.getMsg());
+        if(!collateralPlan.getFlag().equals(OUT_WAREHOUSE.getMsg())){
+           throw new DescribeException(COLLATERAL_PLAN_NOT_EQUAL_OUTBOUND);
         }
-        Collateral collateral = collateralService.findCollateralById(collateralPlan.getCollateralId());
-        if(collateral == null){
-            return ResultUtil.error(COLLATERAL_NOT_EXIST.getCode(),"抵押物不存在");
+
+        if(collateralPlan.getOperatorId()!= BaseContext.getCurrentId())
+            throw new DescribeException(STEP_USER_NOT_EXPECTED);
+
+//        Collateral collateral = collateralService.findCollateralById(collateralPlan.getCollateralId());
+//        if(collateral == null){
+//            throw new DescribeException(COLLATERAL_NOT_EXIST);
+//        }
+
+        Long caseId = collateralPlan.getCaseId();
+        Long userId= BaseContext.getCurrentId();
+        collateralService.updateCollateralStatusByIds(getCollateralIds(collateralPlan.getCollateralIds()),OUT_WAREHOUSE.getMsg());
+        collateralPlanService.updateCollateralStatusById(id,EXECUTION_COMPLETE.getMsg());
+        collateralPlanService.updateOperatorIdAndCommentsById(userId,comments,id);
+
+        stepService.updateUserId1ByCaseIdAndStepName(StepPropertyEnum.DELIVERY_CONFIRMATION.getLabel(),userId,caseId);
+
+        //若所有押品出库,则完成
+        boolean flag = true;
+        List<CollateralVO> collateralVOS = collateralService.findByCaseId(caseId);
+        for(CollateralVO collateralVO:collateralVOS){
+            if(!collateralVO.getStaus().equals(OUT_WAREHOUSE.getMsg())){
+                flag = false;
+                break;
+            }
+        }
+        if(flag){
+            stepService.updateStatusByCaseId(StepEnum.COMPLETED.getMsg(), StepPropertyEnum.COLLATERAL_DELIVERY.getLabel(),caseId);
+            stepService.updateStatusByCaseId(StepEnum.COMPLETED.getMsg(), StepPropertyEnum.DELIVERY_CONFIRMATION.getLabel(),caseId);
+            stepService.tryStartStep(StepPropertyEnum.DELIVERY_CONFIRMATION.getLabel(),caseId);
         }
-        collateralService.updateCollateralStatusByid(collateral.getId(),"出库");
-        collateralPlanService.updateCollateralStatusByid(id,EXECUTION_COMPLETE.getMsg());
+
         return ResultUtil.success("success","抵押物出库成功");
     }
     /**删除抵押物
@@ -259,10 +367,20 @@ public class CollateralController {
     public Result deleteCollateral(@PathVariable("id") Long id){
         Collateral collateral = collateralService.findCollateralById(id);
         if(collateral == null){
-            return ResultUtil.error(COLLATERAL_NOT_EXIST.getCode(),"抵押物不存在");
+            throw new DescribeException(COLLATERAL_NOT_EXIST);
         }
         collateralService.logic_delete(id);
         return ResultUtil.success("success","抵押物删除成功");
     }
 
+    private List<Long> getCollateralIds(String ids){
+        String[] collateralIdsStr = ids.split(",");
+        Long[] collateralIds = Arrays.stream(collateralIdsStr)
+                .map(String::trim) // 去除每个字符串两端的空白字符
+                .map(Long::valueOf) // 将字符串转换为 Long
+                .toArray(Long[]::new); // 转换为 Long 数组
+
+        return Arrays.asList(collateralIds);
+    }
+
 }

+ 64 - 46
src/main/java/com/loan/system/controller/wechat/ContractController.java

@@ -28,6 +28,10 @@ import org.springframework.util.ObjectUtils;
 import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.List;
 import java.util.UUID;
 
@@ -71,19 +75,6 @@ public class ContractController {
 
     }
 
-//    @GetMapping("/{contractSeq}")
-//    @ApiOperation("显示合同表详情(内部人员)")
-//    @PreAuthorize("@pms.hasAnyRoles('SYSTEM_ADMIN','APPROVER','LEAD_SALES', 'ASSIST_SALES', 'FINANCE', 'BACK_OFFICE')")
-//    public Result findContractsDetails(@PathVariable("contractSeq") Integer contractSeq , @RequestParam Long caseId , HttpServletResponse response){
-//        //获取合同信息
-//        List<ContractVO> contractVOS = contractService.findContractByCaseId(caseId);
-//        if(contractVOS.size()<contractSeq)
-//            throw new DescribeException(ExceptionEnum.CONTRACT_NOT_EXIST);
-//        ContractVO contractVO = contractVOS.get(contractSeq-1);
-//
-//        return ResultUtil.success("success",getContractInformation(response,caseId,contractVO));
-//    }
-
     @PostMapping("/{id}")
     @ApiOperation("推送合同")
     @PreAuthorize("@pms.hasAnyRoles('SYSTEM_ADMIN','APPROVER','LEAD_SALES', 'ASSIST_SALES', 'FINANCE', 'BACK_OFFICE')")
@@ -101,6 +92,9 @@ public class ContractController {
         }
 
         Contract contract = contractService.findContractById(contractId);
+        if(ObjectUtils.isEmpty(contract))
+            throw new DescribeException(ExceptionEnum.CONTRACT_NOT_EXIST);
+
         if(contract.getIsPush())
             throw new DescribeException(ExceptionEnum.CONTRACT_HAS_PUSH);
 
@@ -146,42 +140,74 @@ public class ContractController {
         getContractInformation(response,caseId,BeanUtil.copyProperties(contractById,ContractVO.class));
     }
 
-//    @GetMapping("/customer/{contractSeq}")
-//    @ApiOperation("显示合同详情(客户)")
-//    @PreAuthorize("@pms.hasAnyRoles('EXTERNAL')")
-//    public Result findContractsByCustomer(@PathVariable("contractSeq") Integer contractSeq ,@RequestParam Long caseId,HttpServletResponse response){
-//        //显示已经推送过的合同
-//        List<ContractVO> contracts = contractService.findContractByCaseIdAndIsPush(caseId,true);
-//        if(contracts.size()<contractSeq)
-//            throw new DescribeException(ExceptionEnum.CONTRACT_NOT_EXIST);
-//        ContractVO contractVO = contracts.get(contractSeq-1);
-//
-//        return ResultUtil.success("success",getContractInformation(response,caseId,contractVO));
-//    }
     //签署的电子信息先以附件上传
     //再修改合同状态
     @PostMapping("/{id}/sign")
-    @ApiOperation("签署合同(客户)")
-    @PreAuthorize("@pms.hasAnyRoles('EXTERNAL')")
+    @ApiOperation("签署合同")
+    @PreAuthorize("@pms.hasAnyRoles('LEAD_SALES', 'ASSIST_SALES','EXTERNAL')")
     public Result updateContract(@PathVariable("id")Long contractId,@RequestParam Long signId,@RequestParam Long commitedId){
         Contract contract = contractService.findContractById(contractId);
         if(ObjectUtils.isEmpty(contract))
             throw new DescribeException(ExceptionEnum.CONTRACT_NOT_EXIST);
 
-        if(!contract.getIsPush())
-            throw new DescribeException(ExceptionEnum.CONTRACT_NOT_PUSH);
-
         if(contract.getSignedByCustomer())
             throw new DescribeException(ExceptionEnum.CONTRACT_HAS_SIGNED);
 
-        if(!contract.getCustomerId().equals(BaseContext.getCurrentId()))
-            throw new DescribeException(ExceptionEnum.CONTRACT_SIGNED_PERMISSION_NOT_ALLOW);
+        if(signId== null)
+            throw new DescribeException(ExceptionEnum.CONTRACT_NOT_SIGNED);
+
 
         contractService.updateContractById1(contractId,commitedId,signId);
 
         return ResultUtil.success("success");
     }
 
+    @PostMapping("/{id}/signReset")
+    @ApiOperation("重设签署权限")
+    @PreAuthorize("@pms.hasAnyRoles('SYSTEM_ADMIN','APPROVER','LEAD_SALES', 'ASSIST_SALES', 'FINANCE', 'BACK_OFFICE')")
+    public Result updateContractStatus(@PathVariable("id")Long contractId,@RequestParam Long caseId){
+        Contract contract = contractService.findContractById(contractId);
+        if(ObjectUtils.isEmpty(contract))
+            throw new DescribeException(ExceptionEnum.CONTRACT_NOT_EXIST);
+
+        if(caseId == null||!loanService.existsByIdAndIsDelete(caseId))
+            throw new DescribeException(ExceptionEnum.PROJECT_NOT_EXIST);
+
+        StepVO step = stepService.findByStepNameAndCaseId(StepPropertyEnum.CONTRACT_SIGN.getLabel(),caseId);
+        if(ObjectUtils.isEmpty( step)||!step.getStatus().equals(StepEnum.PROCESS.getMsg()))
+            throw new DescribeException(STEP_HAS_NOT_PROCESS);
+
+        Long currentId = step.getUserId1();
+        if(currentId!=null && !BaseContext.getCurrentId().equals(currentId)){
+            throw new DescribeException(STEP_USER_NOT_EXPECTED);
+        }
+
+        contractService.updateSignedCustomerById(contractId);
+        if(contract.getSignedId()!=null){
+            Document document = documentService.findById(contract.getSignedId());
+            String filePath = document.getFilePath();
+
+            if (filePath!=null){
+                try {
+                    Path path = Paths.get(filePath);
+                    boolean deleted = Files.deleteIfExists(path);
+                    if (deleted) {
+                        contractService.deleteSigned(contract.getSignedId());
+                        documentService.deleteFileById(contract.getSignedId());
+                        System.out.println("文件删除成功: " + filePath);
+                    } else {
+                        System.out.println("文件不存在或已被删除: " + filePath);
+                    }
+                } catch (IOException e) {
+                    System.err.println("删除文件时发生错误: " + e.getMessage());
+                    e.printStackTrace();
+                }
+            }
+        }
+
+        return ResultUtil.success("success");
+    }
+
     @PutMapping("/case/{caseId}")
     @ApiOperation("合同签订完成")
     @PreAuthorize("@pms.hasAnyRoles('SYSTEM_ADMIN','APPROVER','LEAD_SALES', 'ASSIST_SALES', 'FINANCE', 'BACK_OFFICE')")
@@ -201,21 +227,9 @@ public class ContractController {
         //合同签约完成
         stepService.updateStatusByCaseId(StepEnum.COMPLETED.getMsg(), StepPropertyEnum.CONTRACT_SIGN_PARENT.getLabel(),caseId);
         stepService.updateStatusByCaseId(StepEnum.COMPLETED.getMsg(),StepPropertyEnum.CONTRACT_SIGN.getLabel(),caseId);
-
-//        //出款开始环节
-//        stepService.updateStatusByCaseId(StepEnum.PROCESS.getMsg(),StepPropertyEnum.DISBURSE_PARENT.getLabel(),caseId);
-//        stepService.updateStatusByCaseId(StepEnum.PROCESS.getMsg(),StepPropertyEnum.PLAN_REPORT.getLabel(),caseId);
+        stepService.tryStartStep(StepPropertyEnum.CONTRACT_SIGN.getLabel(),caseId);
 
 
-//
-//        //取证开始环节
-//        stepService.updateStatusByCaseId(StepEnum.PROCESS.getMsg(),StepPropertyEnum.COLLATERAL_RECEIVE.getLabel(),caseId);
-//        stepService.updateStatusByCaseId(StepEnum.PROCESS.getMsg(),StepPropertyEnum.PLAN_SUBMISSION.getLabel(),caseId);
-//
-//        //送证开始环节
-//        stepService.updateStatusByCaseId(StepEnum.PROCESS.getMsg(),StepPropertyEnum.COLLATERAL_DELIVERY.getLabel(),caseId);
-//        stepService.updateStatusByCaseId(StepEnum.PROCESS.getMsg(),StepPropertyEnum.PLAN_SUBMISSION_2.getLabel(),caseId);
-
         return ResultUtil.success("success");
     }
 
@@ -223,11 +237,15 @@ public class ContractController {
         LoanCaseSimpleVO loancase = loanService.findLoanCaseSimpleByIdAndIsDelete(caseId, false);
         CustomerVO customer = customerService.findByCustomerIdAndIsDelete(loancase.getCustomerId(),false);
         ContractInformation contractInformation = BeanUtil.copyProperties(customer, ContractInformation.class);
+        if (contractVO.getSignedId() != null){
+            Document byId = documentService.findById(contractVO.getSignedId());
+            contractInformation.setSignaturePath1(byId.getFilePath());
+        }
         contractInformation.setContractNo(contractVO.getContractNo());
         contractInformation.setInterestRate(contractVO.getInterestRate());
 
         String downloadName = contractVO.getContractName()+"-"+contractVO.getId();
-        new PoiWordUtil().writeApprove(response,contractPath,contractInformation,downloadName);
+        new PoiWordUtil().writeApprove(response,contractPath+"template1.docx",contractInformation,downloadName);
     }
 
 }

+ 19 - 4
src/main/java/com/loan/system/controller/wechat/CustomerController.java

@@ -1,5 +1,7 @@
 package com.loan.system.controller.wechat;
 
+import com.loan.system.domain.dto.CustomerDTO;
+import com.loan.system.domain.entity.Customer;
 import com.loan.system.domain.pojo.Result;
 import com.loan.system.service.CustomerService;
 import com.loan.system.utils.ResultUtil;
@@ -9,7 +11,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 
-@RestController
+@RestController("AdminCustomerController")
 @RequestMapping("/wechat/customers")
 @Api(tags = "微信客户接口")
 public class CustomerController {
@@ -18,7 +20,7 @@ public class CustomerController {
 
     @GetMapping
     @ApiOperation("查询所有客户")
-    public Result findAllCustomers(Integer pageNum, Integer pageSize){
+    public Result findAllCustomers(@RequestParam(defaultValue = "0") Integer pageNum, @RequestParam(defaultValue = "10") Integer pageSize){
         return ResultUtil.success("success", customerService.getAllCustomers(pageNum, pageSize,false));
     }
 
@@ -28,10 +30,10 @@ public class CustomerController {
         return ResultUtil.success("success", customerService.findByCustomerIdAndIsDelete( id, false));
     }
 
-    @GetMapping("/{key}")
+    @GetMapping("/keys/{key}")
     @ApiOperation("按关键字(姓名/手机号)选择客户")
     @PreAuthorize("@pms.hasAnyRoles('SYSTEM_ADMIN','LEAD_SALES', 'ASSIST_SALES')")
-    public Result findCustomerByKey(@PathVariable("key") String key,Integer pageNum, Integer pageSize){
+    public Result findCustomerByKey(@PathVariable("key") String key,@RequestParam(defaultValue = "0") Integer pageNum, @RequestParam(defaultValue = "10") Integer pageSize){
         return ResultUtil.success("success", customerService.getCustomerByKey(key,false , pageNum, pageSize));
     }
 
@@ -52,4 +54,17 @@ public class CustomerController {
     public Result bankAccount(@RequestBody String mobile){
         return ResultUtil.success("success");
     }
+
+    @PostMapping("/addInfo")
+    @ApiOperation("补充客户信息")
+    public Result addInfo(@RequestBody CustomerDTO customerDTO){
+        customerService.updateInfoByOpenId(customerDTO);
+        return ResultUtil.success("success");
+    }
+
+    @GetMapping("/openId/{id}")
+    @ApiOperation("获取客户信息")
+    public Result getCustomerInfo(@PathVariable("id") String openId){
+        return ResultUtil.success("success", customerService.getCustomerByOpenId(openId));
+    }
 }

+ 24 - 10
src/main/java/com/loan/system/controller/wechat/DictionaryController.java

@@ -1,15 +1,16 @@
 package com.loan.system.controller.wechat;
 
+import com.loan.system.domain.dto.DictDataDTO;
+import com.loan.system.domain.enums.ExceptionEnum;
 import com.loan.system.domain.pojo.Result;
 import com.loan.system.domain.vo.DictionarysVO;
+import com.loan.system.exception.DescribeException;
 import com.loan.system.service.DictionaryService;
 import com.loan.system.utils.ResultUtil;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 
 @RestController
 @RequestMapping("/wechat/dictionary")
@@ -42,14 +43,27 @@ public class DictionaryController {
         return ResultUtil.success("success",dictionaryService.getAllLocations(false));
     }
 
+//    @GetMapping
+//    @ApiOperation("查询业务字典表")
+//    public Result getDictionarys(){
+//        DictionarysVO dictionarys = new DictionarysVO();
+//        dictionarys.setAttributes(dictionaryService.getAllDictAttributes(false));
+//        dictionarys.setTypes( dictionaryService.getAllDictTypes(false));
+//        dictionarys.setChannels(dictionaryService.getAllDictChannels(false));
+//        dictionarys.setLocations(dictionaryService.getAllLocations(false));
+//        dictionarys.setDictDatas(dictionaryService.getAllDictData(false));
+//        return ResultUtil.success("success",dictionarys);
+//    }
+
     @GetMapping
-    @ApiOperation("查询业务字典表")
+    @ApiOperation("查询所有字典数据")
     public Result getDictionarys(){
-        DictionarysVO dictionarys = new DictionarysVO();
-        dictionarys.setAttributes(dictionaryService.getAllDictAttributes(false));
-        dictionarys.setTypes( dictionaryService.getAllDictTypes(false));
-        dictionarys.setChannels(dictionaryService.getAllDictChannels(false));
-        dictionarys.setLocations(dictionaryService.getAllLocations(false));
-        return ResultUtil.success("success",dictionarys);
+        return ResultUtil.success("success",dictionaryService.listDictData());
+    }
+    @GetMapping("/types")
+    @ApiOperation("查询所有字典类型")
+    public Result getAllTypes(){
+        return ResultUtil.success("success",dictionaryService.listDictType());
     }
+
 }

+ 183 - 152
src/main/java/com/loan/system/controller/wechat/DisbursementController.java

@@ -1,9 +1,8 @@
 package com.loan.system.controller.wechat;
 
+import cn.hutool.core.bean.BeanUtil;
 import com.loan.system.context.BaseContext;
-import com.loan.system.domain.dto.ApprovalRecordDTO;
-import com.loan.system.domain.dto.DisbursementDTO;
-import com.loan.system.domain.dto.DisbursementRecordDTO;
+import com.loan.system.domain.dto.*;
 import com.loan.system.domain.entity.*;
 import com.loan.system.domain.enums.*;
 import com.loan.system.domain.pojo.Result;
@@ -11,17 +10,20 @@ import com.loan.system.domain.vo.*;
 import com.loan.system.exception.DescribeException;
 import com.loan.system.service.*;
 import com.loan.system.service.DisbursementRecordService;
+import com.loan.system.utils.RedisData;
 import com.loan.system.utils.ResultUtil;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.StringRedisTemplate;
 import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.ObjectUtils;
 import org.springframework.web.bind.annotation.*;
 
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
-import java.util.List;
+import java.util.*;
 
 import static com.loan.system.domain.enums.ExceptionEnum.*;
 
@@ -48,9 +50,11 @@ public class DisbursementController {
     @Autowired
     private DisbursementRecordService disbursementRecordService;
     @Autowired
-    private RepaymentService repaymentService;
+    private CollateralService collateralService;
     @Autowired
-    private MessageService messageService;
+    private StringRedisTemplate redisTemplate;
+    @Autowired
+    private PawnTicketService pawnTicketService;
 
     @GetMapping("/planDetails")
     @ApiOperation("显示计划详情")//与loanContraller的方法一致,但为了规范
@@ -61,9 +65,27 @@ public class DisbursementController {
 
         DisbursementDetailVO disbursementDetailVO = disbursementService.getLoanCaseAndCustomerByCaseId(caseId);
         //填充
-        Disbursement disbursementByCaseId = disbursementService.getDisbursementByCaseId(caseId);
-        disbursementDetailVO.setDisbursementAmount(disbursementByCaseId.getPlannedAmount());
-        disbursementDetailVO.setCurrentLocation(disbursementByCaseId.getPlannedLocation());
+        if(!ObjectUtils.isEmpty(disbursementDetailVO)){
+            Disbursement disbursementByCaseId = disbursementService.getDisbursementByCaseId(caseId);
+            if(!ObjectUtils.isEmpty(disbursementByCaseId)){
+                disbursementDetailVO.setDisbursementId(disbursementByCaseId.getId());
+                disbursementDetailVO.setDisbursementAmount(disbursementByCaseId.getPlannedAmount());
+                disbursementDetailVO.setCurrentLocation(disbursementByCaseId.getPlannedLocation());
+                disbursementDetailVO.setPlannedTime(disbursementByCaseId.getPlannedTime());
+                disbursementDetailVO.setPlannedComment(disbursementByCaseId.getPlannedComment());
+                disbursementDetailVO.setRejectComment(new RedisData(redisTemplate).getRejectApprovalRecord(caseId,StepPropertyEnum.PLAN_REPORT.getLabel()));
+            }
+            List<CollateralVO> collateralVOS = collateralService.findByCaseId(caseId);
+            List<String> collateralStatus =new ArrayList<>();
+            for(CollateralVO collateralVO:collateralVOS){
+                if(collateralVO.getStaus().isEmpty())
+                    collateralStatus.add("押品未取得");
+                else
+                    collateralStatus.add("押品已取得");
+            }
+            disbursementDetailVO.setCollateralStatus(collateralStatus);
+
+        }
 
         return ResultUtil.success("success",disbursementDetailVO);
     }
@@ -89,14 +111,18 @@ public class DisbursementController {
         }
 
         //上报计划
-        DisbursementVO disbursementVO = disbursementService.addDisbursement(disbursementDTO);
+        DisbursementVO detailsById = disbursementService.findDisbursementDetailsById(disbursementDTO.getCaseId());
+        if(!ObjectUtils.isEmpty(detailsById))
+            disbursementService.updateDisbursementByCaseId(disbursementDTO);
+        else
+            disbursementService.addDisbursement(disbursementDTO);
 
         //修改状态
         stepService.updateUserByCaseId(StepPropertyEnum.PLAN_REPORT.getLabel(), BaseContext.getCurrentId(), disbursementDTO.getCaseId());
         stepService.updateStatusByCaseId( StepEnum.COMPLETED.getMsg(), StepPropertyEnum.PLAN_REPORT.getLabel(),disbursementDTO.getCaseId());
-        stepService.updateStatusByCaseId( StepEnum.PROCESS.getMsg(),StepPropertyEnum.PLAN_AUDIT.getLabel(),disbursementDTO.getCaseId());
-
-        return ResultUtil.success("success",disbursementVO);
+        new RedisData(redisTemplate).deleteApprovalByKey(disbursementDTO.getCaseId(),StepPropertyEnum.PLAN_REPORT.getLabel());
+        stepService.tryStartStep(StepPropertyEnum.PLAN_REPORT.getLabel(),disbursementDTO.getCaseId());
+        return ResultUtil.success("success");
     }
 
     @GetMapping("/approvalDetails")
@@ -108,10 +134,18 @@ public class DisbursementController {
 
         DisbursementDetailVO disbursementDetailVO = disbursementService.getLoanCaseAndCustomerByCaseId(caseId);
         //填充
-        ApprovalRecordVO approvalRecord = approvalService.findByCaseIdAndIsDeleteAndStepName(caseId,StepPropertyEnum.PLAN_AUDIT.getLabel(),BaseContext.getCurrentId());
-        disbursementDetailVO.setApprovalComment(approvalRecord.getComments());
-        StepVO stepVO = stepService.findByStepNameAndCaseId(StepPropertyEnum.REPAY_START.getLabel(),caseId);
-        disbursementDetailVO.setRepaymentUser(userService.findByIdAndIsDelete(stepVO.getUserId1()));
+        if(!ObjectUtils.isEmpty(disbursementDetailVO)){
+            Disbursement disbursementByCaseId = disbursementService.getDisbursementByCaseId(caseId);
+            if(!ObjectUtils.isEmpty(disbursementByCaseId)){
+                disbursementDetailVO.setDisbursementAmount(disbursementByCaseId.getPlannedAmount());
+                disbursementDetailVO.setCurrentLocation(disbursementByCaseId.getPlannedLocation());
+                disbursementDetailVO.setPlannedTime(disbursementByCaseId.getPlannedTime());
+            }
+
+            List<ApprovalRecordVO> approvalRecord = approvalService.findByCaseIdAndStepNameAndApproverIdAndIsDelete(caseId,StepPropertyEnum.PLAN_AUDIT.getLabel(),BaseContext.getCurrentId());
+            if(!ObjectUtils.isEmpty(approvalRecord))
+                disbursementDetailVO.setApprovalRecords1(approvalRecord);
+        }
 
         return ResultUtil.success("success",disbursementDetailVO);
 
@@ -139,38 +173,19 @@ public class DisbursementController {
             throw new DescribeException(STEP_USER_NOT_EXPECTED);
         }
         //选择回款负责人,开启回款开始环节,创建回款单
-        stepService.updateUserId1ByCaseIdAndStepName(StepPropertyEnum.REPAY_START.getLabel(),chargeId,caseId);
-        stepService.updateStatusByCaseId(StepEnum.PROCESS.getMsg(),StepPropertyEnum.REPAY_PARENT.getLabel(),caseId);
-        stepService.updateStatusByCaseId(StepEnum.PROCESS.getMsg(),StepPropertyEnum.REPAY_START.getLabel(),caseId);
+        if(chargeId == null || !userService.existsByIdAndIsDelete(chargeId))
+            throw new DescribeException(ExceptionEnum.USER_NOT_EXIST);
 
-        Repayment repayment = new Repayment();
-        repayment.setCaseId(caseId);
-        repayment.setStartUserId(chargeId);
-        repayment.setTotalAmount(disbursementService.getDisbursementByCaseId(caseId).getPlannedAmount());
-        repaymentService.addRepayment(repayment);
+        stepService.updateUserId1ByCaseIdAndStepName(StepPropertyEnum.DISBURSE_START.getLabel(),chargeId,caseId);
 
         //填写审批意见
-        ApprovalRecordVO approvalRecord_origin = approvalService.findByCaseIdAndIsDeleteAndStepName(caseId,StepPropertyEnum.PLAN_AUDIT.getLabel(),BaseContext.getCurrentId());
-        if (approvalRecord_origin == null) {
-            ApprovalRecord approvalRecord = new ApprovalRecord();
-            approvalRecord.setCaseId(approvalRecord.getCaseId());
-            approvalRecord.setStepName(StepPropertyEnum.PLAN_AUDIT.getLabel());
-            approvalRecord.setApproverId(BaseContext.getCurrentId());
-            approvalRecord.setDecision(DecisionEnum.PASS.getMsg());
-            approvalRecord.setComments(approvalRecordDTO.getComments());
-            approvalRecord.setCreateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
-            approvalRecord.setUpdateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
-            approvalRecord.setIsDelete(false);
-
-            approvalService.save(approvalRecord);
-        }else{
-            approvalService.updateDecisionByCaseIdAndStepNameAndIsDelete(DecisionEnum.PASS.getMsg(),caseId, StepPropertyEnum.PLAN_AUDIT.getLabel(), approvalRecordDTO.getComments(), BaseContext.getCurrentId());
-        }
+        approvalService.addApprovalRecord(caseId,StepPropertyEnum.PLAN_AUDIT.getLabel(),DecisionEnum.PASS.getMsg(),approvalRecordDTO.getComments());
 
         //修改状态
         stepService.updateUserByCaseId(StepPropertyEnum.PLAN_AUDIT.getLabel(), BaseContext.getCurrentId(), caseId);
         stepService.updateStatusByCaseId( StepEnum.COMPLETED.getMsg(),StepPropertyEnum.PLAN_AUDIT.getLabel(),caseId);
-        stepService.updateStatusByCaseId( StepEnum.PROCESS.getMsg(), StepPropertyEnum.DISBURSE_START.getLabel(),caseId);
+        //stepService.updateStatusByCaseId( StepEnum.PROCESS.getMsg(), StepPropertyEnum.DISBURSE_START.getLabel(),caseId);
+        stepService.tryStartStep(StepPropertyEnum.PLAN_AUDIT.getLabel(),caseId);
 
         //TODO:微信推送预审通过消息和通知下一环节
 //        SysMessage message = new SysMessage();
@@ -191,7 +206,7 @@ public class DisbursementController {
     @PostMapping("/approval/reject1")
     @ApiOperation(value = "计划审批驳回")
     @PreAuthorize("@pms.hasRole('APPROVER')")
-    public Result disbursementPlanApprovalReject(@RequestBody ApprovalRecordDTO approvalRecordDTO, @RequestParam Long chargeId) {
+    public Result disbursementPlanApprovalReject(@RequestBody ApprovalRecordDTO approvalRecordDTO) {
         if (ObjectUtils.isEmpty(approvalRecordDTO)||approvalRecordDTO.getCaseId()==null)
             throw new DescribeException(INPUT_ERROR);
 
@@ -208,39 +223,14 @@ public class DisbursementController {
             throw new DescribeException(STEP_USER_NOT_EXPECTED);
         }
 
-        //选择回款负责人,但驳回不应该开启回款开始环节
-        stepService.updateUserId1ByCaseIdAndStepName(StepPropertyEnum.REPAY_START.getLabel(),chargeId,caseId);
-//        stepService.updateStatusByCaseId(StepEnum.PROCESS.getMsg(),StepPropertyEnum.REPAY_PARENT.getLabel(),caseId);
-//        stepService.updateStatusByCaseId(StepEnum.PROCESS.getMsg(),StepPropertyEnum.REPAY_START.getLabel(),caseId);
-
-        Repayment repayment = new Repayment();
-        repayment.setCaseId(caseId);
-        repayment.setStartUserId(chargeId);
-        repayment.setTotalAmount(disbursementService.getDisbursementByCaseId(caseId).getPlannedAmount());
-        repaymentService.addRepayment(repayment);
-
         //填写驳回
-        ApprovalRecordVO approvalRecord_origin = approvalService.findByCaseIdAndIsDeleteAndStepName(caseId,StepPropertyEnum.PLAN_AUDIT.getLabel(),BaseContext.getCurrentId());
-        if (approvalRecord_origin == null) {
-            ApprovalRecord approvalRecord = new ApprovalRecord();
-            approvalRecord.setCaseId(approvalRecord.getCaseId());
-            approvalRecord.setStepName(StepPropertyEnum.PLAN_AUDIT.getLabel());
-            approvalRecord.setApproverId(BaseContext.getCurrentId());
-            approvalRecord.setDecision(DecisionEnum.REJECT.getMsg());
-            approvalRecord.setComments(approvalRecordDTO.getComments());
-            approvalRecord.setCreateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
-            approvalRecord.setUpdateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
-            approvalRecord.setIsDelete(false);
-
-            approvalService.save(approvalRecord);
-        }else{
-            approvalService.updateDecisionByCaseIdAndStepNameAndIsDelete(DecisionEnum.REJECT.getMsg(),caseId, StepPropertyEnum.PLAN_AUDIT.getLabel(), approvalRecordDTO.getComments(), BaseContext.getCurrentId());
-        }
+        approvalService.addApprovalRecord(caseId,StepPropertyEnum.PLAN_AUDIT.getLabel(),DecisionEnum.REJECT.getMsg(),approvalRecordDTO.getComments());
 
         //修改状态
         stepService.updateUserByCaseId(StepPropertyEnum.PLAN_AUDIT.getLabel(), BaseContext.getCurrentId(), caseId);
         stepService.updateStatusByCaseId( StepEnum.PROCESS.getMsg(), StepPropertyEnum.PLAN_REPORT.getLabel(),caseId);
         stepService.updateStatusByCaseId(StepEnum.UNSTART.getMsg(), StepPropertyEnum.PLAN_AUDIT.getLabel(),caseId);
+        new RedisData(redisTemplate).setRejectApprovalRecord(caseId,StepPropertyEnum.PLAN_REPORT.getLabel(),approvalRecordDTO.getComments());
 
         //TODO:微信推送预审通过消息和通知下一环节
 //        SysMessage message = new SysMessage();
@@ -260,18 +250,38 @@ public class DisbursementController {
 
     //上传文件UploadController
     //显示文件列表
-    @GetMapping("/{caseId}/files")
-    @ApiOperation("显示文件列表")
-    public Result findByCaseId(@PathVariable("caseId")Long caseId){
 
-        return ResultUtil.success("success",documentService.findByCaseId(caseId));
+    @GetMapping(("/commitDetail"))
+    @ApiOperation("显示出款启动详情")
+    public Result findLoanCaseDetails3(@RequestParam Long caseId) {
+        //TODO:待修改
+        DisbursementDetailVO disbursementDetailVO = new DisbursementDetailVO();
+
+        DisbursementVO detailsById = disbursementService.findDisbursementDetailsById(caseId);
+        if (detailsById != null)
+            disbursementDetailVO.setDisbursementComment(detailsById.getDisbursementComment());
+
+        List<PawnTicketInfo> pawnTicketInfoList = pawnTicketService.findByCaseIdAndIsDelete(caseId);
+        Map<Long,String> contractIdAndPawn = new HashMap<>();
+        for (PawnTicketInfo pawnTicketInfo : pawnTicketInfoList) {
+            Long contractId = pawnTicketInfo.getContractId();
+            String pawnTicketNo = pawnTicketInfo.getPawnTicketNo();
+            contractIdAndPawn.put(contractId,pawnTicketNo);
+        }
+
+        disbursementDetailVO.setContractAndPawn(contractIdAndPawn);
+        disbursementDetailVO.setRejectComment(new RedisData(redisTemplate).getRejectApprovalRecord(caseId,StepPropertyEnum.DISBURSE_START.getLabel()));
+        return ResultUtil.success("success",disbursementDetailVO);
     }
 
     @PutMapping("/commit")
     @ApiOperation(value = "出款启动")
     @PreAuthorize("@pms.hasAnyRoles('APPROVER','LEAD_SALES')")
-    public Result commitDisbursement(@RequestParam Long caseId) {
-        if(caseId == null ||!loanService.existsByIdAndIsDelete(caseId))
+    public Result commitDisbursement(@RequestBody DisbursementStartDTO disbursementStartDTO) {
+        if (ObjectUtils.isEmpty(disbursementStartDTO)||disbursementStartDTO.getCaseId()==null)
+            throw new DescribeException(INPUT_ERROR);
+        Long caseId = disbursementStartDTO.getCaseId();
+        if(!loanService.existsByIdAndIsDelete(caseId))
             throw new DescribeException(ExceptionEnum.PROJECT_NOT_EXIST);
 
         StepVO stepVO = stepService.findByStepNameAndCaseId(StepPropertyEnum.DISBURSE_START.getLabel(),caseId);
@@ -283,10 +293,15 @@ public class DisbursementController {
             throw new DescribeException(STEP_USER_NOT_EXPECTED);
         }
 
+        //TODO:添加当票信息
+        pawnTicketService.addPawnTicket(disbursementStartDTO.getContractAndPawn(),caseId);
+        disbursementService.updateDisbursementCommentsByCaseId(disbursementStartDTO.getComment(),caseId);
+        new RedisData(redisTemplate).deleteApprovalByKey(caseId,StepPropertyEnum.DISBURSE_START.getLabel());
+
         //修改状态
         stepService.updateUserByCaseId(StepPropertyEnum.DISBURSE_START.getLabel(), BaseContext.getCurrentId(), caseId);
         stepService.updateStatusByCaseId( StepEnum.COMPLETED.getMsg(),StepPropertyEnum.DISBURSE_START.getLabel(),caseId);
-        stepService.updateStatusByCaseId(StepEnum.PROCESS.getMsg(),StepPropertyEnum.DISBURSE_AUDIT.getLabel(),  caseId);
+        stepService.tryStartStep(StepPropertyEnum.DISBURSE_START.getLabel(),caseId);
 
         //TODO:微信推送预审通过消息和通知下一环节
 //        SysMessage message = new SysMessage();
@@ -304,6 +319,32 @@ public class DisbursementController {
         return ResultUtil.success("success");
     }
 
+    @GetMapping("/approvalDetails2")
+    @ApiOperation("显示出款审批详情")//与loanContraller的方法一致,但为了规范
+    @PreAuthorize("@pms.hasAnyRoles('SYSTEM_ADMIN','APPROVER','LEAD_SALES', 'ASSIST_SALES', 'FINANCE', 'BACK_OFFICE')")
+    public Result findLoanCaseDetail3(@RequestParam Long caseId){
+        if(caseId == null||!loanService.existsByIdAndIsDelete(caseId))
+            throw new DescribeException(ExceptionEnum.PROJECT_NOT_EXIST);
+
+        DisbursementDetailVO disbursementDetailVO = disbursementService.getLoanCaseAndCustomerByCaseId(caseId);
+        //填充
+        if(!ObjectUtils.isEmpty(disbursementDetailVO)){
+            Disbursement disbursementByCaseId = disbursementService.getDisbursementByCaseId(caseId);
+            if(!ObjectUtils.isEmpty(disbursementByCaseId)){
+                disbursementDetailVO.setDisbursementAmount(disbursementByCaseId.getPlannedAmount());
+                disbursementDetailVO.setCurrentLocation(disbursementByCaseId.getPlannedLocation());
+                disbursementDetailVO.setPlannedTime(disbursementByCaseId.getPlannedTime());
+            }
+
+            List<ApprovalRecordVO> approvalRecord = approvalService.findByCaseIdAndStepNameAndApproverIdAndIsDelete(caseId,StepPropertyEnum.DISBURSE_AUDIT.getLabel(),BaseContext.getCurrentId());
+            if(!ObjectUtils.isEmpty(approvalRecord))
+                disbursementDetailVO.setApprovalRecords2(approvalRecord);
+        }
+
+        return ResultUtil.success("success",disbursementDetailVO);
+
+    }
+
 
     @PostMapping("/approval/pass2")
     @ApiOperation(value = "出款审批")
@@ -325,31 +366,16 @@ public class DisbursementController {
             throw new DescribeException(STEP_USER_NOT_EXPECTED);
         }
 
-        //填写审批意见 //驳回呢?
-        ApprovalRecordVO approvalRecord_origin = approvalService.findByCaseIdAndIsDeleteAndStepName(caseId,StepPropertyEnum.DISBURSE_AUDIT.getLabel(),BaseContext.getCurrentId());
-        if (approvalRecord_origin == null) {
-            ApprovalRecord approvalRecord = new ApprovalRecord();
-            approvalRecord.setCaseId(approvalRecord.getCaseId());
-            approvalRecord.setStepName(StepPropertyEnum.DISBURSE_AUDIT.getLabel());
-            approvalRecord.setApproverId(BaseContext.getCurrentId());
-            approvalRecord.setDecision(DecisionEnum.PASS.getMsg());
-            approvalRecord.setComments(approvalRecordDTO.getComments());
-            approvalRecord.setCreateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
-            approvalRecord.setUpdateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
-            approvalRecord.setIsDelete(false);
-
-            approvalService.save(approvalRecord);
-        }else{
-            approvalService.updateDecisionByCaseIdAndStepNameAndIsDelete(DecisionEnum.PASS.getMsg(),caseId, StepPropertyEnum.DISBURSE_AUDIT.getLabel(), approvalRecordDTO.getComments(), BaseContext.getCurrentId());
-        }
+        //填写审批意见
+        approvalService.addApprovalRecord(caseId,StepPropertyEnum.DISBURSE_AUDIT.getLabel(),DecisionEnum.PASS.getMsg(),approvalRecordDTO.getComments());
 
         //修改出款单
         disbursementService.updateApprovalUserById(BaseContext.getCurrentId(),disbursementService.getDisbursementByCaseId(caseId).getId());
 
         //修改状态
         stepService.updateUserByCaseId(StepPropertyEnum.DISBURSE_AUDIT.getLabel(), BaseContext.getCurrentId(), caseId);
-        stepService.updateStatusByCaseId(StepPropertyEnum.DISBURSE_AUDIT.getLabel(), StepEnum.COMPLETED.getMsg(),caseId);
-        stepService.updateStatusByCaseId(StepPropertyEnum.FINANCE_DISBURSE.getLabel(), StepEnum.PROCESS.getMsg(), caseId);
+        stepService.updateStatusByCaseId( StepEnum.COMPLETED.getMsg(),StepPropertyEnum.DISBURSE_AUDIT.getLabel(),caseId);
+        stepService.tryStartStep(StepPropertyEnum.DISBURSE_AUDIT.getLabel(),caseId);
 
         return ResultUtil.success("success");
     }
@@ -380,25 +406,11 @@ public class DisbursementController {
 //            throw new DescribeException(PRE_STEP_NOT_COMPLETE);
 
         //填写驳回意见
-        ApprovalRecordVO approvalRecord_origin = approvalService.findByCaseIdAndIsDeleteAndStepName(caseId,StepPropertyEnum.DISBURSE_AUDIT.getLabel(),BaseContext.getCurrentId());
-        if (approvalRecord_origin == null) {
-            ApprovalRecord approvalRecord = new ApprovalRecord();
-            approvalRecord.setCaseId(approvalRecord.getCaseId());
-            approvalRecord.setStepName(StepPropertyEnum.DISBURSE_AUDIT.getLabel());
-            approvalRecord.setApproverId(BaseContext.getCurrentId());
-            approvalRecord.setDecision(DecisionEnum.REJECT.getMsg());
-            approvalRecord.setComments(approvalRecordDTO.getComments());
-            approvalRecord.setCreateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
-            approvalRecord.setUpdateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
-            approvalRecord.setIsDelete(false);
-
-            approvalService.save(approvalRecord);
-        }else{
-            approvalService.updateDecisionByCaseIdAndStepNameAndIsDelete(DecisionEnum.REJECT.getMsg(),caseId, StepPropertyEnum.DISBURSE_AUDIT.getLabel(), approvalRecordDTO.getComments(), BaseContext.getCurrentId());
-        }
+        approvalService.addApprovalRecord(caseId,StepPropertyEnum.DISBURSE_AUDIT.getLabel(),DecisionEnum.REJECT.getMsg(),approvalRecordDTO.getComments());
 
         //修改出款单
         disbursementService.updateApprovalUserById(BaseContext.getCurrentId(),disbursementService.getDisbursementByCaseId(caseId).getId());
+        new RedisData( redisTemplate).setRejectApprovalRecord(caseId,StepPropertyEnum.DISBURSE_START.getLabel(),approvalRecordDTO.getComments());
 
         //修改状态
         stepService.updateUserByCaseId(StepPropertyEnum.DISBURSE_AUDIT.getLabel(), BaseContext.getCurrentId(), caseId);
@@ -411,24 +423,41 @@ public class DisbursementController {
     @GetMapping("/financeDetails")
     @ApiOperation("显示财务出款详情")//与loanContraller的方法一致,但为了规范
     @PreAuthorize("@pms.hasAnyRoles('SYSTEM_ADMIN','APPROVER','LEAD_SALES', 'ASSIST_SALES', 'FINANCE', 'BACK_OFFICE')")
-    public Result findLoanCaseDetails3(@RequestParam Long caseId){
+    public Result findLoanCaseDetails4(@RequestParam Long caseId){
         if(caseId == null || !loanService.existsByIdAndIsDelete(caseId))
             throw new DescribeException(ExceptionEnum.PROJECT_NOT_EXIST);
 
         DisbursementDetailVO disbursementDetailVO = disbursementService.getLoanCaseAndCustomerByCaseId(caseId);
         //填充
-        List<DisbursementRecordVO> records = disbursementRecordService.findRecordById(disbursementService.getDisbursementByCaseId(caseId).getId());
-        disbursementDetailVO.setDisbursementRecords(records);
-        disbursementDetailVO.setTotalAmount(disbursementService.getDisbursementByCaseId(caseId).getPlannedAmount());
+        if(!ObjectUtils.isEmpty(disbursementDetailVO)){
+            Disbursement disbursementByCaseId = disbursementService.getDisbursementByCaseId(caseId);
+            disbursementDetailVO.setDisbursementId(disbursementByCaseId.getId());
+            if(!ObjectUtils.isEmpty(disbursementByCaseId)){
+                List<DisbursementRecordVO> records = disbursementRecordService.findRecordById(disbursementByCaseId.getId());
+
+                double currentAmount = 0;
+                for (int i = 0; i < records.size(); i++){
+                    DisbursementRecordVO record = records.get(i);
+                    record.setFinanceName(userService.findByIdAndIsDelete(record.getFinanceId()).getRealName());
+                    currentAmount += record.getAmount();
+                }
+                disbursementDetailVO.setDisbursementRecords(records);
+                disbursementDetailVO.setCurrentAmount(currentAmount);
+                disbursementDetailVO.setTotalAmount(disbursementByCaseId.getPlannedAmount());
+            }
 
-        return ResultUtil.success("success",loanService.findLoanCaseDetailsById(caseId));
+        }
+
+        return ResultUtil.success("success",disbursementDetailVO);
     }
 
     @PostMapping("/amount")
     @ApiOperation(value = "财务出款")
-    @PreAuthorize("@pms.hasRole('FINANCE')")
-    public Result financeDisbursement(@RequestBody DisbursementRecordDTO disbursementRecordDTO,@RequestParam Long caseId) {
-        if (ObjectUtils.isEmpty(disbursementRecordDTO)||disbursementRecordDTO.getDisbursementId() == null)
+    @PreAuthorize("@pms.hasRole('FINANCE')")//TODO:多次出款,负责人可能不一样
+    public Result financeDisbursement(@RequestBody DisbursementRecordListWrapper disbursementRecordListWrapper, @RequestParam Long caseId, @RequestParam Double currentAmount) {
+        List<DisbursementRecordDTO> disbursementRecordDTOs = disbursementRecordListWrapper.getDisbursementRecordDTOs();
+        System.out.println(disbursementRecordDTOs);
+        if (ObjectUtils.isEmpty(disbursementRecordDTOs)||disbursementRecordDTOs.get(0).getDisbursementId() == null)
             throw new DescribeException(INPUT_ERROR);
 
         if(!loanService.existsByIdAndIsDelete(caseId))
@@ -438,61 +467,60 @@ public class DisbursementController {
         if(ObjectUtils.isEmpty(stepVO)||!stepVO.getStatus().equals(StepEnum.PROCESS.getMsg()))
             throw new DescribeException(STEP_HAS_NOT_PROCESS);
 
-//        Long currentId = stepVO.getUserId1();
-//        if(currentId!=null && !BaseContext.getCurrentId().equals(currentId)){
-//            throw new DescribeException(STEP_USER_NOT_EXPECTED);
-//        }
+        Long disbursementId = disbursementRecordDTOs.get(0).getDisbursementId();
+        double totalAmount=0.0;
+        for(DisbursementRecordDTO disbursementRecordDTO:disbursementRecordDTOs) {
+            totalAmount += disbursementRecordDTO.getAmount();
+            disbursementRecordDTO.setDisbursementId(disbursementId);//防止列表中的某一个id为空,导致记录关联失败
+        }
 
-        //修改出款单
-        //disbursementService.updateOperationUserById(BaseContext.getCurrentId(),disbursementService.getDisbursementByCaseId(caseId).getId());
+        if ((currentAmount + totalAmount) > (disbursementService.getDisbursementByCaseId(caseId).getPlannedAmount() + 0.1))
+                throw new DescribeException(ExceptionEnum.AMOUNT_HAS_EXCEED_PLANNED_AMOUNT);
 
-        //添加出款记录
-        disbursementRecordService.addDisbursementRecord(disbursementRecordDTO);
+        //添加出款记录 TODO:不能将这两个循环合并,总金额过多会报错,导致添加的记录无法回滚。
+        for (DisbursementRecordDTO disbursementRecordDTO:disbursementRecordDTOs)
+            disbursementRecordService.addDisbursementRecord(disbursementRecordDTO);
 
-        //修改状态
-        //stepService.updateUserByCaseId(StepPropertyEnum.FINANCE_DISBURSE.getLabel(), BaseContext.getCurrentId(), caseId);TODO:分多次出款,不一定是同一个人
-        stepService.updateStatusByCaseId( StepEnum.COMPLETED.getMsg(),StepPropertyEnum.FINANCE_DISBURSE.getLabel(),caseId);
-        stepService.updateStatusByCaseId( StepEnum.PROCESS.getMsg(),StepPropertyEnum.DISBURSE_CONFIRM.getLabel(), caseId);
+        //修改状态(出款金额达标才修改)
+        if(Math.abs(currentAmount+totalAmount-disbursementService.getDisbursementByCaseId(caseId).getPlannedAmount())<=Double.MIN_VALUE){
+            stepService.updateStatusByCaseId( StepEnum.COMPLETED.getMsg(),StepPropertyEnum.FINANCE_DISBURSE.getLabel(),caseId);
+            stepService.tryStartStep(StepPropertyEnum.FINANCE_DISBURSE.getLabel(),caseId);
+        }
 
         //TODO:微信推送预审通过消息和通知下一环节
-//        SysMessage message = new SysMessage();
-//        message.setMobile(null);
-//        message.setUserRole("");
-//        message.setMessageTitle("");
-//        message.setMessageContent("");
-//        message.setStepName("");
-//        message.setRelatedId(loanCase.getId());
-//        message.setRelatedType("");
-//        messageService.addMessage(message);
 //        wxService.sendTemplateMessage(loanCase.getCustomer().getMobile(),new TemplateMessage());
 
-
         return ResultUtil.success("success");
     }
 
     @GetMapping("/confirmDetails")
     @ApiOperation("显示业务确认详情")//与loanContraller的方法一致,但为了规范
     @PreAuthorize("@pms.hasAnyRoles('SYSTEM_ADMIN','APPROVER','LEAD_SALES', 'ASSIST_SALES', 'FINANCE', 'BACK_OFFICE')")
-    public Result findLoanCaseDetails4(@RequestParam Long caseId){
+    public Result findLoanCaseDetails5(@RequestParam Long caseId){
         if(caseId == null ||!loanService.existsByIdAndIsDelete(caseId))
             throw new DescribeException(ExceptionEnum.PROJECT_NOT_EXIST);
 
         DisbursementDetailVO disbursementDetailVO = disbursementService.getLoanCaseAndCustomerByCaseId(caseId);
         //填充
-        List<DisbursementRecordVO> records = disbursementRecordService.findRecordById(disbursementService.getDisbursementByCaseId(caseId).getId());
-        disbursementDetailVO.setDisbursementRecords(records);
-
-        Disbursement disbursement = disbursementService.getDisbursementByCaseId(caseId);
-        disbursementDetailVO.setTotalAmount(disbursement.getPlannedAmount());
-        disbursementDetailVO.setConfirmComment(disbursement.getComments());
+       if(!ObjectUtils.isEmpty(disbursementDetailVO)){
+           Disbursement disbursement = disbursementService.getDisbursementByCaseId(caseId);
+           if(!ObjectUtils.isEmpty(disbursement)){
+               List<DisbursementRecordVO> records = disbursementRecordService.findRecordById(disbursement.getId());
+               disbursementDetailVO.setDisbursementRecords(records);
+
+               disbursementDetailVO.setTotalAmount(disbursement.getPlannedAmount());
+               disbursementDetailVO.setConfirmComment(disbursement.getConfirmComment());
+               
+           }
+       }
 
-        return ResultUtil.success("success",loanService.findLoanCaseDetailsById(caseId));
+        return ResultUtil.success("success",disbursementDetailVO);
     }
 
     @PostMapping("/confirm")
     @ApiOperation(value = "业务确认")
     @PreAuthorize("@pms.hasAnyRoles('LEAD_SALES', 'ASSIST_SALES')")
-    public Result confirmDisbursement(@RequestParam("caseId") Long caseId,@RequestParam("comments") String comments) {
+    public Result confirmDisbursement(@RequestParam("caseId") Long caseId,@RequestParam("comment") String comment) {
         if(caseId == null ||!loanService.existsByIdAndIsDelete(caseId))
             throw new DescribeException(ExceptionEnum.PROJECT_NOT_EXIST);
 
@@ -506,11 +534,14 @@ public class DisbursementController {
         }
 
         //设置说明
-        disbursementService.updateCommentsById(comments,disbursementService.getDisbursementByCaseId(caseId).getId());
+        disbursementService.updateCommentsById(comment,disbursementService.getDisbursementByCaseId(caseId).getId());
+        disbursementService.updateStatusByCaseId(DecisionEnum.DISBURSEMENT_COMPLETE.getMsg(),caseId);
 
         //修改状态
         stepService.updateUserByCaseId(StepPropertyEnum.DISBURSE_CONFIRM.getLabel(), BaseContext.getCurrentId(), caseId);
+        stepService.updateStatusByCaseId(StepEnum.COMPLETED.getMsg(), StepPropertyEnum.DISBURSE_PARENT.getLabel(), caseId);
         stepService.updateStatusByCaseId(StepEnum.COMPLETED.getMsg(),StepPropertyEnum.DISBURSE_CONFIRM.getLabel(), caseId);
+        stepService.tryStartStep(StepPropertyEnum.DISBURSE_CONFIRM.getLabel(),caseId);
 
         //填写合同编号
         List<ContractVO> contractByCaseId = contractService.findContractByCaseId(caseId);

+ 285 - 105
src/main/java/com/loan/system/controller/wechat/LoanController.java

@@ -1,31 +1,31 @@
 package com.loan.system.controller.wechat;
 
+import cn.hutool.core.bean.BeanUtil;
 import com.loan.system.context.BaseContext;
 import com.loan.system.domain.dto.*;
 import com.loan.system.domain.entity.*;
-import com.loan.system.domain.enums.ExceptionEnum;
-import com.loan.system.domain.enums.RoleEnum;
-import com.loan.system.domain.enums.StepEnum;
-import com.loan.system.domain.enums.StepPropertyEnum;
+import com.loan.system.domain.enums.*;
 import com.loan.system.domain.pojo.Result;
+import com.loan.system.domain.pojo.TemplateMessage;
 import com.loan.system.domain.vo.LoanCaseVO;
 import com.loan.system.domain.vo.StepVO;
 import com.loan.system.exception.DescribeException;
 import com.loan.system.service.*;
+import com.loan.system.utils.RedisData;
 import com.loan.system.utils.ResultUtil;
 import com.mysql.cj.protocol.Message;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.StringRedisTemplate;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.util.ObjectUtils;
 import org.springframework.web.bind.annotation.*;
 
-import java.util.ArrayList;
-import java.util.List;
+import javax.swing.text.MaskFormatter;
+import java.util.*;
 
-import static com.loan.system.domain.enums.ExceptionEnum.STEP_HAS_NOT_PROCESS;
-import static com.loan.system.domain.enums.ExceptionEnum.STEP_USER_NOT_EXPECTED;
+import static com.loan.system.domain.enums.ExceptionEnum.*;
 
 @RestController
 @RequestMapping("/wechat/case")
@@ -49,13 +49,155 @@ public class LoanController {
     @Autowired
     private ContractAndCollateralService contractAndCollateralService;
     @Autowired
-    private MessageService messageService;
+    private WxService wxService;
+    @Autowired
+    private UserService userService;
+    @Autowired
+    private StringRedisTemplate stringRedisTemplate;
+
+
+    @GetMapping
+    @ApiOperation("显示所有业务")
+    @PreAuthorize("@pms.hasAnyRoles('SYSTEM_ADMIN','APPROVER','LEAD_SALES', 'ASSIST_SALES', 'FINANCE', 'BACK_OFFICE')")
+    public Result findLoanCaseAll(@RequestParam(defaultValue = "0") Integer pageNum,@RequestParam(defaultValue = "20") Integer pageSize){
+        return ResultUtil.success("success",loanService.findLoanCaseAll(pageNum, pageSize,false));
+    }
+
+    @GetMapping("/customer")
+    @ApiOperation("显示客户的所有业务")
+    @PreAuthorize("@pms.hasAnyRoles('EXTERNAL')")
+    public Result findLoanCaseByCustomerId(@RequestParam(defaultValue = "0") Integer pageNum,@RequestParam(defaultValue = "20") Integer pageSize){
+        List<LoanCaseVO> loanCases = loanService.findLoanCaseByCustomerId(BaseContext.getCurrentId(),pageNum,pageSize,false);
+        return ResultUtil.success("success",loanCases);
+    }
 
     @GetMapping("/dealing")
     @ApiOperation("显示处理中的业务")
     @PreAuthorize("@pms.hasAnyRoles('SYSTEM_ADMIN','APPROVER','LEAD_SALES', 'ASSIST_SALES', 'FINANCE', 'BACK_OFFICE')")
-    public Result findLoanCaseByIsComplete(@RequestParam(value = "isComplete",defaultValue =  "false") Boolean isComplete ,Integer pageNum, Integer pageSize){
-        List<LoanCaseVO> loanCases = loanService.findLoanCaseByIsComplete(pageNum, pageSize,isComplete,false);
+    public Result findLoanCaseByIsComplete(@RequestParam(defaultValue = "0") Integer pageNum,@RequestParam(defaultValue = "20") Integer pageSize){
+        List<LoanCaseVO> loanCases = loanService.findLoanCaseByIsComplete(pageNum,pageSize,DecisionEnum.PROCESS.getMsg(),false);
+
+        return ResultUtil.success("success",loanCases);
+    }
+
+    @GetMapping("/completed")
+    @ApiOperation("显示处理中的业务")
+    @PreAuthorize("@pms.hasAnyRoles('SYSTEM_ADMIN','APPROVER','LEAD_SALES', 'ASSIST_SALES', 'FINANCE', 'BACK_OFFICE')")
+    public Result findLoanCaseByCompleted(@RequestParam(defaultValue = "0") Integer pageNum,@RequestParam(defaultValue = "20") Integer pageSize){
+        List<LoanCaseVO> loanCases = loanService.findLoanCaseByIsComplete(pageNum,pageSize,DecisionEnum.COMPLETE.getMsg(),false);
+
+        return ResultUtil.success("success",loanCases);
+    }
+
+    @GetMapping("/stepName/dealings")
+    @ApiOperation("按环节名称查询业务")
+    @PreAuthorize("@pms.hasAnyRoles('SYSTEM_ADMIN','APPROVER','LEAD_SALES', 'ASSIST_SALES', 'FINANCE', 'BACK_OFFICE')")
+    public Result findLoanCaseByStepNameAndIsComplete(@RequestParam String stepName){
+        if (stepName== null)
+            throw new DescribeException(INPUT_ERROR);
+        return ResultUtil.success("success",loanService.listLoanCaseByStepName(stepName));
+    }
+
+    @GetMapping("/{role}/dealings")
+    @ApiOperation("按客户角色查询业务")
+    @PreAuthorize("@pms.hasAnyRoles('SYSTEM_ADMIN','APPROVER','LEAD_SALES', 'ASSIST_SALES', 'FINANCE', 'BACK_OFFICE')")
+    public Result findLoanCaseByRoleAndIsComplete(@PathVariable  String role, @RequestParam(defaultValue = "0") Integer pageNum,@RequestParam(defaultValue = "20") Integer pageSize){
+        if(role.equals(RoleEnum.ALL.getMsg()))
+            return ResultUtil.success("success",loanService.findLoanCaseByIsComplete(pageNum,pageSize,DecisionEnum.PROCESS.getMsg(),false));
+        //根据角色返回业务列表,业务员返回全部未完成、审批员与财务员仅展示未审批或未财务审批的人物
+        Map<String,List<String>> roleAndStep = getRoleAndStep();
+        List<Long> loanCaseIds = loanService.findIdsByIsComplete(DecisionEnum.PROCESS.getMsg(), false);
+        List<Long> ids = new ArrayList<>();
+        List<StepVO> currentSteps=new ArrayList<>();
+
+        for(Long caseId : loanCaseIds){
+            List<StepVO> steps = stepService.getStepByCaseId(caseId);
+
+            for (StepVO step : steps) {
+                if (step.getStatus().equals(StepEnum.PROCESS.getMsg()) &&
+                        roleAndStep.get(role).contains(step.getStepName())) {
+                    currentSteps.add(step);
+                    ids.add(step.getCaseId());
+                    break;
+                }
+            }
+
+        }
+        List<LoanCaseVO> loanCaseVOS = loanService.findLoanCaseByIds(ids, pageNum, pageSize, false);
+        for(int i=0;i<loanCaseVOS.size();i++){
+            LoanCaseVO loanCaseVO = loanCaseVOS.get(i);
+            loanCaseVO.setStep(currentSteps.get(i));
+            loanCaseVO.setCategory(getCategory(currentSteps.get(i).getCode()));
+
+        }
+        return ResultUtil.success("success",loanCaseVOS);
+    }
+    private Integer getCategory(Integer stepCode) {
+        if(stepCode>=500 && stepCode<520)
+            return 1;
+        else if(stepCode>=520 && stepCode<530)
+            return 2;
+        else if(stepCode>=530 && stepCode<540)
+            return 3;
+        else if(stepCode>=540 && stepCode<560)
+            return 4;
+        else if(stepCode>=560 && stepCode<580)
+            return 5;
+
+        return 0;
+    }
+
+
+    @GetMapping("/all/{key}")
+    @ApiOperation("按客户关键字查询业务(所有)")
+    @PreAuthorize("@pms.hasAnyRoles('SYSTEM_ADMIN','APPROVER','LEAD_SALES', 'ASSIST_SALES', 'FINANCE', 'BACK_OFFICE')")
+    public Result findAllLoanCaseByKey(@PathVariable String key,@RequestParam(defaultValue = "0") Integer pageNum,@RequestParam(defaultValue = "20") Integer pageSize){
+        List<Customer> customers = customerService.getAllCustomerByKey(key, false);
+        List<Long> customerIds = new ArrayList<>();
+        for(Customer customer : customers)
+            customerIds.add(customer.getId());
+
+        List<LoanCaseVO> loanCases = loanService.findLoanCaseByCustomerIds(customerIds,pageNum,pageSize,false);
+
+        return ResultUtil.success("success",loanCases);
+    }
+
+    @GetMapping("/dealing/{key}")
+    @ApiOperation("按客户关键字查询业务")
+    @PreAuthorize("@pms.hasAnyRoles('SYSTEM_ADMIN','APPROVER','LEAD_SALES', 'ASSIST_SALES', 'FINANCE', 'BACK_OFFICE')")
+    public Result findLoanCaseByKey(@PathVariable String key,@RequestParam(defaultValue = "0") Integer pageNum,@RequestParam(defaultValue = "20") Integer pageSize){
+        List<Customer> customers = customerService.getAllCustomerByKey(key, false);
+        List<Long> customerIds = new ArrayList<>();
+        for(Customer customer : customers)
+            customerIds.add(customer.getId());
+
+        List<LoanCaseVO> loanCases = loanService.findLoanCaseByCustomerIds(customerIds,pageNum,pageSize,DecisionEnum.PROCESS.getMsg(),false);
+
+        return ResultUtil.success("success",loanCases);
+    }
+
+    @GetMapping("/dealing/currentUser/{userId}")
+    @ApiOperation("按当前处理人查询待处理业务")
+    @PreAuthorize("@pms.hasAnyRoles('SYSTEM_ADMIN','APPROVER','LEAD_SALES', 'ASSIST_SALES', 'FINANCE', 'BACK_OFFICE')")
+    public Result findLoanCaseByCurrentUser(@PathVariable Long userId,@RequestParam(defaultValue = "0") Integer pageNum,@RequestParam(defaultValue = "20") Integer pageSize) {
+        //获取所有业务id
+        List<Long> loanCaseIds = loanService.findIdsByIsComplete(DecisionEnum.PROCESS.getMsg(), false);
+        List<Long> ids = new ArrayList<>();
+        for (Long loanCaseId : loanCaseIds) {
+            //寻找每个id的阶段
+            List<StepVO> stepByCaseId = stepService.getStepByCaseId(loanCaseId);
+            //判断是否有未完成的阶段
+            for (StepVO stepVO : stepByCaseId)
+                if (!stepVO.getStatus().equals(StepEnum.COMPLETED.getMsg()) &&
+                        ((stepVO.getUserId1() != null && stepVO.getUserId1().equals(userId))
+                                || (stepVO.getUserId2() != null && stepVO.getUserId2().equals(userId)))) {
+                    //返回该id
+                    ids.add(loanCaseId);
+                    break;
+                }
+
+        }
+        List<LoanCaseVO> loanCases = loanService.findLoanCaseByIds(ids,pageNum,pageSize,false);
         return ResultUtil.success("success",loanCases);
     }
 
@@ -70,12 +212,14 @@ public class LoanController {
     @ApiOperation("创建业务")
     @PreAuthorize("@pms.hasAnyRoles('LEAD_SALES','ASSIST_SALES')")
     public Result createLoanCase(@RequestParam("customerId") Long customerId){
-        if(!customerService.existsByIdAndIsDelete(customerId))
+        if(customerId == null ||!customerService.existsByIdAndIsDelete(customerId))
             throw new DescribeException(ExceptionEnum.USER_NOT_EXIST);
         //创建订单
         LoanCaseVO loanCase = loanService.addLoanCaseByCustomerId(customerId);
         //创建流程
-        stepService.addStepByCaseId(loanCase.getId());
+//        stepService.addStepByCaseId(loanCase.getId());
+        List<List<Integer>> seq = StepPropertyEnum.seqList();
+        stepService.addStepByCaseIdAndSequences(loanCase.getId(),seq);
         //设置当前处理人
         stepService.updateUserByCaseId(StepPropertyEnum.BUSINESS_ACCEPT.getLabel(),BaseContext.getCurrentId(),loanCase.getId());
         return ResultUtil.success("success",loanCase);
@@ -88,7 +232,7 @@ public class LoanController {
     @PostMapping("/{id}")//请求中操作复杂,putmapping仅适用于更新操作
     @ApiOperation("提交/保存业务")
     @PreAuthorize("@pms.hasAnyRoles('LEAD_SALES', 'ASSIST_SALES')")
-    public Result saveLoanCase(@PathVariable("id")Long caseId, @RequestBody LoanCaseDTO loanCaseDTO, @RequestParam("isComplete")Boolean isComplete){//isComplete 若保存,则设置为未完成,若提交,则设置为已完成
+    public Result saveLoanCase(@PathVariable("id")Long caseId, @RequestBody LoanCaseDTO loanCaseDTO, @RequestParam(value = "isComplete",defaultValue = "false")Boolean isComplete){//isComplete 若保存,则设置为未完成,若提交,则设置为已完成
         if(!loanService.existsByIdAndIsDelete(caseId))
             throw new DescribeException(ExceptionEnum.PROJECT_NOT_EXIST);
 
@@ -107,53 +251,88 @@ public class LoanController {
         //1.补充业务信息
         loanService.updateLoanCaseById(loanCaseDTO,caseId);
 
-        //2.设置合同(若存在则修改)
-        contractService.deleteAllByCaseId(caseId);
-        List<Contract> contracts = new ArrayList<>();//新增的合同
-        for(ContractDTO contractDTO : loanCaseDTO.getContracts()){
-            Contract c = contractService.saveContract(contractDTO);
-
-            contracts.add(c);
+        RedisData redisData = new RedisData(stringRedisTemplate);
+        redisData.delete(caseId);
+        if(!isComplete){//TODO:利用redis保存草稿信息
+            redisData.setLoanCase(caseId,loanCaseDTO);
+
+        }else {
+            /*
+            //TODO:提交后才真正保存到数据库,并删除原有的草稿
+            因为后续驳回会修改,所以是如果有数据则修改,无数据则新增
+             */
+            //2.设置合同(若存在则修改)
+            contractService.deleteAllByCaseId(caseId);
+            List<Contract> contracts = new ArrayList<>();
+            for (ContractDTO contractDTO : loanCaseDTO.getContracts()){
+                Long contractId = contractDTO.getId();
+                if(contractId != null && contractService.existsById(contractId)){
+                    //修改合同
+                    contractService.updateContractById(contractId,contractDTO,false);
+                    contracts.add(BeanUtil.copyProperties(contractDTO,Contract.class));
+                }else {
+                    //新增合同(若为负数,表示不存在)
+                    Contract contract = contractService.saveContract(contractDTO);
+                    contracts.add(contract);
+                }
+            }
+
+            //3.设置押品
+            collateralService.deleteAllByCaseId(caseId);
+            List<Long> collateralIds = new ArrayList<>();
+            for(CollateralDTO collateralDTO : loanCaseDTO.getCollateral()){
+                Long collateralId = collateralDTO.getId();
+                if(collateralId != null && collateralService.existsById(collateralId)){
+                    //修改押品
+                    collateralService.updateCollateralById(collateralId,collateralDTO,false);
+                }else {
+                    //新增押品
+                    Collateral collateral = collateralService.saveCollateral(collateralDTO);
+                    collateralId = collateral.getId();
+                }
+
+                collateralIds.add(collateralId);
+            }
+
+            //4.设置合同、押品关联
+            contractAndCollateralService.deleteAllByCaseId(caseId);
+            for(int i=0 ; i < loanCaseDTO.getCollateralAndContract().size(); i++){
+                Contract contract = contracts.get( i);
+                List<Integer> collaterals = loanCaseDTO.getCollateralAndContract().get(i).get(contract.getBusinessAttr());
+
+                for (Integer collateralId : collaterals)
+                    contractAndCollateralService.addContractAndCollateral(contract.getId(),collateralIds.get(collateralId-1),caseId);
+            }
+
+            //5.添加其它客户
+            customerOtherService.deleteAllByCaseId(caseId);
+            if(!ObjectUtils.isEmpty(loanCaseDTO.getCustomers1())){
+                System.out.println(loanCaseDTO.getCustomers1());
+                if(loanCaseDTO.getCustomers1().getId() != null && customerOtherService.existsById(loanCaseDTO.getCustomers1().getId()))
+                    customerOtherService.updateCustomerById(loanCaseDTO.getCustomers1(),loanCaseDTO.getCustomers1().getId());
+                else
+                    customerOtherService.addCustomers(loanCaseDTO.getCustomers1());
+            }
+
+            if (!ObjectUtils.isEmpty(loanCaseDTO.getCustomers2())){
+                if(loanCaseDTO.getCustomers2().getId() != null && customerOtherService.existsById(loanCaseDTO.getCustomers2().getId()))
+                    customerOtherService.updateCustomerById(loanCaseDTO.getCustomers2(),loanCaseDTO.getCustomers2().getId());
+                else
+                    customerOtherService.addCustomers(loanCaseDTO.getCustomers2());
+            }
         }
-
-        //3.设置押品
-        collateralService.deleteAllByCaseId(caseId);
-        List<Long> collateralIds = new ArrayList<>();
-        for(CollateralDTO collateralDTO : loanCaseDTO.getCollateral()){
-            Collateral collateral = collateralService.saveCollateral(collateralDTO);
-
-            collateralIds.add(collateral.getId());
-        }
-
-        //4.设置合同、押品关联
-        contractAndCollateralService.deleteAllByCaseId(caseId);
-        for(int i=0 ; i < loanCaseDTO.getCollateralAndContract().size(); i++){
-            Contract contract = contracts.get( i);
-            List<Integer> collaterals = loanCaseDTO.getCollateralAndContract().get(i).get(contract.getBusinessAttr());
-
-            for (Integer collateralId : collaterals)
-                contractAndCollateralService.addContractAndCollateral(contract.getId(),collateralIds.get(collateralId-1),caseId);
-        }
-
-        //5.添加其它客户
-        customerOtherService.deleteAllByCaseId(caseId);
-        if(!ObjectUtils.isEmpty(loanCaseDTO.getCustomers1()))
-            customerOtherService.addCustomers(loanCaseDTO.getCustomers1());
-
-        if (!ObjectUtils.isEmpty(loanCaseDTO.getCustomers2()))
-            customerOtherService.addCustomers(loanCaseDTO.getCustomers2());
-
-
         //6.设置客户婚姻
-        customerService.updateMarriedStatusById(loanCaseDTO.getCustomerId(),loanCaseDTO.getMarriedStatus());
+        customerService.updateMarriedStatusAndIsIllegalById(loanCaseDTO.getCustomerId(),loanCaseDTO.getMarriedStatus(),loanCaseDTO.getIsIllegal());
 
         //7.设置阶段负责人与状态(如果第一个人是辅办人员,那第二个人必须是主办)
         if(isComplete){
+            redisData.deleteApprovalByKey(caseId,StepPropertyEnum.BUSINESS_ACCEPT.getLabel());
             stepService.updateStatusByCaseId(StepEnum.COMPLETED.getMsg(),StepPropertyEnum.BUSINESS_ACCEPT_PARENT.getLabel(),caseId);
             stepService.updateStatusByCaseId(StepEnum.COMPLETED.getMsg(),StepPropertyEnum.BUSINESS_ACCEPT.getLabel(),caseId);
+            stepService.updateUserId1ByCaseIdAndStepName(StepPropertyEnum.BUSINESS_ACCEPT.getLabel(),BaseContext.getCurrentId(),caseId);
+            stepService.updateUserId1ByCaseIdAndStepName(StepPropertyEnum.PRE_TRIAL.getLabel(),BaseContext.getCurrentId(),caseId);
             //设置当阶段为完成,下阶段为开始
-            stepService.updateStatusByCaseId(StepEnum.PROCESS.getMsg(),StepPropertyEnum.PRE_TRIAL_PARENT.getLabel(),caseId);
-            stepService.updateStatusByCaseId(StepEnum.PROCESS.getMsg(),StepPropertyEnum.PRE_TRIAL.getLabel(),caseId);
+            stepService.tryStartStep(StepPropertyEnum.BUSINESS_ACCEPT.getLabel(),caseId);
 
             //TODO:8.微信推送预审通过消息和通知下一环节
 //            SysMessage message = new SysMessage();
@@ -165,7 +344,7 @@ public class LoanController {
   //          message.setRelatedId(caseId);
 //            message.setRelatedType("");
  //           messageService.addMessage(message);
-//            wxService.sendTemplateMessage(loanCase.getCustomer().getMobile(),new TemplateMessage());
+            System.out.println(wxService.sendTemplateMessage(customerService.findByIdAndIsDelete(loanCaseDTO.getCustomerId()).getOpenid(),new TemplateMessage()));;
 
         }
 
@@ -173,54 +352,6 @@ public class LoanController {
     }
 
 
-//    @PostMapping("/{id}/save")//请求中操作复杂,putmapping仅适用于更新操作
-//    @ApiOperation("随时保存业务(未)")
-//    public Result saveLoanCase(@PathVariable("id")Long caseId, @RequestBody LoanCaseDTO loanCaseDTO, @RequestParam("IsComplete")Boolean isComplete){//isComplete 若保存,则设置为未完成,若提交,则设置为已完成
-//        //1.补充业务信息
-//       loanService.updateLoanCaseById(loanCaseDTO,caseId);
-//
-//        //2.设置合同(若存在则修改)
-//        List<Contract> contract = new ArrayList<>();//新增的合同
-//        for(ContractDTO contractDTO : loanCaseDTO.getContracts()){
-//            //contract.setCaseId(caseId);
-//            Contract c =contractService.findContractByCaseIdAndBusinessAttr( caseId,contractDTO.getBusinessAttr(),false);
-//            if(ObjectUtils.isEmpty(c))
-//                c = contractService.saveContract(contractDTO);
-//            else
-//                contractService.updateContractById(c.getId(),contractDTO,false);
-//
-//            //考虑删除合同/押品的情况
-//            contract.add(c);
-//        }
-//
-//        //3.设置押品
-//        List<Long> collateralIds = new ArrayList<>();
-//        for(CollateralDTO collateralDTO : loanCaseDTO.getCollateral()){
-//            Collateral collateral = collateralService.findCollateralByNameAndCaseId(collateralDTO.getCollateralName(),caseId,false);
-//            if(ObjectUtils.isEmpty(collateral))
-//                collateral = collateralService.saveCollateral(collateralDTO);
-//            else
-//                collateralService.updateCollateralById(collateral.getId(),collateralDTO,false);
-//
-//            collateralIds.add(collateral.getId());
-//        }
-////        //4.设置附件
-////        for(DocumentDTO documentDTO : loanCaseDTO.getDocuments()){
-////            //若存在,则修改
-////
-////            //若不存在,则添加
-////        }
-//
-//        //5.设置客户婚姻
-//        customerService.updateMarriedStatusById(loanCaseDTO.getCustomerId(),loanCaseDTO.getMarriedStatus());
-//
-//        //6.设置阶段负责人与状态(如果第一个人是辅办人员,那第二个人必须是主办)
-//        stepService.updateUserByCaseId(StepPropertyEnum.BUSINESS_ACCEPT.getLabel(),BaseContext.getCurrentId(),caseId);
-//
-//        return ResultUtil.success("success");
-//    }
-//
-
 
     @PostMapping("/{id}/preApprove/cancel")
     @ApiOperation("取消预审")
@@ -242,18 +373,67 @@ public class LoanController {
         stepService.updateStatusByCaseId(StepEnum.COMPLETED.getMsg(),StepPropertyEnum.PRE_TRIAL_PARENT.getLabel(),caseId);
         stepService.updateStatusByCaseId(StepEnum.COMPLETED.getMsg(),StepPropertyEnum.PRE_TRIAL.getLabel(),caseId);
 
-        stepService.updateStatusByCaseId(StepEnum.PROCESS.getMsg(),StepPropertyEnum.APPROVAL_PARENT.getLabel(),caseId);
-        stepService.updateStatusByCaseId(StepEnum.PROCESS.getMsg(),StepPropertyEnum.APPROVAL.getLabel(),caseId);
+        stepService.skipStep(StepPropertyEnum.PRE_TRIAL_PARENT.getLabel(),caseId);
 
         stepService.updateUserByCaseId(StepPropertyEnum.PRE_TRIAL.getLabel(), BaseContext.getCurrentId(), caseId);
 
         //添加审批记录
         approveService.addPreApprovalRecord(StepPropertyEnum.PRE_TRIAL.getLabel(),BaseContext.getCurrentId(),caseId);
 
-        //List<StepVO> list = stepService.getStepByCaseId(caseId);
+        return ResultUtil.success("success");
+    }
+
+    @PutMapping("/{id}/complete")
+    @ApiOperation("完成业务")
+    @PreAuthorize("@pms.hasAnyRoles('LEAD_SALES', 'ASSIST_SALES')")
+    public Result completeLoanCase(@PathVariable("id")Long caseId){
+        if(!loanService.existsByIdAndIsDelete(caseId))
+            throw new DescribeException(ExceptionEnum.PROJECT_NOT_EXIST);
 
+        List<StepVO> steps = stepService.getStepByCaseId(caseId);
+        for(StepVO step : steps){
+            if(!step.getStatus().equals(StepEnum.COMPLETED.getMsg()))
+                throw new DescribeException(PROJECT_HAS_NOT_COMPLETED);
+        }
+        loanService.updateIsCompleteByCaseId(StepEnum.COMPLETED.getMsg(),caseId);
         return ResultUtil.success("success");
     }
+    private Map<String,List<String>> getRoleAndStep(){
+        List<String> saleList= Arrays.asList(
+                StepPropertyEnum.BUSINESS_ACCEPT.getLabel(),
+                StepPropertyEnum.PRE_TRIAL.getLabel(),
+                StepPropertyEnum.CONTRACT_SIGN.getLabel(),
+                StepPropertyEnum.PLAN_SUBMISSION.getLabel(),
+                StepPropertyEnum.EVIDENCE_CONFIRMATION.getLabel(),
+                StepPropertyEnum.PLAN_REPORT.getLabel(),
+                StepPropertyEnum.DISBURSE_START.getLabel(),
+                StepPropertyEnum.DISBURSE_CONFIRM.getLabel(),
+                StepPropertyEnum.PLAN_SUBMISSION_2.getLabel(),
+                StepPropertyEnum.DELIVERY_CONFIRMATION.getLabel(),
+                StepPropertyEnum.REPAY_START.getLabel(),
+                StepPropertyEnum.BALANCE_REPAY.getLabel()
+        );
+        List<String> approvalList= Arrays.asList(
+                StepPropertyEnum.APPROVAL.getLabel(),            //审批、取证审批分派、计划审核、出账审核、送证审批分派、回款审批
+                StepPropertyEnum.APPROVAL_ASSIGNMENT.getLabel(),
+                StepPropertyEnum.PLAN_AUDIT.getLabel(),
+                StepPropertyEnum.DISBURSE_AUDIT.getLabel(),
+                StepPropertyEnum.APPROVAL_ASSIGNMENT_2.getLabel(),
+                StepPropertyEnum.REPAY_APPROVAL.getLabel()
+        );
+        List<String> financeList= Arrays.asList(
+                StepPropertyEnum.FINANCE_DISBURSE.getLabel(),//财务出款、财务核算、财务确认
+                StepPropertyEnum.FINANCE_CHECK.getLabel(),
+                StepPropertyEnum.FINANCE_CONFIRM.getLabel()
+        );
+
+        Map<String,List<String>> map = new HashMap<>();
+        map.put(RoleEnum.LEAD_SALES.getMsg(),saleList);
+        map.put(RoleEnum.APPROVER.getMsg(),approvalList);
+        map.put(RoleEnum.FINANCE.getMsg(),financeList);
+        return map;
+    }
+
 
 
 }

+ 345 - 0
src/main/java/com/loan/system/controller/wechat/LoanController_copy.java

@@ -0,0 +1,345 @@
+package com.loan.system.controller.wechat;
+
+import com.loan.system.context.BaseContext;
+import com.loan.system.domain.dto.CollateralDTO;
+import com.loan.system.domain.dto.ContractDTO;
+import com.loan.system.domain.dto.LoanCaseDTO;
+import com.loan.system.domain.entity.Collateral;
+import com.loan.system.domain.entity.Contract;
+import com.loan.system.domain.entity.Customer;
+import com.loan.system.domain.entity.User;
+import com.loan.system.domain.enums.*;
+import com.loan.system.domain.pojo.Result;
+import com.loan.system.domain.vo.LoanCaseVO;
+import com.loan.system.domain.vo.StepVO;
+import com.loan.system.exception.DescribeException;
+import com.loan.system.service.*;
+import com.loan.system.utils.ResultUtil;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.util.ObjectUtils;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.loan.system.domain.enums.ExceptionEnum.*;
+
+@RestController
+@RequestMapping("/wechat/case/cpoy")
+@Api(tags = "业务受理接口(副本)")
+public class LoanController_copy {
+
+    @Autowired
+    private LoanService loanService;
+    @Autowired
+    private StepService stepService;
+    @Autowired
+    private ContractService contractService;
+    @Autowired
+    private ApprovalService approveService;
+    @Autowired
+    private CustomerService customerService;
+    @Autowired
+    private CustomerOtherService customerOtherService;
+    @Autowired
+    private CollateralService collateralService;
+    @Autowired
+    private ContractAndCollateralService contractAndCollateralService;
+    @Autowired
+    private MessageService messageService;
+    @Autowired
+    private UserService userService;
+
+    @GetMapping
+    @ApiOperation("显示所有业务")
+    @PreAuthorize("@pms.hasAnyRoles('SYSTEM_ADMIN','APPROVER','LEAD_SALES', 'ASSIST_SALES', 'FINANCE', 'BACK_OFFICE')")
+    public Result findLoanCaseAll(@RequestParam(defaultValue = "0") Integer pageNum,@RequestParam(defaultValue = "20") Integer pageSize){
+        List<LoanCaseVO> loanCases = loanService.findLoanCaseAll(pageNum, pageSize,false);
+        return ResultUtil.success("success",loanCases);
+    }
+
+    @GetMapping("/customer")
+    @ApiOperation("显示客户的所有业务")
+    @PreAuthorize("@pms.hasAnyRoles('EXTERNAL')")
+    public Result findLoanCaseByCustomerId(@RequestParam(defaultValue = "0") Integer pageNum,@RequestParam(defaultValue = "20") Integer pageSize){
+        List<LoanCaseVO> loanCases = loanService.findLoanCaseByCustomerId(BaseContext.getCurrentId(),pageNum,pageSize,false);
+        return ResultUtil.success("success",loanCases);
+    }
+
+    @GetMapping("/dealing")
+    @ApiOperation("显示处理中的业务")
+    @PreAuthorize("@pms.hasAnyRoles('SYSTEM_ADMIN','APPROVER','LEAD_SALES', 'ASSIST_SALES', 'FINANCE', 'BACK_OFFICE')")
+    public Result findLoanCaseByIsComplete(@RequestParam(defaultValue = "0") Integer pageNum,@RequestParam(defaultValue = "20") Integer pageSize){
+        //根据角色返回业务列表,业务员返回全部未完成、审批员与财务员仅展示未审批或未财务审批的人物
+        List<Long> loanCaseIds = loanService.findIdsByIsComplete(DecisionEnum.PROCESS.getMsg(), false);
+        User user = userService.findByIdAndIsDelete(BaseContext.getCurrentId());
+        List<Long> ids = new ArrayList<>();
+        List<LoanCaseVO> loanCases=new ArrayList<>();
+        if(isContainRole(user.getRole(),RoleEnum.APPROVER.getMsg())){
+            for(Long caseId : loanCaseIds){
+                List<StepVO> steps = stepService.getStepByCaseId(caseId);
+                for(StepVO step : steps)
+                    if(step.getStatus().equals(DecisionEnum.PROCESS.getMsg()) &&
+                            (step.getStepName().equals(StepPropertyEnum.APPROVAL.getLabel())||step.getStepName().equals(StepPropertyEnum.APPROVAL_ASSIGNMENT.getLabel())
+                                    ||step.getStepName().equals(StepPropertyEnum.APPROVAL_ASSIGNMENT_2.getLabel())||step.getStepName().equals(StepPropertyEnum.REPAY_APPROVAL.getLabel())
+                                    ||step.getStepName().equals(StepPropertyEnum.DISBURSE_AUDIT.getLabel())||step.getStepName().equals(StepPropertyEnum.PLAN_AUDIT.getLabel()))){
+                        ids.add(caseId);
+                        break;
+                    }
+            }
+            loanCases = loanService.findLoanCaseByIds(ids,pageNum,pageSize,false);
+        }else if(isContainRole(user.getRole(),RoleEnum.FINANCE.getMsg())) {
+            for(Long caseId : loanCaseIds){
+                List<StepVO> steps = stepService.getStepByCaseId(caseId);
+                for (StepVO step : steps)
+                    if (step.getStatus().equals(DecisionEnum.PROCESS.getMsg()) &&
+                            (step.getStepName().equals(StepPropertyEnum.FINANCE_DISBURSE.getLabel()) || step.getStepName().equals(StepPropertyEnum.FINANCE_CHECK.getLabel()) ||
+                                    step.getStepName().equals(StepPropertyEnum.FINANCE_CONFIRM.getLabel()))) {
+                        ids.add(step.getCaseId());
+                        break;
+                    }
+            }
+            loanCases = loanService.findLoanCaseByIds(ids,pageNum,pageSize,false);
+        }else {
+            loanCases = loanService.findLoanCaseByIsComplete(pageNum,pageSize,DecisionEnum.PROCESS.getMsg(),false);
+        }
+
+        return ResultUtil.success("success",loanCases);
+    }
+
+    @GetMapping("/all/{key}")
+    @ApiOperation("按客户关键字查询业务(所有)")
+    @PreAuthorize("@pms.hasAnyRoles('SYSTEM_ADMIN','APPROVER','LEAD_SALES', 'ASSIST_SALES', 'FINANCE', 'BACK_OFFICE')")
+    public Result findAllLoanCaseByKey(@PathVariable String key,@RequestParam(defaultValue = "0") Integer pageNum,@RequestParam(defaultValue = "20") Integer pageSize){
+        List<Customer> customers = customerService.getAllCustomerByKey(key, false);
+        List<Long> customerIds = new ArrayList<>();
+        for(Customer customer : customers)
+            customerIds.add(customer.getId());
+
+        List<LoanCaseVO> loanCases = loanService.findLoanCaseByCustomerIds(customerIds,pageNum,pageSize,false);
+
+        return ResultUtil.success("success",loanCases);
+    }
+
+    @GetMapping("/dealing/{key}")
+    @ApiOperation("按客户关键字查询业务")
+    @PreAuthorize("@pms.hasAnyRoles('SYSTEM_ADMIN','APPROVER','LEAD_SALES', 'ASSIST_SALES', 'FINANCE', 'BACK_OFFICE')")
+    public Result findLoanCaseByKey(@PathVariable String key,@RequestParam(defaultValue = "0") Integer pageNum,@RequestParam(defaultValue = "20") Integer pageSize){
+        List<Customer> customers = customerService.getAllCustomerByKey(key, false);
+        List<Long> customerIds = new ArrayList<>();
+        for(Customer customer : customers)
+            customerIds.add(customer.getId());
+
+        List<LoanCaseVO> loanCases = loanService.findLoanCaseByCustomerIds(customerIds,pageNum,pageSize,DecisionEnum.PROCESS.getMsg(),false);
+
+        return ResultUtil.success("success",loanCases);
+    }
+
+    @GetMapping("/dealing/currentUser/{userId}")
+    @ApiOperation("按当前处理人查询待处理业务")
+    @PreAuthorize("@pms.hasAnyRoles('SYSTEM_ADMIN','APPROVER','LEAD_SALES', 'ASSIST_SALES', 'FINANCE', 'BACK_OFFICE')")
+    public Result findLoanCaseByCurrentUser(@PathVariable Long userId,@RequestParam(defaultValue = "0") Integer pageNum,@RequestParam(defaultValue = "20") Integer pageSize){
+        //获取所有业务id
+        List<Long> loanCaseIds = loanService.findIdsByIsComplete(DecisionEnum.PROCESS.getMsg(), false);
+        List<Long> ids = new ArrayList<>();
+        for(Long loanCaseId : loanCaseIds){
+            //寻找每个id的阶段
+            List<StepVO> stepByCaseId = stepService.getStepByCaseId(loanCaseId);
+            //判断是否有未完成的阶段
+            for(StepVO stepVO : stepByCaseId)
+                if(!stepVO.getStatus().equals(StepEnum.COMPLETED.getMsg())&&
+                        ((stepVO.getUserId1()!=null  && stepVO.getUserId1().equals(userId))
+                            ||(stepVO.getUserId2()!=null  && stepVO.getUserId2().equals(userId)))){
+                    //返回该id
+                    ids.add(loanCaseId);
+                    break;
+                }
+
+        }
+
+        List<LoanCaseVO> loanCases = loanService.findLoanCaseByIds(ids,pageNum,pageSize,false);
+        return ResultUtil.success("success",loanCases);
+    }
+
+    @GetMapping("/{id}/details")
+    @ApiOperation("显示业务详情")
+    @PreAuthorize("@pms.hasAnyRoles('SYSTEM_ADMIN','APPROVER','LEAD_SALES', 'ASSIST_SALES', 'FINANCE', 'BACK_OFFICE')")
+    public Result findLoanCaseDetails(@PathVariable("id")Long caseId){
+        return ResultUtil.success("success",loanService.findLoanCaseDetailsById(caseId));
+    }
+
+    @PostMapping("/create")
+    @ApiOperation("创建业务")
+    @PreAuthorize("@pms.hasAnyRoles('LEAD_SALES','ASSIST_SALES')")
+    public Result createLoanCase(@RequestParam("customerId") Long customerId){
+        if(customerId == null ||!customerService.existsByIdAndIsDelete(customerId))
+            throw new DescribeException(ExceptionEnum.USER_NOT_EXIST);
+        //创建订单
+        LoanCaseVO loanCase = loanService.addLoanCaseByCustomerId(customerId);
+        //创建流程
+//        stepService.addStepByCaseId(loanCase.getId());
+        List<List<Integer>> seq = StepPropertyEnum.seqList();
+        stepService.addStepByCaseIdAndSequences(loanCase.getId(),seq);
+        //设置当前处理人
+        stepService.updateUserByCaseId(StepPropertyEnum.BUSINESS_ACCEPT.getLabel(),BaseContext.getCurrentId(),loanCase.getId());
+        return ResultUtil.success("success",loanCase);
+    }
+
+    /*
+    1.添加业务,开启业务流程
+    2.绑定阶段和业务
+     */
+    @PostMapping("/{id}")//请求中操作复杂,putmapping仅适用于更新操作
+    @ApiOperation("提交/保存业务")
+    @PreAuthorize("@pms.hasAnyRoles('LEAD_SALES', 'ASSIST_SALES')")
+    public Result saveLoanCase(@PathVariable("id")Long caseId, @RequestBody LoanCaseDTO loanCaseDTO, @RequestParam(value = "isComplete",defaultValue = "false")Boolean isComplete){//isComplete 若保存,则设置为未完成,若提交,则设置为已完成
+        if(!loanService.existsByIdAndIsDelete(caseId))
+            throw new DescribeException(ExceptionEnum.PROJECT_NOT_EXIST);
+
+        if (ObjectUtils.isEmpty(loanCaseDTO))
+            throw new DescribeException(ExceptionEnum.INPUT_ERROR);
+
+        StepVO stepVO = stepService.findByStepNameAndCaseId(StepPropertyEnum.BUSINESS_ACCEPT.getLabel(),caseId);
+        if(ObjectUtils.isEmpty(stepVO) || !stepVO.getStatus().equals(StepEnum.PROCESS.getMsg()))
+            throw new DescribeException(STEP_HAS_NOT_PROCESS);
+
+        Long currentId = stepVO.getUserId1();
+        if(currentId!=null && !BaseContext.getCurrentId().equals(currentId)){
+            throw new DescribeException(STEP_USER_NOT_EXPECTED);
+        }
+
+        //1.补充业务信息
+        loanService.updateLoanCaseById(loanCaseDTO,caseId);
+
+        //2.设置合同(若存在则修改)
+        contractService.deleteAllByCaseId(caseId);
+        List<Contract> contracts = new ArrayList<>();//新增的合同
+        for(ContractDTO contractDTO : loanCaseDTO.getContracts()){
+            Contract c = contractService.saveContract(contractDTO);
+
+            contracts.add(c);
+        }
+
+        //3.设置押品
+        collateralService.deleteAllByCaseId(caseId);
+        List<Long> collateralIds = new ArrayList<>();
+        for(CollateralDTO collateralDTO : loanCaseDTO.getCollateral()){
+            Collateral collateral = collateralService.saveCollateral(collateralDTO);
+
+            collateralIds.add(collateral.getId());
+        }
+
+        //4.设置合同、押品关联
+        contractAndCollateralService.deleteAllByCaseId(caseId);
+        for(int i=0 ; i < loanCaseDTO.getCollateralAndContract().size(); i++){
+            Contract contract = contracts.get( i);
+            List<Integer> collaterals = loanCaseDTO.getCollateralAndContract().get(i).get(contract.getBusinessAttr());
+
+            for (Integer collateralId : collaterals)
+                contractAndCollateralService.addContractAndCollateral(contract.getId(),collateralIds.get(collateralId-1),caseId);
+        }
+
+        //5.添加其它客户
+        customerOtherService.deleteAllByCaseId(caseId);
+        if(!ObjectUtils.isEmpty(loanCaseDTO.getCustomers1()))
+            customerOtherService.addCustomers(loanCaseDTO.getCustomers1());
+
+        if (!ObjectUtils.isEmpty(loanCaseDTO.getCustomers2()))
+            customerOtherService.addCustomers(loanCaseDTO.getCustomers2());
+
+
+        //6.设置客户婚姻
+        customerService.updateMarriedStatusAndIsIllegalById(loanCaseDTO.getCustomerId(),loanCaseDTO.getMarriedStatus(),loanCaseDTO.getIsIllegal());
+
+        //7.设置阶段负责人与状态(如果第一个人是辅办人员,那第二个人必须是主办)
+        if(isComplete){
+            //stepService.updateStatusByCaseId(StepEnum.COMPLETED.getMsg(),StepPropertyEnum.BUSINESS_ACCEPT_PARENT.getLabel(),caseId);
+            stepService.updateStatusByCaseId(StepEnum.COMPLETED.getMsg(),StepPropertyEnum.BUSINESS_ACCEPT.getLabel(),caseId);
+            //设置当阶段为完成,下阶段为开始
+            stepService.tryStartStep(StepPropertyEnum.BUSINESS_ACCEPT.getLabel(),caseId);
+
+
+            //TODO:8.微信推送预审通过消息和通知下一环节
+//            SysMessage message = new SysMessage();
+//            message.setMobile(null);
+ //           message.setUserRole(RoleEnum.ASSIST_SALES.getMsg());
+//            message.setMessageTitle("");
+//            message.setMessageContent("");
+ //           message.setStepName(StepPropertyEnum.PRE_TRIAL.getLabel());
+  //          message.setRelatedId(caseId);
+//            message.setRelatedType("");
+ //           messageService.addMessage(message);
+//            wxService.sendTemplateMessage(loanCase.getCustomer().getMobile(),new TemplateMessage());
+
+        }
+
+        return ResultUtil.success("success");
+    }
+
+
+
+    @PostMapping("/{id}/preApprove/cancel")
+    @ApiOperation("取消预审")
+    @PreAuthorize("@pms.hasAnyRoles('LEAD_SALES', 'ASSIST_SALES')")
+    public Result cancelPreApprove(@PathVariable("id")Long caseId){
+        if(!loanService.existsByIdAndIsDelete(caseId))
+            throw new DescribeException(ExceptionEnum.PROJECT_NOT_EXIST);
+
+        StepVO step = stepService.findByStepNameAndCaseId(StepPropertyEnum.PRE_TRIAL.getLabel(),caseId);
+        if(ObjectUtils.isEmpty( step)||!step.getStatus().equals(StepEnum.PROCESS.getMsg()))
+            throw new DescribeException(STEP_HAS_NOT_PROCESS);
+
+        Long currentId = step.getUserId1();
+        if(currentId!=null && !BaseContext.getCurrentId().equals(currentId)){
+            throw new DescribeException(STEP_USER_NOT_EXPECTED);
+        }
+
+        //设置预审核阶段已完成,审批阶段开始
+        stepService.updateStatusByCaseId(StepEnum.COMPLETED.getMsg(),StepPropertyEnum.PRE_TRIAL_PARENT.getLabel(),caseId);
+        stepService.updateStatusByCaseId(StepEnum.COMPLETED.getMsg(),StepPropertyEnum.PRE_TRIAL.getLabel(),caseId);
+
+//        stepService.updateStatusByCaseId(StepEnum.PROCESS.getMsg(),StepPropertyEnum.APPROVAL_PARENT.getLabel(),caseId);
+//        stepService.updateStatusByCaseId(StepEnum.PROCESS.getMsg(),StepPropertyEnum.APPROVAL.getLabel(),caseId);
+        stepService.skipStep(StepPropertyEnum.PRE_TRIAL_PARENT.getLabel(),caseId);
+
+        stepService.updateUserByCaseId(StepPropertyEnum.PRE_TRIAL.getLabel(), BaseContext.getCurrentId(), caseId);
+
+        //添加审批记录
+        approveService.addPreApprovalRecord(StepPropertyEnum.PRE_TRIAL.getLabel(),BaseContext.getCurrentId(),caseId);
+
+        //List<StepVO> list = stepService.getStepByCaseId(caseId);
+
+        return ResultUtil.success("success");
+    }
+
+    @PutMapping("/{id}/complete")
+    @ApiOperation("完成业务")
+    @PreAuthorize("@pms.hasAnyRoles('LEAD_SALES', 'ASSIST_SALES')")
+    public Result completeLoanCase(@PathVariable("id")Long caseId){
+        if(!loanService.existsByIdAndIsDelete(caseId))
+            throw new DescribeException(ExceptionEnum.PROJECT_NOT_EXIST);
+
+        List<StepVO> steps = stepService.getStepByCaseId(caseId);
+        for(StepVO step : steps){
+            if(!step.getStatus().equals(StepEnum.COMPLETED.getMsg()))
+                throw new DescribeException(PROJECT_HAS_NOT_COMPLETED);
+        }
+        loanService.updateIsCompleteByCaseId(StepEnum.COMPLETED.getMsg(),caseId);
+        return ResultUtil.success("success");
+    }
+
+    private Boolean isContainRole(String roles,String role){
+        String[] roleArray =roles.split( ",");
+
+        for(String r : roleArray)
+            if(r.equals(role))
+                return true;
+
+        return false;
+    }
+
+
+}

+ 298 - 145
src/main/java/com/loan/system/controller/wechat/RepaymentController.java

@@ -1,15 +1,14 @@
 package com.loan.system.controller.wechat;
 
+import cn.hutool.core.bean.BeanUtil;
 import com.loan.system.context.BaseContext;
 import com.loan.system.domain.dto.*;
-import com.loan.system.domain.entity.ApprovalRecord;
-import com.loan.system.domain.entity.Disbursement;
-import com.loan.system.domain.entity.Repayment;
-import com.loan.system.domain.entity.RepaymentRecord;
+import com.loan.system.domain.entity.*;
 import com.loan.system.domain.enums.*;
 import com.loan.system.domain.pojo.Result;
 import com.loan.system.domain.vo.*;
 import com.loan.system.exception.DescribeException;
+import com.loan.system.repository.ContractSeqRepository;
 import com.loan.system.service.*;
 import com.loan.system.service.DisbursementRecordService;
 import com.loan.system.utils.ResultUtil;
@@ -23,9 +22,11 @@ import org.springframework.web.bind.annotation.*;
 
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
-import java.util.List;
+import java.util.*;
+import java.util.stream.Collectors;
 
 import static com.loan.system.domain.enums.ExceptionEnum.*;
+import static com.loan.system.utils.ValidUtil.isAllFieldsNull;
 
 @RestController
 @RequestMapping("/wechat/repayment")
@@ -37,7 +38,9 @@ public class RepaymentController {
     @Autowired
     private StepService stepService;
     @Autowired
-    private DisbursementRecordService disbursementRecordService;
+    private ContractService contractService;
+    @Autowired
+    private ContractRepaymentService contractRepaymentService;
     @Autowired
     private RepaymentService repaymentService;
     @Autowired
@@ -52,38 +55,23 @@ public class RepaymentController {
         if(!loanService.existsByIdAndIsDelete(caseId))
             throw new DescribeException(ExceptionEnum.PROJECT_NOT_EXIST);
 
-        DisbursementDetailVO disbursementDetailVO = disbursementService.getLoanCaseAndCustomerByCaseId(caseId);
-        RepaymentDetailVO repaymentDetailVO = new RepaymentDetailVO();
-        repaymentDetailVO.setCustomer(disbursementDetailVO.getCustomer());
-        repaymentDetailVO.setLoanCase(disbursementDetailVO.getLoanCase());
+        StepVO stepVO = stepService.findByStepNameAndCaseId(StepPropertyEnum.REPAY_START.getLabel(),caseId);
+        if(ObjectUtils.isEmpty(stepVO) || stepVO.getStatus().equals(StepEnum.UNSTART.getMsg()))
+            throw new DescribeException(STEP_HAS_NOT_PROCESS);
 
-        //填充
-        Repayment repayment = repaymentService.findByCaseIdAndIsDelete(caseId, false);
-        List<RepaymentRecordVO> repaymentRecordVOS = repaymentRecordService.findByRepaymentIdAndIsDelete(repayment.getId(), false);
-        Double currentAmount= 0.0;
-        for (RepaymentRecordVO repaymentRecordVO : repaymentRecordVOS)
-            if(!repaymentRecordVO.getIsInterest())//审批、财务环节显示审批通过后的总额
-                currentAmount += repaymentRecordVO.getAmount();
-
-        repaymentDetailVO.setRepaymentRecords(repaymentRecordVOS);
-        repaymentDetailVO.setCurrentAmount(currentAmount);
-        repaymentDetailVO.setTotalAmount(repayment.getTotalAmount());
-        //财务核算后
-        repaymentDetailVO.setInterests(repayment.getInterest());
-        //余额回款
-        repaymentDetailVO.setWay(repayment.getRepayWay());
-
-        return ResultUtil.success("success",repaymentDetailVO);
+        return ResultUtil.success("success",repaymentService.getDetails(caseId, StepPropertyEnum.REPAY_START.getLabel()));
     }
 
 
-    @PostMapping
+    @PostMapping("/{id}")
     @ApiOperation(value = "启动回款")
     @PreAuthorize("@pms.hasAnyRoles('LEAD_SALES', 'ASSIST_SALES')")
-    public Result addDisbursement(@RequestBody RepaymentRecordDTO repaymentRecordDTO, @RequestParam Long caseId, @RequestParam Long recordId) {
-        if(ObjectUtils.isEmpty(repaymentRecordDTO))
+    public Result addDisbursement(@RequestBody RepaymentRecordDTO repaymentRecordDTO, @RequestParam Long caseId, @PathVariable("id") Long recordId) {
+        if(ObjectUtils.isEmpty(repaymentRecordDTO)||isAllFieldsNull(repaymentRecordDTO))
             throw new DescribeException(INPUT_ERROR);
 
+        System.out.println(repaymentRecordDTO);
+
         if(caseId == null ||!loanService.existsByIdAndIsDelete(caseId))
             throw new DescribeException(ExceptionEnum.PROJECT_NOT_EXIST);
 
@@ -91,35 +79,57 @@ public class RepaymentController {
         if(ObjectUtils.isEmpty(stepVO) || !stepVO.getStatus().equals(StepEnum.PROCESS.getMsg()))
             throw new DescribeException(STEP_HAS_NOT_PROCESS);
 
-        Long currentId = stepVO.getUserId1();
-        if(currentId!=null && !BaseContext.getCurrentId().equals(currentId)){
-            throw new DescribeException(STEP_USER_NOT_EXPECTED);
-        }
 
-        //最新回款记录还在审批中,则不能回款
         Repayment repayment = repaymentService.findByCaseIdAndIsDelete(caseId, false);
-        List<RepaymentRecordVO> repaymentRecordVOS = repaymentRecordService.findByRepaymentIdAndIsDelete(repayment.getId(), false);
-
-        //上报计划
-        if(recordId == -1){
-            //审批意见为驳回,无法新增
-            if(repaymentRecordVOS.get(repaymentRecordVOS.size()-1).getApprovalDecision().equals(DecisionEnum.REJECT.getMsg()))
-                throw new DescribeException(DISBURSEMENT_HAS_NOT_COMPLETED);
-            repaymentRecordService.addRepaymentRecord(repaymentRecordDTO,repayment.getId());
+        if(ObjectUtils.isEmpty(repayment)){
+            Repayment rep = new Repayment();
+            rep.setCaseId(caseId);
+            rep.setStartUserId(BaseContext.getCurrentId());
+            rep.setTotalAmount(disbursementService.getDisbursementByCaseId(caseId).getPlannedAmount());
+            repayment=repaymentService.addRepayment(rep);
+        }
+
+        RepaymentRecord record =new RepaymentRecord();
+        //上报计划(-1表示当前为新增)
+        if(recordId <= 0){
+            List<RepaymentRecord> repaymentRecords = repaymentRecordService.findByRepaymentIdAndIsDelete(repayment.getId(), false);
+            if(!repaymentRecords.isEmpty()){
+                record = repaymentRecords.get(repaymentRecords.size()-1);
+                if(record.getApprovalDecision()==null || !record.getApprovalDecision().equals(DecisionEnum.PASS.getMsg()))
+                    throw new DescribeException(REPAYMENT_HAS_BEEN_REJECTED);
+            }
+            RepaymentRecord repaymentRecord = repaymentRecordService.addRepaymentRecord(repaymentRecordDTO, repayment.getId());
+            recordId = repaymentRecord.getId();
         } else{
             //审批意见为通过,无法修改
-            if(repaymentRecordVOS.get(repaymentRecordVOS.size()-1).getApprovalDecision().equals(DecisionEnum.PASS.getMsg()))
-                throw new DescribeException(DISBURSEMENT_HAS_COMPLETED);
+            record = repaymentRecordService.findByIdAndIsDelete(recordId);
+            if(record.getApprovalDecision()==null || record.getApprovalDecision().equals(DecisionEnum.PASS.getMsg()))
+                throw new DescribeException(REPAYMENT_HAS_COMPLETED);
+
             repaymentRecordService.updateRepaymentRecordById(repaymentRecordDTO,recordId);
+            //获取合同回款
+            List<Long> Ids = contractRepaymentService.findByRepaymentRecordIdAndIsDelete(recordId);
+            contractRepaymentService.deleteByIds(Ids);
+
+        }
+
+        //创建新关联关系
+        Iterator<Map.Entry<Long, Double>> iterator = repaymentRecordDTO.getContractIdAndAmount().entrySet().iterator();
+        while (iterator.hasNext()) {
+            Map.Entry<Long, Double> entry = iterator.next();
+            Long contractId = entry.getKey();
+            double amount = entry.getValue();
+            contractRepaymentService.addContractRepayment(recordId,contractId,caseId,amount,record.getRepayTime());
+
         }
-        // DisbursementVO disbursementVO = disbursementService.addDisbursement(disbursementDTO);
 
         //修改状态
-        if(isCleared(caseId)){//若结清,则回款完成
-            repaymentService.updateIsClearedByCaseId(true,caseId);
+        if(isCleared(caseId,StepPropertyEnum.REPAY_START.getLabel())){
+            //若结清,则回款完成
             stepService.updateStatusByCaseId( StepEnum.COMPLETED.getMsg(),StepPropertyEnum.REPAY_START.getLabel(), caseId);
         }
-        stepService.updateStatusByCaseId( StepEnum.PROCESS.getMsg(),StepPropertyEnum.REPAY_APPROVAL.getLabel(),caseId);
+
+        stepService.tryStartStep(StepPropertyEnum.REPAY_START.getLabel(),caseId);
 
         //TODO:微信推送预审通过消息和通知下一环节
 //        SysMessage message = new SysMessage();
@@ -136,19 +146,22 @@ public class RepaymentController {
         return ResultUtil.success("success");
     }
 
-    @GetMapping("/{caseId}/appravalDetails")
+    @GetMapping("/{caseId}/approvalDetails")
     @ApiOperation("显示审批详情")//与loanContraller的方法一致,但为了规范
     @PreAuthorize("@pms.hasAnyRoles('SYSTEM_ADMIN','APPROVER','LEAD_SALES', 'ASSIST_SALES', 'FINANCE', 'BACK_OFFICE')")
     public Result findLoanCaseDetails2(@PathVariable("caseId")Long caseId){
-        return ResultUtil.success("success",getDetails(caseId));
+        if (caseId == null ||!loanService.existsByIdAndIsDelete(caseId))
+            throw new DescribeException(ExceptionEnum.PROJECT_NOT_EXIST);
+
+        return ResultUtil.success("success",repaymentService.getDetails(caseId, StepPropertyEnum.REPAY_APPROVAL.getLabel()));
     }
 
     //TODO:在回款记录添加审批记录,且每次审批完之后才能再回款
     @PostMapping("/approval/pass")
     @ApiOperation(value = "回款审批")
     @PreAuthorize("@pms.hasRole('APPROVER')")
-    public Result repaymentApproval(@RequestBody ApprovalDTO approvalDTO) {
-        if(ObjectUtils.isEmpty(approvalDTO)||approvalDTO.getCaseId() == null)
+    public Result repaymentApproval(@RequestBody RepaymentApprovalDTO approvalDTO,@RequestParam Long chargeId) {
+        if(ObjectUtils.isEmpty(approvalDTO)||approvalDTO.getCaseId() == null||approvalDTO.getRecordId() == null)
             throw new DescribeException(INPUT_ERROR);
 
         if(!loanService.existsByIdAndIsDelete(approvalDTO.getCaseId()))
@@ -160,15 +173,8 @@ public class RepaymentController {
         if(!stepVO.getStatus().equals(StepEnum.PROCESS.getMsg()))
             throw new DescribeException(STEP_HAS_NOT_PROCESS);
 
-        Long currentId = stepVO.getUserId1();
-        if(currentId!=null && !BaseContext.getCurrentId().equals(currentId)){
-            throw new DescribeException(STEP_USER_NOT_EXPECTED);
-        }
-
         //填写审批意见
-        Repayment repayment = repaymentService.findByCaseIdAndIsDelete(caseId, false);
-        repaymentRecordService.updateApprovalById(approvalDTO.getComments(),DecisionEnum.REJECT.getMsg(),repayment.getId());
-
+        repaymentRecordService.updateApprovalById(approvalDTO.getComments(),DecisionEnum.PASS.getMsg(),BaseContext.getCurrentId(),approvalDTO.getRecordId());
         //TODO:微信推送预审通过消息和通知下一环节
 //        SysMessage message = new SysMessage();
 //        message.setMobile(null);
@@ -181,14 +187,14 @@ public class RepaymentController {
 //        messageService.addMessage(message);
 //        wxService.sendTemplateMessage(loanCase.getCustomer().getMobile(),new TemplateMessage());
 
-        //修改出款单
-        repaymentService.updateApprovalUserByCaseId(BaseContext.getCurrentId(),caseId);
-
         //修改状态
         stepService.updateUserByCaseId(StepPropertyEnum.REPAY_APPROVAL.getLabel(), BaseContext.getCurrentId(), caseId);
-        if(isCleared(caseId))
+        //TODO:更新结清状态(因为是一审一批,只有通过的时候才结清状态,不通过则不结清,保证了结清时的总金额为审批通过的)
+        contractIsCleared(repaymentService.findByCaseIdAndIsDelete(caseId,false).getId(),chargeId);
+
+        if(isCleared(caseId,StepPropertyEnum.REPAY_APPROVAL.getLabel()))
             stepService.updateStatusByCaseId(StepEnum.COMPLETED.getMsg(),StepPropertyEnum.REPAY_APPROVAL.getLabel(), caseId);
-        stepService.updateStatusByCaseId( StepEnum.PROCESS.getMsg(), StepPropertyEnum.FINANCE_CHECK.getLabel(),caseId);
+        stepService.tryStartStep(StepPropertyEnum.REPAY_APPROVAL.getLabel(),caseId);
 
         return ResultUtil.success("success");
     }
@@ -196,33 +202,21 @@ public class RepaymentController {
     @PostMapping("/approval/reject")
     @ApiOperation(value = "回款审批驳回")
     @PreAuthorize("@pms.hasRole('APPROVER')")
-    public Result repaymentCancel(@RequestBody ApprovalDTO approvalDTO) {
-        if(ObjectUtils.isEmpty(approvalDTO)||approvalDTO.getCaseId() == null)
+    public Result repaymentCancel(@RequestBody RepaymentApprovalDTO approvalDTO) {
+        if(ObjectUtils.isEmpty(approvalDTO)||approvalDTO.getCaseId() == null||approvalDTO.getRecordId() == null)
             throw new DescribeException(INPUT_ERROR);
 
         if(!loanService.existsByIdAndIsDelete(approvalDTO.getCaseId()))
             throw new DescribeException(ExceptionEnum.PROJECT_NOT_EXIST);
 
         Long caseId = approvalDTO.getCaseId();
-        StepVO step = stepService.findByStepNameAndCaseId(StepPropertyEnum.REPAY_START.getLabel(), caseId);
-        if(step.getStatus().equals(StepEnum.PROCESS.getMsg()))
-            throw new DescribeException(PRE_STEP_NOT_COMPLETE);
 
         StepVO stepVO = stepService.findByStepNameAndCaseId(StepPropertyEnum.REPAY_APPROVAL.getLabel(),caseId);
         if(stepVO.getStatus().equals(StepEnum.COMPLETED.getMsg()))
             throw new DescribeException(ExceptionEnum.STEP_HAS_COMPLETEED);
 
-        Long currentId = stepVO.getUserId1();
-        if(currentId!=null && !BaseContext.getCurrentId().equals(currentId)){
-            throw new DescribeException(STEP_USER_NOT_EXPECTED);
-        }
-
         //填写驳回意见
-        Repayment repayment = repaymentService.findByCaseIdAndIsDelete(caseId, false);
-        repaymentRecordService.updateApprovalById(approvalDTO.getComments(),DecisionEnum.REJECT.getMsg(),repayment.getId());
-
-        //修改出款单
-        repaymentService.updateApprovalUserByCaseId(BaseContext.getCurrentId(),caseId);
+        repaymentRecordService.updateApprovalById(approvalDTO.getComments(),DecisionEnum.REJECT.getMsg(),BaseContext.getCurrentId(),approvalDTO.getRecordId());
 
         //修改负责人
         stepService.updateUserByCaseId(StepPropertyEnum.REPAY_APPROVAL.getLabel(), BaseContext.getCurrentId(), caseId);
@@ -244,19 +238,67 @@ public class RepaymentController {
         return ResultUtil.success("success");
     }
 
+    //TODO:用于判断总的金额是否结清
+    private Boolean isCleared(Long caseId,String stepName){
+        Repayment repayment = repaymentService.findByCaseIdAndIsDelete(caseId, false);
+        //获取回款记录
+        List<RepaymentRecord> repaymentRecords = repaymentRecordService.findByRepaymentIdAndIsDelete(repayment.getId(), false);
+        Double totalAmount = repaymentService.findByCaseIdAndIsDelete(caseId, false).getTotalAmount();
+
+        Double currentAmount= 0.0;
+        for (RepaymentRecord repaymentRecord : repaymentRecords)
+            if(stepName.equals(StepPropertyEnum.REPAY_APPROVAL.getLabel())){
+                if(repaymentRecord.getApprovalDecision()!=null && repaymentRecord.getApprovalDecision().equals(DecisionEnum.PASS.getMsg())
+                        && !repaymentRecord.getIsInterest())//审批、财务环节显示审批通过后的总额
+                    currentAmount += repaymentRecord.getAmount();
+            }else if(stepName.equals(StepPropertyEnum.REPAY_START.getLabel())){
+                if( !repaymentRecord.getIsInterest())//审批、财务环节显示审批通过后的总额
+                    currentAmount += repaymentRecord.getAmount();
+            }
+
+        return Math.abs(totalAmount-currentAmount)< Double.MIN_VALUE;
+    }
+
+    /*TODO:更新合同结清状态
+    * 1.根据recordId查合同关联表,
+    * 2.查出每个合同id对应的回款金额
+    * 3.若回款金额与借款金额相同,则结清
+    * */
+    private void contractIsCleared(Long repaymentId,Long chargeId) {
+        //1.
+        List<RepaymentRecord> repaymentRecords = repaymentRecordService.findByRepaymentIdAndIsDelete(repaymentId, false);
+        List<Long> recordIds= repaymentRecords.stream().map(RepaymentRecord::getId).collect(Collectors.toList());
+        List<ContractRepayment> contractRepayments = contractRepaymentService.findByRepaymentRecordIdsAndIsDelete(recordIds);
+
+        //2.
+        List<Long> contractIds = contractRepayments.stream().map(ContractRepayment::getContractId).collect(Collectors.toList());
+        for(Long contractId:contractIds){
+            double amount = 0.0;
+            for (ContractRepayment contractRepayment:contractRepayments){
+                RepaymentRecord repaymentRecord = repaymentRecordService.findByIdAndIsDelete(contractRepayment.getRepaymentRecordId());
+                if(!repaymentRecord.getIsInterest() && contractRepayment.getContractId().equals(contractId))
+                    amount += contractRepayment.getAmount();
+            }
+
+            System.out.println("amount:"+amount);
+            //3.
+            if(Math.abs(amount-contractService.findContractById(contractId).getContractAmount())< Double.MIN_VALUE)
+                contractService.updateRepayById(true,0.0,chargeId,contractId,false);
+        }
+    }
     @GetMapping("/financeDetails")
     @ApiOperation("显示财务核算详情")//与loanContraller的方法一致,但为了规范
     @PreAuthorize("@pms.hasAnyRoles('SYSTEM_ADMIN','APPROVER','LEAD_SALES', 'ASSIST_SALES', 'FINANCE', 'BACK_OFFICE')")
     public Result findLoanCaseDetails3(@RequestParam Long caseId){
-        if(caseId==null)
-            throw new DescribeException(INPUT_ERROR);
-        return ResultUtil.success("success",getDetails(caseId));
+        if (caseId == null ||!loanService.existsByIdAndIsDelete(caseId))
+            throw new DescribeException(ExceptionEnum.PROJECT_NOT_EXIST);
+        return ResultUtil.success("success",repaymentService.getDetails(caseId,StepPropertyEnum.FINANCE_CHECK.getLabel()));
     }
 
-    @PostMapping("/financeCheck")
+    @PostMapping("/financeCheck/{caseId}")
     @ApiOperation(value = "财务核算")
     @PreAuthorize("@pms.hasRole('FINANCE')")
-    public Result financeDisbursement( @RequestParam Long caseId,@RequestParam Double interest) {
+    public Result financeDisbursement( @PathVariable Long caseId,@RequestParam Double interest,@RequestParam Long contractId) {
         if(caseId==null||!loanService.existsByIdAndIsDelete(caseId))
             throw new DescribeException(ExceptionEnum.PROJECT_NOT_EXIST);
 
@@ -264,22 +306,28 @@ public class RepaymentController {
         if(ObjectUtils.isEmpty(stepVO)||!stepVO.getStatus().equals(StepEnum.PROCESS.getMsg()))
             throw new DescribeException(STEP_HAS_NOT_PROCESS);
 
-        Repayment repayment = repaymentService.findByCaseIdAndIsDelete(caseId, false);
-        if(!repayment.getIsCleared())
+        Contract contract = contractService.findContractById(contractId);
+        if(!contract.getIsCleared())
             throw new DescribeException(FUND_NOT_CLEAR);
+        if(contract.getFinanceUserId()!=null && !contract.getFinanceUserId().equals(BaseContext.getCurrentId()))
+            throw new DescribeException(STEP_USER_NOT_EXPECTED);
 
-//        Long currentId = stepVO.getUserId1();
-//        if(currentId!=null && !BaseContext.getCurrentId().equals(currentId)){
-//            throw new DescribeException(STEP_USER_NOT_EXPECTED);
-//        }
-
-        //修改回款单
-        repaymentService.updateIntersetsByCaseId(interest,caseId);
+        //修改合同信息
+        contractService.updateRepayById(true,interest,BaseContext.getCurrentId(),contractId,false);
 
         //修改状态
         stepService.updateUserByCaseId(StepPropertyEnum.FINANCE_CHECK.getLabel(), BaseContext.getCurrentId(), caseId);
-        stepService.updateStatusByCaseId( StepEnum.COMPLETED.getMsg(),StepPropertyEnum.FINANCE_CHECK.getLabel(),caseId);
-        stepService.updateStatusByCaseId(StepEnum.PROCESS.getMsg(),StepPropertyEnum.BALANCE_REPAY.getLabel(), caseId);
+        boolean flag = true;
+        List<Contract> contractByCaseId = contractService.findContractByCaseId2(caseId);
+        for (Contract contract2 : contractByCaseId)
+            if (contract2.getFinanceUserId()== null){
+                flag = false;
+                break;
+            }
+        if (flag)//如果全部合同都有财务人员,则表示全部核算完成
+            stepService.updateStatusByCaseId( StepEnum.COMPLETED.getMsg(),StepPropertyEnum.FINANCE_CHECK.getLabel(),caseId);
+
+        stepService.tryStartStep(StepPropertyEnum.FINANCE_CHECK.getLabel(),caseId);
 
         //TODO:微信推送预审通过消息和通知下一环节
 //        SysMessage message = new SysMessage();
@@ -296,25 +344,20 @@ public class RepaymentController {
         return ResultUtil.success("success");
     }
 
-    private Boolean isCleared(Long caseId){
-        Repayment repayment = repaymentService.findByCaseIdAndIsDelete(caseId, false);
-        //获取回款记录
-        List<RepaymentRecordVO> repaymentRecordVOS = repaymentRecordService.findByRepaymentIdAndIsDelete(repayment.getId(), false);
-
-        Double currentAmount= 0.0;
-        for (RepaymentRecordVO repaymentRecordVO : repaymentRecordVOS)
-            currentAmount += repaymentRecordVO.getAmount();
-
-        Double totalAmount = repaymentService.findByCaseIdAndIsDelete(caseId, false).getTotalAmount();
-
-        return (totalAmount-currentAmount)< Double.MIN_VALUE;
+    @GetMapping("/balanceDetails")
+    @ApiOperation("显示费息回款详情")//与loanContraller的方法一致,但为了规范
+    @PreAuthorize("@pms.hasAnyRoles('SYSTEM_ADMIN','APPROVER','LEAD_SALES', 'ASSIST_SALES', 'FINANCE', 'BACK_OFFICE')")
+    public Result findLoanCaseDetails4(@RequestParam Long caseId){
+        if (caseId == null ||!loanService.existsByIdAndIsDelete(caseId))
+            throw new DescribeException(ExceptionEnum.PROJECT_NOT_EXIST);
 
+        return ResultUtil.success("success",repaymentService.getDetails(caseId,StepPropertyEnum.BALANCE_REPAY.getLabel()));
     }
 
     @PostMapping("/balanceRepay")
     @ApiOperation(value = "费息回款")
     @PreAuthorize("@pms.hasAnyRoles('LEAD_SALES', 'ASSIST_SALES')")
-    public Result balanceRepay(@RequestParam Long caseId , @RequestBody RepaymentRecordDTO repaymentRecordDTO , @RequestParam String way) {
+    public Result balanceRepay(@RequestParam Long caseId , @RequestBody RepaymentRecordDTO repaymentRecordDTO ) {
         if(ObjectUtils.isEmpty(repaymentRecordDTO)||caseId==null)
             throw new DescribeException(INPUT_ERROR);
         if(!loanService.existsByIdAndIsDelete(caseId))
@@ -324,19 +367,31 @@ public class RepaymentController {
         if(ObjectUtils.isEmpty(stepVO)||!stepVO.getStatus().equals(StepEnum.PROCESS.getMsg()))
             throw new DescribeException(STEP_HAS_NOT_PROCESS);
 
-        Long currentId = stepVO.getUserId1();
-        if(currentId!=null && !BaseContext.getCurrentId().equals(currentId)){
-            throw new DescribeException(STEP_USER_NOT_EXPECTED);
-        }
+//        Long currentId = stepVO.getUserId1();
+//        if(currentId!=null && !BaseContext.getCurrentId().equals(currentId)){
+//            throw new DescribeException(STEP_USER_NOT_EXPECTED);
+//        }
 
-        repaymentService.updateRepayWayByCaseId(way,caseId);
         //添加回款记录
         repaymentRecordDTO.setIsInterest( true);
-        repaymentRecordService.addRepaymentRecord(repaymentRecordDTO, repaymentService.findByCaseIdAndIsDelete(caseId, false).getId());
+        RepaymentRecord record = repaymentRecordService.addRepaymentRecord(repaymentRecordDTO, repaymentService.findByCaseIdAndIsDelete(caseId, false).getId());
+        //创建新关联关系
+        Iterator<Map.Entry<Long, Double>> iterator = repaymentRecordDTO.getContractIdAndAmount().entrySet().iterator();
+        while (iterator.hasNext()) {
+            Map.Entry<Long, Double> entry = iterator.next();
+            Long contractId = entry.getKey();
+            double amount = entry.getValue();
+            contractRepaymentService.addContractRepayment(record.getId(),contractId,caseId,amount,record.getRepayTime());
+
+        }
+
+        //TODO:添加赎当号码
 
         stepService.updateUserId1ByCaseIdAndStepName(StepPropertyEnum.BALANCE_REPAY.getLabel(), BaseContext.getCurrentId(), caseId);
-        stepService.updateStatusByCaseId(StepEnum.COMPLETED.getMsg(),StepPropertyEnum.BALANCE_REPAY.getLabel(),caseId);
-        stepService.updateStatusByCaseId(StepEnum.PROCESS.getMsg(),StepPropertyEnum.FINANCE_CONFIRM.getLabel(), caseId);
+        if(interestIsCleared(repaymentService.findByCaseIdAndIsDelete(caseId, false).getId()))//当全部的合同的费息都完成时才结束环节
+            stepService.updateStatusByCaseId(StepEnum.COMPLETED.getMsg(),StepPropertyEnum.BALANCE_REPAY.getLabel(),caseId);
+
+        stepService.tryStartStep(StepPropertyEnum.BALANCE_REPAY.getLabel(),caseId);
 
         //TODO:微信推送预审通过消息和通知下一环节
 //        SysMessage message = new SysMessage();
@@ -352,11 +407,38 @@ public class RepaymentController {
 
         return ResultUtil.success("success");
     }
+    /*TODO:更新合同费息结清状态
+     * 1.根据recordId查合同关联表,
+     * 2.查出每个合同id对应的回款金额
+     * 3.若全部合同的回款金额与费息相同,则结清
+     * */
+    private Boolean interestIsCleared(Long repaymentId) {
+        //1.
+        List<RepaymentRecord> repaymentRecords = repaymentRecordService.findByRepaymentIdAndIsInterestAndIsDelete(repaymentId, false);
+        List<Long> recordIds= repaymentRecords.stream().map(RepaymentRecord::getId).collect(Collectors.toList());
+        List<ContractRepayment> contractRepayments = contractRepaymentService.findByRepaymentRecordIdsAndIsDelete(recordIds);
+
+        //2.
+        List<Long> contractIds = contractRepayments.stream().map(ContractRepayment::getContractId).collect(Collectors.toList());
+        for(Long contractId:contractIds){
+            double amount = 0.0;
+            for (ContractRepayment contractRepayment:contractRepayments){
+                RepaymentRecord record = repaymentRecordService.findByIdAndIsDelete(contractRepayment.getRepaymentRecordId());
+                if(contractRepayment.getContractId().equals(contractId)&&record.getIsInterest())
+                    amount += contractRepayment.getAmount();
+            }
+
+            //3.
+            if(Math.abs(amount-contractService.findContractById(contractId).getInterestAmount())> Double.MIN_VALUE)
+                return false;
+        }
+        return true;
+    }
 
     @PostMapping("/financeConfirm")
     @ApiOperation(value = "财务确认")
     @PreAuthorize("@pms.hasRole('FINANCE')")
-    public Result financeConfirm(@RequestParam Long caseId) {
+    public Result financeConfirm(@RequestParam List<Long> recordIds,@RequestParam Long caseId) {//TODO:一下子可以确认多笔
         if(caseId==null || !loanService.existsByIdAndIsDelete(caseId))
             throw new DescribeException(ExceptionEnum.PROJECT_NOT_EXIST);
 
@@ -364,13 +446,22 @@ public class RepaymentController {
         if(ObjectUtils.isEmpty(stepVO)||!stepVO.getStatus().equals(StepEnum.PROCESS.getMsg()))
             throw new DescribeException(STEP_HAS_NOT_PROCESS);
 
-        Long currentId = stepVO.getUserId1();
-        if(currentId!=null && !BaseContext.getCurrentId().equals(currentId)){
-            throw new DescribeException(STEP_USER_NOT_EXPECTED);
+//        Long currentId = stepVO.getUserId1();
+//        if(currentId!=null && !BaseContext.getCurrentId().equals(currentId)){
+//            throw new DescribeException(STEP_USER_NOT_EXPECTED);
+//        }
+        for(Long recordId:recordIds){
+            repaymentRecordService.updateApprovalById("",DecisionEnum.PASS.getMsg(),BaseContext.getCurrentId(),recordId);
         }
 
+
         stepService.updateUserId1ByCaseIdAndStepName(StepPropertyEnum.FINANCE_CONFIRM.getLabel(), BaseContext.getCurrentId(), caseId);
-        stepService.updateStatusByCaseId(StepEnum.COMPLETED.getMsg(),StepPropertyEnum.FINANCE_CONFIRM.getLabel(),caseId);
+        if(interestIsCleared(repaymentService.findByCaseIdAndIsDelete(caseId, false).getId())){
+            stepService.updateStatusByCaseId(StepEnum.COMPLETED.getMsg(),StepPropertyEnum.FINANCE_CONFIRM.getLabel(),caseId);
+
+//            loanService.updateIsCompleteByCaseId(DecisionEnum.COMPLETE.getMsg(),caseId);
+        }
+        stepService.tryStartStep(StepPropertyEnum.FINANCE_CONFIRM.getLabel(),caseId);
 
         //TODO:微信推送预审通过消息和通知下一环节
 //        SysMessage message = new SysMessage();
@@ -387,29 +478,91 @@ public class RepaymentController {
         return ResultUtil.success("success");
     }
 
-    private RepaymentDetailVO getDetails(Long caseId){
-        DisbursementDetailVO disbursementDetailVO = disbursementService.getLoanCaseAndCustomerByCaseId(caseId);
-        RepaymentDetailVO repaymentDetailVO = new RepaymentDetailVO();
-        repaymentDetailVO.setCustomer(disbursementDetailVO.getCustomer());
-        repaymentDetailVO.setLoanCase(disbursementDetailVO.getLoanCase());
+    @PostMapping("/repayComplete")
+    @ApiOperation(value = "回款完成")
+    @PreAuthorize("@pms.hasAnyRoles('APPROVAL')")
+    public Result repayComplete(@RequestParam Long caseId) {
+        if(caseId==null || !loanService.existsByIdAndIsDelete(caseId))
+            throw new DescribeException(ExceptionEnum.PROJECT_NOT_EXIST);
 
-        //填充
-        Repayment repayment = repaymentService.findByCaseIdAndIsDelete(caseId, false);
-        List<RepaymentRecordVO> repaymentRecordVOS = repaymentRecordService.findByRepaymentIdAndIsDelete(repayment.getId(), false);
-        Double currentAmount= 0.0;
-        for (RepaymentRecordVO repaymentRecordVO : repaymentRecordVOS)
-            if(repaymentRecordVO.getApprovalDecision().equals(DecisionEnum.PASS.getMsg())&& !repaymentRecordVO.getIsInterest())//审批、财务环节显示审批通过后的总额
-                currentAmount += repaymentRecordVO.getAmount();
-
-        repaymentDetailVO.setRepaymentRecords(repaymentRecordVOS);
-        repaymentDetailVO.setCurrentAmount(currentAmount);
-        repaymentDetailVO.setTotalAmount(repayment.getTotalAmount());
-        //财务核算后
-        repaymentDetailVO.setInterests(repayment.getInterest());
-        //余额回款
-        repaymentDetailVO.setWay(repayment.getRepayWay());
-
-        return repaymentDetailVO;
+        StepVO stepVO = stepService.findByStepNameAndCaseId(StepPropertyEnum.REPAYMENT_COMPLETE.getLabel(),caseId);
+        if(ObjectUtils.isEmpty(stepVO)||!stepVO.getStatus().equals(StepEnum.PROCESS.getMsg()))
+            throw new DescribeException(STEP_HAS_NOT_PROCESS);
+
+        StepVO stepVO1 = stepService.findByStepNameAndCaseId(StepPropertyEnum.FINANCE_CONFIRM.getLabel(), caseId);
+        if(ObjectUtils.isEmpty(stepVO1)||!stepVO1.getStatus().equals(StepEnum.COMPLETED.getMsg()))
+            throw new DescribeException(PRE_STEP_NOT_COMPLETE);
+
+        List<StepVO> steps = stepService.getStepByCaseId(caseId);
+        for(StepVO step:steps){
+            if(!step.getStatus().equals(StepEnum.COMPLETED.getMsg()))
+                throw new DescribeException(STEP_EXIST_NOT_COMPLETE);
+        }
+
+
+        //更新回款单
+        repaymentService.updateStatusByCaseId(DecisionEnum.REPAYMENT_COMPLETE.getMsg(),caseId);
+
+
+        stepService.updateUserId1ByCaseIdAndStepName(StepPropertyEnum.REPAYMENT_COMPLETE.getLabel(),BaseContext.getCurrentId(), caseId);
+        //stepService.updateStatusByCaseId(StepEnum.COMPLETED.getMsg(),StepPropertyEnum.REPAY_PARENT.getLabel(),caseId);
+        stepService.updateStatusByCaseId(StepEnum.COMPLETED.getMsg(),StepPropertyEnum.REPAYMENT_COMPLETE.getLabel(),caseId);
+
+        stepService.tryStartStep(StepPropertyEnum.REPAYMENT_COMPLETE.getLabel(),caseId);
+        return ResultUtil.success("success");
     }
 
+    @PostMapping("/caseComplete")
+    @ApiOperation(value = "业务完成")
+    @PreAuthorize("@pms.hasAnyRoles('BACK_OFFICE')")
+    public Result loanCaseComplete(@RequestParam Long caseId) {
+        if(caseId==null || !loanService.existsByIdAndIsDelete(caseId))
+            throw new DescribeException(ExceptionEnum.PROJECT_NOT_EXIST);
+
+        StepVO stepVO = stepService.findByStepNameAndCaseId(StepPropertyEnum.CASE_COMPLETE.getLabel(),caseId);
+        if(ObjectUtils.isEmpty(stepVO)||!stepVO.getStatus().equals(StepEnum.PROCESS.getMsg()))
+            throw new DescribeException(STEP_HAS_NOT_PROCESS);
+
+        StepVO stepVO1 = stepService.findByStepNameAndCaseId(StepPropertyEnum.FINANCE_CONFIRM.getLabel(), caseId);
+        if(ObjectUtils.isEmpty(stepVO1)||!stepVO1.getStatus().equals(StepEnum.COMPLETED.getMsg()))
+            throw new DescribeException(PRE_STEP_NOT_COMPLETE);
+
+        //设置业务状态
+        loanService.updateIsCompleteByCaseId(DecisionEnum.COMPLETE.getMsg(),caseId);
+
+        stepService.updateUserId1ByCaseIdAndStepName(StepPropertyEnum.CASE_COMPLETE.getLabel(),BaseContext.getCurrentId(), caseId);
+        stepService.updateStatusByCaseId(StepEnum.COMPLETED.getMsg(),StepPropertyEnum.REPAY_PARENT.getLabel(),caseId);
+        stepService.updateStatusByCaseId(StepEnum.COMPLETED.getMsg(),StepPropertyEnum.CASE_COMPLETE.getLabel(),caseId);
+
+        stepService.tryStartStep(StepPropertyEnum.CASE_COMPLETE.getLabel(),caseId);
+        return ResultUtil.success("success");
+    }
+
+
+    //TODO:因为现在是一审一批,所以仅最后一笔金额可能是未通过
+//    private Boolean isCleared(Long caseId,String stepName){
+//        Repayment repayment = repaymentService.findByCaseIdAndIsDelete(caseId, false);
+//        //获取回款记录
+//        List<RepaymentRecord> repaymentRecords = repaymentRecordService.findByRepaymentIdAndIsDelete(repayment.getId(), false);
+//        Double totalAmount = repaymentService.findByCaseIdAndIsDelete(caseId, false).getTotalAmount();
+//
+//        Double currentAmount= 0.0;
+//        if(stepName.equals(StepPropertyEnum.REPAY_START.getLabel())){
+//            //不计算最后一次,因为最后一次一定未审批
+//            totalAmount-= repaymentRecords.get(repaymentRecords.size()-1).getAmount();
+//            for (int i=0;i<repaymentRecords.size()-1;i++){
+//                RepaymentRecord repaymentRecord = repaymentRecords.get(i);
+//                if(repaymentRecord.getApprovalDecision().equals(DecisionEnum.PASS.getMsg())&&!repaymentRecord.getIsInterest())//审批、财务环节显示审批通过后的总额
+//                    currentAmount += repaymentRecord.getAmount();
+//            }
+//        }else{
+//            for (RepaymentRecord repaymentRecord : repaymentRecords)
+//                if(repaymentRecord.getApprovalDecision().equals(DecisionEnum.PASS.getMsg())&& !repaymentRecord.getIsInterest())//审批、财务环节显示审批通过后的总额
+//                    currentAmount += repaymentRecord.getAmount();
+//
+//        }
+//
+//        return Math.abs(totalAmount-currentAmount)< Double.MIN_VALUE;
+//    }
+
 }

+ 238 - 24
src/main/java/com/loan/system/controller/wechat/StatisticsController.java

@@ -1,17 +1,20 @@
 package com.loan.system.controller.wechat;
 
+import com.loan.system.config.FileUploadConfig;
+import com.loan.system.domain.entity.*;
+import com.loan.system.domain.enums.StepPropertyEnum;
 import com.loan.system.domain.pojo.Result;
+import com.loan.system.domain.vo.*;
+import com.loan.system.service.*;
 import com.loan.system.utils.ResultUtil;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import org.apache.poi.xssf.usermodel.XSSFRow;
 import org.apache.poi.xssf.usermodel.XSSFSheet;
 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.format.annotation.DateTimeFormat;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.ServletOutputStream;
 import javax.servlet.http.HttpServletResponse;
@@ -20,35 +23,246 @@ import java.io.InputStream;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.LocalTime;
-import java.util.HashMap;
-import java.util.Map;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
+import java.util.stream.Collectors;
 
 @RestController
 @RequestMapping("/wechat/statistics")
-@Api("数据统计接口")
+@Api(tags = "数据统计接口")
 public class StatisticsController {
+    @Autowired
+    private LoanService loanService;
+    @Autowired
+    private DisbursementService disbursementService;
+    @Autowired
+    private DisbursementRecordService disbursementRecordService;
+    @Autowired
+    private RepaymentService repaymentService;
+    @Autowired
+    private RepaymentRecordService repaymentRecordService;
+    @Autowired
+    private FileUploadConfig fileUploadConfig;
+    @Autowired
+    private ContractService contractService;
+    @Autowired
+    private ContractRepaymentService contractRepaymentService;
+    @Autowired
+    private CustomerService customerService;
+    @Autowired
+    private CustomerOtherService customerOtherService;
+    @Autowired
+    private RecommenderService recommenderService;
+    @Autowired
+    private StepService stepService;
+    @Autowired
+    private UserService userService;
 
     @GetMapping("/dailyReport")
     @ApiOperation("获取日报表")
     public Result dailyReport(@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,
-                              @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end) {
+                              @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end) {//TODO:利息也要
 
-        //TODO:统计echart数据
-//        Map<String, Object> stats = new HashMap<>();
-//
-//        // 示例数据 - 需要替换为真实数据库查询
-//        stats.put("roles", Map.of(
-//                "student", userService.countByRole("student"),
-//                "school_admin", userService.countByRole("school_admin"),
-//                "admin", userService.countByRole("admin")
-//        ));
-//
-//        stats.put("status", Map.of(
-//                "active", userService.countByStatus("active"),
-//                "inactive", userService.countByStatus("inactive")
-//        ));
+        DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+        String beginTime = begin.atStartOfDay().format(fmt);
+        String endTime = begin.atTime(23, 59, 59).format(fmt);
 
-        return ResultUtil.success();
+        List<DailyReport> dailyReports =new ArrayList<>();
+
+        //TODO:repayTime要改成数据库标准时间
+        List<RepaymentRecord> records = repaymentRecordService.findBetweenRange(beginTime, endTime);
+        for (RepaymentRecord record : records){
+            DailyReport dailyReport = new DailyReport();
+            Repayment repayment = repaymentService.findByIdAndIsDelete(record.getRepaymentId());
+            Long caseId = repayment.getCaseId();
+            LoanCaseSimpleVO loanCase = loanService.findLoanCaseSimpleByIdAndIsDelete(caseId, false);
+
+            dailyReport.setCustomerName(customerService.findByIdAndIsDelete(loanCase.getCustomerId()).getName());//1.
+            dailyReport.setLoanCaseAttribute(loanCase.getBusinessAttrs());//2.
+            dailyReport.setDisbursementDate(disbursementService.getLoanTime(caseId));//3.
+            dailyReport.setLoanAmount(loanCase.getTotalLoanAmount());//4.
+
+            List<RepaymentRecord> repaymentRecords = repaymentRecordService.findByRepaymentIdAndIsDelete(record.getRepaymentId(), false);
+            double totalRepayAmount = 0.0;
+            for (RepaymentRecord repaymentRecord : repaymentRecords){
+                if(!repaymentRecord.getIsInterest())
+                    totalRepayAmount += repaymentRecord.getAmount();
+            }
+            dailyReport.setRepayTotalAmount(totalRepayAmount);//5.
+            dailyReport.setRepayDate(record.getRepayTime());//7.
+            dailyReport.setRemainAmount(loanCase.getTotalLoanAmount()-totalRepayAmount);//6.
+            if (dailyReport.getRemainAmount()<Double.MIN_VALUE){
+                //还清才能结算利息
+                List<ContractVO> contracts = contractService.findContractByCaseId(caseId);
+                double totalInterest = 0.0;
+                for (ContractVO contract : contracts)
+                    if (contract.getIsCleared())
+                        totalInterest += contract.getInterestAmount();
+
+                dailyReport.setLoanInterest(totalInterest);//8.
+            }
+
+            dailyReports.add(dailyReport);
+        }
+
+        return ResultUtil.success("success",dailyReports);
+    }
+
+    @GetMapping("/dailyReport/export")
+    @ApiOperation("导出日报表")
+    public void exportDailyReport(@RequestBody List<DailyReport> dailyReports ,@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,
+                                  @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end,
+                                  HttpServletResponse response) {
+        DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yy-MM-dd HH:mm:ss");
+        String beginTime = begin.atStartOfDay().format(fmt);
+        String endTime = begin.atTime(23, 59, 59).format(fmt);
+
+        List<DailyReport> dailyReportList = dailyReports.stream()
+                .filter(Objects::nonNull)
+                .filter(c -> c.getRepayDate() != null && !c.getRepayDate().equals(" "))
+                .filter(c -> {
+                    try {
+                        LocalDate d = LocalDate.parse(c.getRepayDate(), fmt);
+                        return !d.isBefore(LocalDate.parse(beginTime, fmt)) && !d.isAfter(LocalDate.parse(endTime, fmt));
+                    } catch (Exception e) {
+                        return false;   // 格式不对直接丢弃
+                    }
+                })
+                .collect(Collectors.toList());
+        //查询概览运营数据,提供给Excel模板文件
+        InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(fileUploadConfig.getUploadDir() + "出账明细.xlsx");
+        try {
+            //基于提供好的模板文件创建一个新的Excel表格对象
+            XSSFWorkbook excel = new XSSFWorkbook(inputStream);
+
+            //获得Excel文件中的一个Sheet页
+            XSSFSheet sheet = excel.getSheet("Sheet1");
+            //TODO:row(从0开始)行,cell(从0开始)获取单元格
+            //获得第1行
+            XSSFRow row = sheet.getRow(0);
+            row.getCell(0).setCellValue(begin.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日")));
+
+            //获取单元格
+            for (int i = 0; i <dailyReportList.size(); i++) {
+                DailyReport dailyReport = dailyReportList.get(i);
+                row = sheet.getRow(3+i);
+                row.getCell(0).setCellValue(dailyReport.getCustomerName());
+                row.getCell(1).setCellValue(dailyReport.getLoanCaseAttribute());
+                row.getCell(2).setCellValue(dailyReport.getDisbursementDate());
+                row.getCell(3).setCellValue(dailyReport.getLoanAmount());
+                row.getCell(4).setCellValue(dailyReport.getRepayTotalAmount());
+                row.getCell(5).setCellValue(dailyReport.getRemainAmount());
+                row.getCell(6).setCellValue(dailyReport.getRepayDate());
+                row.getCell(7).setCellValue(dailyReport.getLoanInterest());
+
+            }
+
+            //通过输出流将文件下载到客户端浏览器中
+            ServletOutputStream out = response.getOutputStream();
+            excel.write(out);
+
+            //关闭资源
+            out.flush();
+            out.close();
+            excel.close();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    @GetMapping("/loanCaseReport")
+    @ApiOperation("获取业务统计表")
+    public Result loanCaseReport(@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,
+                                 @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end) {
+        DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+        String beginTime = begin.atStartOfDay().format(fmt);
+        String endTime = end.atTime(23, 59, 59).format(fmt);
+
+        List<LoanCaseStatistic> loanCaseStatistics = new ArrayList<>();
+
+        List<LoanCaseSimpleVO> loanCases = loanService.findLoanCaseBetweenRange(beginTime, endTime);
+        for (LoanCaseSimpleVO loanCase : loanCases){
+            LoanCaseStatistic loanCaseStatistic = new LoanCaseStatistic();
+            List<StepVO> steps = stepService.getParentStepByCaseId(loanCase.getId());
+            for (StepVO step : steps){
+                loanCaseStatistic.setStartDate(loanCase.getCreateTime());//2.
+                loanCaseStatistic.setCustomerName(customerService.findByCustomerIdAndIsDelete(loanCase.getCustomerId(), false).getName());//3.
+                loanCaseStatistic.setBusinessType(loanCase.getBusinessType());//4.
+                loanCaseStatistic.setAmount(loanCase.getTotalLoanAmount());//5.
+                loanCaseStatistic.setStepName(step.getStepName());//6.
+
+                loanCaseStatistic.setEndDate(loanCase.getUpdateTime());//9.
+            }
+
+
+            loanCaseStatistics.add(loanCaseStatistic);
+        }
+
+
+        return ResultUtil.success("success",loanCaseStatistics);
+    }
+
+    @GetMapping("/loanCaseReport/export")
+    @ApiOperation("导出业务统计表")
+    public void exportLaonCaseReport(@RequestBody List<LoanCaseStatistic> loanCaseStatistics, @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,
+                                     @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end, HttpServletResponse response) {
+        DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yy-MM-dd HH:mm:ss");
+        String beginTime = begin.atStartOfDay().format(fmt);
+        String endTime = end.atTime(23, 59, 59).format(fmt);
+
+        List<LoanCaseStatistic> loanCaseStatisticList = loanCaseStatistics.stream()
+                .filter(Objects::nonNull)
+                .filter(c -> c.getEndDate() != null && !c.getEndDate().equals(" "))
+                .filter(c -> {
+                    try {
+                        LocalDate d = LocalDate.parse(c.getEndDate(), fmt);
+                        return !d.isBefore(LocalDate.parse(beginTime, fmt)) && !d.isAfter(LocalDate.parse(endTime, fmt));
+                    } catch (Exception e) {
+                        return false;   // 格式不对直接丢弃
+                    }
+                })
+                .collect(Collectors.toList());
+        //查询概览运营数据,提供给Excel模板文件
+        InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(fileUploadConfig.getUploadDir() + "出账明细.xlsx");
+        try {
+            //基于提供好的模板文件创建一个新的Excel表格对象
+            XSSFWorkbook excel = new XSSFWorkbook(inputStream);
+
+            //获得Excel文件中的一个Sheet页
+            XSSFSheet sheet = excel.getSheet("Sheet1");
+            //TODO:row(从0开始)行,cell(从0开始)获取单元格
+            //获得第1行
+            XSSFRow row = sheet.getRow(0);
+            row.getCell(1).setCellValue(begin.format(DateTimeFormatter.ofPattern("M月")));
+
+            //获取单元格
+            for (int i = 0; i < loanCaseStatisticList.size(); i++) {
+                LoanCaseStatistic loanCaseStatistic = loanCaseStatisticList.get(i);
+                row = sheet.getRow(3+i);
+                row.getCell(0).setCellValue(loanCaseStatistic.getWeekSeq());
+                row.getCell(1).setCellValue(loanCaseStatistic.getStartDate());
+                row.getCell(2).setCellValue(loanCaseStatistic.getCustomerName());
+                row.getCell(3).setCellValue(loanCaseStatistic.getBusinessType());
+                row.getCell(4).setCellValue(loanCaseStatistic.getAmount());
+                row.getCell(5).setCellValue(loanCaseStatistic.getStepName());
+                row.getCell(6).setCellValue(loanCaseStatistic.getUserName1());
+                row.getCell(7).setCellValue(loanCaseStatistic.getUserName2());
+                row.getCell(8).setCellValue(loanCaseStatistic.getEndDate());
+                row.getCell(9).setCellValue(loanCaseStatistic.getPlace());
+
+            }
+
+            //通过输出流将文件下载到客户端浏览器中
+            ServletOutputStream out = response.getOutputStream();
+            excel.write(out);
+
+            //关闭资源
+            out.flush();
+            out.close();
+            excel.close();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
     }
 
     @GetMapping("/financeEfficiency")
@@ -72,7 +286,7 @@ public class StatisticsController {
     }
 
     //到处数据
-    public void exportBusinessData(HttpServletResponse response) {
+    public void exportData(HttpServletResponse response, String templatePath) {
         LocalDate begin = LocalDate.now().minusDays(30);
         LocalDate end = LocalDate.now().minusDays(1);
 

+ 26 - 4
src/main/java/com/loan/system/controller/wechat/StepController.java

@@ -1,14 +1,19 @@
 package com.loan.system.controller.wechat;
 
+import com.loan.system.domain.enums.ExceptionEnum;
+import com.loan.system.domain.enums.StepEnum;
 import com.loan.system.domain.pojo.Result;
+import com.loan.system.domain.vo.StepVO;
+import com.loan.system.exception.DescribeException;
+import com.loan.system.service.LoanService;
 import com.loan.system.service.StepService;
 import com.loan.system.utils.ResultUtil;
 import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.apache.commons.lang3.ObjectUtils;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
 
 @RestController
 @RequestMapping("/wechat/step")
@@ -16,9 +21,26 @@ import org.springframework.web.bind.annotation.RestController;
 public class StepController {
     @Autowired
     private StepService stepService;
+    @Autowired
+    private LoanService loanService;
 
     @GetMapping
+    @ApiOperation("查询所有环节")
     public Result findStep(@RequestParam("caseId")Long caseId){
+        if(caseId==null||!loanService.existsByIdAndIsDelete(caseId))
+            throw  new DescribeException(ExceptionEnum.PROJECT_NOT_EXIST);
+
         return ResultUtil.success("success",stepService.getStepByCaseId(caseId));
     }
+
+    @PutMapping("/skipStep")
+    @ApiOperation("跳过当前环节")
+    @PreAuthorize("@pms.hasAnyRoles('SYSTEM_ADMIN','APPROVER','LEAD_SALES', 'ASSIST_SALES', 'FINANCE', 'BACK_OFFICE')")
+    public Result skipStep(@RequestParam("stepName")String stepName,@RequestParam("caseId")Long caseId){
+        if(caseId==null||!loanService.existsByIdAndIsDelete(caseId))
+            throw  new DescribeException(ExceptionEnum.PROJECT_NOT_EXIST);
+
+        stepService.skipStep(stepName,caseId);
+        return ResultUtil.success("success");
+    }
 }

+ 30 - 44
src/main/java/com/loan/system/controller/wechat/UploadController.java

@@ -1,11 +1,16 @@
 package com.loan.system.controller.wechat;
 
+import cn.hutool.core.util.StrUtil;
 import com.loan.system.config.FileUploadConfig;
 import com.loan.system.domain.entity.Document;
 import com.loan.system.domain.enums.ExceptionEnum;
+import com.loan.system.domain.enums.StepEnum;
 import com.loan.system.domain.pojo.Result;
 import com.loan.system.domain.vo.DocumentVO;
+import com.loan.system.domain.vo.StepVO;
+import com.loan.system.exception.DescribeException;
 import com.loan.system.service.DocumentService;
+import com.loan.system.service.StepService;
 import com.loan.system.utils.ResultUtil;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
@@ -27,6 +32,8 @@ import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
 import java.util.*;
 
+import static com.loan.system.domain.enums.ExceptionEnum.STEP_HAS_NOT_PROCESS;
+
 @RestController
 @RequestMapping("/wechat/file")
 @Api(tags = "文件处理接口")
@@ -35,31 +42,33 @@ public class UploadController {
     private DocumentService fileService;
     @Autowired
     private FileUploadConfig config;
+    @Autowired
+    private StepService stepService;
 
     /** 上传文件(支持任意类型,只要在白名单内) */
     @PostMapping("/upload/{caseId}/{type}")
     @ApiOperation("文件上传")//若合同不是统一提交,则合同1,合同2,合同3
-    public Result uploadFile(@PathVariable("caseId") Long caseId,@PathVariable("type") String fileType,@RequestParam MultipartFile file,@RequestParam Map<String , String>  isDelete) throws IOException{
+    @PreAuthorize("@pms.hasAnyRoles('LEAD_SALES','ASSIST_SALES')")
+    public Result uploadFile(@PathVariable("caseId") Long caseId,@PathVariable("type") String fileType,@RequestParam(required = false) MultipartFile file,@RequestParam Map<String , String>  isDelete) throws IOException{
         Iterator<Map.Entry<String, String>> iterator = isDelete.entrySet().iterator();
         while (iterator.hasNext()) {
             Map.Entry<String, String> entry = iterator.next();
-            System.out.println(entry.getKey());
             Long id = Long.parseLong(entry.getKey());
-            System.out.println(entry.getValue());
             Integer value = Integer.parseInt(entry.getValue());
             Document document = fileService.findById(id);
             if (ObjectUtils.isEmpty( document))
                 break;
 
             if( value!= 0 ){
+                System.out.println("删除文件"+id);
                 fileService.deleteFileById(id);
                 //删除本地文件
-               deleteFile1(document.getFilePath());
+               deleteFile(document.getFilePath());
             }
         }
 
-        if (file.isEmpty())
-            return ResultUtil.error(ExceptionEnum.FILE_IS_EMPTY);
+        if (file == null)
+            return ResultUtil.success("success");
 
         String originalName = file.getOriginalFilename();
         String ext = FilenameUtils.getExtension(originalName).toLowerCase(Locale.ROOT);
@@ -104,7 +113,7 @@ public class UploadController {
         return ResultUtil.success("上传成功",documentVO);
     }
 
-    private void deleteFile1(String filePath) {
+    private void deleteFile(String filePath) {
         if (filePath == null || filePath.isEmpty()) {
             return;
         }
@@ -127,8 +136,9 @@ public class UploadController {
     /** 下载文件 */
     @GetMapping("/download/{fileName}")
     @ApiOperation("文件下载")
-    public void downloadFile(@PathVariable String fileName, HttpServletResponse response)throws  IOException{
-        File file = new File(config.getUploadDir(), fileName);
+    public void downloadFile(@PathVariable String fileName, @RequestParam String caseId, @RequestParam String fileType, HttpServletResponse response)throws  IOException{
+        String path = config.getUploadDir() + caseId + "/" + fileType + "/" ;
+        File file = new File(path, fileName);
         if (!file.exists()) {
             response.sendError(HttpServletResponse.SC_NOT_FOUND, "文件不存在");
             return;
@@ -165,46 +175,22 @@ public class UploadController {
         return ResultUtil.success("文件删除成功");
     }
 
-    /** 删除文件 */
-    /** 删除文件 */
-    private void deleteFile(Long caseId, String fileType) {
-        // 构造待删除文件所在的目录路径
-        File uploadDir = new File(config.getUploadDir(), caseId + "/" + fileType);
-
-        if (!uploadDir.exists()) {
-            System.out.println("Directory does not exist: " + uploadDir.getAbsolutePath());
-            return; // 目录不存在,直接返回
-        }
+    @GetMapping("/{caseId}")
+    @ApiOperation("获取文件列表(type可选)")
+    public Result getFileList(@PathVariable Long caseId, @RequestParam(required = false) String type){
+        List<DocumentVO> files = fileService.findByCaseId(caseId);
 
-        // 获取目录下所有文件
-        File[] files = uploadDir.listFiles();
-        if (files == null || files.length == 0) {
-            System.out.println("No files to delete in directory: " + uploadDir.getAbsolutePath());
-            return; // 没有文件需要删除
-        }
+        if(StrUtil.isBlank( type))
+            return ResultUtil.success("success",files);
 
-        boolean allDeleted = true;
-        for (File file : files) {
-            System.out.println("Attempting to delete file: " + file.getAbsolutePath());
-            if (!file.delete()) { // 尝试删除每个文件
-                allDeleted = false; // 如果有文件未能成功删除,则标记为false
-                System.out.println("Failed to delete file: " + file.getAbsolutePath());
-            } else {
-                System.out.println("Successfully deleted file: " + file.getAbsolutePath());
-            }
+        List<DocumentVO> fileList = new ArrayList<>();
+        for(DocumentVO file : files){
+            if(file.getDictType().equals( type))
+                fileList.add(file);
         }
 
-        if (!allDeleted) {
-            System.out.println("Failed to delete some files in directory: " + uploadDir.getAbsolutePath());
-        } else {
-            System.out.println("All files deleted successfully in directory: " + uploadDir.getAbsolutePath());
-        }
+        return ResultUtil.success("success",fileList);
     }
 
 
-
-//    @PostMapping("save/{caseId}/{type}")
-//    public Result saveFile(@PathVariable("caseId") Long caseId,@PathVariable("type") String type,@RequestParam String fileName){
-//        return ResultUtil.success();
-//    }
 }

+ 147 - 146
src/main/java/com/loan/system/controller/wechat/UserController.java

@@ -1,32 +1,30 @@
 package com.loan.system.controller.wechat;
 
 import cn.hutool.core.bean.BeanUtil;
+import com.alibaba.fastjson.JSON;
+import com.github.xiaoymin.knife4j.core.util.StrUtil;
 import com.loan.system.constant.JwtClaimsConstant;
+import com.loan.system.domain.dto.UserDTO;
 import com.loan.system.domain.dto.UserLoginDTO;
 import com.loan.system.domain.dto.WeChatLoginDTO;
-import com.loan.system.domain.entity.BizRecommender;
-import com.loan.system.domain.entity.Customer;
-import com.loan.system.domain.entity.Role;
-import com.loan.system.domain.entity.User;
+import com.loan.system.domain.entity.*;
+import com.loan.system.domain.enums.DecisionEnum;
 import com.loan.system.domain.enums.ExceptionEnum;
 import com.loan.system.domain.enums.RoleEnum;
+import com.loan.system.domain.enums.StepEnum;
 import com.loan.system.domain.pojo.Result;
-import com.loan.system.domain.vo.BizRecommenderVO;
-import com.loan.system.domain.vo.CustomerLoginVO;
-import com.loan.system.domain.vo.CustomerVO;
-import com.loan.system.domain.vo.UserLoginVO;
+import com.loan.system.domain.vo.*;
 import com.loan.system.exception.DescribeException;
 import com.loan.system.properties.JwtProperties;
 import com.loan.system.repository.RoleRepository;
-import com.loan.system.service.CustomerService;
+import com.loan.system.service.*;
 import com.loan.system.service.Impl.UserServiceImpl;
-import com.loan.system.service.UserService;
-import com.loan.system.service.WxService;
 import com.loan.system.utils.JwtUtil;
 import com.loan.system.utils.ResultUtil;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import org.apache.commons.lang3.ObjectUtils;
+import org.json.JSONObject;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -36,10 +34,7 @@ import org.springframework.web.bind.annotation.*;
 import javax.security.auth.login.LoginException;
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 import java.util.stream.Collectors;
 
 /**
@@ -71,134 +66,126 @@ public class UserController {//包含内部人员、外部人员
     2.若不是内部人员,查询外部人员
     3.外部人员也不存在,进行注册(因为小程序端直接获取手机号,任何用户都可以登录)
      */
-    @PostMapping("/login")
-    @ApiOperation("微信登陆")
-    public Result login(@RequestBody UserLoginDTO userLoginDTO){
 
-        User user = userService.getUserByMobile(userLoginDTO.getTel());
-        UserLoginVO userLoginVO = new UserLoginVO();
+//    @GetMapping("/get_sessionId")
+//    @ApiOperation("获取微信openid")
+    public Map<String, String> get_sessionId(String code){
+        return userService.get_sessionId(code);
+    }
 
+    public Result customer_login(Customer customer){
+        customer=customerService.findBymobileAndIsDelete(customer.getMobile());
+        if (ObjectUtils.isEmpty(customer))
+            throw new IllegalArgumentException("Customer object is null");
         //为微信用户生成jwt令牌
         Map<String ,Object> claims=new HashMap<>();
-        Long userId = null;
-
-        if (!ObjectUtils.isEmpty(user)){
-            userLoginVO.setId(user.getId());
-            userLoginVO.setRole(user.getRole());
-            userLoginVO.setOpenid(user.getOpenid());
-        }else{
-            CustomerVO customer = customerService.getCustomerByMobile(userLoginDTO.getTel());
-            if(ObjectUtils.isEmpty(customer)) {
-                Customer customer1 = new Customer();
-                customer1.setMobile(userLoginDTO.getTel());
-                //补充
-                customerService.addCustomer(customer1);
+        //用openid还是id?
+        //claims.put(JwtClaimsConstant.CUSTOMER_ID,customer.getOpenid());
+        claims.put(JwtClaimsConstant.USER_ID,customer.getId());
+        claims.put(JwtClaimsConstant.isCustomer,1);
+        String token = JwtUtil.createJWT(jwtProperties.getUserSecretKey(), jwtProperties.getUserTtl(), claims);
+        log.info("手机号码:{}",customer.getMobile());
+        CustomerLoginVO customerLoginVO = CustomerLoginVO.builder()
+                .id(customer.getId())
+                .openid(customer.getOpenid())
+                .token(token)
+                .mobile(customer.getMobile())
+                .name(customer.getName())
+                .role(customer.getRole())
+                .build();
 
-                customer = customerService.getCustomerByMobile(userLoginDTO.getTel());
-            }
-            userLoginVO.setId(customer.getId());
-            userLoginVO.setRole(RoleEnum.EXTERNAL.getMsg());
-            userLoginVO.setOpenid(customer.getOpenid());
-        }
+        return ResultUtil.success("success", customerLoginVO);
+    }
 
-        claims.put(JwtClaimsConstant.USER_ID,userLoginVO.getId());
+    /**
+     * 用户登陆
+     * @param userLoginDTO
+     * @return
+     */
+    public Result user_login(UserLoginDTO userLoginDTO){
+        User user= userService.findByPhoneNumberAndIsDelete(userLoginDTO.getTel());
+        if (ObjectUtils.isEmpty(user))
+            throw new DescribeException(ExceptionEnum.USER_NOT_EXIST);
+        //为微信用户生成jwt令牌
+        Map<String ,Object> claims=new HashMap<>();
+        claims.put(JwtClaimsConstant.USER_ID,user.getId());
+        claims.put(JwtClaimsConstant.isCustomer,0);
         String token = JwtUtil.createJWT(jwtProperties.getUserSecretKey(), jwtProperties.getUserTtl(), claims);
-        userLoginVO.setToken(token);
+
+        if(user.getOpenid()== null){
+            userService.setOpenidById(userLoginDTO.getOpenId(),user.getId());
+        }
+        UserLoginVO userLoginVO = UserLoginVO.builder()
+                .id(user.getId())
+                .openid(user.getOpenid())
+                .token(token)
+                .role(user.getRole())
+                .is_customer(0)
+                .name(user.getRealName())
+                .build();
 
         return ResultUtil.success("success", userLoginVO);
     }
-//    @GetMapping("/get_sessionId")
-//    @ApiOperation("获取微信openid")
-//    public Result get_sessionId(String code){
-//        return userService.get_sessionId(code);
-//    }
-//    public Result customer_login(Customer customer){
-//        customer=customerService.findBymobileAndIsDelete(customer.getMobile());
-//        if (ObjectUtils.isEmpty(customer))
-//            throw new IllegalArgumentException("Customer object is null");
-//        //为微信用户生成jwt令牌
-//        Map<String ,Object> claims=new HashMap<>();
-//        //用openid还是id?
-//        //claims.put(JwtClaimsConstant.CUSTOMER_ID,customer.getOpenid());
-//        claims.put(JwtClaimsConstant.USER_ID,customer.getId());
-//        String token = JwtUtil.createJWT(jwtProperties.getUserSecretKey(), jwtProperties.getUserTtl(), claims);
-//        log.info("手机号码:{}",customer.getMobile());
-//        CustomerLoginVO customerLoginVO = CustomerLoginVO.builder()
-//                .id(customer.getId())
-//                .openid(customer.getOpenid())
-//                .token(token)
-//                .name(customer.getName())
-//                .is_customer(1)
-//                .build();
-//
-//        return ResultUtil.success("success", customerLoginVO);
-//    }
-//
-//    /**
-//     * 用户登陆
-//     * @param userLoginDTO
-//     * @return
-//     */
-//    public Result user_login(UserLoginDTO userLoginDTO){
-//        User user= userService.findByPhoneNumberAndIsDelete(userLoginDTO.getTel());
-//        if (ObjectUtils.isEmpty(user))
-//            throw new IllegalArgumentException("User object is null");
-//        //为微信用户生成jwt令牌
-//        Map<String ,Object> claims=new HashMap<>();
-//        claims.put(JwtClaimsConstant.USER_ID,user.getId());
-//        String token = JwtUtil.createJWT(jwtProperties.getUserSecretKey(), jwtProperties.getUserTtl(), claims);
-//        log.info("手机号码:{}",userLoginDTO.getTel());
-//        log.info("用户ID:{}",user.getId());
-//        UserLoginVO userLoginVO = UserLoginVO.builder()
-//                .id(user.getId())
-//                .openid(user.getOpenid())
-//                .token(token)
-//                .role(user.getRole())
-//                .is_customer(0)
-//                .userName(user.getUsername())
-//                .build();
-//
-//        return ResultUtil.success("success", userLoginVO);
-//    }
-//
-//    /**
-//     * 注册客户
-//     * @param customer
-//     * @return
-//     */
-//    public Result register(Customer customer){
-//        customer.setCreateTime(LocalDateTime.now()
-//                .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
-//        customer.setUpdateTime(LocalDateTime.now()
-//                .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
-//        customer.setIsDelete(false);
-//        customerService.addCustomer(customer);
-//        return this.customer_login(customer);
-//    }
-//
-//    @PostMapping("/login_wechat")
-//    @ApiOperation("微信手机号登陆")
-//    public Result login(@RequestBody WeChatLoginDTO weChatLoginDTO){
-//        String access_token=wxService.getAccessToken();
-//        String phoneNumber=wxService.getUserPhoneNumber(access_token,weChatLoginDTO.getCode());
-//        boolean user_is_exist = userService.existsByMobileAndIsDelete(phoneNumber);
-//        boolean customer_is_exist=customerService.existsBymobileAndIsDelete(phoneNumber);
-//        log.info("code:{}",phoneNumber);
-//        log.info("用户是否存在:{}",user_is_exist);
-//        if(!customer_is_exist&&!user_is_exist){
-//            Customer customer = new Customer();
-//            customer.setMobile(phoneNumber);
-//            customer.setOpenid(weChatLoginDTO.getOpenid());
-//            return this.register(customer);
-//        }else if(customer_is_exist){   //存在客户
-//            Customer customer=customerService.findBymobileAndIsDelete(phoneNumber);
-//            return this.customer_login(customer);
-//        }else { //存在用户
-//            UserLoginDTO userLoginDTO = new UserLoginDTO();
-//            userLoginDTO.setTel(phoneNumber);
-//            return this.user_login(userLoginDTO);
-//        }
-//    }
+
+    /**
+     * 注册客户
+     * @param customer
+     * @return
+     */
+    public Result register(Customer customer){
+        customerService.addCustomer(customer);
+        return this.customer_login(customer);
+    }
+
+    @PostMapping("/login")
+    @ApiOperation("微信手机号登陆")
+    public Result login(@RequestBody WeChatLoginDTO weChatLoginDTO){//@RequestBody WeChatLoginDTO weChatLoginDTO
+        if(weChatLoginDTO.getPhoneCode()==null||weChatLoginDTO.getOpenCode()==null)
+            throw new DescribeException(ExceptionEnum.CODE_NOT_EXIST);
+        String access_token=wxService.getAccessToken();
+        String phoneNumber=wxService.getUserPhoneNumber(access_token,weChatLoginDTO.getPhoneCode());
+        String openId = get_sessionId(weChatLoginDTO.getOpenCode()).get("openid");
+        boolean user_is_exist = userService.existsByMobileAndIsDelete(phoneNumber);
+        boolean customer_is_exist=customerService.existsBymobileAndIsDelete(phoneNumber);
+        log.info("code:{}",phoneNumber);
+        log.info("用户是否存在:{}",user_is_exist);
+        if(!customer_is_exist&&!user_is_exist){
+            Customer customer = new Customer();
+            customer.setMobile(phoneNumber);
+            customer.setOpenid(openId);
+            return this.register(customer);
+        }else if(customer_is_exist){   //存在客户
+            Customer customer=customerService.findBymobileAndIsDelete(phoneNumber);
+            return this.customer_login(customer);
+        }else { //存在用户
+            UserLoginDTO userLoginDTO = new UserLoginDTO();
+            userLoginDTO.setTel(phoneNumber);
+            userLoginDTO.setOpenId(openId);
+            return this.user_login(userLoginDTO);
+        }
+    }
+    @PostMapping("/loginTest")
+    @ApiOperation("微信手机号登陆")
+    public Result loginTest(@RequestParam String tel){//@RequestBody WeChatLoginDTO weChatLoginDTO
+
+        String phoneNumber=tel;
+        boolean user_is_exist = userService.existsByMobileAndIsDelete(phoneNumber);
+        boolean customer_is_exist=customerService.existsBymobileAndIsDelete(phoneNumber);
+        log.info("code:{}",phoneNumber);
+        log.info("用户是否存在:{}",user_is_exist);
+        if(!customer_is_exist&&!user_is_exist){
+            Customer customer = new Customer();
+            customer.setMobile(phoneNumber);
+            return this.register(customer);
+        }else if(customer_is_exist){   //存在客户
+            Customer customer=customerService.findBymobileAndIsDelete(phoneNumber);
+            return this.customer_login(customer);
+        }else { //存在用户
+            UserLoginDTO userLoginDTO = new UserLoginDTO();
+            userLoginDTO.setTel(phoneNumber);
+            return this.user_login(userLoginDTO);
+        }
+    }
 //    @PostMapping("/login")
 //    @ApiOperation("账号登陆")
 //    public Result login(@RequestBody UserLoginDTO userLoginDTO){
@@ -221,28 +208,25 @@ public class UserController {//包含内部人员、外部人员
 
     @PostMapping("/role")
     @ApiOperation("添加用户角色")
+    @PreAuthorize("@pms.hasAnyRoles('SYSTEM_ADMIN')")
     public Result addRole(@RequestParam Long userId, @RequestBody Role role){
         roleRepository.save(role);
         return ResultUtil.success("success");
     }
 
-//    @GetMapping("/users")
-//    @ApiOperation("查询所有用户")
-//    public Result findAllUsers(Boolean isDelete){
-//        return ResultUtil.success("success", userService.getAllUsers(isDelete));
-//    }
-
-    @GetMapping("/users/sales")
-    @ApiOperation("查询所有业务员")
-    @PreAuthorize("@pms.hasAnyRoles('SYSTEM_ADMIN','APPROVER')")
-    public Result findAllSales(){
-        return ResultUtil.success("success", userService.getAllSalesByIsDelete(false));
+    @PutMapping("/user/{id}")
+    @ApiOperation("更新用户信息")
+    @PreAuthorize("@pms.hasAnyRoles('SYSTEM_ADMIN')")
+    public Result updateUser(@PathVariable Long id, @RequestBody UserDTO user){
+        userService.updateUserById(id,user);
+        return ResultUtil.success("success");
     }
 
+
     @GetMapping("/recommenders")
     @ApiOperation("查询所有推荐人")
-    public Result findAllRecommenders(Boolean isDelete){
-        List<BizRecommender> allRecommenders = userService.getAllRecommenders(isDelete);
+    public Result findAllRecommenders(){
+        List<BizRecommender> allRecommenders = userService.getAllRecommenders(false);
 
         return ResultUtil.success("success", allRecommenders.stream()
                 .collect(Collectors.groupingBy(
@@ -253,4 +237,21 @@ public class UserController {//包含内部人员、外部人员
                         )
                 ));
     }
+
+    @GetMapping("/sales")
+    @ApiOperation("查询所有业务员")
+    @PreAuthorize("@pms.hasAnyRoles('SYSTEM_ADMIN','APPROVER')")
+    public Result findAllSales(@RequestParam String stepName){
+        if (stepName==null)
+            throw new DescribeException(ExceptionEnum.INPUT_ERROR);
+        return ResultUtil.success("success", userService.listSales(stepName));
+    }
+    @GetMapping("/finances")
+    @ApiOperation("查询所有财务")
+    @PreAuthorize("@pms.hasAnyRoles('SYSTEM_ADMIN','APPROVER')")
+    public Result findAllFinances(){
+
+        return ResultUtil.success("success", userService.findAllFinances());
+    }
+
 }

+ 2 - 1
src/main/java/com/loan/system/domain/dto/CollateralDTO.java

@@ -12,12 +12,13 @@ import java.math.BigDecimal;
 @AllArgsConstructor
 @NoArgsConstructor
 public class CollateralDTO implements Serializable {
+    private Long id;
     private Long caseId;//业务id
     //private Long contractId;//合同id
     private String collateralName;//押品名称
     private String collateralType;//押品类型/业务属性
     private Long ownerCustomerId;//押品所属客户id
-    private BigDecimal allocatedAmount;//押品分配金额
+    private double allocatedAmount;//押品分配金额
     private String address;//押品信息地址
     private String currentAddress;//押品实际地址
     private Boolean isInvolvedInLitigation;//是否涉及诉讼

+ 3 - 3
src/main/java/com/loan/system/domain/dto/CollateralPlanApprovalDTO.java

@@ -16,10 +16,10 @@ import java.util.List;
 public class CollateralPlanApprovalDTO implements Serializable {
     private static final long serialVersionUID = 1L;
 
-    private Long id;
+    private Long planId;//计划上报id
     private Long caseId;
     private String comments;
     private String decision;
-    private Long userId;
-    private User operator;
+    private Long userId;//取证/出证确认人
+
 }

+ 2 - 1
src/main/java/com/loan/system/domain/dto/CollateralPlanDTO.java

@@ -10,7 +10,8 @@ import lombok.NoArgsConstructor;
 @NoArgsConstructor
 public class CollateralPlanDTO extends CollateralDTO{
     private static final long serialVersionUID = 1L;
-    private Long collateralId;
+
+    private String collateralIds;
     private Long caseId;
     private String collateralName;
     private String collateralTime;

+ 1 - 1
src/main/java/com/loan/system/domain/dto/ContractDTO.java

@@ -13,7 +13,7 @@ import java.math.BigDecimal;
 @AllArgsConstructor
 @NoArgsConstructor
 public class ContractDTO implements Serializable {
-
+    private Long id;
     private String businessAttr;//业务属性
     private Long caseId;//业务id
     private Long customerId;//客户id

+ 25 - 0
src/main/java/com/loan/system/domain/dto/CustomerDTO.java

@@ -0,0 +1,25 @@
+package com.loan.system.domain.dto;
+
+import com.loan.system.domain.entity.BaseEntity;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Index;
+import javax.persistence.Table;
+import java.io.Serializable;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class CustomerDTO implements Serializable {
+    private String openid;
+    private String name;
+    private String sex;
+    private String idNumber;
+    private String mobile;
+    private String bankAccount;
+    private String bankName;
+}

+ 1 - 0
src/main/java/com/loan/system/domain/dto/CustomersOtherDTO.java

@@ -14,6 +14,7 @@ import java.io.Serializable;
 @AllArgsConstructor
 @NoArgsConstructor
 public class CustomersOtherDTO implements Serializable {
+    private Long id;
     private Long caseId;
     private String name;
     private String idNumber;

+ 21 - 0
src/main/java/com/loan/system/domain/dto/DictDataDTO.java

@@ -0,0 +1,21 @@
+package com.loan.system.domain.dto;
+
+import com.loan.system.domain.entity.BaseEntity;
+import lombok.*;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+import javax.validation.constraints.Size;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class DictDataDTO{
+    private Integer dictSort;
+    private String dictLabel;//标签
+    private String dictValue;//值(英文)
+    private String dictType;//类型
+    private Character isDefault;
+    private Boolean status;
+}

+ 23 - 0
src/main/java/com/loan/system/domain/dto/DictTypeDTO.java

@@ -0,0 +1,23 @@
+package com.loan.system.domain.dto;
+
+import com.loan.system.domain.entity.BaseEntity;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+import javax.validation.constraints.Size;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class DictTypeDTO extends BaseEntity {
+    private static final long serialVersionUID = 34L;
+    private String dictName;
+    private String dictType;
+    private Boolean status;
+    private String remark;
+
+}

+ 4 - 2
src/main/java/com/loan/system/domain/dto/DisbursementDTO.java

@@ -7,20 +7,22 @@ import javax.persistence.Column;
 import javax.persistence.Entity;
 import javax.persistence.Index;
 import javax.persistence.Table;
+import java.io.Serializable;
 import java.math.BigDecimal;
 import java.time.Instant;
 
 @Data
 @AllArgsConstructor
 @NoArgsConstructor
-public class DisbursementDTO extends BaseEntity {
+public class DisbursementDTO implements Serializable {
     private Long caseId;//业务id
 //    private Long payoutApproveUserId;//出款审批人 id
 //    private Long payoutOperatorUserId;//财务出款人
 //    private Long applyBy;//出款上报人id
-    //private String disbursementType;//押品/财务
     private Double plannedAmount;//计划金额
+    private String plannedTime;//计划时间
     private String plannedLocation;//计划地点
+    private String plannedComment;//计划说明
     private String disbursementStatus;//出款状态
     //private Long contractId;//合同id
 

+ 1 - 0
src/main/java/com/loan/system/domain/dto/DisbursementRecordDTO.java

@@ -17,6 +17,7 @@ import java.math.BigDecimal;
 public class DisbursementRecordDTO implements Serializable {
     private Long disbursementId;
     private Double amount;
+    private String receiptName;//收款人
     private String disbursementLocation;
     private String disbursementAccount;
     private String disbursementBank;

+ 15 - 0
src/main/java/com/loan/system/domain/dto/DisbursementRecordListWrapper.java

@@ -0,0 +1,15 @@
+package com.loan.system.domain.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.List;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class DisbursementRecordListWrapper implements Serializable {
+    private List<DisbursementRecordDTO> disbursementRecordDTOs;
+}

+ 17 - 0
src/main/java/com/loan/system/domain/dto/DisbursementStartDTO.java

@@ -0,0 +1,17 @@
+package com.loan.system.domain.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.Map;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class DisbursementStartDTO implements Serializable {
+    private Long caseId;
+    private Map<Long,String> contractAndPawn;
+    private String comment;
+}

+ 2 - 2
src/main/java/com/loan/system/domain/dto/LoanCaseDTO.java

@@ -31,9 +31,9 @@ public class LoanCaseDTO implements Serializable {
     private String businessType;//业务类型
     private CustomersOtherDTO customers1;//其它客户1
     private CustomersOtherDTO customers2;//其它客户2
-    private BigDecimal totalLoanAmount;//总借款金额
+    private Double totalLoanAmount;//总借款金额
 //    private List<DocumentDTO> documents;// 文件
     private String marriedStatus;//婚姻状况
     private String currentAddress;// 房产产证地址
-    private Boolean isInvolvedInLitigation;//是否涉及诉讼
+    private Boolean isIllegal;//是否涉及诉讼
 }

+ 15 - 0
src/main/java/com/loan/system/domain/dto/RepaymentApprovalDTO.java

@@ -0,0 +1,15 @@
+package com.loan.system.domain.dto;
+
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class RepaymentApprovalDTO {
+    private Long caseId;
+    private Long recordId;
+    private String comments;
+}

+ 5 - 1
src/main/java/com/loan/system/domain/dto/RepaymentRecordDTO.java

@@ -5,6 +5,8 @@ import lombok.Data;
 import lombok.NoArgsConstructor;
 
 import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
 
 
 @Data
@@ -12,11 +14,13 @@ import java.io.Serializable;
 @NoArgsConstructor
 public class RepaymentRecordDTO implements Serializable {
 
-    private Long repaymentId;
     private Double amount;
+    private String repayTime;
     private String repayBank;
     private String repayLocation;
     private String repayAccount;
+    private String repayWay;
     private Boolean isInterest;//是否为费息
+    private Map<Long,Double> contractIdAndAmount;
 
 }

+ 4 - 2
src/main/java/com/loan/system/domain/dto/UserLoginDTO.java

@@ -12,7 +12,9 @@ import java.io.Serializable;
 @NoArgsConstructor
 @AllArgsConstructor
 public class UserLoginDTO implements Serializable {
-    String code;
     String tel;
-    String openid;
+    String password;
+    String validCode;//验证码
+    String openId;
+    Boolean isPassword;
 }

+ 2 - 2
src/main/java/com/loan/system/domain/dto/WeChatLoginDTO.java

@@ -6,6 +6,6 @@ import java.io.Serializable;
 
 @Data
 public class WeChatLoginDTO implements Serializable {
-    private String code;
-    private String openid;
+    private String openCode;
+    private String phoneCode;
 }

+ 3 - 0
src/main/java/com/loan/system/domain/entity/ApprovalRecord.java

@@ -33,6 +33,9 @@ public class ApprovalRecord extends BaseEntity{
     @Column(name = "comments")
     private String comments;
 
+    @Column(name="version",length = 20)
+    private Long version;
+
     @Column(name = "create_time")
     private String createTime;
 

+ 2 - 2
src/main/java/com/loan/system/domain/entity/Collateral.java

@@ -32,7 +32,7 @@ public class Collateral extends BaseEntity{
     private Long ownerCustomerId;
 
     @Column(name = "allocated_amount", precision = 18, scale = 2)
-    private BigDecimal allocatedAmount;
+    private Double allocatedAmount;
 
     @Column(name = "address", length = 500)
     private String address;
@@ -41,7 +41,7 @@ public class Collateral extends BaseEntity{
     private String currentAddress;
 
     @Column(name = "eval_price", precision = 18, scale = 2)
-    private BigDecimal evalPrice;
+    private Double evalPrice;
 
     @Column(name = "is_involved_in_litigation")
     private Boolean isInvolvedInLitigation;

+ 14 - 10
src/main/java/com/loan/system/domain/entity/CollateralPlan.java

@@ -4,6 +4,7 @@ import lombok.*;
 
 import javax.persistence.*;
 import java.time.Instant;
+
 @Builder
 @Entity
 @Table(name = "collateral_plan")
@@ -16,16 +17,16 @@ public class CollateralPlan extends BaseEntity {
     @Column(name = "case_id")
     private Long caseId;
 
-    @Column(name = "collateral_id")
-    private Long collateralId;
+    @Column(name = "collateral_ids")
+    private String collateralIds;
 
     @Column(name = "user_id")
-    private Long userId;
+    private Long userId;//计划上报员
 
     @Column(name = "time")
     private String time;
 
-    @Column(name = "place", length = 255)
+    @Column(name = "place")
     private String place;
 
     @Column(name = "flag", length = 10)
@@ -35,10 +36,10 @@ public class CollateralPlan extends BaseEntity {
     private String comments;
 
     @Column(name = "create_time")
-    private String  createTime;
+    private String createTime;
 
     @Column(name = "update_time")
-    private String  updateTime;
+    private String updateTime;
 
     @Column(name = "is_delete")
     private Boolean isDelete;
@@ -46,9 +47,12 @@ public class CollateralPlan extends BaseEntity {
     @Column(name = "status", length = 10)
     private String status;
 
-    @Column(name="operator_id")
-    private Long operatorId;
+    @Column(name = "approval_record_id")
+    private Long approvalRecordId;
+
+    @Column(name = "operator_comments")
+    private String operatorComments;
 
-    @Column(name="operator_name")
-    private String operatorName;
+    @Column(name = "operator_id", length = 20)
+    private Long operatorId;//送证/取证员
 }

+ 11 - 2
src/main/java/com/loan/system/domain/entity/Contract.java

@@ -38,9 +38,18 @@ public class Contract extends BaseEntity{
     @Column(name = "interest_rate", precision = 5, scale = 4)
     private Double interestRate;
 
+    @Column(name = "interest_amount", precision = 18, scale = 2)
+    private Double interestAmount;
+
+    @Column(name = "is_cleared")
+    private Boolean isCleared;
+
     @Column(name = "loan_period")
     private Integer loanPeriod;
 
+    @Column(name = "finance_user_id",length = 20)
+    private Long financeUserId;
+
     @Lob
     @Column(name = "content")
     private String content;
@@ -51,8 +60,8 @@ public class Contract extends BaseEntity{
     @Column(name = "commited_id")
     private Long commitedId;
 
-    @Column(name = "sifned_id")
-    private Long sifnedId;
+    @Column(name = "signed_id")
+    private Long signedId;
 
     @Column(name = "signed_time")
     private String signedTime;

+ 43 - 0
src/main/java/com/loan/system/domain/entity/ContractRepayment.java

@@ -0,0 +1,43 @@
+package com.loan.system.domain.entity;
+
+import lombok.*;
+
+import javax.persistence.*;
+import javax.validation.constraints.NotNull;
+import java.time.Instant;
+
+@Entity
+@Table(name = "contract_repayment")
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class ContractRepayment extends BaseEntity{
+    private static final long serialVersionUID = 31L;
+
+    @NotNull
+    @Column(name = "contract_id", nullable = false)
+    private Long contractId;
+
+    @NotNull
+    @Column(name = "repayment_record_id", nullable = false)
+    private Long repaymentRecordId;
+
+    @Column(name = "case_id")
+    private Long caseId;
+
+    @Column(name = "amount" , precision = 18, scale = 2)
+    private Double amount;
+
+    @Column(name = "comment" )
+    private String comment;
+
+    @Column(name = "create_time")
+    private String createTime;//应该等于repayTime
+
+    @Column(name = "update_time")
+    private String updateTime;
+
+    @Column(name = "is_delete")
+    private Boolean isDelete;
+
+}

+ 1 - 3
src/main/java/com/loan/system/domain/entity/ContractSeq.java

@@ -8,9 +8,7 @@ import javax.validation.constraints.Size;
 
 
 @Entity
-@Table(name = "contract_seq", uniqueConstraints = {
-        @UniqueConstraint(name = "uk_seq_data", columnNames = {"seq_data"})
-})
+@Table(name = "contract_seq")
 @Data
 @AllArgsConstructor
 @NoArgsConstructor

+ 6 - 0
src/main/java/com/loan/system/domain/entity/Customer.java

@@ -22,6 +22,9 @@ public class Customer extends BaseEntity{
     @Column(name = "name", length = 100)
     private String name;
 
+    @Column(name = "role", length = 20)
+    private String role;
+
     @Column(name = "sex", length = 10)
     private String sex;
 
@@ -43,6 +46,9 @@ public class Customer extends BaseEntity{
     @Column(name = "bank_name", length = 50)
     private String bankName;
 
+    @Column(name = "is_illegal", length = 1)
+    private Boolean isIllegal;
+
     @Column(name = "face_auth")
     private Boolean faceAuth;
 

+ 47 - 0
src/main/java/com/loan/system/domain/entity/DictData.java

@@ -0,0 +1,47 @@
+package com.loan.system.domain.entity;
+
+import lombok.*;
+
+import javax.persistence.*;
+import javax.validation.constraints.Size;
+import java.time.Instant;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Entity
+@Table(name = "dict_data")
+public class DictData extends BaseEntity{
+    private static final long serialVersionUID = 33L;
+    @Column(name = "dict_sort")
+    private Integer dictSort;
+
+    @Size(max = 100)
+    @Column(name = "dict_label", length = 100)
+    private String dictLabel;
+
+    @Size(max = 100)
+    @Column(name = "dict_value", length = 100)
+    private String dictValue;
+
+    @Size(max = 100)
+    @Column(name = "dict_type", length = 100)
+    private String dictType;
+
+    @Column(name = "is_default")
+    private Character isDefault;
+
+    @Column(name = "status")
+    private Boolean status;
+
+    @Column(name = "create_time")
+    private String createTime;
+
+    @Column(name = "update_time")
+    private String updateTime;
+
+    @Size(max = 500)
+    @Column(name = "remark", length = 500)
+    private String remark;
+
+}

+ 18 - 19
src/main/java/com/loan/system/domain/entity/DictType.java

@@ -3,36 +3,35 @@ package com.loan.system.domain.entity;
 import lombok.*;
 
 import javax.persistence.*;
+import javax.validation.constraints.Size;
 import java.time.Instant;
 
 @Entity
-@Table(name = "dict_type", indexes = {
-        @Index(name = "idx_enabled", columnList = "enabled")
-}, uniqueConstraints = {
-        @UniqueConstraint(name = "code", columnNames = {"code"})
-})
+@Table(name = "dict_type")
 @Data
 @AllArgsConstructor
 @NoArgsConstructor
 public class DictType extends BaseEntity{
-    private static final long serialVersionUID = 13L;
+    private static final long serialVersionUID = 34L;
+    @Size(max = 100)
+    @Column(name = "dict_name", length = 100)
+    private String dictName;
 
-    @Column(name = "code")
-    private Integer code;
+    @Size(max = 100)
+    @Column(name = "dict_type", length = 100)
+    private String dictType;
 
-    @Column(name = "name", length = 100)
-    private String name;
+    @Column(name = "status")
+    private Boolean status;
 
-    @Column(name = "enabled")
-    private Boolean enabled;
+    @Column(name = "create_time")
+    private String createTime;
 
-    @Column(name = "sort_order")
-    private Integer sortOrder;
+    @Column(name = "update_time")
+    private String updateTime;
 
-    @Column(name = "created_at")
-    private String createdAt;
-
-    @Column(name = "is_delete")
-    private Boolean isDelete;
+    @Size(max = 500)
+    @Column(name = "remark", length = 500)
+    private String remark;
 
 }

+ 10 - 4
src/main/java/com/loan/system/domain/entity/Disbursement.java

@@ -34,8 +34,8 @@ public class Disbursement extends BaseEntity{
     @Column(name = "apply_at")
     private String applyAt;
 
-    @Column(name = "disbursement_type", length = 10)
-    private String disbursementType;
+    @Column(name = "planned_time", length = 200)
+    private String plannedTime;
 
     @Column(name = "planned_amount", precision = 18, scale = 2)
     private Double plannedAmount;
@@ -43,14 +43,20 @@ public class Disbursement extends BaseEntity{
     @Column(name = "planned_location")
     private String plannedLocation;
 
+    @Column(name = "planned_comment")
+    private String plannedComment;
+
     @Column(name = "disbursement_status", length = 30)
     private String disbursementStatus;
 
     @Column(name = "contract_id")
     private Long contractId;
 
-    @Column(name="comments", length = 200)
-    private String comments;
+    @Column(name="disbursement_comment", length = 200)
+    private String disbursementComment;
+
+    @Column(name="confirm_comment", length = 200)
+    private String confirmComment;
 
     @Column(name = "create_time")
     private String createTime;

+ 3 - 1
src/main/java/com/loan/system/domain/entity/DisbursementRecord.java

@@ -29,6 +29,9 @@ public class DisbursementRecord extends BaseEntity{
     @Column(name = "create_time")
     private String createTime;
 
+    @Column(name = "receipt_name",length = 20)
+    private String receiptName;
+
     @Column(name ="disbursement_location" ,length = 255)
     private String disbursementLocation;
 
@@ -38,7 +41,6 @@ public class DisbursementRecord extends BaseEntity{
     @Column(name ="disbursement_bank" ,length = 255)
     private String disbursementBank;
 
-
     @Column(name = "is_delete")
     private Boolean isDelete;
 

+ 135 - 110
src/main/java/com/loan/system/domain/entity/ExceptionLog.java

@@ -1,131 +1,156 @@
 package com.loan.system.domain.entity;
 
-import org.hibernate.annotations.Proxy;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.*;
+import org.apache.commons.io.output.ByteArrayOutputStream;
+import org.apache.commons.lang3.exception.ExceptionUtils;
 
 import javax.persistence.*;
-import java.util.Date;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+import java.io.IOException;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Base64;
+import java.util.zip.GZIPOutputStream;
 
 @Entity
 @Table(name = "exception_log")
-@Proxy(lazy = false)
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
 public class ExceptionLog {
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
-    private int id;
+    @Column(name = "id", nullable = false)
+    private Long id;
 
-    @Lob
-    @Column(name = "exception_message")
-    private String exceptionMessage;
-    @Column(name = "exception_name")
-    private String exceptionName;
-    @Column(name = "exception_method")
-    private String exceptionMethod; //异常方法
-    @Column(name = "oper_user_name", length = 50)
-    private String operUserName; //用户名
-    @Column(name = "oper_ip", length = 50)
-    private String operIp; //ip地址
-    @Column(name = "oper_uri")
-    private String operUri; //请求地址
-    @Column(name = "oper_time")
-    @Temporal(TemporalType.TIMESTAMP)
-    private Date operTime; //操作时间
-    @Lob
-    @Column(name="method_param")
-    private String methodParam;
-
-    @Override
-    public String toString() {
-        return "ExceptionLog{" +
-                "id=" + id +
-                ", exceptionMessage='" + exceptionMessage + '\'' +
-                ", exceptionName='" + exceptionName + '\'' +
-                ", exceptionMethod='" + exceptionMethod + '\'' +
-                ", operUserName='" + operUserName + '\'' +
-                ", operIp='" + operIp + '\'' +
-                ", operUri='" + operUri + '\'' +
-                ", operTime=" + operTime +
-                ", methodParam='" + methodParam + '\'' +
-                '}';
-    }
-
-    public int getId() {
-        return id;
-    }
-
-    public ExceptionLog setId(int id) {
-        this.id = id;
-        return this;
-    }
-
-    public String getExceptionMessage() {
-        return exceptionMessage;
-    }
-
-    public ExceptionLog setExceptionMessage(String exceptionMessage) {
-        this.exceptionMessage = exceptionMessage;
-        return this;
-    }
-
-    public String getExceptionName() {
-        return exceptionName;
-    }
+    @Size(max = 120)
+    @Column(name = "exception_type", length = 120)
+    private String exceptionType;
 
-    public ExceptionLog setExceptionName(String exceptionName) {
-        this.exceptionName = exceptionName;
-        return this;
-    }
+    @Size(max = 500)
+    @Column(name = "message", length = 500)
+    private String message;
 
-    public String getExceptionMethod() {
-        return exceptionMethod;
-    }
+    @Size(max = 200)
+    @Column(name = "summary", length = 200)
+    private String summary;
 
-    public ExceptionLog setExceptionMethod(String exceptionMethod) {
-        this.exceptionMethod = exceptionMethod;
-        return this;
-    }
+    @Size(max = 200)
+    @Column(name = "cause", length = 200)
+    private String cause;
 
-    public String getOperUserName() {
-        return operUserName;
-    }
+    @Lob
+    @Column(name = "stack_trace")
+    private String stackTrace;
 
-    public ExceptionLog setOperUserName(String operUserName) {
-        this.operUserName = operUserName;
-        return this;
-    }
+    @Size(max = 255)
+    @Column(name = "url")
+    private String url;
 
-    public String getOperIp() {
-        return operIp;
-    }
+    @Column(name = "user_id")
+    private Long userId;
 
-    public ExceptionLog setOperIp(String operIp) {
-        this.operIp = operIp;
-        return this;
-    }
+    @Size(max = 45)
+    @Column(name = "ip", length = 45)
+    private String ip;
 
-    public String getOperUri() {
-        return operUri;
-    }
+    @Size(max = 300)
+    @Column(name = "user_agent", length = 300)
+    private String userAgent;
 
-    public ExceptionLog setOperUri(String operUri) {
-        this.operUri = operUri;
-        return this;
-    }
+    @Size(max = 10)
+    @Column(name = "method", length = 10)
+    private String method;
 
-    public Date getOperTime() {
-        return operTime;
-    }
-
-    public ExceptionLog setOperTime(Date operTime) {
-        this.operTime = operTime;
-        return this;
-    }
-
-    public String getMethodParam() {
-        return methodParam;
-    }
-
-    public ExceptionLog setMethodParam(String methodParam) {
-        this.methodParam = methodParam;
-        return this;
-    }
-}
+    @Lob
+    @Column(name = "params")
+    private String params;
+
+    @Column(name = "is_resolve")
+    private Boolean isResolve;
+
+    @NotNull
+    @Column(name = "create_time", nullable = false)
+    private String createTime;
+
+    private static final ObjectMapper MAPPER = new ObjectMapper();
+
+    /** 快速构建:只传异常 + 请求上下文 */
+    public static ExceptionLog build(Exception e, String url, String method,
+                                     String ip, String userAgent, Long userId,
+                                     Object paramsObj) {
+        Throwable root = ExceptionUtils.getRootCause(e);
+        if (root == null) root = e;
+
+        return ExceptionLog.builder()
+                .exceptionType(e.getClass().getSimpleName())
+                .message(trim(e.getMessage(), 500))
+                .summary(buildSummary(e))
+                .cause(root.getClass().getSimpleName())
+                .stackTrace(compressTrace(e, 50))
+                .url(trim(url, 255))
+                .method(trim(method, 10))
+                .ip(trim(ip, 45))
+                .userAgent(trim(userAgent, 300))
+                .userId(userId == null ? 0L : userId)
+                .params(toJson(paramsObj))
+                .createTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")))
+                .build();
+    }
+
+    /** 摘要:类名 + 第一行堆栈 */
+    private static String buildSummary(Exception e) {
+        StringBuilder sb = new StringBuilder(e.getClass().getSimpleName());
+        if (e.getMessage() != null) {
+            sb.append(": ").append(trim(e.getMessage(), 120));
+        }
+        if (e.getStackTrace().length > 0) {
+            StackTraceElement first = e.getStackTrace()[0];
+            sb.append(" at ")
+                    .append(first.getClassName())
+                    .append(":")
+                    .append(first.getLineNumber());
+        }
+        return trim(sb.toString(), 200);
+    }
+
+    /** 截取堆栈前 max 行并 GZIP + Base64 */
+    private static String compressTrace(Exception e, int max) {
+        String raw = ExceptionUtils.getStackTrace(e);
+        String[] lines = raw.split("\n");
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < Math.min(max, lines.length); i++) {
+            sb.append(lines[i]).append('\n');
+        }
+        try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
+             GZIPOutputStream gzip = new GZIPOutputStream(bos)) {
+            gzip.write(sb.toString().getBytes("UTF-8"));
+            gzip.finish();
+            return Base64.getEncoder().encodeToString(bos.toByteArray());
+        } catch (IOException ignored) {
+            return "";
+        }
+    }
+
+    private static String toJson(Object obj) {
+        if (obj == null) return null;
+        try {
+            JsonNode node = MAPPER.valueToTree(obj);
+            // TODO 这里可继续做脱敏
+            return MAPPER.writeValueAsString(node);
+        } catch (Exception ignore) {
+            return null;
+        }
+    }
+
+    private static String trim(String str, int max) {
+        if (str == null) return "";
+        return str.length() > max ? str.substring(0, max) : str;
+    }
+
+}

+ 4 - 4
src/main/java/com/loan/system/domain/entity/LoanCase.java

@@ -35,13 +35,13 @@ public class LoanCase extends BaseEntity{
     private Long recommenderId;
 
     @Column(name = "requested_amount", precision = 18, scale = 2)
-    private BigDecimal requestedAmount;
+    private Double requestedAmount;//最大金额限制
 
     @Column(name = "total_loan_amount", precision = 18, scale = 2)
-    private BigDecimal totalLoanAmount;
+    private Double totalLoanAmount;
 
-    @Column(name = "is_complete", length = 1)
-    private Boolean isComplete;
+    @Column(name = "is_complete", length = 10)
+    private String isComplete;
 
     @Column(name = "create_time")
     private String createTime;

+ 40 - 0
src/main/java/com/loan/system/domain/entity/PawnTicketInfo.java

@@ -0,0 +1,40 @@
+package com.loan.system.domain.entity;
+
+import lombok.*;
+
+import javax.persistence.*;
+import javax.validation.constraints.Size;
+import java.time.Instant;
+
+@Entity
+@Table(name = "pawn_ticket_info")
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class PawnTicketInfo extends BaseEntity{
+    private static final long serialVersionUID = 32L;
+
+    @Column(name = "case_id")
+    private Long caseId;
+
+    @Column(name = "contract_id")
+    private Long contractId;
+
+    @Size(max = 255)
+    @Column(name = "pawn_ticket_no")
+    private String pawnTicketNo;
+
+    @Column(name = "begin_time")
+    private String beginTime;
+
+    @Size(max = 255)
+    @Column(name = "redeem_ticket_no")
+    private String redeemTicketNo;
+
+    @Column(name = "end_time")
+    private String endTime;
+
+    @Column(name = "is_delete")
+    private Boolean isDelete;
+
+}

+ 3 - 0
src/main/java/com/loan/system/domain/entity/Repayment.java

@@ -50,6 +50,9 @@ public class Repayment extends BaseEntity{
     @Column(name = "repay_way",length = 10)
     private String repayWay;
 
+    @Column(name = "repay_status",length = 20)
+    private String repayStatus;
+
     @Column(name = "create_time")
     private String createTime;
 

+ 8 - 2
src/main/java/com/loan/system/domain/entity/RepaymentRecord.java

@@ -20,11 +20,14 @@ public class RepaymentRecord extends BaseEntity {
     @Column(name = "repayment_id")
     private Long repaymentId;
 
+    @Column(name = "plan_user_id" , length = 20)
+    private Long planUserId;
+
     @Column(name = "amount", precision = 18, scale = 2)
     private Double amount;
 
-    @Column(name = "create_time")
-    private String createTime;
+    @Column(name = "repay_time")
+    private String repayTime;
 
     @Size(max = 200)
     @Column(name = "repay_bank", length = 200)
@@ -47,6 +50,9 @@ public class RepaymentRecord extends BaseEntity {
     @Column(name = "approval_user_id")
     private Long approvalUserId;
 
+    @Column(name = "repay_way",length = 20)
+    private String repayWay;
+
     @Column(name = "is_interest")
     private Boolean isInterest;
 

+ 12 - 0
src/main/java/com/loan/system/domain/entity/Step.java

@@ -16,6 +16,9 @@ import java.time.Instant;
 public class Step extends BaseEntity{
     private static final long serialVersionUID = 22L;
 
+    @Column(name = "code")
+    private Integer code;
+
     @Column(name = "step_name", length = 50)
     private String stepName;
 
@@ -43,6 +46,15 @@ public class Step extends BaseEntity{
     @Column(name = "pre_id")
     private Long preId;
 
+    @Column(name = "parent_code")
+    private Integer parentCode;
+
+    @Column(name = "pre_codes")
+    private String preCodes;
+
+    @Column(name = "next_codes")
+    private String nextCodes;
+
     @Column(name = "next_id")
     private Long nextId;
 

+ 22 - 1
src/main/java/com/loan/system/domain/enums/DecisionEnum.java

@@ -4,13 +4,34 @@ package com.loan.system.domain.enums;
  * 决定结果枚举类
  */
 public enum DecisionEnum {
+
+    //业务状态
+    PROCESS("PROCESS", "处理中"),
+    COMPLETE("COMPLETE", "已完成"),
+
+
     PASS("PASS", "通过"),
     REJECT("REJECT", "驳回"),
     TERMINATE("TERMINATE", "终结"),
     WAITING_APPROVAL("WAIT_APPROVAL", "待审批"),
     REJECTION("REJECTION", "拒绝"),
     WAITING_EXECUTION("WAIT_EXECUTION", "待执行"),
-    EXECUTION_COMPLETE("EXECUTION_COMPLETE", "执行完成");
+    EXECUTION_COMPLETE("EXECUTION_COMPLETE", "执行完成"),
+    ENTER_WAREHOUSE("ENTER_WAREHOUSE", "入库"),
+    OUT_WAREHOUSE("OUT_WAREHOUSE", "出库"),
+
+
+    //出款状态
+    DISBURSEMENT_PROCESS("DISBURSEMENT_PROCESS", "出款处理中"),
+    DISBURSEMENT_COMPLETE("DISBURSEMENT_COMPLETE", "出款完成"),
+
+    //回款状态
+    REPAYMENT_PROCESS("REPAYMENT_PROCESS", "回款中"),
+    REPAYMENT_COMPLETE("REPAYMENT_STEP_COMPLETE", "回款完成"),
+
+    //财务状态
+    FINANCE_PROCESS("FINANCE_PROCESS", "财务处理中"),
+    FINANCE_COMPLETE("FINANCE_COMPLETE", "财务完成");
 
     private final String status;
     private final String msg;

+ 26 - 7
src/main/java/com/loan/system/domain/enums/ExceptionEnum.java

@@ -55,19 +55,25 @@ public enum ExceptionEnum {
     TOKEN_EXPIRED(-101,"Token Expired"),
     WITHOUT_TOKEN(-102,"WITHOUT TOKEN"),
     LOGIN_EXPIRED(-103,"登录过期"),
+    CODE_NOT_EXIST(-104, "code为空,请输入code"),
 
     USER_NOT_EXIST(-110, "账户不存在"),
     USER_EXIST(-111, "账户已存在"),
     USERNAME_IS_NULL(-112, "账户不能为空"),
     WRONG_PASSWORD(-113, "密码错误,若密码连续错误3次以上账户将被锁定"),
-    USER_MUST_BE_UNAUTHORIZED(-114, "被授权的用户必须是未被授权的"),
-    USER_NUMBER_EXIST(-114, "工号已存在"),
+    USER_MUST_BE_UNAUTHORIZED(-114, "账号已被禁用"),
+    USER_NUMBER_EXIST(-115, "工号已存在"),
+    CODE_IS_NULL(-116, "验证吗不能为空"),
+    CODE_ERROR(-117, "验证码错误"),
+    PASSWORD_IS_NULL(-118, "密码不能为空"),
+    PASSWORD_ERROR(-119, "密码错误"),
+
 
     PROJECT_EXIST(-200,"项目已存在"),
     PROJECT_NOT_EXIST(-201,"业务不存在"),
     PROJECT_LABEL_EXIST(-202,"项目标签已存在"),
-    PROJECT_LABEL_NOT_EXIST(-203,"项目标签不存在"),
-    LOANCASE_IS_Completed(-204,"项目已经完成,无法重复提交"),
+    PROJECT_HAS_NOT_COMPLETED(-203,"业务未完成,请勿操作"),
+    LOANCASE_IS_COMPLETED(-204,"项目已经完成,无法重复提交"),
     PROJECT_TYPE_NOT_EXIST(-205,"项目类型不存在"),
     PROJECT_TYPE_IS_NECESSARY(-206,"项目类型是必须的"),
     PROJECT_LABEL_HAS_NOT_EXIST(-207,"存在项目标签不存在"),
@@ -92,11 +98,11 @@ public enum ExceptionEnum {
     CONTRACT_HAS_SIGNED(-280,"合同以签署完成,请勿重复操作"),
     CONTRACT_HAS_PUSH(-281,"合同已推送,请勿重复操作"),
     CONTRACT_NOT_PUSH(-282,"合同未推送,禁止操作"),
+    CONTRACT_NOT_SIGNED(-283,"合同未签署,请签署后提交" ),
 
 
     CANCEL_PREAPPROVAL_IS_COMPLETED(-300, "取消预审已完成,请勿重复操作"),
-    DISBURSEMENT_HAS_NOT_COMPLETED(-301, "出款未完成,无法新增"),
-    DISBURSEMENT_HAS_COMPLETED(-302, "出款已完成,无法修改"),
+    APPROVAL_USER_IS_COMPLETED(-301, "您已审批已完成,请勿重复操作"),
 
     COLLATERAL_NOT_EXIST(-310, "抵押物不存在"),
     COLLATERAL_PLAN_NOT_EXIST(-311,"计划不存在"),
@@ -105,6 +111,9 @@ public enum ExceptionEnum {
     COLLATERAL_PLAN_NOT_EQUAL_WAREHOUSE(-314,"计划与入库操作不符"),
     COLLATERAL_PLAN_NOT_EQUAL_OUTBOUND(-315,"计划与出库操作不符"),
     COLLATERAL_PLAN_ALREADY_EXIST(-316,"该押品已有计划未执行完成,不能重复添加"),
+    PLAN_HAS_NOT_PASSED(-317,"计划还未通过,无法新增"),
+    PLAN_HAS_BEEN_PASSED(-318,"计划已上报,无法修改"),
+    COLLATERAL_PLAN_HAS_ENOUGH(-319,"计划数已达上限"),
 
 
 
@@ -120,6 +129,7 @@ public enum ExceptionEnum {
     STEP_HAS_COMPLETEED(-359,"环节已完成,不能重复操作"),
     PRE_STEP_NOT_COMPLETE(-360,"上一环节未完成,无法操作"),
     STEP_HAS_NOT_PROCESS(-361,"环节不在进行中,无法操作"),
+    STEP_EXIST_NOT_COMPLETE(-362,"有环节未完成,无法完成业务"),
 
 
     FUND_EXIST(-400,"经费已存在"),
@@ -129,7 +139,16 @@ public enum ExceptionEnum {
     FUND_OUTPUT_HAS_NOT_EXIST(-404,"存在支出表不存在"),
     FUND_SHOULD_NOT_BE_NULL(-405,"经费来源不能为空"),
     INSUFFICIENT_BALANCE_OF_FUND(-410,"经费余额不足"),
-    FUND_OUTPUT_EXCESSIVE(-411,"经费使用超出所需"), ACCOUNT_IS_LOCK(-412, "账户已经被锁定请15分钟后再试"), WEAK_PASSWORD_ACCOUNT_IS_LOCK(-413, "账户因弱密码被锁定请联系管理员解锁"), WRONG_PASSWORD_ACCOUNT(-414, "密码错误次数已达上线,账户将被锁定请15分钟后再试");
+    FUND_OUTPUT_EXCESSIVE(-411,"经费使用超出所需"),
+    ACCOUNT_IS_LOCK(-412, "账户已经被锁定请15分钟后再试"),
+    WEAK_PASSWORD_ACCOUNT_IS_LOCK(-413, "账户因弱密码被锁定请联系管理员解锁"),
+    WRONG_PASSWORD_ACCOUNT(-414, "密码错误次数已达上线,账户将被锁定请15分钟后再试"),
+    DISBURSEMENT_HAS_NOT_COMPLETED(-415, "出款未完成,无法新增"),
+    DISBURSEMENT_HAS_COMPLETED(-415, "出款已完成,无法修改"),
+    DISBURSEMENT_NOT_EXIST(-416, "出款信息不存在"),
+    AMOUNT_HAS_EXCEED_PLANNED_AMOUNT(-417, "金额超出计划金额"),
+    REPAYMENT_HAS_BEEN_REJECTED(-418, "回款款已拒绝,无法新增"),
+    REPAYMENT_HAS_COMPLETED(-415, "出款已完成,无法修改");
 
     private Integer code;
     private String msg;

+ 2 - 1
src/main/java/com/loan/system/domain/enums/RoleEnum.java

@@ -12,7 +12,8 @@ public enum RoleEnum {
     ASSIST_SALES(4, " ASSIST_SALES"),//辅办业务员
     FINANCE(5, "FINANCE"),//财务人员
     BACK_OFFICE(6, "BACK_OFFICE"),//综合内勤
-    EXTERNAL(7, "EXTERNAL");//外部人员
+    EXTERNAL(7, "EXTERNAL"),//外部人员
+    ALL(8, "ALL");
 
     private Integer code;
     private String msg;

+ 68 - 27
src/main/java/com/loan/system/domain/enums/StepPropertyEnum.java

@@ -1,5 +1,6 @@
 package com.loan.system.domain.enums;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 
@@ -13,40 +14,42 @@ public enum StepPropertyEnum {
     BUSINESS_ACCEPT_PARENT(501, "业务受理环节", true),
     BUSINESS_ACCEPT(502, "业务受理", false),
 
-    PRE_TRIAL_PARENT(503, "预审环节", true),
-    PRE_TRIAL(504, "预审", false),
+    PRE_TRIAL_PARENT(511, "预审环节", true),
+    PRE_TRIAL(512, "预审", false),
 
-    APPROVAL_PARENT(505, "审批环节", true),
-    APPROVAL(506, "审批", false),
+    APPROVAL_PARENT(521, "审批环节", true),
+    APPROVAL(522, "审批", false),
 
-    CONTRACT_SIGN_PARENT(507, "合同签约环节", true),
-    CONTRACT_SIGN(508, "合同签约", false),
+    CONTRACT_SIGN_PARENT(531, "合同签约环节", true),
+    CONTRACT_SIGN(532, "合同签约", false),
 
-    DISBURSE_PARENT(509, "出款环节", true),
-    PLAN_REPORT(510, "计划上报", false),
-    PLAN_AUDIT(511, "计划审核", false),
-    DISBURSE_START(512, "出账启动", false),
-    DISBURSE_AUDIT(513, "出账审核", false),
-    FINANCE_DISBURSE(514, "财务出账", false),
-    DISBURSE_CONFIRM(515, "出账确认", false),
+    COLLATERAL_RECEIVE(541, "押品取证环节", true),
+    PLAN_SUBMISSION(542, "取证计划上报", false),
+    APPROVAL_ASSIGNMENT(543, "取证审批分派", false),
+    EVIDENCE_CONFIRMATION(544, "确认取证", false),
 
-    REPAY_PARENT(516, "回款环节", true),
-    REPAY_START(517, "回款启动", false),
-    REPAY_APPROVAL(518, "回款审批", false),
-    FINANCE_CHECK(519, "财务核算", false),
-    BALANCE_REPAY(520, "余额回款", false),
-    FINANCE_CONFIRM(521, "财务确认", false),
+    DISBURSE_PARENT(551, "出款环节", true),
+    PLAN_REPORT(552, "计划上报", false),
+    PLAN_AUDIT(553, "计划审核", false),
+    DISBURSE_START(554, "出账启动", false),
+    DISBURSE_AUDIT(555, "出账审核", false),
+    FINANCE_DISBURSE(556, "财务出账", false),
+    DISBURSE_CONFIRM(557, "出账确认", false),
 
+    COLLATERAL_DELIVERY(561, "押品送证环节", true),
+    PLAN_SUBMISSION_2(562, "送证计划上报", false),
+    APPROVAL_ASSIGNMENT_2(563, "送证审批分派", false),
+    DELIVERY_CONFIRMATION(564, "送证确认", false),
 
-    COLLATERAL_RECEIVE(522, "押品取证环节", true),
-    PLAN_SUBMISSION(523, "计划上报", false),
-    APPROVAL_ASSIGNMENT(524, "审批分派", false),
-    EVIDENCE_CONFIRMATION(525, "确认取证", false),
+    REPAY_PARENT(571, "回款环节", true),
+    REPAY_START(572, "回款启动", false),
+    REPAY_APPROVAL(573, "回款审批", false),
+    FINANCE_CHECK(574, "财务核算", false),
+    BALANCE_REPAY(575, "余额回款", false),
+    FINANCE_CONFIRM(576, "财务确认", false),
+    REPAYMENT_COMPLETE(577, "回款完成", false),
+    CASE_COMPLETE(578, "业务完成", false);
 
-    COLLATERAL_DELIVERY(526, "押品送证环节", true),
-    PLAN_SUBMISSION_2(527, "计划上报", false),
-    APPROVAL_ASSIGNMENT_2(528, "审批分派", false),
-    DELIVERY_CONFIRMATION(529, "送证确认", false);
 
     /* ========== 字段 & 构造 ========== */
     private final int code;
@@ -68,4 +71,42 @@ public enum StepPropertyEnum {
         return Arrays.asList(values()); // 顺序与源码声明一致
     }
 
+    public static List<List<Integer>> seqList(){
+        List<List<Integer>> list = new ArrayList<>(Arrays.asList(
+                Arrays.asList(),//受理0
+                Arrays.asList(3),
+                Arrays.asList(),//预审2
+                Arrays.asList(5),
+                Arrays.asList(),//审批4
+                Arrays.asList(7),
+                Arrays.asList(),//合同签约6
+                Arrays.asList(9),
+                Arrays.asList(),//押品取证8
+                Arrays.asList(10),
+                Arrays.asList(11),
+                Arrays.asList(13),
+                Arrays.asList(),//出款12
+                Arrays.asList(14),
+                Arrays.asList(15),
+                Arrays.asList(16),
+                Arrays.asList(17),
+                Arrays.asList(18),
+                Arrays.asList(20),
+                Arrays.asList(),//送证19
+                Arrays.asList(21),
+                Arrays.asList(22),
+                Arrays.asList(24),
+                Arrays.asList(),//回款23
+                Arrays.asList(25),
+                Arrays.asList(26),
+                Arrays.asList(27),
+                Arrays.asList(28),
+                Arrays.asList(29),
+                Arrays.asList(30),
+                Arrays.asList()
+        ));
+
+        return list;
+    }
+
 }

+ 2 - 2
src/main/java/com/loan/system/domain/pojo/ContractInformation.java

@@ -23,7 +23,7 @@ public class ContractInformation {
     private String mobile;//客户手机号
     private String bankName;//客户银行
     private String bankAccount;//客户银行账号
-    private String signature1;
+    private String signaturePath1;
     private String contactAddress1;
     //押品信息
     private String address;//押品地址
@@ -31,7 +31,7 @@ public class ContractInformation {
     private String collateralArea;
 
     //业务方
-    private String signature2;
+    private String signaturePath2;
     private String contactAddress2;
     private String userMobile;
 

+ 2 - 2
src/main/java/com/loan/system/domain/vo/ApprovalRecordVO.java

@@ -13,10 +13,10 @@ public class ApprovalRecordVO implements Serializable {
 
     private Long caseId;//业务ID
     private String stepName;//环节名称
-    private Long approverId;//审批人ID
+    private UserVO approver;//审批人
     private String decision;//审批结果
     private String comments;//审批意见
-
+    private Long version;
 
 
 }

+ 17 - 0
src/main/java/com/loan/system/domain/vo/CaseAndUserVO.java

@@ -0,0 +1,17 @@
+package com.loan.system.domain.vo;
+
+import com.loan.system.domain.entity.User;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+import java.util.Map;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class CaseAndUserVO {
+    List<UserVO> users;//所有业务员
+    Map<Long,List<LoanCaseVO>> caseUsers;//每个业务对应的业务员
+}

+ 11 - 7
src/main/java/com/loan/system/domain/vo/CollateralPlanVO.java

@@ -14,16 +14,20 @@ import java.util.List;
 public class CollateralPlanVO implements Serializable {
     private Long id;
     private Long caseId;
-    private Long collateralId;
-    private Long userId;
+    private List<CollateralVO> collaterals;
+    private UserVO planUser;
     private String time;
     private String place;
     private String flag;
     private String comments;
-    private String createTime;
-    private String updateTime;
     private String status;
-    private Long operatorId;
-    private String operatorName;
-    private Boolean isDelete;
+
+    //审批
+    private ApprovalRecordVO approvalRecord;
+    private UserVO approvalUser;
+
+    //执行
+    private String executeComments;
+    private UserVO executeUser;
+
 }

+ 5 - 1
src/main/java/com/loan/system/domain/vo/ContractVO.java

@@ -4,6 +4,7 @@ import lombok.AllArgsConstructor;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 
+import javax.persistence.Column;
 import java.io.Serializable;
 import java.math.BigDecimal;
 
@@ -19,10 +20,13 @@ public class ContractVO implements Serializable {
     private String contractName;//合同名称
     private Double contractAmount;//借款金额
     private Double interestRate;//年利率
+    private Double interestAmount;
+    private Boolean isCleared;
     private Integer loanPeriod;//借款期限
+    private UserVO financeUser;
     private String content;//合同内容
     private Boolean signedByCustomer;//是否签署
-    private Long sifnedId;//电子签名附件id
+    private Long signedId;//电子签名附件id
     private String commitedId;//承诺签名id
     private String signedTime;//签署实际
 }

+ 2 - 1
src/main/java/com/loan/system/domain/vo/CustomerLoginVO.java

@@ -16,5 +16,6 @@ public class CustomerLoginVO implements Serializable {
     private String openid;
     private String token;
     private String name;
-    private int is_customer;
+    private String mobile;
+    private String role;
 }

+ 2 - 0
src/main/java/com/loan/system/domain/vo/CustomerVO.java

@@ -14,11 +14,13 @@ public class CustomerVO implements Serializable {
     private Long id;
     private String openid;
     private String name;
+    private String role;
     private String sex;
     private String idNumber;
     private String mobile;
     private String marriedStatus;
     private String bankAccount;
     private String bankName;
+    private Boolean isIllegal;
     private Boolean faceAuth;
 }

+ 33 - 0
src/main/java/com/loan/system/domain/vo/DailyReport.java

@@ -0,0 +1,33 @@
+package com.loan.system.domain.vo;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class DailyReport {
+    private String customerName;//客户名称
+    private String loanCaseAttribute;// 业务属性
+    private String DisbursementDate;// 出款日期
+    private Double loanAmount;// 借款金额(万)
+    private Double repayTotalAmount;// 累计还款(万)
+    private Double remainAmount;// 剩余金额(万)
+    private String repayDate;// 还款日期
+    private Double loanInterest;// 典当利息 (元)
+
+    private Double balance2025;//2025年余额
+    private Double balance2024;//2024年余额
+    private Double balance2023;//2023年余额
+    private Double balanceTotal;//总计余额
+    private Double balanceClass1;//房产类余额
+    private Double balanceClass2;//股权类余额
+    private Double balanceMonthOut;//本月出账金额(万)
+    private Double balanceMonthIn;//本月收回金额(万)
+    private Double balanceYearOut;//本年累计出帐金额(万)
+    private Double balanceYearIn;//本年收回累计金额(万)
+    private Double interestMonth;//本月收息(元)
+    private Double interestYear;//本年累计收息(元)
+
+}

+ 3 - 4
src/main/java/com/loan/system/domain/vo/DictionarysVO.java

@@ -1,9 +1,6 @@
 package com.loan.system.domain.vo;
 
-import com.loan.system.domain.entity.DictAttribute;
-import com.loan.system.domain.entity.DictBusinessType;
-import com.loan.system.domain.entity.DictChannel;
-import com.loan.system.domain.entity.DictLocation;
+import com.loan.system.domain.entity.*;
 import lombok.AllArgsConstructor;
 import lombok.Data;
 import lombok.NoArgsConstructor;
@@ -19,4 +16,6 @@ public class DictionarysVO implements Serializable {
     List<DictBusinessType> types;
     List<DictLocation> locations;
     List<DictChannel> channels;
+    List<DictType> dictTypes;
+    List<DictData> dictDatas;
 }

+ 15 - 2
src/main/java/com/loan/system/domain/vo/DisbursementDetailVO.java

@@ -8,24 +8,37 @@ import lombok.NoArgsConstructor;
 
 import java.io.Serializable;
 import java.util.List;
+import java.util.Map;
 
 @Data
 @AllArgsConstructor
 @NoArgsConstructor
 public class DisbursementDetailVO implements Serializable {
+    private Long disbursementId;
     private CustomerVO customer;
     private LoanCaseSimpleVO loanCase;
     //计划上报
     private Double disbursementAmount;
     private String currentLocation;
+    private String plannedTime;
+    private String plannedComment;
+    private String rejectComment;
     //计划审批
-    private User repaymentUser;
-    private String approvalComment;
+    private List<ApprovalRecordVO> approvalRecords1;
+    //出款启动
+    private String disbursementComment;
+    private String rejectComment2;
+    private Map<Long ,String> contractAndPawn;
+
+    //出款审批
+    private List<ApprovalRecordVO> approvalRecords2;
     //财务出款
     private List<DisbursementRecordVO> disbursementRecords;
+    private Double currentAmount;//目前金额
     private Double totalAmount;//总金额
     //业务确认
     private String confirmComment;
+    private List<String> collateralStatus;//押品状态
 
 
 }

+ 24 - 0
src/main/java/com/loan/system/domain/vo/DisbursementDetails.java

@@ -0,0 +1,24 @@
+package com.loan.system.domain.vo;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class DisbursementDetails {
+    private String contractNo;//合同编号
+    private String loanTime;//借款日期
+    private String pawnTicketNo;//当票号
+    private String customerName;//当户名称
+    private Double pawnAmount;// 典当金额(万)
+    private List<String> userName;// 业务员
+    private String recommenderName;// 渠道推荐人
+    private String channelName;// 渠道推荐团队
+    private String redeemTime;// 赎当日期
+    private String redeemTicketNo;// 赎当号码
+
+}

+ 3 - 1
src/main/java/com/loan/system/domain/vo/DisbursementRecordVO.java

@@ -17,9 +17,11 @@ import java.math.BigDecimal;
 public class DisbursementRecordVO implements Serializable {
     private Long id;//记录id
     private Long disbursementId;//出款单id
-    private Long financeId;//出款负责人id
+    private Long financeId;
+    private String financeName;
     private Double amount;//出款金额
     private String createTime;//创建时间
+    private String receiptName;//收款人
     private String disbursementLocation;//出款地点
     private String disbursementAccount;//出款账户
     private String disbursementBank;//出款银行

+ 5 - 3
src/main/java/com/loan/system/domain/vo/DisbursementVO.java

@@ -17,12 +17,14 @@ public class DisbursementVO extends BaseEntity {
     private Long payoutOperatorUserId;//财务出款人
     private Long applyBy;//出款上报人id
     private String applyAt;//出款申请时间
-    //private String disbursementType;//押品/财务
     private Double plannedAmount;//计划金额
+    private String plannedTime;//计划时间
     private String plannedLocation;//计划地点
+    private String plannedComment;
     private String disbursementStatus;//出款状态
-    private String comments;//说明
-    private String collateralStatus;//押品状态
+    private String disbursementComment;
+    private String confirmComment;//说明
+
 
 
 

+ 35 - 0
src/main/java/com/loan/system/domain/vo/LoanCaseDetails.java

@@ -0,0 +1,35 @@
+package com.loan.system.domain.vo;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+import java.util.Map;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class LoanCaseDetails {
+    private String contractNo;//合同号
+    private String pawnTicketNo;// 当票号
+    private String loanTime;// 借款日期(最后出款时间)
+    private String customerName;// 当户名称
+    private String customerName2;//客户名称2
+    private String phoneNumber;// 联系电话
+    private Double pawnAmount;// 典当金额(万)
+    private List<String> locations;
+    private List<String> attributes;
+    private String channelName;// 业务来源(渠道)
+    private List<String> userName;// 业务员
+    private String repayTime;// 回款日期
+    private Double repayTotalAmount;// 累计回款金额(万)
+    private Double lastRepayAmount;//赎当金额(万元):最后一次还款金额
+    private Double balance;// 典当余额(万)
+    private Double interestAmount;// 费息金额(元)
+    private String redeemTime;// 赎当日期
+    private String redeemTicketNo;// 赎当号码
+    private String comment;// 备注
+
+
+}

+ 4 - 2
src/main/java/com/loan/system/domain/vo/LoanCaseSimpleVO.java

@@ -19,7 +19,9 @@ public class LoanCaseSimpleVO implements Serializable {
     private String channelName;
     private String group;
     private Long recommenderId;
-    private BigDecimal totalLoanAmount;
-    private Boolean isComplete;
+    private Double totalLoanAmount;
+    private String createTime;
+    private String updateTime;
+    private String isComplete;
 
 }

+ 21 - 0
src/main/java/com/loan/system/domain/vo/LoanCaseStatistic.java

@@ -0,0 +1,21 @@
+package com.loan.system.domain.vo;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class LoanCaseStatistic {
+    private Integer weekSeq;//每周序号
+    private String startDate;// 日期(业务开始时间)
+    private String customerName;// 借款人
+    private String businessType;// 业务类型
+    private double amount;// 金额(万)
+    private String stepName;// 业务环节
+    private String userName1;// 主办人员
+    private String userName2;// 辅办人员
+    private String endDate;// 完成时间
+    private String place;// 地点(取微信定位)
+}

+ 8 - 2
src/main/java/com/loan/system/domain/vo/LoanCaseVO.java

@@ -22,19 +22,25 @@ public class LoanCaseVO implements Serializable {
     private Long id;
     private CustomerVO customer;
     //private Long caseId;
+    private String userName;
     private String businessAttrs;//业务属性
     private List<ContractVO> contracts;
     private String address;//房产实际地点
+    private String rejectComment;//驳回意见
     private List<Map<Long,List<Long>>> collateralAndContract;
+    private StepVO step;
+    private Integer category;
+    private List<StepVO> steps;
     private List<CollateralVO> collateral;//押品
     private BizRecommenderVO recommender;//推荐人id
     private String businessType;//业务类型
+    private String channelName;
     private CustomersOtherVO customers1;//其它客户1
     private CustomersOtherVO customers2;//其它客户2
-    private BigDecimal totalLoanAmount;//总借款金额
+    private Double totalLoanAmount;//总借款金额
     private List<DocumentVO> documents;// 文件
     private String currentAddress;// 房产产证地址
-    private Boolean isInvolvedInLitigation;//是否涉及诉讼
     private Boolean IsDelete;
     private String createTime;
+    private String isComplete;
 }

+ 8 - 4
src/main/java/com/loan/system/domain/vo/RepaymentDetailVO.java

@@ -7,6 +7,7 @@ import lombok.NoArgsConstructor;
 
 import java.io.Serializable;
 import java.util.List;
+import java.util.Map;
 
 @Data
 @AllArgsConstructor
@@ -14,14 +15,17 @@ import java.util.List;
 public class RepaymentDetailVO implements Serializable {
     private CustomerVO customer;
     private LoanCaseSimpleVO loanCase;
+    private List<ContractVO> contracts;
     //回款启动
     private List<RepaymentRecordVO> repaymentRecords;//回款记录+审批
+    private Map<Long,Double> contractIdAndCurrentAmount;//目前回款金额
+    //回款映射记录
+
     private Double totalAmount;//业务回款总额
     private Double currentAmount;//目前回款总额
+    private List<String> collateralStatus;//押品状态
+
+
 
-    //财务核算
-    private Double interests;//利息
-    //费息回款
-    private String way;//打包还是正常
 
 }

+ 29 - 0
src/main/java/com/loan/system/domain/vo/RepaymentDetails.java

@@ -0,0 +1,29 @@
+package com.loan.system.domain.vo;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.w3c.dom.stylesheets.LinkStyle;
+
+import java.util.List;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class RepaymentDetails {
+    private String contractNo;//合同号
+    private String pawnTicketNo;// 当票号
+    private String loanTime;// 借款日期
+    private String customerName;// 当户名称
+    private Double pawnAmount;// 典当金额(万)
+    private String repayTime;// 回款日期
+    private Double repayAmount;// 回款金额(万)
+    private Double balance;// 典当余额(万)=典当金额-回款金额
+    private Double interestAmount;// 费息金额(元)
+    private String redeemTicketNo;// 赎当号码
+    private List< String> userName;// 业务员
+    private String recommenderName;// 渠道推荐人
+    private String channelName;// 渠道推荐团队
+    private String comment;// 备注
+
+}

+ 6 - 2
src/main/java/com/loan/system/domain/vo/RepaymentRecordVO.java

@@ -11,6 +11,7 @@ import javax.persistence.Entity;
 import javax.persistence.Table;
 import javax.validation.constraints.Size;
 import java.io.Serializable;
+import java.util.Map;
 
 
 @Data
@@ -19,14 +20,17 @@ import java.io.Serializable;
 public class RepaymentRecordVO implements Serializable {
     private Long id;
     private Long repaymentId;
+    private UserVO planUser;
     private Double amount;
-    private String createTime;
+    private String repayTime;
     private String repayBank;
     private String repayLocation;
     private String repayAccount;
     private String approvalComment;
     private String approvalDecision;
-    private User approvalUser;
+    private UserVO approvalUser;
+    private String repayWay;
+    private Map<Long,Double> contractIdAndAmount;
     private Boolean isInterest;//是否为费息
 
 }

+ 3 - 1
src/main/java/com/loan/system/domain/vo/StepVO.java

@@ -14,12 +14,14 @@ import java.io.Serializable;
 public class StepVO implements Serializable {
 
     private Long id;
+    private Integer code;
     private String stepName;
     private Long caseId;
     private String status;
     private Long userId1;
     private Long userId2;
     private String beginTime;
-    private Long parentId;
+    private Integer parentCode;
+    private String updateTime;
 
 }

+ 1 - 1
src/main/java/com/loan/system/domain/vo/UserLoginVO.java

@@ -16,7 +16,7 @@ public class UserLoginVO implements Serializable {
     private Long id;
     private String openid;
     private String token;
-    private String userName;
+    private String name;
     private String role;
     private Integer is_customer;
 

+ 25 - 1
src/main/java/com/loan/system/exception/GlobalExceptionHandler.java

@@ -1,15 +1,23 @@
 package com.loan.system.exception;
 
+import com.loan.system.context.BaseContext;
+import com.loan.system.domain.entity.ExceptionLog;
 import com.loan.system.domain.enums.ExceptionEnum;
 import com.loan.system.domain.pojo.Result;
+import com.loan.system.service.ExceptionLogService;
 import com.loan.system.utils.ResultUtil;
+import com.loan.system.utils.logUtils.IPUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.ControllerAdvice;
 import org.springframework.web.bind.annotation.ExceptionHandler;
 import org.springframework.web.bind.annotation.ResponseBody;
 
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
 import java.nio.file.AccessDeniedException;
+import java.util.concurrent.CompletableFuture;
 
 /**
  *  统一异常处理
@@ -21,8 +29,24 @@ import java.nio.file.AccessDeniedException;
 public class GlobalExceptionHandler {
     private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
 
+    @Autowired
+    private ExceptionLogService exceptionLogService;
     @ExceptionHandler(value = Exception.class)
-    public Result exceptionGet(Exception e) {
+    public Result exceptionGet(Exception e , HttpServletRequest req) {
+
+        CompletableFuture.runAsync(() -> {
+            ExceptionLog logPo = ExceptionLog.build(
+                    e,
+                    req.getRequestURI(),
+                    req.getMethod(),
+                    IPUtils.getIpAddr(req),
+                    req.getHeader("User-Agent"),
+                    BaseContext.getCurrentId(),
+                    null
+            );
+            exceptionLogService.save(logPo);
+        });
+
         if (e instanceof DescribeException) {
             DescribeException myException = (DescribeException) e;
             logger.error("[ 异常 >> "+e.toString()+" ]");

+ 10 - 0
src/main/java/com/loan/system/interceptor/JwtTokenAdminInterceptor.java

@@ -20,6 +20,7 @@ import org.springframework.web.servlet.HandlerInterceptor;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.util.ArrayList;
+import java.util.Date;
 import java.util.List;
 import java.util.stream.Collectors;
 
@@ -53,11 +54,20 @@ public class JwtTokenAdminInterceptor implements HandlerInterceptor {
             log.info("jwt校验:{}", token);
             Claims claims = JwtUtil.parseJWT(jwtProperties.getAdminSecretKey(), token);
             Long userId = Long.valueOf(claims.get(JwtClaimsConstant.USER_ID).toString());
+            // 验证token是否过期
+            Date expiration = claims.getExpiration();
+            if (expiration != null && expiration.before(new Date())) {
+                response.setStatus(401);
+                log.info("token已过期");
+                return false;
+            }
+
             BaseContext.setCurrentId(userId);
             setSpringSecurityAuthentication(userId);
             //3、通过,放行
             return true;
         } catch (Exception ex) {
+            ex.printStackTrace();
             //4、不通过,响应401状态码
             response.setStatus(401);
             return false;

+ 43 - 19
src/main/java/com/loan/system/interceptor/JwtTokenUserInterceptor.java

@@ -2,8 +2,11 @@ package com.loan.system.interceptor;
 
 import com.loan.system.constant.JwtClaimsConstant;
 import com.loan.system.context.BaseContext;
+import com.loan.system.domain.entity.Customer;
 import com.loan.system.domain.entity.User;
+import com.loan.system.domain.enums.RoleEnum;
 import com.loan.system.properties.JwtProperties;
+import com.loan.system.service.CustomerService;
 import com.loan.system.service.UserService;
 import com.loan.system.utils.JwtUtil;
 import io.jsonwebtoken.Claims;
@@ -14,12 +17,14 @@ import org.springframework.security.core.GrantedAuthority;
 import org.springframework.security.core.authority.SimpleGrantedAuthority;
 import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.stereotype.Component;
+import org.springframework.util.ObjectUtils;
 import org.springframework.web.method.HandlerMethod;
 import org.springframework.web.servlet.HandlerInterceptor;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.util.ArrayList;
+import java.util.Date;
 import java.util.List;
 import java.util.stream.Collectors;
 
@@ -34,6 +39,8 @@ public class JwtTokenUserInterceptor implements HandlerInterceptor {
     private JwtProperties jwtProperties;
     @Autowired
     private UserService userService;
+    @Autowired
+    private CustomerService customerService;
 
     /**
      * 在拦截的请求前校验jwt
@@ -53,13 +60,23 @@ public class JwtTokenUserInterceptor implements HandlerInterceptor {
             log.info("jwt校验:{}", token);
             Claims claims = JwtUtil.parseJWT(jwtProperties.getUserSecretKey(), token);
             Long userId = Long.valueOf(claims.get(JwtClaimsConstant.USER_ID).toString());
+            int isCustomer = Integer.valueOf(claims.get(JwtClaimsConstant.isCustomer).toString());
+            // 验证token是否过期
+            Date expiration = claims.getExpiration();
+            if (expiration != null && expiration.before(new Date())) {
+                response.setStatus(401);
+                log.info("jwt校验失败:{}", token);
+                return false;
+            }
+
             BaseContext.setCurrentId(userId);
-            setSpringSecurityAuthentication(userId);
+            setSpringSecurityAuthentication(userId,isCustomer);
             //3、通过,放行
             return true;
         } catch (Exception ex) {
+            ex.printStackTrace();
             //4、不通过,响应401状态码
-            response.setStatus(404);
+            response.setStatus(401);
             return false;
         }
     }
@@ -67,27 +84,34 @@ public class JwtTokenUserInterceptor implements HandlerInterceptor {
     /**
      * 设置Spring Security认证信息
      */
-    private void setSpringSecurityAuthentication(Long userId) {
+    private void setSpringSecurityAuthentication(Long userId, int isCustomer) {
         try {
-            // 查询用户信息和权限
-            User user = userService.findByIdAndIsDelete(userId);
-            if (user == null) {
-                log.info("用户不存在: {}", userId);
-                return;
-            }else{
-                log.info("用户信息: {}", user.getId());
-            }
+            List<GrantedAuthority> authorities=new ArrayList<>();
+            if (isCustomer==0){
+                // 查询用户信息和权限
+                User user = userService.findByIdAndIsDelete(userId);
+                if(ObjectUtils.isEmpty( user))
+                    return;
+
+                //获取用户角色并转换为Spring Security权限
+                authorities=getUserAuthorities(user);
+                // 创建认证信息
+                UsernamePasswordAuthenticationToken authentication =
+                        new UsernamePasswordAuthenticationToken(user, null, authorities);
+                SecurityContextHolder.getContext().setAuthentication(authentication);
 
-            // 获取用户角色并转换为Spring Security权限
-            List<GrantedAuthority> authorities = getUserAuthorities(user);
+            }else {
+                Customer customer = customerService.findByIdAndIsDelete(userId);
+                if (customer == null)
+                    return;
 
-            // 创建认证信息
-            UsernamePasswordAuthenticationToken authentication =
-                    new UsernamePasswordAuthenticationToken(user, null, authorities);
-            SecurityContextHolder.getContext().setAuthentication(authentication);
+                authorities.add(new SimpleGrantedAuthority(RoleEnum.EXTERNAL.getMsg()));
+                // 创建认证信息
+                UsernamePasswordAuthenticationToken authentication =
+                        new UsernamePasswordAuthenticationToken(customer, null, authorities);
+                SecurityContextHolder.getContext().setAuthentication(authentication);
+            }
 
-            log.info("Spring Security认证设置完成 - 用户: {}, 角色: {}",
-                    user.getUsername(), authorities);
         } catch (Exception e) {
             log.info("设置Spring Security认证信息失败: {}", e.getMessage());
         }

+ 18 - 2
src/main/java/com/loan/system/repository/ApproveRecordRepository.java

@@ -2,6 +2,7 @@ package com.loan.system.repository;
 
 import com.loan.system.domain.entity.ApprovalRecord;
 import com.loan.system.domain.entity.Contract;
+import com.loan.system.domain.vo.ApprovalRecordVO;
 import org.springframework.data.jpa.repository.JpaRepository;
 import org.springframework.data.jpa.repository.Modifying;
 import org.springframework.data.jpa.repository.Query;
@@ -15,13 +16,28 @@ import java.util.List;
  * @Description
  */
 public interface ApproveRecordRepository extends JpaRepository<ApprovalRecord,Long> {
-    List<ApprovalRecord> findByCaseIdAndIsDelete(Long id, Boolean isDelete);
+    @Query(value = "SELECT c FROM ApprovalRecord c WHERE c.caseId = ?1 and c.stepName = ?2 and c.isDelete = ?3 ORDER BY c.createTime DESC")
+    List<ApprovalRecord> findByCaseIdAndStepNameAndIsDelete(Long id, String stepName,Boolean isDelete);
 
-    ApprovalRecord findByCaseIdAndIsDeleteAndStepNameAndApproverId(Long caseId, Boolean isDelete, String stepName,Long approverId);
+    List<ApprovalRecord> findByCaseIdAndIsDeleteAndStepNameAndApproverId(Long caseId, Boolean isDelete, String stepName,Long approverId);
 
     @Modifying
     @Transactional
     @Query(value = "UPDATE approval_record SET decision = ?1, update_time = ?5, comments = ?6 WHERE case_id = ?2 AND step_name = ?3 AND is_delete = ?4 AND approver_id = ?7", nativeQuery = true)
     void updateDecisionByCaseIdAndStepNameAndIsDeleteAndApproverId(String decision, Long caseId, String stepName, Boolean isDelete,String updateTime,String  comments, Long approverId);
 
+    @Query(value = "SELECT c FROM ApprovalRecord c WHERE c.id = ?1 and c.isDelete = ?2")
+    ApprovalRecord findRecordById(Long approvalRecordId,Boolean isDelete);
+
+    @Transactional
+    @Modifying
+    @Query(value = "update ApprovalRecord a set " +
+            "a.comments = CASE WHEN :#{#approvalRecord.comments} IS NOT NULL THEN :#{#approvalRecord.comments} ELSE a.comments END, " +
+            "a.decision = CASE WHEN :#{#approvalRecord.decision} IS NOT NULL THEN :#{#approvalRecord.decision} ELSE a.decision END, " +
+            "a.updateTime = CASE WHEN :#{#approvalRecord.updateTime} IS NOT NULL THEN :#{#approvalRecord.updateTime} ELSE a.updateTime END " +
+            "where a.id = :recordId and a.isDelete = :isDelete")
+    void updateRecordByIdAndIsDelete(ApprovalRecord approvalRecord, Long recordId, boolean isDelete);
+
+    @Query(value = "SELECT c FROM ApprovalRecord c WHERE c.caseId = ?2 and c.stepName = ?1 and c.isDelete = ?3")
+    List<ApprovalRecord> findByCaseIdAndStepNameAndIsDelete(String stepName, Long caseId, boolean isDelete);
 }

+ 24 - 12
src/main/java/com/loan/system/repository/CollateralPlanRepository.java

@@ -7,18 +7,16 @@ import org.springframework.data.jpa.repository.Modifying;
 import org.springframework.data.jpa.repository.Query;
 import org.springframework.transaction.annotation.Transactional;
 
+import javax.persistence.Column;
 import java.util.List;
 
 public interface CollateralPlanRepository extends JpaRepository<CollateralPlan,Long> {
 
-    @Query("select c from CollateralPlan c where c.collateralId = ?1 and c.isDelete = ?2 and c.status='待审批'")
-    CollateralPlan findByCollateralIdAndIsDelete(Long collateralId, boolean isDelete);
-
     @Query("select c from CollateralPlan c where c.id = ?1 and c.isDelete = ?2")
     CollateralPlan findByIdAndIsDelete(Long id, Boolean isDelete);
 
-    @Query("select c from CollateralPlan c where c.collateralId = ?1 and c.isDelete = ?2")
-    List<CollateralPlan> findsByCollateralIdAndIsDelete(Long collateralId, boolean isDelete);
+//    @Query("select c from CollateralPlan c where c.collateralId = ?1 and c.isDelete = ?2")
+//    List<CollateralPlan> findsByCollateralIdAndIsDelete(Long collateralId, boolean isDelete);
 
     @Query("select c from CollateralPlan c where c.caseId = ?1 and c.isDelete = ?2")
     List<CollateralPlan> findByCaseIdAndIsDelete(Long caseId, boolean isDelete);
@@ -28,11 +26,6 @@ public interface CollateralPlanRepository extends JpaRepository<CollateralPlan,L
     @Query("update CollateralPlan c set c.isDelete = true where c.id = ?1")
     void logic_delete(Long id);
 
-    @Modifying
-    @Transactional
-    @Query("update CollateralPlan c set c.userId = ?2 , c.updateTime=CURRENT_TIMESTAMP where c.collateralId = ?1")
-    void updateCollateralUserIdeByid(Long collateralId, Long userId);
-
     @Modifying
     @Transactional
     @Query("update CollateralPlan c set c.status = ?2 , c.updateTime=CURRENT_TIMESTAMP where c.id = ?1")
@@ -40,7 +33,26 @@ public interface CollateralPlanRepository extends JpaRepository<CollateralPlan,L
 
     @Modifying
     @Transactional
-    @Query("update CollateralPlan c set c.operatorId = ?2 , c.operatorName = ?3 , c.updateTime=CURRENT_TIMESTAMP where c.id = ?1")
-    void updateCollateraloperatorIdByid(Long collateralId, Long operatorId,String operatorName);
+    @Query("update CollateralPlan c set " +
+            "c.collateralIds = CASE WHEN :#{#collateralPlan.collateralIds} IS NOT NULL THEN :#{#collateralPlan.collateralIds} ELSE c.collateralIds END, " +
+            "c.time = CASE WHEN :#{#collateralPlan.time} IS NOT NULL THEN :#{#collateralPlan.time} ELSE c.time END, " +
+            "c.flag = CASE WHEN :#{#collateralPlan.flag} IS NOT NULL THEN :#{#collateralPlan.flag} ELSE c.flag END, " +
+            "c.comments = CASE WHEN :#{#collateralPlan.comments} IS NOT NULL THEN :#{#collateralPlan.comments} ELSE c.comments END, " +
+            "c.status = CASE WHEN :#{#collateralPlan.status} IS NOT NULL THEN :#{#collateralPlan.status} ELSE c.status END " +
+            "where c.id = :planId")
+    void updatePlanById(CollateralPlan collateralPlan, Long planId);
 
+    @Transactional
+    @Modifying
+    @Query("update CollateralPlan c set c.approvalRecordId = ?1 , c.operatorId = ?2 where c.id = ?3")
+    void updateApprovalRecordAndOperatorById(Long recordId,Long  operatorId, Long id);
+
+    @Query("select c from CollateralPlan c where c.caseId = ?1 and c.flag = ?2 and c.isDelete = ?3")
+    List<CollateralPlan> findByCaseIdAndFlagAndIsDelete(Long caseId, String flag, boolean b);
+
+    @Modifying
+    @Transactional
+    @Query("update CollateralPlan c set c.operatorId = ?1 , c.operatorComments = ?2 where c.id = ?3")
+    void updateOperatorIdAndCommentsById(Long userId, String comments, Long id);
 }
+

+ 15 - 3
src/main/java/com/loan/system/repository/CollateralRepository.java

@@ -6,6 +6,7 @@ import org.springframework.data.jpa.repository.Modifying;
 import org.springframework.data.jpa.repository.Query;
 import org.springframework.transaction.annotation.Transactional;
 
+import java.util.Collection;
 import java.util.List;
 
 /**
@@ -32,8 +33,8 @@ public interface CollateralRepository extends JpaRepository<Collateral,Long> {
             "c.isInvolvedInLitigation = CASE WHEN :#{#collateral.isInvolvedInLitigation} IS NOT NULL THEN :#{#collateral.isInvolvedInLitigation} ELSE c.isInvolvedInLitigation END, " +
             "c.staus = CASE WHEN :#{#collateral.staus} IS NOT NULL THEN :#{#collateral.staus} ELSE c.staus END, " +
             "c.updateTime = CASE WHEN :#{#collateral.updateTime} IS NOT NULL THEN :#{#collateral.updateTime} ELSE c.updateTime END, " +
-            "c.isDelete = CASE WHEN :isDelete IS NOT NULL THEN :isDelete ELSE c.isDelete END " +
-            "WHERE c.id = :id and c.isDelete = false")
+            "c.isDelete = :isDelete " +
+            "WHERE c.id = :id ")
     void updateCollateralById(Long id, Collateral collateral, boolean isDelete);
 
     @Query("SELECT c FROM Collateral c WHERE c.collateralName = ?1 AND c.caseId = ?2 AND c.isDelete = ?3")
@@ -41,7 +42,7 @@ public interface CollateralRepository extends JpaRepository<Collateral,Long> {
 
     @Transactional
     @Modifying
-    @Query("delete FROM Collateral c WHERE c.caseId = ?1")
+    @Query("update Collateral c set c.isDelete = true WHERE c.caseId = ?1")
     void deleteAllByCaseId(Long caseId);
 
     //逻辑删除
@@ -57,4 +58,15 @@ public interface CollateralRepository extends JpaRepository<Collateral,Long> {
 
     @Query("SELECT c FROM Collateral c WHERE c.id = ?1 And c.isDelete = false")
     Collateral findCollateralById(Long id);
+
+    @Query("SELECT c FROM Collateral c WHERE c.id IN ?1 And c.isDelete = ?2")
+    List<Collateral> findByIdsAndIsDelete(List<Long> collateralIds, boolean isDelete);
+
+    @Modifying
+    @Transactional
+    @Query("UPDATE Collateral c SET c.staus = ?2 ,c.updateTime = CURRENT_TIMESTAMP  WHERE c.id in ?1 And c.isDelete= false ")
+    void updateCollateralStatusByIds(List<Long> ids, String status);
+
+    @Query("SELECT c FROM Collateral c WHERE c.id = ?1 AND c.caseId = ?2 AND c.isDelete = ?3")
+    Collateral findCollateralByIdAndCaseIdAndIsDelete(Long id, Long caseId, boolean b);
 }

+ 2 - 0
src/main/java/com/loan/system/repository/ContractAndCollateralRepository.java

@@ -22,4 +22,6 @@ public interface ContractAndCollateralRepository extends JpaRepository<ContractA
     void deleteAllByCaseId(Long caseId);
 
     List<ContractAndCollateral> findByCaseIdAndIsDelete(Long caseId, Boolean isDelete);
+
+    List<ContractAndCollateral> findByContractIdAndIsDelete(Long contractId, boolean b);
 }

+ 35 - 0
src/main/java/com/loan/system/repository/ContractRepaymentRepository.java

@@ -0,0 +1,35 @@
+package com.loan.system.repository;
+
+import com.loan.system.domain.entity.ApprovalRecord;
+import com.loan.system.domain.entity.ContractRepayment;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+/**
+ * @author EdwinXu
+ * @date 2020/9/2 - 15:35
+ * @Description
+ */
+public interface ContractRepaymentRepository extends JpaRepository<ContractRepayment,Long> {
+
+    @Query("select c.id from ContractRepayment c where c.repaymentRecordId = ?1 and c.isDelete = ?2")
+    List<Long> findByRepaymentRecordIdAndIsDelete(Long recordId, boolean b);
+
+    @Modifying
+    @Transactional
+    @Query("update ContractRepayment c set c.isDelete = true where c.id in ?1")
+    void deleteByIds(List<Long> ids);
+
+    @Query("select c from ContractRepayment c where c.repaymentRecordId in ?1 and c.isDelete = ?2")
+    List<ContractRepayment> findByRepaymentRecordIdsAndIsDelete(List<Long> recordIds, boolean b);
+
+    @Query("select c from ContractRepayment c where c.contractId = ?1 and c.isDelete = ?2")
+    List<ContractRepayment> findByContractIdAndIsDelete(Long id, boolean b);
+
+    @Query("select c from ContractRepayment c where c.repaymentRecordId = ?1 and c.isDelete = ?2")
+    List<ContractRepayment> findDataByRepaymentRecordIdAndIsDelete(Long recordId, boolean b);
+}

+ 30 - 4
src/main/java/com/loan/system/repository/ContractRepository.java

@@ -2,6 +2,7 @@ package com.loan.system.repository;
 
 import com.loan.system.domain.entity.Contract;
 import com.loan.system.domain.vo.ContractVO;
+import io.swagger.models.Contact;
 import org.springframework.data.jpa.repository.JpaRepository;
 import org.springframework.data.jpa.repository.Modifying;
 import org.springframework.data.jpa.repository.Query;
@@ -36,11 +37,11 @@ public interface ContractRepository extends JpaRepository<Contract,Long> {
             "c.loanPeriod = CASE WHEN :#{#contract.loanPeriod} IS NOT NULL THEN :#{#contract.loanPeriod} ELSE c.loanPeriod END, " +
             "c.content = CASE WHEN :#{#contract.content} IS NOT NULL THEN :#{#contract.content} ELSE c.content END, " +
             "c.signedByCustomer = CASE WHEN :#{#contract.signedByCustomer} IS NOT NULL THEN :#{#contract.signedByCustomer} ELSE c.signedByCustomer END, " +
-            "c.sifnedId = CASE WHEN :#{#contract.sifnedId} IS NOT NULL THEN :#{#contract.sifnedId} ELSE c.sifnedId END, " +
+            "c.signedId = CASE WHEN :#{#contract.signedId} IS NOT NULL THEN :#{#contract.signedId} ELSE c.signedId END, " +
             "c.signedTime = CASE WHEN :#{#contract.signedTime} IS NOT NULL THEN :#{#contract.signedTime} ELSE c.signedTime END, " +
             "c.updateTime = CASE WHEN :#{#contract.updateTime} IS NOT NULL THEN :#{#contract.updateTime} ELSE c.updateTime END, " +
-            "c.isDelete = CASE WHEN :isDelete IS NOT NULL THEN :isDelete ELSE c.isDelete END " +
-            "WHERE c.id = :id and c.isDelete = :isDelete")
+            "c.isDelete = :isDelete  " +
+            "WHERE c.id = :id ")
     void updateContractById(Long id, Contract contract, boolean isDelete);
 
     List<Contract> findByCaseIdAndIsDelete(Long caseId, boolean isDelete);
@@ -55,7 +56,7 @@ public interface ContractRepository extends JpaRepository<Contract,Long> {
 
     @Transactional
     @Modifying
-    @Query("delete FROM Contract c WHERE c.caseId = ?1")
+    @Query("update Contract c set c.isDelete= true WHERE c.caseId = ?1")
     void deleteAllByCaseId(Long caseID);
 
     @Transactional
@@ -65,4 +66,29 @@ public interface ContractRepository extends JpaRepository<Contract,Long> {
 
     @Query("SELECT c FROM Contract c WHERE c.id = ?1")
     Contract findContractById(Long contractId);
+
+    @Transactional
+    @Modifying
+    @Query("UPDATE Contract c SET c.signedByCustomer = false WHERE c.id = ?1")
+    void updateSignedCustomerById(Long contractId);
+
+    @Transactional
+    @Modifying
+    @Query("UPDATE Contract c set c.signedId = null  WHERE c.signedId = ?1")
+    void deleteSigned(Long signedId);
+
+    @Transactional
+    @Modifying
+    @Query("UPDATE Contract c SET " +
+            "c.isCleared = CASE WHEN :isCleared IS NOT NULL THEN :isCleared ELSE c.isCleared END," +
+            "c.interestAmount = CASE WHEN :interest IS NOT NULL THEN :interest ELSE c.interestAmount END," +
+            "c.financeUserId = CASE WHEN :currentId IS NOT NULL THEN :currentId ELSE c.financeUserId END" +
+            " where c.id= :contractId and c.isDelete =:isDelete")
+    void updateRepayById(boolean isCleared,  Double interest, Long currentId, Long contractId, boolean isDelete);
+
+    @Query("SELECT c.interestAmount FROM Contract c WHERE c.caseId = ?1 AND c.isDelete = ?2")
+    List<Double> findIntersetByCaseIdAndIsDelete(Long caseId, boolean b);
+
+    @Query("select c from Contract  c where c.caseId= ?1 and c.isDelete = ?2")
+    List<Contract> findByCaseIdAndIsDelete2(Long caseId, boolean b);
 }

+ 3 - 2
src/main/java/com/loan/system/repository/CustomerOtherRepository.java

@@ -27,7 +27,8 @@ public interface CustomerOtherRepository extends JpaRepository<CustomersOther,Lo
     @Query("UPDATE CustomersOther c SET " +
            "c.name = CASE WHEN :#{#customersOtherDTO.name} IS NOT NULL THEN :#{#customersOtherDTO.name} ELSE c.name END, " +
            "c.idNumber = CASE WHEN :#{#customersOtherDTO.idNumber} IS NOT NULL THEN :#{#customersOtherDTO.idNumber} ELSE c.idNumber END, " +
-           "c.mobile = CASE WHEN :#{#customersOtherDTO.mobile} IS NOT NULL THEN :#{#customersOtherDTO.mobile} ELSE c.mobile END " +
+           "c.mobile = CASE WHEN :#{#customersOtherDTO.mobile} IS NOT NULL THEN :#{#customersOtherDTO.mobile} ELSE c.mobile END," +
+            "c.isDelete = false " +
            "WHERE c.id = :id")
     void updateCustomerById(@Param("customersOtherDTO") CustomersOtherDTO customersOtherDTO, @Param("id") Long id);
 
@@ -38,6 +39,6 @@ public interface CustomerOtherRepository extends JpaRepository<CustomersOther,Lo
 
     @Transactional
     @Modifying
-    @Query("DELETE FROM CustomersOther c WHERE c.caseId = ?1")
+    @Query("update CustomersOther c set c.isDelete = true WHERE c.caseId = ?1")
     void deleteAllByCaseId(Long caseId);
 }

+ 31 - 2
src/main/java/com/loan/system/repository/CustomerRepository.java

@@ -1,6 +1,8 @@
 package com.loan.system.repository;
 
+import com.loan.system.domain.dto.CustomerDTO;
 import com.loan.system.domain.entity.Customer;
+import com.loan.system.domain.entity.User;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.Pageable;
 import org.springframework.data.jpa.repository.JpaRepository;
@@ -30,11 +32,38 @@ public interface CustomerRepository extends JpaRepository<Customer,Long> {
 
     @Transactional
     @Modifying
-    @Query("update Customer c set c.marriedStatus = ?2 where c.id = ?1")
-    void updateMarriedStatusById(Long customerId, String marriedStatus);
+    @Query("update Customer c set c.marriedStatus = ?2 ,c.isIllegal = ?3 where c.id = ?1")
+    void updateMarriedStatusAndIsIllegalById(Long customerId, String marriedStatus,Boolean isIllegal);
 
     @Query("select co from Customer co where co.id = ?1 and co.isDelete = ?2")
     Customer findByCustomerId(Long customerId , Boolean isDelete);
 
     boolean existsByIdAndIsDelete(Long customerId, boolean isDelete);
+
+    @Query("select co from Customer co where (co.mobile like ?1 or co.name like ?1) and co.isDelete = ?2")
+    List<Customer> findAllByKey(String key, boolean isDelete);
+
+    @Transactional
+    @Modifying
+    @Query("update Customer c set c.isDelete = 1 where c.mobile = ?1 and c.name = ?2")
+    void deleteByMobileAndName(String mobile, String name);
+
+    @Transactional
+    @Modifying
+    @Query(value = "UPDATE Customer c SET " +
+            "c.name = COALESCE(:#{#customerDTO.name}, c.name), " +
+            "c.sex = COALESCE(:#{#customerDTO.sex}, c.sex), " +
+            "c.idNumber = COALESCE(:#{#customerDTO.idNumber}, c.idNumber), " +
+            "c.bankAccount = COALESCE(:#{#customerDTO.bankAccount}, c.bankAccount), " +
+            "c.bankName = COALESCE(:#{#customerDTO.bankName}, c.bankName) " +
+            "WHERE c.openid = :#{#customerDTO.openid} AND c.isDelete = :isDelete")
+    void updateInfoByOpenIdAndIsDelete(CustomerDTO customerDTO, boolean isDelete);
+
+    @Transactional
+    @Modifying
+    @Query("update Customer c set c.isDelete = 1 where c.id = ?1")
+    void deleteByLogic(Long id);
+
+    @Query("select c from Customer c where c.openid = ?1")
+    Customer findByOpenId(String openId);
 }

+ 15 - 0
src/main/java/com/loan/system/repository/DictBusinessTypeRepository.java

@@ -0,0 +1,15 @@
+package com.loan.system.repository;
+
+import com.loan.system.domain.entity.DictBusinessType;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import java.util.List;
+
+/**
+ * @author EdwinXu
+ * @date 2020/9/2 - 15:35
+ * @Description
+ */
+public interface DictBusinessTypeRepository extends JpaRepository<DictBusinessType,Long> {
+    List<DictBusinessType> findByIsDelete(Boolean isDelete);
+}

+ 34 - 0
src/main/java/com/loan/system/repository/DictDataRepository.java

@@ -0,0 +1,34 @@
+package com.loan.system.repository;
+
+import com.loan.system.domain.dto.DictDataDTO;
+import com.loan.system.domain.entity.ApprovalRecord;
+import com.loan.system.domain.entity.DictData;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+/**
+ * @author EdwinXu
+ * @date 2020/9/2 - 15:35
+ * @Description
+ */
+public interface DictDataRepository extends JpaRepository<DictData,Long> {
+
+    List<DictData> findByStatus(Boolean status);
+
+    @Modifying
+    @Transactional
+    @Query("update DictData  d set " +
+            "d.dictLabel = CASE WHEN :#{#dataDTO.dictLabel} IS NOT NULL THEN :#{#dataDTO.dictLabel} ELSE d.dictLabel END," +
+            "d.dictSort = CASE WHEN :#{#dataDTO.dictSort} IS NOT NULL THEN :#{#dataDTO.dictSort} ELSE d.dictSort END," +
+            "d.dictValue = CASE WHEN :#{#dataDTO.dictValue} IS NOT NULL THEN :#{#dataDTO.dictValue} ELSE d.dictValue END," +
+            "d.dictType = CASE WHEN :#{#dataDTO.dictType} IS NOT NULL THEN :#{#dataDTO.dictType} ELSE d.dictType END," +
+            "d.status = CASE WHEN :#{#dataDTO.status} IS NOT NULL THEN :#{#dataDTO.status} ELSE d.status END," +
+            "d.isDefault = CASE WHEN :#{#dataDTO.isDefault} IS NOT NULL THEN :#{#dataDTO.isDefault} ELSE d.isDefault END," +
+            "d.updateTime = :updateTime" +
+            " where d.id = :id")
+    void updateById(DictDataDTO dataDTO, Long id,String updateTime);
+}

+ 0 - 1
src/main/java/com/loan/system/repository/DictStepRepository.java

@@ -1,7 +1,6 @@
 package com.loan.system.repository;
 
 import com.loan.system.domain.entity.DictStep;
-import com.loan.system.domain.entity.DictType;
 import org.springframework.data.jpa.repository.JpaRepository;
 
 import java.util.List;

+ 16 - 5
src/main/java/com/loan/system/repository/DictTypeRepository.java

@@ -1,9 +1,11 @@
 package com.loan.system.repository;
 
-import com.loan.system.domain.entity.DictAttribute;
-import com.loan.system.domain.entity.DictBusinessType;
+import com.loan.system.domain.dto.DictTypeDTO;
 import com.loan.system.domain.entity.DictType;
 import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.transaction.annotation.Transactional;
 
 import java.util.List;
 
@@ -12,6 +14,15 @@ import java.util.List;
  * @date 2020/9/2 - 15:35
  * @Description
  */
-public interface DictTypeRepository extends JpaRepository<DictBusinessType,Long> {
-    List<DictBusinessType> findByIsDelete(Boolean isDelete);
-}
+public interface DictTypeRepository extends JpaRepository<DictType,Long> {
+
+    @Modifying
+    @Transactional
+    @Query("update DictType  d set " +
+            "d.dictName = CASE WHEN :#{#dictTypeDTO.dictName} IS NOT NULL THEN :#{#dictTypeDTO.dictName} ELSE d.dictName END," +
+            "d.dictType = CASE WHEN :#{#dictTypeDTO.dictType} IS NOT NULL THEN :#{#dictTypeDTO.dictType} ELSE d.dictType END," +
+            "d.status = CASE WHEN :#{#dictTypeDTO.status} IS NOT NULL THEN :#{#dictTypeDTO.status} ELSE d.status END," +
+            "d.updateTime = :format" +
+            " where d.id = :id")
+    void updateDictById(DictTypeDTO dictTypeDTO, Long id, String format);
+}

+ 23 - 1
src/main/java/com/loan/system/repository/DisbursementRepository.java

@@ -1,5 +1,6 @@
 package com.loan.system.repository;
 
+import com.loan.system.domain.dto.DisbursementDTO;
 import com.loan.system.domain.entity.Collateral;
 import com.loan.system.domain.entity.Disbursement;
 import org.springframework.data.jpa.repository.JpaRepository;
@@ -34,6 +35,27 @@ public interface DisbursementRepository extends JpaRepository<Disbursement,Long>
 
     @Transactional
     @Modifying
-    @Query("update Disbursement d set d.comments = ?1 where d.id = ?2")
+    @Query("update Disbursement d set d.confirmComment = ?1 where d.id = ?2")
     void updateCommentsById(String comments, Long id);
+
+    @Transactional
+    @Modifying
+    @Query("update Disbursement d set  d.disbursementStatus = ?1 where d.caseId = ?2")
+    void updateStatusByCaseId(String status,Long caseId);
+
+    boolean existsDisbursementByCaseIdAndIsDelete(Long caseId, boolean isDelete);
+
+    @Transactional
+    @Modifying
+    @Query(value = "UPDATE Disbursement d SET " +
+            "d.plannedAmount = COALESCE(:#{#disbursementDTO.plannedAmount}, d.plannedAmount), " +
+            "d.plannedLocation = COALESCE(:#{#disbursementDTO.plannedLocation}, d.plannedLocation), " +
+            "d.plannedTime = COALESCE(:#{#disbursementDTO.plannedTime}, d.plannedTime) " +
+            "WHERE d.caseId = :#{#disbursementDTO.caseId}")
+    void updateDisbursementByCaseId(DisbursementDTO disbursementDTO);
+
+    @Transactional
+    @Modifying
+    @Query("update Disbursement d set d.disbursementComment = ?1 where d.caseId = ?2")
+    void updateDisbursementCommentsByCaseId(String comment, Long caseId);
 }

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác