contract-lifecycle-part1.md 9.1 KB

签约功能生命周期详解 - 第一部分

1. 控制器层 (Controller)

1.1 合同创建接口

接口定义ContractController.createContract()

@PostMapping("/create")
@PreAuthorize("hasRole('ENTERPRISE')")
public ApiResult<ContractCreateResponse> createContract(@RequestBody @Validated ContractCreateRequest request) {
    return contractService.createContract(request);
}

功能职责

  • 接收合同创建请求
  • 参数校验
  • 权限校验(仅企业用户可创建合同)
  • 调用服务层处理合同创建逻辑
  • 返回统一格式的创建结果

请求参数(ContractCreateRequest)

{
  "contractName": "供应链采购合同",
  "contractType": "PURCHASE",
  "partyA": {
    "enterpriseId": "ENT10001",
    "enterpriseName": "核心企业有限公司"
  },
  "partyB": {
    "enterpriseId": "ENT10002",
    "enterpriseName": "供应商有限公司"
  },
  "contractAmount": 500000.00,
  "contractPeriod": 180,
  "startDate": "2023-09-01",
  "endDate": "2024-02-28",
  "description": "关于设备采购的合同"
}

响应结果(ContractCreateResponse)

{
  "code": 200,
  "message": "合同创建成功",
  "data": {
    "contractId": "CON20230815001",
    "contractName": "供应链采购合同",
    "contractStatus": "DRAFT",
    "createTime": "2023-08-15T14:30:45Z",
    "downloadUrl": "/api/v1/contract/download/CON20230815001"
  }
}

1.2 合同提交签署接口

接口定义ContractController.submitForSigning()

@PostMapping("/{contractId}/submit")
@PreAuthorize("hasRole('ENTERPRISE')")
public ApiResult<ContractSubmitResponse> submitForSigning(@PathVariable String contractId) {
    return contractService.submitForSigning(contractId);
}

功能职责

  • 接收合同提交签署请求
  • 参数校验(合同ID)
  • 权限校验
  • 调用服务层处理合同提交签署逻辑
  • 返回统一格式的处理结果

响应结果(ContractSubmitResponse)

{
  "code": 200,
  "message": "合同已提交签署",
  "data": {
    "contractId": "CON20230815001",
    "contractStatus": "PENDING_SIGNING",
    "submitTime": "2023-08-15T15:30:45Z",
    "signingUrl": "/api/v1/contract/sign/CON20230815001"
  }
}

1.3 合同签署接口

接口定义ContractController.signContract()

@PostMapping("/{contractId}/sign")
@PreAuthorize("hasAnyRole('ENTERPRISE')")
public ApiResult<ContractSignResponse> signContract(
        @PathVariable String contractId,
        @RequestBody @Validated ContractSignRequest request) {
    return contractService.signContract(contractId, request);
}

功能职责

  • 接收合同签署请求
  • 参数校验
  • 权限校验
  • 调用服务层处理合同签署逻辑
  • 返回统一格式的签署结果

请求参数(ContractSignRequest)

{
  "signerName": "张三",
  "signerPosition": "法定代表人",
  "signMethod": "DIGITAL_SIGNATURE",
  "verificationCode": "123456"
}

响应结果(ContractSignResponse)

{
  "code": 200,
  "message": "合同签署成功",
  "data": {
    "contractId": "CON20230815001",
    "contractStatus": "SIGNED",
    "signTime": "2023-08-15T16:30:45Z",
    "signedUrl": "/api/v1/contract/download/signed/CON20230815001"
  }
}

1.4 合同查询接口

接口定义ContractController.getContractDetails()

@GetMapping("/{contractId}")
@PreAuthorize("hasAnyRole('ENTERPRISE', 'BANK')")
public ApiResult<ContractDetailResponse> getContractDetails(@PathVariable String contractId) {
    return contractService.getContractDetails(contractId);
}

功能职责

  • 接收合同查询请求
  • 参数校验(合同ID)
  • 权限校验
  • 调用服务层处理合同查询逻辑
  • 返回统一格式的合同详情

响应结果(ContractDetailResponse)

{
  "code": 200,
  "message": "获取成功",
  "data": {
    "contractId": "CON20230815001",
    "contractName": "供应链采购合同",
    "contractType": "PURCHASE",
    "contractStatus": "SIGNED",
    "contractAmount": 500000.00,
    "partyA": {
      "enterpriseId": "ENT10001",
      "enterpriseName": "核心企业有限公司",
      "legalPerson": "张三",
      "signed": true,
      "signTime": "2023-08-15T16:30:45Z"
    },
    "partyB": {
      "enterpriseId": "ENT10002",
      "enterpriseName": "供应商有限公司",
      "legalPerson": "李四",
      "signed": true,
      "signTime": "2023-08-15T17:10:30Z"
    },
    "contractPeriod": 180,
    "startDate": "2023-09-01",
    "endDate": "2024-02-28",
    "createTime": "2023-08-15T14:30:45Z",
    "updateTime": "2023-08-15T17:10:30Z",
    "contractFileId": "FILE20230815001",
    "downloadUrl": "/api/v1/contract/download/signed/CON20230815001"
  }
}

1.5 合同列表查询接口

接口定义ContractController.listContracts()

@GetMapping("/list")
@PreAuthorize("hasAnyRole('ENTERPRISE', 'BANK')")
public ApiResult<PageResult<ContractListItemResponse>> listContracts(
        @RequestParam(required = false) String contractName,
        @RequestParam(required = false) ContractStatus status,
        @RequestParam(required = false) ContractType type,
        @RequestParam(defaultValue = "1") Integer pageNum,
        @RequestParam(defaultValue = "10") Integer pageSize) {
    ContractQueryParam param = new ContractQueryParam();
    param.setContractName(contractName);
    param.setStatus(status);
    param.setType(type);
    param.setPageNum(pageNum);
    param.setPageSize(pageSize);
    return contractService.listContracts(param);
}

2. 服务层 (Service)

2.1 合同服务

主要实现类ContractServiceImpl

2.1.1 创建合同流程 createContract()

@Override
@Transactional(rollbackFor = Exception.class)
public ApiResult<ContractCreateResponse> createContract(ContractCreateRequest request) {
    log.info("开始创建合同, 合同名称: {}", request.getContractName());
    
    // 1. 校验企业是否存在
    if (!enterpriseService.checkEnterpriseExists(request.getPartyA().getEnterpriseId())) {
        return ApiResult.failed("甲方企业不存在");
    }
    
    if (!enterpriseService.checkEnterpriseExists(request.getPartyB().getEnterpriseId())) {
        return ApiResult.failed("乙方企业不存在");
    }
    
    // 2. 检查用户是否有权限创建合同(是否属于甲方企业)
    String currentUserId = securityService.getCurrentUserId();
    if (!enterpriseService.isUserBelongToEnterprise(currentUserId, request.getPartyA().getEnterpriseId())) {
        return ApiResult.forbidden("您没有权限为该企业创建合同");
    }
    
    // 3. 生成合同ID
    String contractId = contractIdGenerator.generate();
    
    // 4. 构建合同对象
    Contract contract = new Contract();
    contract.setContractId(contractId);
    contract.setContractName(request.getContractName());
    contract.setContractType(request.getContractType());
    contract.setPartyAId(request.getPartyA().getEnterpriseId());
    contract.setPartyAName(request.getPartyA().getEnterpriseName());
    contract.setPartyBId(request.getPartyB().getEnterpriseId());
    contract.setPartyBName(request.getPartyB().getEnterpriseName());
    contract.setContractAmount(request.getContractAmount());
    contract.setContractPeriod(request.getContractPeriod());
    contract.setStartDate(DateUtil.parseDate(request.getStartDate()));
    contract.setEndDate(DateUtil.parseDate(request.getEndDate()));
    contract.setDescription(request.getDescription());
    contract.setContractStatus(ContractStatus.DRAFT);
    contract.setCreateUser(currentUserId);
    contract.setCreateTime(new Date());
    
    // 5. 保存合同基本信息
    contractMapper.insert(contract);
    
    // 6. 生成合同模板文件
    String contractFileId = contractFileService.generateContractFile(contract);
    
    // 7. 更新合同文件ID
    contract.setContractFileId(contractFileId);
    contractMapper.updateContractFile(contractId, contractFileId);
    
    // 8. 记录合同创建日志
    contractLogService.logContractOperation(
            contractId,
            ContractOperationType.CREATE,
            "创建合同",
            currentUserId);
    
    // 9. 构建返回结果
    ContractCreateResponse response = new ContractCreateResponse();
    response.setContractId(contractId);
    response.setContractName(request.getContractName());
    response.setContractStatus(ContractStatus.DRAFT);
    response.setCreateTime(contract.getCreateTime());
    response.setDownloadUrl("/api/v1/contract/download/" + contractId);
    
    log.info("合同创建成功, 合同ID: {}", contractId);
    return ApiResult.success("合同创建成功", response);
}

处理逻辑

  1. 校验企业是否存在
  2. 检查用户是否有权限创建合同
  3. 生成合同ID
  4. 构建合同对象
  5. 保存合同基本信息
  6. 生成合同模板文件
  7. 更新合同文件ID
  8. 记录合同创建日志
  9. 构建返回结果