| | |
| | | import com.ruoyi.user.domain.AccountCertification; |
| | | import com.ruoyi.user.domain.AccountCertificationApply; |
| | | import com.ruoyi.user.domain.AccountUser; |
| | | import com.ruoyi.user.domain.dto.CompanyCertificationApplyDto; |
| | | import com.ruoyi.user.domain.vo.AccountCertificationApplyDetailVo; |
| | | import com.ruoyi.user.domain.vo.AccountCertificationApplyVo; |
| | | import com.ruoyi.user.domain.vo.AccountCertificationStatusVo; |
| | | import com.ruoyi.user.domain.vo.CompanyCertificationStatusVo; |
| | | import com.ruoyi.user.mapper.AccountCertificationApplyMapper; |
| | | import com.ruoyi.user.mapper.AccountCertificationMapper; |
| | | import com.ruoyi.user.mapper.AccountUserMapper; |
| | |
| | | /** 审核结果:驳回 */ |
| | | private static final String AUDIT_REJECT = "2"; |
| | | |
| | | /** 审核状态:待审核(提交后的初始状态) */ |
| | | private static final String AUDIT_PENDING = "0"; |
| | | |
| | | /** account_user.auth_status:审核中 */ |
| | | private static final String AUTH_AUDITING = "1"; |
| | | |
| | | /** account_user.auth_status:已认证 */ |
| | | private static final String AUTH_VERIFIED = "2"; |
| | | |
| | | /** account_user.auth_status:认证失败 */ |
| | | private static final String AUTH_FAILED = "3"; |
| | | |
| | | /** 主体类型:个人(C端实名认证固定为该类型) */ |
| | | private static final String SUBJECT_PERSONAL = "1"; |
| | | |
| | | /** 主体类型:个体工商户 */ |
| | | private static final String SUBJECT_INDIVIDUAL = "2"; |
| | | |
| | | /** 主体类型:企业 */ |
| | | private static final String SUBJECT_COMPANY = "3"; |
| | | |
| | | /** 有效期类型:长期(此时起止日期可空) */ |
| | | private static final String VALID_TYPE_LONG_TERM = "1"; |
| | | |
| | | /** 有效期类型:短期(此时起止日期必填) */ |
| | | private static final String VALID_TYPE_SHORT_TERM = "2"; |
| | | |
| | | @Autowired |
| | | private AccountCertificationApplyMapper certificationApplyMapper; |
| | |
| | | throw new ServiceException("该申请已审核,不能重复处理"); |
| | | } |
| | | |
| | | // 同步到 account_user.auth_status:会员列表的「认证状态」列取的就是它 |
| | | // 同步认证状态到 account_user:个人写 auth_status,企业/个体写 company_auth_status,两列互不覆盖。 |
| | | AccountUser user = new AccountUser(); |
| | | user.setUserId(apply.getUserId()); |
| | | user.setAuthStatus(pass ? AUTH_VERIFIED : AUTH_FAILED); |
| | | user.setUpdateBy(operator); |
| | | accountUserMapper.updateUserAuthStatus(user); |
| | | if (isCompanySubject(apply.getSubjectType())) |
| | | { |
| | | user.setCompanyAuthStatus(pass ? AUTH_VERIFIED : AUTH_FAILED); |
| | | // 审核通过时才把主体类型落为 2/3;驳回不动,避免未通过审核就被标成企业主体 |
| | | if (pass) |
| | | { |
| | | user.setSubjectType(apply.getSubjectType()); |
| | | } |
| | | accountUserMapper.updateUserCompanyAuthStatus(user); |
| | | } |
| | | else |
| | | { |
| | | user.setAuthStatus(pass ? AUTH_VERIFIED : AUTH_FAILED); |
| | | accountUserMapper.updateUserAuthStatus(user); |
| | | } |
| | | |
| | | if (pass) |
| | | { |
| | | saveCertificationSnapshot(apply, operator); |
| | | } |
| | | return 1; |
| | | } |
| | | |
| | | @Override |
| | | @Transactional |
| | | public void submitPersonalCertification(Long userId, String realName, String idCard) |
| | | { |
| | | // STEP 1: 校验会员ID(登录态缺失时直接失败,避免无归属写入) |
| | | if (StringUtils.isNull(userId)) |
| | | { |
| | | throw new ServiceException("提交实名认证失败"); |
| | | } |
| | | // STEP 2: 姓名/身份证号二次校验:Controller 已用 @Validated 拦过一遍, |
| | | // 这里是服务层兜底,防止绕过 Controller 直接调用服务时落脏数据 |
| | | if (StringUtils.isEmpty(realName) || StringUtils.isEmpty(idCard)) |
| | | { |
| | | throw new ServiceException("姓名与身份证号不能为空"); |
| | | } |
| | | // STEP 3: 防重闸门——该会员已有待审核申请时拒绝,避免后台审核列表堆积重复单 |
| | | if (certificationApplyMapper.countPendingPersonalApplyByUserId(userId) > 0) |
| | | { |
| | | throw new ServiceException("已有实名认证申请正在审核中,请勿重复提交"); |
| | | } |
| | | // STEP 4: 组装申请快照并落库(主体类型固定「个人」;审核状态置「待审核」; |
| | | // 身份证号统一转大写,兼容末位小写 x) |
| | | String operator = SecurityUtils.getUsername(); |
| | | AccountCertificationApply apply = new AccountCertificationApply(); |
| | | apply.setUserId(userId); |
| | | apply.setSubjectType(SUBJECT_PERSONAL); |
| | | apply.setRealName(realName.trim()); |
| | | apply.setIdCard(idCard.trim().toUpperCase()); |
| | | apply.setAuditStatus(AUDIT_PENDING); |
| | | apply.setCreateBy(operator); |
| | | if (certificationApplyMapper.insertCertificationApply(apply) <= 0) |
| | | { |
| | | throw new ServiceException("提交实名认证失败,请稍后重试"); |
| | | } |
| | | // STEP 5: 联动 account_user.auth_status 为「审核中」,个人中心与会员列表据此显示 |
| | | AccountUser user = new AccountUser(); |
| | | user.setUserId(userId); |
| | | user.setAuthStatus(AUTH_AUDITING); |
| | | user.setUpdateBy(operator); |
| | | accountUserMapper.updateUserAuthStatus(user); |
| | | } |
| | | |
| | | @Override |
| | | public AccountCertificationStatusVo getCertificationStatus(Long userId) |
| | | { |
| | | AccountCertificationStatusVo vo = new AccountCertificationStatusVo(); |
| | | // 登录态缺失视为从未提交:返回空对象,前端按「未认证」渲染空表单(不返回 null) |
| | | if (StringUtils.isNull(userId)) |
| | | { |
| | | return vo; |
| | | } |
| | | AccountCertificationApply apply = certificationApplyMapper.selectLatestPersonalApplyByUserId(userId); |
| | | if (StringUtils.isNull(apply)) |
| | | { |
| | | return vo; |
| | | } |
| | | // 回填最近一次申请的资料与状态:认证失败时前端据 auditRemark 展示驳回原因 |
| | | vo.setRealName(apply.getRealName()); |
| | | vo.setIdCard(apply.getIdCard()); |
| | | vo.setAuditStatus(apply.getAuditStatus()); |
| | | vo.setAuditRemark(apply.getAuditRemark()); |
| | | return vo; |
| | | } |
| | | |
| | | @Override |
| | | @Transactional |
| | | public void submitCompanyCertification(Long userId, CompanyCertificationApplyDto dto) |
| | | { |
| | | // STEP 1: 校验会员ID(登录态缺失时直接失败,避免无归属写入) |
| | | if (StringUtils.isNull(userId)) |
| | | { |
| | | throw new ServiceException("提交企业认证失败"); |
| | | } |
| | | // STEP 2: 入参兜底:Controller 已用 @Validated 拦过,这里防止绕过 Controller 直接落脏数据 |
| | | if (StringUtils.isNull(dto)) |
| | | { |
| | | throw new ServiceException("认证资料不能为空"); |
| | | } |
| | | // STEP 3: 有效期必填兜底——「短期」必须填起止日期,「长期」允许为空(前端此时隐藏该输入) |
| | | checkValidPeriod(dto.getLicenseValidType(), dto.getLicenseValidPeriod(), "营业执照"); |
| | | checkValidPeriod(dto.getLegalIdValidType(), dto.getLegalIdValidPeriod(), "法人身份证"); |
| | | // STEP 4: 防重闸门——该会员已有待审核的企业申请时拒绝,避免后台审核列表堆积重复单 |
| | | if (certificationApplyMapper.countPendingCompanyApplyByUserId(userId) > 0) |
| | | { |
| | | throw new ServiceException("已有企业认证申请正在审核中,请勿重复提交"); |
| | | } |
| | | // STEP 5: 组装申请快照(主体类型取入参 2/3;审核状态置「待审核」) |
| | | String operator = SecurityUtils.getUsername(); |
| | | AccountCertificationApply apply = new AccountCertificationApply(); |
| | | apply.setUserId(userId); |
| | | apply.setSubjectType(dto.getSubjectType()); |
| | | apply.setCompanyName(dto.getCompanyName().trim()); |
| | | apply.setLicenseImage(dto.getLicenseImage()); |
| | | apply.setCreditCode(dto.getCreditCode().trim()); |
| | | apply.setLicenseValidType(dto.getLicenseValidType()); |
| | | apply.setLicenseValidPeriod(dto.getLicenseValidPeriod()); |
| | | apply.setRegisteredRegion(dto.getRegisteredRegion()); |
| | | apply.setCompanyAddress(dto.getCompanyAddress()); |
| | | apply.setLegalPerson(dto.getLegalPerson().trim()); |
| | | apply.setLegalIdCardFront(dto.getLegalIdCardFront()); |
| | | apply.setLegalIdCardBack(dto.getLegalIdCardBack()); |
| | | apply.setLegalIdValidType(dto.getLegalIdValidType()); |
| | | apply.setLegalIdValidPeriod(dto.getLegalIdValidPeriod()); |
| | | apply.setLegalIdAddress(dto.getLegalIdAddress()); |
| | | apply.setContactName(dto.getContactName().trim()); |
| | | apply.setContactPhone(dto.getContactPhone().trim()); |
| | | apply.setContactEmail(dto.getContactEmail().trim()); |
| | | apply.setPayeeType(dto.getPayeeType()); |
| | | apply.setBankCardImage(dto.getBankCardImage()); |
| | | apply.setBankCardNo(dto.getBankCardNo().trim()); |
| | | apply.setBankCity(dto.getBankCity()); |
| | | apply.setAuditStatus(AUDIT_PENDING); |
| | | apply.setCreateBy(operator); |
| | | // STEP 6: 落库 |
| | | if (certificationApplyMapper.insertCertificationApply(apply) <= 0) |
| | | { |
| | | throw new ServiceException("提交企业认证失败,请稍后重试"); |
| | | } |
| | | // STEP 7: 联动 account_user.company_auth_status 为「审核中」(与个人 auth_status 相互独立) |
| | | AccountUser user = new AccountUser(); |
| | | user.setUserId(userId); |
| | | user.setCompanyAuthStatus(AUTH_AUDITING); |
| | | user.setUpdateBy(operator); |
| | | accountUserMapper.updateUserCompanyAuthStatus(user); |
| | | } |
| | | |
| | | @Override |
| | | public CompanyCertificationStatusVo getCompanyCertificationStatus(Long userId) |
| | | { |
| | | CompanyCertificationStatusVo vo = new CompanyCertificationStatusVo(); |
| | | // 登录态缺失视为从未提交:返回空对象,前端按「未认证」渲染空表单(不返回 null) |
| | | if (StringUtils.isNull(userId)) |
| | | { |
| | | return vo; |
| | | } |
| | | AccountCertificationApply apply = certificationApplyMapper.selectLatestCompanyApplyByUserId(userId); |
| | | if (StringUtils.isNull(apply)) |
| | | { |
| | | return vo; |
| | | } |
| | | // 一次性回填整份资料与审核状态:审核中进占位页、已驳回展示原因并允许修改重提 |
| | | vo.setSubjectType(apply.getSubjectType()); |
| | | vo.setCompanyName(apply.getCompanyName()); |
| | | vo.setLicenseImage(apply.getLicenseImage()); |
| | | vo.setCreditCode(apply.getCreditCode()); |
| | | vo.setLicenseValidType(apply.getLicenseValidType()); |
| | | vo.setLicenseValidPeriod(apply.getLicenseValidPeriod()); |
| | | vo.setRegisteredRegion(apply.getRegisteredRegion()); |
| | | vo.setCompanyAddress(apply.getCompanyAddress()); |
| | | vo.setLegalPerson(apply.getLegalPerson()); |
| | | vo.setLegalIdCardFront(apply.getLegalIdCardFront()); |
| | | vo.setLegalIdCardBack(apply.getLegalIdCardBack()); |
| | | vo.setLegalIdValidType(apply.getLegalIdValidType()); |
| | | vo.setLegalIdValidPeriod(apply.getLegalIdValidPeriod()); |
| | | vo.setLegalIdAddress(apply.getLegalIdAddress()); |
| | | vo.setContactName(apply.getContactName()); |
| | | vo.setContactPhone(apply.getContactPhone()); |
| | | vo.setContactEmail(apply.getContactEmail()); |
| | | vo.setPayeeType(apply.getPayeeType()); |
| | | vo.setBankCardImage(apply.getBankCardImage()); |
| | | vo.setBankCardNo(apply.getBankCardNo()); |
| | | vo.setBankCity(apply.getBankCity()); |
| | | vo.setAuditStatus(apply.getAuditStatus()); |
| | | vo.setAuditRemark(apply.getAuditRemark()); |
| | | return vo; |
| | | } |
| | | |
| | | /** |
| | | * 判定主体类型是否为企业/个体工商户(subject_type ∈ {2,3})。 |
| | | */ |
| | | private boolean isCompanySubject(String subjectType) |
| | | { |
| | | return SUBJECT_INDIVIDUAL.equals(subjectType) || SUBJECT_COMPANY.equals(subjectType); |
| | | } |
| | | |
| | | /** |
| | | * 有效期必填兜底:类型为「短期」时,起止日期不得为空。 |
| | | * |
| | | * @param validType 有效期类型(1长期 2短期) |
| | | * @param validPeriod 有效期起止(文本) |
| | | * @param label 字段中文名,用于拼接错误提示 |
| | | */ |
| | | private void checkValidPeriod(String validType, String validPeriod, String label) |
| | | { |
| | | if (VALID_TYPE_SHORT_TERM.equals(validType) && StringUtils.isEmpty(validPeriod)) |
| | | { |
| | | throw new ServiceException("请选择" + label + "有效期起止日期"); |
| | | } |
| | | } |
| | | |
| | | /** |
| | |
| | | certification.setRegisterDate(apply.getRegisterDate()); |
| | | certification.setLicenseValidPeriod(apply.getLicenseValidPeriod()); |
| | | certification.setLicenseImage(apply.getLicenseImage()); |
| | | certification.setLicenseValidType(apply.getLicenseValidType()); |
| | | certification.setLegalIdCardFront(apply.getLegalIdCardFront()); |
| | | certification.setLegalIdCardBack(apply.getLegalIdCardBack()); |
| | | certification.setLegalIdValidType(apply.getLegalIdValidType()); |
| | | certification.setLegalIdValidPeriod(apply.getLegalIdValidPeriod()); |
| | | certification.setLegalIdAddress(apply.getLegalIdAddress()); |
| | | certification.setContactName(apply.getContactName()); |
| | | certification.setContactPhone(apply.getContactPhone()); |
| | | certification.setContactEmail(apply.getContactEmail()); |
| | | certification.setPayeeType(apply.getPayeeType()); |
| | | certification.setBankCardImage(apply.getBankCardImage()); |
| | | certification.setBankCardNo(apply.getBankCardNo()); |
| | | certification.setBankCity(apply.getBankCity()); |
| | | certification.setCreateBy(operator); |
| | | certification.setRemark("由认证申请(申请号 " + apply.getId() + ")审核通过生成"); |
| | | certificationMapper.insertCertification(certification); |