浏览代码

定制接口和功能提交

peicj 5 天之前
父节点
当前提交
308edb5397

+ 40 - 11
ruoyi-admin/src/main/java/com/ruoyi/aicall/controller/ApiController.java

@@ -1254,6 +1254,15 @@ public class ApiController extends BaseController {
     {
         return AjaxResult.success(ccExtNumService.selectUnBindCcExtNumList());
     }
+    /**
+     * 查询公司未绑定的分机管理列表
+     */
+    @PostMapping("/extnum/selectCompanyUnBindCcExtNumList")
+    @ResponseBody
+    public AjaxResult selectCompanyUnBindCcExtNumList(@RequestBody CcExtNum ccExtNum)
+    {
+        return AjaxResult.success(ccExtNumService.selectCcExtNumList(ccExtNum));
+    }
     /**
      * 查询未绑定的分机管理列表分页
      */
@@ -1338,7 +1347,6 @@ public class ApiController extends BaseController {
     @Transactional
     public AjaxResult addUserOrBindExtNumReturnUser(@RequestBody SysUser user)
     {
-        log.info("新增用户请求 - 用户名:{}, 密码:{}, 分机号:{}", user.getLoginName(), user.getPassword(), user.getExtNum());
         if(StringUtils.isBlank(user.getPassword())){
             throw new RuntimeException("密码不能为空");
         }
@@ -1359,13 +1367,8 @@ public class ApiController extends BaseController {
         if (null == extNum) {
             throw new RuntimeException("新增用户失败,分机号" + user.getExtNum() + "不存在");
         }
-        // 校验分机号是否已被绑定
-        if (StringUtils.isNotEmpty(extNum.getUserCode())) {
-            throw new RuntimeException("新增用户失败,分机号" + user.getExtNum() + "已被用户" + extNum.getUserCode() + "绑定");
-        }
             
         user.setSalt(ShiroUtils.randomSalt());
-        String plainPassword = user.getPassword();
         
         user.setPassword(passwordService.encryptPassword(user.getLoginName(), user.getPassword(), user.getSalt()));
         
@@ -1406,22 +1409,48 @@ public class ApiController extends BaseController {
         AuthorizationUtils.clearAllCachedAuthorizationInfo();
         int i = userService.updateUser(user);
         if(i>0){
-            //修改绑定分机
-            CcExtNum extNum = new CcExtNum();
-            extNum.setExtNum(user.getExtNum());
-            extNum.setUserCode(user.getLoginName());
             //先清除原分机绑定
             int cleanNum = ccExtNumService.cleanCcExtNumByUserCode(user.getLoginName());
             if(cleanNum>0){
+                //修改绑定分机
+                CcExtNum extNum = new CcExtNum();
+                extNum.setExtNum(user.getExtNum());
+                extNum.setUserCode(user.getLoginName());
                 int updateNum = ccExtNumService.updateCcExtNumByUserCode(extNum);
                 if(updateNum>0){
-                    return AjaxResult.success(user);
+                    CcExtNum num = ccExtNumService.selectCcExtNumByExtNum(user.getExtNum());
+                    if(null != num){
+                        user.setExtPass(num.getExtPass());
+                        return AjaxResult.success(user);
+                    }
                 }
             }
         }
         throw new RuntimeException("修改用户失败");
     }
 
+    /**
+     * 删除用户且解绑分机
+     */
+    @PostMapping("/deleteUserOrunBindExtNum")
+    @ResponseBody
+    @Transactional
+    public AjaxResult deleteUserOrunBindExtNum(@RequestBody SysUser user)
+    {
+        //先解绑分机
+        CcExtNum extNum = new CcExtNum();
+        extNum.setExtNum(user.getExtNum());
+        extNum.setUserCode(user.getUserCode());
+        int updateNum = ccExtNumService.updateCcExtNumByUserCode(extNum);
+        if(updateNum>0){
+            //删除用户
+            int i = userService.deleteUserById(user.getUserId());
+            if(i>0){
+                return AjaxResult.success();
+            }
+        }
+        throw new RuntimeException("删除用户且解绑分机失败");
+    }
 
     /**
      * 获取手动外呼客户沟通信息

+ 27 - 0
ruoyi-admin/src/main/java/com/ruoyi/cc/controller/CcExtNumController.java

@@ -155,4 +155,31 @@ public class CcExtNumController extends BaseController
         List<CcExtNum> list = ccExtNumService.selectCcExtNumList(new CcExtNum());
         return AjaxResult.success(list);
     }
+
+    /**
+     * 批量新增分机管理页面
+     */
+    @GetMapping("/batchAdd")
+    public String batchAdd()
+    {
+        return prefix + "/batchAdd";
+    }
+
+    /**
+     * 批量新增保存分机管理
+     */
+    @RequiresPermissions("cc:extnum:batchAdd")
+    @Log(title = "分机管理-批量新增", businessType = BusinessType.INSERT)
+    @PostMapping("/batchAdd")
+    @ResponseBody
+    public AjaxResult batchAddSave(int count, String extPass, String userCode, Long startExtNum) {
+        try {
+            int successCount = ccExtNumService.batchInsertCcExtNum(count, extPass, userCode, startExtNum);
+            return AjaxResult.success("成功生成" + successCount + "个分机号");
+        } catch (RuntimeException e) {
+            return AjaxResult.error(e.getMessage());
+        } catch (Exception e) {
+            return AjaxResult.error("批量新增失败:" + e.getMessage());
+        }
+    }
 }

+ 23 - 0
ruoyi-admin/src/main/java/com/ruoyi/cc/mapper/CcExtNumMapper.java

@@ -74,4 +74,27 @@ public interface CcExtNumMapper
     int updateCompanyBindExtNum(CcExtNum extNum);
 
     int companyUnbindExtNum(List<String> userCodeList);
+
+    /**
+     * 批量新增分机信息
+     * 
+     * @param extNumList 分机信息列表
+     * @return 结果
+     */
+    int batchInsertCcExtNum(List<CcExtNum> extNumList);
+
+    /**
+     * 查询大于指定值的所有分机号(用于批量生成分机号时优化性能)
+     * 
+     * @param minExtNum 最小分机号(不包含)
+     * @return 分机号集合
+     */
+    List<Long> selectExtNumsGreaterThan(Long minExtNum);
+
+    /**
+     * 查询当前最大的分机号
+     * 
+     * @return 最大分机号,如果没有数据则返回null
+     */
+    Long selectMaxExtNum();
 }

+ 10 - 0
ruoyi-admin/src/main/java/com/ruoyi/cc/service/ICcExtNumService.java

@@ -99,4 +99,14 @@ public interface ICcExtNumService
     int updateCompanyBindExtNum(CcExtNum extNum);
 
     int companyUnbindExtNum(List<String> userCodeList);
+
+    /**
+     * 批量新增分机
+     * @param count 生成数量
+     * @param extPass 分机密码
+     * @param userCode 绑定工号(可选)
+     * @param startExtNum 起始分机号(可选,不填则从上次最大分机号+1开始)
+     * @return 结果
+     */
+    int batchInsertCcExtNum(int count, String extPass, String userCode, Long startExtNum);
 }

+ 176 - 6
ruoyi-admin/src/main/java/com/ruoyi/cc/service/impl/CcExtNumServiceImpl.java

@@ -5,15 +5,14 @@ import java.util.*;
 import com.auth0.jwt.JWT;
 import com.auth0.jwt.algorithms.Algorithm;
 import com.ruoyi.cc.service.ICcParamsService;
+import com.ruoyi.common.utils.StringUtils;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 import com.ruoyi.cc.mapper.CcExtNumMapper;
 import com.ruoyi.cc.domain.CcExtNum;
 import com.ruoyi.cc.service.ICcExtNumService;
 import com.ruoyi.common.core.text.Convert;
-import org.springframework.util.CollectionUtils;
 
 /**
  * 【请填写功能名称】Service业务层处理
@@ -30,6 +29,13 @@ public class CcExtNumServiceImpl implements ICcExtNumService
     @Autowired
     private ICcParamsService ccParamsService;
     private String authTokenSecret;
+    
+    // 缓存最大分机号,初始值为0表示未初始化,需要从数据库查询
+    // 使用volatile保证多线程可见性
+    private volatile long cachedMaxExtNum = 0;
+    
+    // 用于同步获取和更新缓存的锁对象
+    private final Object cacheLock = new Object();
 
     /**
      * 查询【请填写功能名称】
@@ -106,7 +112,7 @@ public class CcExtNumServiceImpl implements ICcExtNumService
     @Override
     public CcExtNum selectCcExtNumByExtNum(Long extNum) {
         List<CcExtNum> list = selectCcExtNumList(new CcExtNum().setExtNum(extNum));
-        if (list.size() > 0) {
+        if (!list.isEmpty()) {
             return list.get(0);
         }
         return null;
@@ -115,7 +121,7 @@ public class CcExtNumServiceImpl implements ICcExtNumService
     @Override
     public CcExtNum selectCcExtNumByUserCode(String userCode) {
         List<CcExtNum> list = selectCcExtNumList(new CcExtNum().setUserCode(userCode));
-        if (list.size() > 0) {
+        if (!list.isEmpty()) {
             return list.get(0);
         }
         return null;
@@ -134,7 +140,7 @@ public class CcExtNumServiceImpl implements ICcExtNumService
             Map<String, Object> map = new HashMap<>();
             Calendar instance = Calendar.getInstance();
             instance.add(Calendar.HOUR, 24);
-            String token = JWT.create()
+            return JWT.create()
                     //添加头部
                     .withHeader(map)
                     //添加payload
@@ -147,7 +153,6 @@ public class CcExtNumServiceImpl implements ICcExtNumService
                     .withExpiresAt(instance.getTime())
                     //设置签名 密钥
                     .sign(Algorithm.HMAC256(authTokenSecret));
-            return token;
 
         } catch (Exception err) {
             log.error("error:" + err.getMessage());
@@ -182,4 +187,169 @@ public class CcExtNumServiceImpl implements ICcExtNumService
     public int companyUnbindExtNum(List<String> userCodeList) {
         return ccExtNumMapper.companyUnbindExtNum(userCodeList);
     }
+
+    @Override
+    public int batchInsertCcExtNum(int count, String extPass, String userCode, Long startExtNum) {
+        // ==================== 1. 参数校验(安全检查)====================
+        if (count <= 0 || count > 10000) {
+            throw new RuntimeException("生成数量必须在1-10000之间");
+        }
+        
+        // 密码可以为空字符串,但不能为null
+        if (extPass == null) {
+            extPass = "";
+        }
+        
+        // 密码长度校验(最多50个字符)
+        if (extPass.length() > 50) {
+            throw new RuntimeException("分机密码长度不能超过50个字符");
+        }
+        
+        // 工号长度校验(最多32个字符)
+        if (StringUtils.isNotEmpty(userCode) && userCode.length() > 32) {
+            throw new RuntimeException("工号长度不能超过32个字符");
+        }
+        
+        // ==================== 2. 工号唯一性校验 ====================
+        if (StringUtils.isNotEmpty(userCode)) {
+            CcExtNum checkUserCode = selectCcExtNumByUserCode(userCode);
+            if (checkUserCode != null) {
+                throw new RuntimeException("该工号已经绑定分机" + checkUserCode.getExtNum() + ",不允许重复绑定!");
+            }
+        }
+        
+        // ==================== 3. 确定起始分机号(使用缓存+数据库双重保障)====================
+        long actualStartExtNum;
+        long currentMaxExtNum;
+        
+        synchronized (cacheLock) {
+            // 如果缓存为0,说明是第一次使用或系统刚重启,需要从数据库查询
+            if (cachedMaxExtNum == 0) {
+                Long dbMaxExtNum = ccExtNumMapper.selectMaxExtNum();
+                currentMaxExtNum = (dbMaxExtNum == null) ? 0L : dbMaxExtNum;
+                cachedMaxExtNum = currentMaxExtNum; // 更新缓存
+                log.info("首次初始化分机号缓存,数据库最大分机号: {}", currentMaxExtNum);
+            } else {
+                currentMaxExtNum = cachedMaxExtNum;
+            }
+            
+            // 确定实际起始分机号
+            if (startExtNum == null || startExtNum <= 0) {
+                actualStartExtNum = currentMaxExtNum + 1;
+                if (actualStartExtNum <= 0) {
+                    actualStartExtNum = 1L; // 确保起始值至少为1
+                }
+            } else {
+                // 校验用户指定的起始分机号不能小于当前最大值
+                if (startExtNum <= currentMaxExtNum) {
+                    throw new RuntimeException("起始分机号(" + startExtNum + ")不能小于等于当前最大分机号(" + currentMaxExtNum + "),可选择不填起始分机号");
+                }
+                actualStartExtNum = startExtNum;
+            }
+        }
+        
+        // ==================== 4. 查询已存在的分机号(用于去重)====================
+        List<Long> existingExtNums = ccExtNumMapper.selectExtNumsGreaterThan(actualStartExtNum - 1);
+        Set<Long> existingExtNumSet = new HashSet<>(existingExtNums);
+        
+        // ==================== 5. 分批生成分机号并插入(防止内存溢出)====================
+        int totalInserted = 0;
+        long currentExtNum = actualStartExtNum;
+        int remainingCount = count;
+        
+        // 分机号最大值限制(防止Long溢出)
+        final long MAX_EXT_NUM = Long.MAX_VALUE - 10000; // 预留安全空间
+        
+        // 外层批次大小:每次生成1000个分机号
+        final int GENERATE_BATCH_SIZE = 1000;
+        // 内层插入批次大小:每次插入500条到数据库
+        final int INSERT_BATCH_SIZE = 500;
+        
+        try {
+            while (remainingCount > 0) {
+                // 计算当前批次要生成的数量
+                int currentBatchSize = Math.min(GENERATE_BATCH_SIZE, remainingCount);
+                List<CcExtNum> currentBatchList = new ArrayList<>(currentBatchSize);
+                
+                // 生成当前批次的分机号
+                int generatedInBatch = 0;
+                long attempts = 0;
+                // 防死循环:每个批次最多尝试 currentBatchSize * 10 次
+                long maxAttemptsPerBatch = (long) currentBatchSize * 10L;
+                
+                while (generatedInBatch < currentBatchSize) {
+                    attempts++;
+                    
+                    // 【关键】安全检查1:防止死循环
+                    if (attempts > maxAttemptsPerBatch) {
+                        String errorMsg = String.format(
+                            "生成分机号失败:在区间[%d, %d]内可用分机号不足(已尝试%d次)。建议:1)删除部分已有分机号 2)指定更大的起始位置",
+                            actualStartExtNum, currentExtNum, attempts
+                        );
+                        log.error(errorMsg);
+                        throw new RuntimeException(errorMsg);
+                    }
+                    
+                    // 【关键】安全检查2:防止Long溢出
+                    if (currentExtNum <= 0 || currentExtNum >= MAX_EXT_NUM) {
+                        String errorMsg = String.format(
+                            "分机号已达到系统上限(currentExtNum=%d, MAX_EXT_NUM=%d),无法继续生成",
+                            currentExtNum, MAX_EXT_NUM
+                        );
+                        log.error(errorMsg);
+                        throw new RuntimeException(errorMsg);
+                    }
+                    
+                    // 如果当前分机号不存在,则添加到当前批次列表
+                    if (!existingExtNumSet.contains(currentExtNum)) {
+                        CcExtNum newExt = new CcExtNum();
+                        newExt.setExtNum(currentExtNum);
+                        newExt.setExtPass(extPass);
+                        newExt.setUserCode(userCode != null ? userCode : "");
+                        currentBatchList.add(newExt);
+                        generatedInBatch++;
+                        
+                        // 将新生成的分机号加入已存在集合,避免同一批次内重复
+                        existingExtNumSet.add(currentExtNum);
+                    }
+                    currentExtNum++;
+                }
+                
+                // ==================== 6. 分批插入数据库 ====================
+                if (!currentBatchList.isEmpty()) {
+                    for (int i = 0; i < currentBatchList.size(); i += INSERT_BATCH_SIZE) {
+                        int endIndex = Math.min(i + INSERT_BATCH_SIZE, currentBatchList.size());
+                        List<CcExtNum> insertBatchList = currentBatchList.subList(i, endIndex);
+                        int inserted = ccExtNumMapper.batchInsertCcExtNum(insertBatchList);
+                        totalInserted += inserted;
+                    }
+                    
+                    // 更新剩余计数
+                    remainingCount -= generatedInBatch;
+                    
+                    // 【关键】更新缓存的最大分机号(在同步块中保证线程安全)
+                    synchronized (cacheLock) {
+                        long newMaxExtNum = currentBatchList.get(currentBatchList.size() - 1).getExtNum();
+                        if (newMaxExtNum > cachedMaxExtNum) {
+                            cachedMaxExtNum = newMaxExtNum;
+                            log.debug("更新分机号缓存为: {}", cachedMaxExtNum);
+                        }
+                    }
+                    
+                    // 记录进度日志
+                    log.info("批量生成分机号进度: {}/{}", totalInserted, count);
+                }
+            }
+            
+            log.info("批量生成分机号完成,共生成 {} 条记录", totalInserted);
+            return totalInserted;
+            
+        } catch (RuntimeException e) {
+            log.error("批量生成分机号失败: {}", e.getMessage(), e);
+            throw e;
+        } catch (Exception e) {
+            log.error("批量生成分机号发生未知错误", e);
+            throw new RuntimeException("批量生成分机号失败: " + e.getMessage(), e);
+        }
+    }
 }

+ 18 - 0
ruoyi-admin/src/main/resources/mapper/cc/CcExtNumMapper.xml

@@ -29,6 +29,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
                 </foreach>
             </if>
         </where>
+        order by ext_num asc
     </select>
     
     <select id="selectCcExtNumByExtId" parameterType="Long" resultMap="CcExtNumResult">
@@ -89,6 +90,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <if test="extPass != null and extPass != ''">and ext_pass = #{extPass}</if>
         <if test="startExtNum != null">and ext_num &gt;= #{startExtNum}</if>
         <if test="endExtNum != null">and ext_num  &lt;= #{endExtNum}</if>
+        order by ext_num asc
     </select>
 
     <update id="updateCompanyBindExtNum">
@@ -103,4 +105,20 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             #{userCode}
         </foreach>
     </update>
+
+    <insert id="batchInsertCcExtNum" parameterType="java.util.List">
+        insert into cc_ext_num (ext_num, ext_pass, user_code)
+        values
+        <foreach collection="list" item="item" separator=",">
+            (#{item.extNum}, #{item.extPass}, #{item.userCode})
+        </foreach>
+    </insert>
+
+    <select id="selectExtNumsGreaterThan" parameterType="java.lang.Long" resultType="java.lang.Long">
+        select ext_num from cc_ext_num where ext_num &gt; #{minExtNum}
+    </select>
+
+    <select id="selectMaxExtNum" resultType="java.lang.Long">
+        select max(ext_num) from cc_ext_num
+    </select>
 </mapper>

+ 2 - 2
ruoyi-admin/src/main/resources/templates/aicall/callPhone/callPhone.html

@@ -499,8 +499,8 @@
                     }
                 },
                 {
-                    field: 'timeLen',
-                    title: i18n('callPhone.table.timeLen'),
+                    field: 'validTimeLen',
+                    title: i18n('callPhone.table.validTimeLen'),
                     width: 80,
                     formatter: function(value, row, index, field) {
                         // 计算分钟数,向下取整

+ 5 - 5
ruoyi-admin/src/main/resources/templates/cc/extnum/add.html

@@ -36,21 +36,21 @@
     <script th:inline="javascript">
         var prefix = ctx + "cc/extnum"
 
-        $.validator.addMethod("pattern", function(value, element, regexp) {
-            return this.optional(element) || regexp.test(value);
-        }, "格式不正确");
+        // $.validator.addMethod("pattern", function(value, element, regexp) {
+        //     return this.optional(element) || regexp.test(value);
+        // }, "格式不正确");
 
         $("#form-num-add").validate({
             focusCleanup: true,
             rules: {
                 extNum: {
                     required: true,
-                    pattern: /^1\d{3}$/
+                    // pattern: /^1\d{3}$/
                 }
             },
             messages: {
                 extNum: {
-                    pattern: "请输入以1开头的4位数字分机号,例如:1001"
+                    // pattern: "请输入以1开头的4位数字分机号,例如:1001"
                 }
             }
         });

+ 74 - 0
ruoyi-admin/src/main/resources/templates/cc/extnum/batchAdd.html

@@ -0,0 +1,74 @@
+<!DOCTYPE html>
+<html lang="zh" xmlns:th="http://www.thymeleaf.org">
+<head>
+    <th:block th:include="include :: header('批量新增分机')" />
+</head>
+<body class="white-bg">
+    <div class="wrapper wrapper-content animated fadeInRight ibox-content">
+        <form class="form-horizontal m" id="form-num-batch-add">
+            <div class="col-xs-12">
+                <div class="form-group">
+                    <label class="col-sm-3 control-label is-required">生成分机号数量:</label>
+                    <div class="col-sm-8">
+                        <input name="count" class="form-control" type="number" min="1" max="2000" required placeholder="请输入要生成的分机号数量(1-10000)">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-12">
+                <div class="form-group">
+                    <label class="col-sm-3 control-label">起始分机号:</label>
+                    <div class="col-sm-8">
+                        <input name="startExtNum" class="form-control" type="number" min="1" placeholder="选填">
+                        <span class="help-block m-b-none"><i class="fa fa-info-circle"></i> 非必填,指定后将从该分机号开始生成</span>
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-12">
+                <div class="form-group">
+                    <label class="col-sm-3 control-label is-required">分机密码:</label>
+                    <div class="col-sm-8">
+                        <input name="extPass" class="form-control" type="text" placeholder="选填,所有分机密码将相同">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-12">
+                <div class="form-group">
+                    <label class="col-sm-3 control-label">绑定工号:</label>
+                    <div class="col-sm-8">
+                        <input name="userCode" class="form-control" type="text" placeholder="选填,所有分机将绑定同一工号">
+                        <span class="help-block m-b-none"><i class="fa fa-info-circle"></i> 非必填,如需绑定请填写</span>
+                    </div>
+                </div>
+            </div>
+        </form>
+    </div>
+    <th:block th:include="include :: footer" />
+    <script th:inline="javascript">
+        var prefix = ctx + "cc/extnum"
+
+        $("#form-num-batch-add").validate({
+            focusCleanup: true,
+            rules: {
+                count: {
+                    required: true,
+                    digits: true,
+                    range: [1, 10000]
+                },
+            },
+            messages: {
+                count: {
+                    required: "请输入生成数量",
+                    digits: "请输入数字",
+                    range: "数量范围为1-10000"
+                },
+            }
+        });
+
+        function submitHandler() {
+            if ($.validate.form()) {
+                $.operate.save(prefix + "/batchAdd", $('#form-num-batch-add').serialize());
+            }
+        }
+    </script>
+</body>
+</html>

+ 8 - 0
ruoyi-admin/src/main/resources/templates/cc/extnum/extnum.html

@@ -31,6 +31,9 @@
                 <a class="btn btn-success" onclick="$.operate.add()" shiro:hasPermission="cc:extnum:add">
                     <i class="fa fa-plus"></i> <span th:text="#{btn.add}"></span>
                 </a>
+                <a class="btn btn-info" onclick="batchAdd()" shiro:hasPermission="cc:extnum:batchAdd">
+                    <i class="fa fa-plus-circle"></i> 批量新增
+                </a>
                 <a class="btn btn-primary single disabled" onclick="$.operate.edit()" shiro:hasPermission="cc:extnum:edit">
                     <i class="fa fa-edit"></i> <span th:text="#{btn.edit}"></span>
                 </a>
@@ -86,6 +89,11 @@
             };
             $.table.init(options);
         });
+
+        // 批量新增分机
+        function batchAdd() {
+            $.modal.open("批量新增分机", prefix + "/batchAdd", '700', '500');
+        }
     </script>
 </body>
 </html>

+ 10 - 0
ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java

@@ -108,6 +108,16 @@ public class SysUser extends BaseEntity
 
     /** 分机密码 */
     private String extPass;
+
+    /** 分机绑定用户 */
+    private String userCode;
+    public String getUserCode() {
+        return userCode;
+    }
+
+    public void setUserCode(String userCode) {
+        this.userCode = userCode;
+    }
     public String getExtPass() {
         return extPass;
     }