杜洪波
2026-03-24 616ca0caf25685efec6094686f01c0413f869af9
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
package com.product.saas.service;
 
import java.io.File;
import java.util.Date;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
 
import com.product.admin.config.CmnConst;
import com.product.admin.service.CodeService;
import com.product.admin.service.LoginAuthService;
import com.product.core.config.Global;
import com.product.core.dao.BaseDao;
import com.product.core.entity.FieldSetEntity;
import com.product.core.exception.BaseException;
import com.product.core.service.support.AbstractBaseService;
import com.product.core.transfer.Transactional;
import com.product.file.service.FileManagerService;
import com.product.module.sys.service.UserService;
import com.product.saas.config.SaasCode;
import com.product.saas.config.SaasConst;
import com.product.saas.service.idel.ITenantApplyService;
import com.product.tool.flow.service.FlowService;
import com.product.util.BaseUtil;
 
import cn.hutool.core.io.FileUtil;
 
/**
 *    租户申请 
 *
 */
@Component
public class TenantApplyService extends AbstractBaseService implements ITenantApplyService{
 
    @Autowired
    BaseDao baseDao;
    
    @Autowired
    CodeService codeService;
    
    @Autowired
    UserService userService;
    
    @Autowired
    FlowService flowService;
    
    @Autowired
    LoginAuthService loginAuthService;
    
    @Autowired
    FileManagerService fileManagerService;
    
    /**
     *     租户信息读取和验证
     * @param fse
     * @return
     */
    public boolean validTenantInfo(FieldSetEntity fse) {
        // 获取手机号和验证码
        String phone = fse.getString("phone");
        String code = fse.getString("code");
        // 验证验证码是否正确
        loginAuthService.verifyPhoneCaptcha(phone, code);
        String unitName = fse.getString("unitName");
        // 验证信息是否匹配
        FieldSetEntity fseTenantByPhone = baseDao.getFieldSetEntityByFilter(SaasConst.PRODUCT_SYS_TENANT_APPLY, "applicant_phone = ?", new Object[] {phone}, false);
        FieldSetEntity fseTenantByName = baseDao.getFieldSetEntityByFilter(SaasConst.PRODUCT_SYS_TENANT_APPLY, "unit_name = ?", new Object[] {unitName}, false);
        // 情况1:手机号和单位名都不存在 -> 通过
        if (fseTenantByPhone == null && fseTenantByName == null) {
            return true;
        }
        // 情况2:只存在手机号 -> 手机号已申请
        if (fseTenantByPhone != null && fseTenantByName == null) {
            throw new BaseException(SaasCode.TENANT_APPLY_VALID_UNIT_HAS_APPLY.getValue(), SaasCode.TENANT_APPLY_VALID_UNIT_HAS_APPLY.getText());
        }
        // 情况3:只存在单位名 -> 单位已申请
        if (fseTenantByPhone == null && fseTenantByName != null) {
            throw new BaseException(SaasCode.TENANT_APPLY_VALID_PHONE_HAS_APPLY.getValue(), SaasCode.TENANT_APPLY_VALID_PHONE_HAS_APPLY.getText());
        }
        // 情况4:都存在 -> 检查是否是同一条记录
        if (fseTenantByPhone.getUUID().equals(fseTenantByName.getUUID())) {
            return true;
        }
        // 情况5:都存在但不是同一条记录 -> 手机号和单位名都已申请
        throw new BaseException(SaasCode.TENANT_APPLY_VALID_UNIT_AND_PHONE_HAS_APPLY.getValue(), SaasCode.TENANT_APPLY_VALID_UNIT_AND_PHONE_HAS_APPLY.getText());
    }
    
    /**
     *     获取指定租户申请,根据申请人手机号
     * @param applicantPhone    申请人手机号
     * @return
     */
    public FieldSetEntity getTenantApplyByPhone(String applicantPhone) {
        StringBuilder sql = new StringBuilder();
        sql.append("SELECT A.*, B.file_name AS business_license_name, B.attachment_size AS business_license_size, C.dict_label AS apply_status_label \n");
        sql.append("FROM product_sys_tenant_apply A \n");
        sql.append("LEFT JOIN product_sys_attachments B ON B.uuid = A.business_license \n");
        sql.append("LEFT JOIN product_sys_dict C ON C.dict_value = A.apply_status AND C.dict_name = 'SYSTEM_TENANT_APPLY_STATUS' \n");
        sql.append("WHERE A.applicant_phone = ?");
        return baseDao.getFieldSetEntityBySQL(sql.toString(), new Object[] {applicantPhone}, false);
    }
    
    /**
     *     保存租户申请
     *     approval_sign:送审标识(0:保存;1:送审或激活)
     * @param fse
     * @return
     */
    @Override
    @Transactional
    public boolean saveTenantApply(FieldSetEntity fse) {
        // 获取送审标志
        String flowSign = fse.getString("approval_sign");
        if (!BaseUtil.strIsNull(flowSign) || "1".equals(flowSign)) {
            // 保存租户信息
            fse.setValue("apply_status", 2);
            fse.setValue("is_passed", 0);
            baseDao.saveFieldSetEntity(fse);
            
            // 查询送审记录
            FieldSetEntity fseTask = baseDao.getFieldSetEntityByFilter("product_sys_flow_task", "table_name = 'product_sys_tenant_apply' AND record_uuid = ?", new Object[] {fse.getUUID()}, false);
            if (fseTask == null) {
                // 获取送审开始的后一个节点信息
                StringBuilder sql = new StringBuilder();
                sql.append("SELECT * FROM product_sys_flow_node \n");
                sql.append("WHERE uuid IN ( \n");
                sql.append("    SELECT target_uuid FROM product_sys_flow_link \n");
                sql.append("    WHERE source_uuid IN ( \n");
                sql.append("        SELECT uuid FROM product_sys_flow_node \n");
                sql.append("        WHERE module_type = 1 AND flow_uuid IN ( \n");
                sql.append("            SELECT uuid FROM product_sys_flow_model \n");
                sql.append("            WHERE type_code = ? \n");
                sql.append("        ) \n");
                sql.append("    ) \n");
                sql.append(") \n");
                FieldSetEntity fseFlowNode = baseDao.getFieldSetEntityBySQL(sql.toString(), new Object[] {SaasConst.FLOW_TENANT_APPLY}, false);
                if (fseFlowNode == null || BaseUtil.strIsNull(fseFlowNode.getString("default_users"))) {
                    throw new BaseException("租户申请流程有误", "租户申请流程有误");
                }
                // 封装送审参数
                FieldSetEntity fseFlowTask = new FieldSetEntity(SaasConst.PRODUCT_SYS_TENANT_APPLY);
                fseFlowTask.setValue("uuid", fse.getUUID());
                fseFlowTask.setValue("type_code", SaasConst.FLOW_TENANT_APPLY);
                fseFlowTask.setValue("accepters", fseFlowNode.getString("default_users"));
                fseFlowTask.setValue("flow_title", "租户申请-" + fse.getString("unit_name"));
                // 执行送审
                flowService.autoSendFlow(fseFlowTask);
            } else {
                // 激活送审任务
                FieldSetEntity fseTaskDetail = new FieldSetEntity("product_sys_flow_detail");
                fseTaskDetail.setValue("task_uuid", fseTask.getUUID());
                fseTaskDetail.setValue("is_sub_flow", "0");
                fseTaskDetail.setValue("opinion", "租户撤回后重新提交");
                flowService.activate(fseTaskDetail);
            }
            return true;
        } else {
            fse.setValue("apply_status", 1);
            fse.setValue("is_passed", 0);
            // 保存租户信息
            return baseDao.saveFieldSetEntity(fse);
        }
    }
 
    /**
     *     撤销租户申请
     * @param fse
     * @return
     */
    @Override
    @Transactional
    public boolean cancelTenantApply(FieldSetEntity fse){
        // 获取对应流程任务
        FieldSetEntity fseTask = baseDao.getFieldSetEntityByFilter("product_sys_flow_task", "table_name = 'product_sys_tenant_apply' AND record_uuid = ?", new Object[] {fse.getUUID()}, false);
        if (fseTask == null) {
            throw new BaseException(SaasCode.TENANT_AAPLY_INFO_FLOW_TASK_ERROR.getValue(), SaasCode.TENANT_AAPLY_INFO_FLOW_TASK_ERROR.getText());
        }
        // 终止流程
        flowService.stop(fseTask);
        // 标记申请数据为未送审
        return baseDao.executeUpdate("UPDATE product_sys_tenant_apply SET apply_status = 1 WHERE applicant_phone = ? AND unit_name = ? ",
                new Object[] {fse.getString("applicant_phone"), fse.getString("unit_name")});
    }
    
    /**
     *     刷新申请单状态(流程处理器调用)
     * @param fseApply
     */
    public void refreshApplyStatus(FieldSetEntity fseApply) {
        if ("1".equals(fseApply.getString("is_passed"))) {
            // 审核通过
            baseDao.executeUpdate("UPDATE product_sys_tenant_apply SET apply_status = 3 WHERE uuid = ?", new Object[] {fseApply.getUUID()});
        } else {
            // 审核失败
            baseDao.executeUpdate("UPDATE product_sys_tenant_apply SET apply_status = 4 WHERE uuid = ?", new Object[] {fseApply.getUUID()});
        }
    }
    
    /**
     * 申请完成
     * @param fseApply
     */
    @Transactional
    public void applyFinish(FieldSetEntity fseApply) {
        // 创建客户信息
        FieldSetEntity fseClient = new FieldSetEntity(SaasConst.PRODUCT_SYS_CLIENTS);
        fseClient.setValue("client_name", fseApply.getString("unit_name"));
        fseClient.setValue("client_tel", fseApply.getString("applicant_phone"));
        fseClient.setValue("client_code", codeService.createCode(SaasConst.PRODUCT_SYS_CLIENTS, "client_code", ""));
        fseClient.setValue("attachment_capacity", "2130000000");
        fseClient.setValue("platform_admin", fseApply.getString("platform_admin"));
        fseClient.setValue("expiration_date", fseApply.getString("expiration_date"));
        fseClient.setValue("client_unit_type", fseApply.getString("unit_type"));
        fseClient.setValue("client_address_province_id", fseApply.getString("area_province"));
        fseClient.setValue("client_address_city_id", fseApply.getString("area_city"));
        fseClient.setValue("client_address_county_id", fseApply.getString("area_county"));
        fseClient.setValue("client_address_line_one", fseApply.getString("address"));
        fseClient.setValue(CmnConst.CREATED_BY, "1");
        fseClient.setValue(CmnConst.CREATED_UTC_DATETIME, new Date());
        baseDao.add(fseClient);
        // 复制license到web模块
        copyLicense(fseApply.getString("license"), fseClient.getString("client_code"));
        
        // 创建组织机构单位
        FieldSetEntity fseOrgUnit = new FieldSetEntity(CmnConst.PRODUCT_SYS_ORG_LEVELS);
        fseOrgUnit.setValue("client_uuid", fseClient.getUUID());
        fseOrgUnit.setValue("org_level_name", fseApply.getString("unit_name"));
        fseOrgUnit.setValue("org_level_all", "成都XXXX软件有限公司>" + fseApply.getString("unit_name"));
        fseOrgUnit.setValue("org_level_code", codeService.createCode("product_sys_org_levels", "org_level_code", "001"));
        fseOrgUnit.setValue("org_level_code_parent", "001");
        fseOrgUnit.setValue("org_level_type", 0);
        fseOrgUnit.setValue("sequence", 1);
        fseOrgUnit.setValue(CmnConst.CREATED_BY, "1");
        fseOrgUnit.setValue(CmnConst.CREATED_UTC_DATETIME, new Date());
        baseDao.add(fseOrgUnit);
        // 创建租户管理员用户信息
        FieldSetEntity fseUser = new FieldSetEntity(CmnConst.PRODUCT_SYS_USERS);
        fseUser.setValue(CmnConst.USER_NAME, fseApply.getString("applicant_name"));
        fseUser.setValue(CmnConst.USER_ACCOUNT, fseApply.getString("applicant_phone"));
        fseUser.setValue(CmnConst.USER_PRIMARY_EMAIL, fseApply.getString("applicant_email"));
        fseUser.setValue(CmnConst.USER_MOBILE_NUMBER, fseApply.getString("applicant_phone"));
        fseUser.setValue(CmnConst.USER_PWD, userService.createPassWord(fseApply.getString("applicant_phone"), fseApply.getString("applicant_pwd")));
        fseUser.setValue(CmnConst.IS_MANAGER, 1);
        fseUser.setValue(CmnConst.STATUS, 1);
        fseUser.setValue(CmnConst.CREATED_BY, "1");
        fseUser.setValue(CmnConst.CREATED_UTC_DATETIME, new Date());
        baseDao.add(fseUser);
        FieldSetEntity fseUserInfo = baseDao.getFieldSetEntity(CmnConst.PRODUCT_SYS_USERS, fseUser.getUUID(), false);
        // 创建租户管理员信息
        FieldSetEntity fseManager = new FieldSetEntity(CmnConst.PRODUCT_SYS_ORG_MANAGER);
        fseManager.setValue(CmnConst.USER_ID, fseUserInfo.getString(CmnConst.USER_ID));
        fseManager.setValue(CmnConst.ORG_LEVEL_UUID, fseOrgUnit.getUUID());
        fseManager.setValue(CmnConst.MANAGER_TYPE, 2);
        fseManager.setValue(CmnConst.ROLE_UUIDS, "eabb00f3-2118-4165-967b-a7d88f472f67-notchange");
        fseManager.setValue(CmnConst.IS_USED, 1);
        fseManager.setValue(CmnConst.CLIENT_UUID, fseClient.getUUID());
        fseManager.setValue(CmnConst.CREATED_BY, "1");
        fseManager.setValue(CmnConst.CREATED_UTC_DATETIME, new Date());
        baseDao.add(fseManager);
        baseDao.executeUpdate("UPDATE product_sys_tenant_apply SET client_uuid = ? WHERE uuid = ?", new Object[] {fseClient.getUUID(), fseApply.getUUID()});
    }
    
    /**
     *     复制license到指定目录
     * @param fileUUID        附件UUID
     * @param clientCode    客户编码
     */
    public void copyLicense(String fileUUID, String clientCode) {
        
        // 获取文件信息
        FieldSetEntity fse = baseDao.getFieldSetEntity(SaasConst.PRODUCT_SYS_ATTACHMENTS, fileUUID, false);
        if (fse == null) {
            throw new BaseException(SaasCode.TENANT_APPLY_LICENSE_DATA_NO_EXIST.getValue(), SaasCode.TENANT_APPLY_LICENSE_DATA_NO_EXIST.getText());
        }
        
        // 构建源文件路径
        String baseDir = System.getProperty("user.dir");
        String localDir = Global.getSystemConfig("local.dir", "");
        String attachmentUrl = fse.getString("attachment_url");
        String attachmentTitle = fse.getString("attachment_title");
        
        String filePath = baseDir + File.separator + localDir + File.separator + attachmentUrl + File.separator + attachmentTitle;
        
        // 检查源文件是否存在
        if (!FileUtil.exist(filePath)) {
            throw new BaseException(SaasCode.TENANT_APPLY_LICENSE_FILE_NO_EXIST.getValue(), SaasCode.TENANT_APPLY_LICENSE_FILE_NO_EXIST.getText());
        }
        
        // 构建目标目录
        String targetDir = baseDir + File.separator + "resources" + File.separator;
        FileUtil.mkdir(targetDir);
        
        // 构建目标文件名:license + clientCode + .dat
        // 无论原文件是否有扩展名,都使用.dat扩展名
        String targetFileName = "license" + clientCode + ".dat";
        String targetPath = targetDir + targetFileName;
        
        // 复制文件
        try {
            // 使用Hutool复制,第三个参数true表示覆盖已存在的文件
            FileUtil.copy(filePath, targetPath, true);
            // 验证复制结果
            if (FileUtil.exist(targetPath)) {
                long sourceSize = FileUtil.size(new File(filePath));
                long targetSize = FileUtil.size(new File(targetPath));
                if (sourceSize != targetSize) {
                    throw new BaseException(SaasCode.TENANT_APPLY_LICENSE_FILE_COPY_FAIL.getValue(),  SaasCode.TENANT_APPLY_LICENSE_FILE_COPY_FAIL.getValue() + "目标文件不完整");
                }
            } else {
                throw new BaseException(SaasCode.TENANT_APPLY_LICENSE_FILE_COPY_FAIL.getValue(),  SaasCode.TENANT_APPLY_LICENSE_FILE_COPY_FAIL.getValue() + "目标文件不存在");
            }
        } catch (Exception e) {
            throw new BaseException(SaasCode.TENANT_APPLY_LICENSE_FILE_COPY_FAIL.getValue(),  SaasCode.TENANT_APPLY_LICENSE_FILE_COPY_FAIL.getValue() + e.getMessage());
        }
    }
}