doum
11 小时以前 11e35e0257e48667292b4f563ddf6ce02a3a22bb
Merge remote-tracking branch 'origin/master'
已添加1个文件
已修改13个文件
384 ■■■■■ 文件已修改
server/dmmall_service/src/main/java/com/doumee/core/utils/Constants.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/dmmall_service/src/main/java/com/doumee/core/utils/UniqueVerificationCodeGenerator.java 255 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/dmmall_service/src/main/java/com/doumee/service/business/GoodsorderService.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/dmmall_service/src/main/java/com/doumee/service/business/MemberService.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/dmmall_service/src/main/java/com/doumee/service/business/impl/ActivityServiceImpl.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/dmmall_service/src/main/java/com/doumee/service/business/impl/AddrServiceImpl.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/dmmall_service/src/main/java/com/doumee/service/business/impl/AftersaleServiceImpl.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/dmmall_service/src/main/java/com/doumee/service/business/impl/GoodsorderServiceImpl.java 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/dmmall_service/src/main/java/com/doumee/service/business/impl/MemberServiceImpl.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/dmmall_service/src/main/java/com/doumee/service/business/impl/ShopServiceImpl.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/dmmall_service/src/main/java/com/doumee/service/business/impl/ShopcartServiceImpl.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/dmmall_service/src/main/java/com/doumee/task/ScheduleTool.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/dmmall_web/src/main/java/com/doumee/api/web/AccountApi.java 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/dmmall_web/src/main/java/com/doumee/api/web/mall/PaymentCallback.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/dmmall_service/src/main/java/com/doumee/core/utils/Constants.java
@@ -168,6 +168,7 @@
        public static final String ACTIVITY_SIGN_KEY = "actcode_";
        public static final String AFTERSALE_KEY = "salecode_";
        public static final String WITHDRAW_KEY = "withdraw_";
        public static final String EXCHANGE_KEY = "exchange_";
    }
    /**
     * ä¼ä¸šæ•°æ®æ¥æº 0平台注册 1后台导入
server/dmmall_service/src/main/java/com/doumee/core/utils/UniqueVerificationCodeGenerator.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,255 @@
package com.doumee.core.utils;
import java.security.SecureRandom;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.ThreadLocalRandom;
import java.util.List;
import java.util.ArrayList;
/**
 * ä¸é‡å¤æ ¸é”€ç ç”Ÿæˆå™¨
 * ç”¨äºŽç”Ÿæˆå”¯ä¸€ä¸”易于识别的核销码
 */
public class UniqueVerificationCodeGenerator {
    private final Set<String> usedCodes;
    private final int codeLength;
    private final String prefix;
    private final String suffix;
    private final Random random;
    private final boolean useSecureRandom;
    private final CodeFormat format;
    // æ ¸é”€ç æ ¼å¼æžšä¸¾
    public enum CodeFormat {
        NUMERIC_ONLY("0123456789"),
        ALPHANUMERIC("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"),
        LETTERS_ONLY("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
        private final String characters;
        CodeFormat(String characters) {
            this.characters = characters;
        }
        public String getCharacters() {
            return characters;
        }
    }
    /**
     * æž„造函数 - é»˜è®¤æ•°å­—格式
     * @param codeLength æ ¸é”€ç é•¿åº¦
     */
    public UniqueVerificationCodeGenerator(int codeLength) {
        this(codeLength, "", "", CodeFormat.NUMERIC_ONLY, false);
    }
    /**
     * æž„造函数 - å®Œæ•´é…ç½®
     * @param codeLength æ ¸é”€ç é•¿åº¦
     * @param prefix å‰ç¼€
     * @param suffix åŽç¼€
     * @param format æ ¸é”€ç æ ¼å¼
     * @param useSecureRandom æ˜¯å¦ä½¿ç”¨å®‰å…¨éšæœºæ•°ç”Ÿæˆå™¨
     */
    public UniqueVerificationCodeGenerator(int codeLength, String prefix, String suffix,
                                         CodeFormat format, boolean useSecureRandom) {
        if (codeLength < 1) {
            throw new IllegalArgumentException("核销码长度必须大于0");
        }
        this.codeLength = codeLength;
        this.prefix = prefix != null ? prefix : "";
        this.suffix = suffix != null ? suffix : "";
        this.format = format;
        this.usedCodes = new HashSet<>();
        this.useSecureRandom = useSecureRandom;
        this.random = useSecureRandom ? new SecureRandom() : ThreadLocalRandom.current();
    }
    /**
     * ç”Ÿæˆä¸‹ä¸€ä¸ªä¸é‡å¤çš„æ ¸é”€ç 
     * @return æ ¸é”€ç ï¼Œå¦‚果没有可用组合则返回null
     */
    public String nextUniqueCode() {
        int maxAttempts = 1000;
        int attempts = 0;
        while (attempts < maxAttempts) {
            String code = generateCode();
            if (!usedCodes.contains(code)) {
                usedCodes.add(code);
                return code;
            }
            attempts++;
        }
        // å¦‚果随机生成失败,尝试顺序生成
        return generateSequentialCode();
    }
    /**
     * ç”ŸæˆæŒ‡å®šæ•°é‡çš„不重复核销码
     * @param count æ•°é‡
     * @return æ ¸é”€ç åˆ—表
     */
    public List<String> nextUniqueCodes(int count) {
        List<String> result = new ArrayList<>();
        for (int i = 0; i < count; i++) {
            String code = nextUniqueCode();
            if (code == null) {
                break; // æ²¡æœ‰æ›´å¤šå¯ç”¨ç»„合
            }
            result.add(code);
        }
        return result;
    }
    /**
     * ç”Ÿæˆå•个核销码(不检查重复)
     * @return æ ¸é”€ç 
     */
    private String generateCode() {
        StringBuilder sb = new StringBuilder();
        sb.append(prefix);
        String characters = format.getCharacters();
        for (int i = 0; i < codeLength; i++) {
            int index = random.nextInt(characters.length());
            sb.append(characters.charAt(index));
        }
        sb.append(suffix);
        return sb.toString();
    }
    /**
     * é¡ºåºç”Ÿæˆæ ¸é”€ç ï¼ˆä½œä¸ºå¤‡é€‰æ–¹æ¡ˆï¼‰
     */
    private String generateSequentialCode() {
        String characters = format.getCharacters();
        long totalCombinations = (long) Math.pow(characters.length(), codeLength);
        if (usedCodes.size() >= totalCombinations) {
            return null; // æ‰€æœ‰å¯èƒ½ç»„合都已使用
        }
        // å¯»æ‰¾ä¸‹ä¸€ä¸ªæœªä½¿ç”¨çš„组合
        for (long i = 0; i < totalCombinations; i++) {
            String code = convertToCode(i, characters);
            String fullCode = prefix + code + suffix;
            if (!usedCodes.contains(fullCode)) {
                usedCodes.add(fullCode);
                return fullCode;
            }
        }
        return null;
    }
    /**
     * å°†æ•°å­—转换为指定字符集的编码
     */
    private String convertToCode(long number, String characters) {
        StringBuilder sb = new StringBuilder();
        long base = characters.length();
        for (int i = 0; i < codeLength; i++) {
            sb.append(characters.charAt((int) (number % base)));
            number /= base;
        }
        return sb.reverse().toString();
    }
    /**
     * é‡ç½®ç”Ÿæˆå™¨
     */
    public void reset() {
        usedCodes.clear();
    }
    /**
     * èŽ·å–å·²ä½¿ç”¨çš„æ ¸é”€ç æ•°é‡
     */
    public int getUsedCount() {
        return usedCodes.size();
    }
    /**
     * æ£€æŸ¥æ˜¯å¦è¿˜æœ‰å¯ç”¨çš„æ ¸é”€ç ç»„合
     */
    public boolean hasMoreCodes() {
        String characters = format.getCharacters();
        long totalCombinations = (long) Math.pow(characters.length(), codeLength);
        return usedCodes.size() < totalCombinations;
    }
    // ==================== é™æ€ä¾¿æ·æ–¹æ³• ====================
    /**
     * ç”Ÿæˆæ•°å­—型核销码(默认6位)
     */
    public static String generateNumericCode() {
        return generateNumericCode(6);
    }
    /**
     * ç”ŸæˆæŒ‡å®šé•¿åº¦çš„æ•°å­—型核销码
     */
    public static String generateNumericCode(int length) {
        UniqueVerificationCodeGenerator generator =
            new UniqueVerificationCodeGenerator(length, "", "", CodeFormat.NUMERIC_ONLY, true);
        return generator.nextUniqueCode();
    }
    /**
     * æ‰¹é‡ç”Ÿæˆæ•°å­—型核销码
     */
    public static List<String> generateNumericCodes(int length, int count) {
        UniqueVerificationCodeGenerator generator =
            new UniqueVerificationCodeGenerator(length, "", "", CodeFormat.NUMERIC_ONLY, true);
        return generator.nextUniqueCodes(count);
    }
    /**
     * ç”Ÿæˆå¸¦å‰ç¼€çš„æ ¸é”€ç 
     */
    public static String generatePrefixedCode(String prefix, int length) {
        UniqueVerificationCodeGenerator generator =
            new UniqueVerificationCodeGenerator(length, prefix, "", CodeFormat.NUMERIC_ONLY, true);
        return generator.nextUniqueCode();
    }
    /**
     * ç”Ÿæˆå­—母数字混合核销码
     */
    public static String generateAlphanumericCode(int length) {
        UniqueVerificationCodeGenerator generator =
            new UniqueVerificationCodeGenerator(length, "", "", CodeFormat.ALPHANUMERIC, true);
        return generator.nextUniqueCode();
    }
    /**
     * ç”Ÿæˆè®¢å•号格式的核销码(如:ORD20241201XXXXXX)
     */
    public static String generateOrderCode(String prefix) {
        String datePart = java.time.LocalDateTime.now().format(
            java.time.format.DateTimeFormatter.ofPattern("yyyyMMdd"));
        UniqueVerificationCodeGenerator generator =
            new UniqueVerificationCodeGenerator(6, prefix + datePart, "", CodeFormat.NUMERIC_ONLY, true);
        return generator.nextUniqueCode();
    }
    /**
     * ç”Ÿæˆä¼˜æƒ åˆ¸ç æ ¼å¼ï¼ˆå¦‚:COUPON-XXXXXX)
     */
    public static String generateCouponCode() {
        UniqueVerificationCodeGenerator generator =
            new UniqueVerificationCodeGenerator(8, "COUPON-", "", CodeFormat.ALPHANUMERIC, true);
        return generator.nextUniqueCode();
    }
}
server/dmmall_service/src/main/java/com/doumee/service/business/GoodsorderService.java
@@ -239,4 +239,7 @@
    void orderRefund(Goodsorder goodsorder);
    String createExchangeCode();
}
server/dmmall_service/src/main/java/com/doumee/service/business/MemberService.java
@@ -130,7 +130,7 @@
    AccountResponse wxLogin(String code);
//    AccountResponse wxLoginTest( Integer recId);
    AccountResponse wxLoginTest( Integer memberId);
    /**
server/dmmall_service/src/main/java/com/doumee/service/business/impl/ActivityServiceImpl.java
@@ -1117,8 +1117,9 @@
                .eq(Activity::getStatus,Constants.ZERO)
                .eq(Objects.nonNull(model.getLabelId()),Activity::getLabelId,model.getLabelId())
                .eq(Objects.nonNull(model.getBrandId()),Activity::getBrandId,model.getBrandId())
                .like(StringUtils.isNotBlank(model.getInfo()),Activity::getContent,model.getInfo())
                .orderByDesc(Labels::getId)
                .and(StringUtils.isNotBlank(model.getInfo()),i->i.like(Activity::getContent,model.getInfo()).or()
                        .like(Activity::getName,model.getInfo()))
                .orderByDesc(Activity::getId)
        ;
        queryWrapper.orderByDesc(Activity::getCreateDate);
        IPage<Activity> activityIPage = activityJoinMapper.selectJoinPage(page, Activity.class, queryWrapper);
server/dmmall_service/src/main/java/com/doumee/service/business/impl/AddrServiceImpl.java
@@ -1,5 +1,7 @@
package com.doumee.service.business.impl;
import com.doumee.core.constants.ResponseStatus;
import com.doumee.core.exception.BusinessException;
import com.doumee.core.model.PageData;
import com.doumee.core.model.PageWrap;
import com.doumee.core.utils.Constants;
@@ -41,7 +43,15 @@
    @Override
    public Integer create(AddrDTO addrDTO,Integer memberId) {
        if(Objects.isNull(addrDTO)
        || StringUtils.isBlank(addrDTO.getAddr())
        || StringUtils.isBlank(addrDTO.getName())
        || StringUtils.isBlank(addrDTO.getPhone())
        || Objects.isNull(addrDTO.getAreaId())
        || Objects.isNull(addrDTO.getIsDefault())
        ){
            throw new BusinessException(ResponseStatus.BAD_REQUEST);
        }
        Addr addr = new Addr();
        addr.setMemberId(memberId);
        addr.setIsDefault(addrDTO.getIsDefault());
@@ -165,6 +175,16 @@
    @Override
    public void update(AddrDTO addrDTO) {
        if(Objects.isNull(addrDTO)
                || StringUtils.isBlank(addrDTO.getAddr())
                || StringUtils.isBlank(addrDTO.getName())
                || StringUtils.isBlank(addrDTO.getPhone())
                || Objects.isNull(addrDTO.getAreaId())
                || Objects.isNull(addrDTO.getIsDefault())
                || Objects.isNull(addrDTO.getId())
        ){
            throw new BusinessException(ResponseStatus.BAD_REQUEST);
        }
        //存在设置
        if (Objects.nonNull(addrDTO.getIsDefault())
                && Constants.equalsInteger(addrDTO.getIsDefault(),Constants.ONE)){
server/dmmall_service/src/main/java/com/doumee/service/business/impl/AftersaleServiceImpl.java
@@ -1173,6 +1173,10 @@
                .eq(Goodsorder::getId, goodsorder.getId())
        );
        //释放核销码
        if(Constants.equalsInteger(goodsorder.getReceiveType(),Constants.ONE)&&StringUtils.isNotBlank(goodsorder.getExchangeCode())){
            RedisUtil.deleteObject(redisTemplate,Constants.RedisKeys.EXCHANGE_KEY+goodsorder.getExchangeCode());
        }
    }
server/dmmall_service/src/main/java/com/doumee/service/business/impl/GoodsorderServiceImpl.java
@@ -1205,6 +1205,10 @@
        goodsorder.setCancelInfo(cancelInfo);
        goodsorder.setCancelUser(optUserId);
        goodsorderMapper.updateById(goodsorder);
        if(Constants.equalsInteger(goodsorder.getReceiveType(),Constants.ONE)){
            //释放核销码
            this.releaseExchangeCode(goodsorder.getExchangeCode());
        }
        String goodsName = "";
        List<GoodsorderDetail> goodsorderDetailList =  goodsorderDetailMapper.selectList(new QueryWrapper<GoodsorderDetail>().eq("ORDER_ID",goodsorder.getId()));
        if(!Objects.isNull(goodsorderDetailList)&&goodsorderDetailList.size()>Constants.ZERO){
@@ -1282,6 +1286,10 @@
        goodsorder.setCancelInfo(StringUtils.isBlank(cancelInfo)?"用户主动取消":cancelInfo);
        goodsorder.setCancelUser(optUserId);
        goodsorderMapper.updateById(goodsorder);
        if(Constants.equalsInteger(goodsorder.getReceiveType(),Constants.ONE)){
            //释放核销码
            this.releaseExchangeCode(goodsorder.getExchangeCode());
        }
        String goodsName = "";
        List<GoodsorderDetail> goodsorderDetailList =  goodsorderDetailMapper.selectList(new QueryWrapper<GoodsorderDetail>().eq("ORDER_ID",goodsorder.getId()));
        if(!Objects.isNull(goodsorderDetailList)&&goodsorderDetailList.size()>Constants.ZERO){
@@ -1311,8 +1319,6 @@
                memberCouponMapper.updateById(memberCoupon);
            }
        }
    }
    public BigDecimal getDeductAmount(List<PayDetailRequest> requestList){
@@ -1777,6 +1783,8 @@
        goodsorder.setStatus(Constants.OrderStatus.DONE.getKey());
        goodsorder.setDoneDate(new Date());
        goodsorderMapper.updateById(goodsorder);
        //释放核销码
        this.releaseExchangeCode(goodsorder.getExchangeCode());
        //存在现金支付 èµ é€ ç§¯åˆ†
        if(Constants.equalsInteger(goodsorder.getPayMethod(),Constants.ZERO)){
            //赠送消费者积分
@@ -1911,8 +1919,6 @@
        if(!goodsorder.getStatus().equals(Constants.OrderStatus.DONE.getKey())){
            throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"操作失败:订单未完成,无法退款!");
        }
    }
@@ -2222,4 +2228,39 @@
    @Override
    public String createExchangeCode(){
        List<Goodsorder> goodsorderList = goodsorderMapper.selectList(new QueryWrapper<Goodsorder>().lambda()
                .eq(Goodsorder::getIsdeleted,Constants.ZERO)
                .eq(Goodsorder::getReceiveType,Constants.ONE)
                .in(Goodsorder::getStatus,Constants.OrderStatus.WAIT_RECEIVE.getKey(),
                Constants.OrderStatus.WAIT_PAY.getKey(),
                Constants.OrderStatus.PAY_DONE.getKey())
        );
        String exchangeCode = UniqueVerificationCodeGenerator.generateNumericCode();
        if(CollectionUtils.isNotEmpty(goodsorderList)){
            Boolean flag = true;
            while (flag){
                String finalExchangeCode = exchangeCode;
                flag = goodsorderList.stream().filter(i->i.getExchangeCode().equals(finalExchangeCode)).count()>0L?true:false;
                if(flag){
                    exchangeCode = UniqueVerificationCodeGenerator.generateNumericCode();
                }
            }
        }
        RedisUtil.addObject(redisTemplate,Constants.RedisKeys.EXCHANGE_KEY+exchangeCode,exchangeCode);
        return exchangeCode;
    }
    /**
     * é‡Šæ”¾æ ¸é”€ç 
     * @param code
     */
    public void releaseExchangeCode(String code){
        if(StringUtils.isNotBlank(code)){
            RedisUtil.deleteObject(redisTemplate,Constants.RedisKeys.EXCHANGE_KEY+code);
        }
    }
}
server/dmmall_service/src/main/java/com/doumee/service/business/impl/MemberServiceImpl.java
@@ -339,6 +339,17 @@
    @Override
    public AccountResponse wxLoginTest(Integer memberId){
        Member member = memberMapper.selectById(memberId);
        AccountResponse accountResponse = new AccountResponse();
        String token = JwtTokenUtil.generateTokenForRedis(member.getId(), Constants.ZERO, JSONObject.toJSONString(member), redisTemplate);
        accountResponse.setToken(token);
        accountResponse.setMember(member);
        return accountResponse;
    }
    @Override
    @Transactional(rollbackFor = {Exception.class,BusinessException.class})
    public AccountResponse wxPhone(WxPhoneRequest wxPhoneRequest){
        try {
server/dmmall_service/src/main/java/com/doumee/service/business/impl/ShopServiceImpl.java
@@ -712,7 +712,9 @@
                .selectAll(Shop.class)
                .select(" CONVERT( ST_Distance_Sphere ( POINT ( LONGITUDE, LATITUDE ), POINT ( '"+dto.getLgt()+"' , '"+dto.getLat()+"' )) /1000,DECIMAL(15,2))",Shop::getDistance)
                .leftJoin(SystemUser.class,SystemUser::getId,Shop::getCreator)
                .like(StringUtils.isNotBlank(dto.getCityName()),Shop::getAddr,dto.getCityName())
                .leftJoin("areas a1 on a1.id=t.area_id")
                .leftJoin("areas a2 on a2.id=a1.parent_id")
                .like(StringUtils.isNotBlank(dto.getCityName()),"a2.name",dto.getCityName())
                .like(StringUtils.isNotBlank(dto.getShopName()),Shop::getName,dto.getShopName())
                .orderByDesc(!isArea,Shop::getId)
                .orderByAsc(isArea," distance ")
server/dmmall_service/src/main/java/com/doumee/service/business/impl/ShopcartServiceImpl.java
@@ -234,13 +234,6 @@
                .eq("MEMBER_ID",addCartGoodsRequest.getMemberId())
                .eq("GOODS_SKU_ID",addCartGoodsRequest.getGoodsSkuId())
        );
//        Goods goods = goodsMapper.selectById(addCartGoodsRequest.getGoodsId());
//        if(Objects.isNull(goods)){
//            throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(),"未查询到商品信息");
//        }
//        if(!goods.getType().equals(Constants.ZERO)){
//            throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(),"非商城商品无法加入购物车");
//        }
        GoodsSku goodsSku = goodsSkuMapper.selectById(addCartGoodsRequest.getGoodsSkuId());
        if(Objects.isNull(goodsSku)){
            throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(),"未查询到商品SKU信息");
server/dmmall_service/src/main/java/com/doumee/task/ScheduleTool.java
@@ -40,6 +40,7 @@
    @Autowired
    private AreasService areasService;
//    @Autowired
//    private AftersaleService aftersaleService;
//
server/dmmall_web/src/main/java/com/doumee/api/web/AccountApi.java
@@ -59,14 +59,14 @@
        return  ApiResponse.success(memberService.wxPhone(wxPhoneRequest));
    }
//    @ApiOperation(value = "测试登陆接口", notes = "小程序端")
//    @GetMapping("/testLogin")
//    @ApiImplicitParams({
//            @ApiImplicitParam(paramType = "query", dataType = "Integer", name = "memberId", value = "用户编码", required = false)
//    })
//    public ApiResponse testLogin(@RequestParam   Integer memberId) {
//        return  ApiResponse.success(memberService.wxLoginTest(memberId));
//    }
    @ApiOperation(value = "测试登陆接口", notes = "小程序端")
    @GetMapping("/testLogin")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", dataType = "Integer", name = "memberId", value = "用户编码", required = false)
    })
    public ApiResponse testLogin(@RequestParam  Integer memberId) {
        return  ApiResponse.success(memberService.wxLoginTest(memberId));
    }
    @ApiOperation(value = "获取系统配置", notes = "小程序端")
    @GetMapping("/getPlatformAboutUs")
server/dmmall_web/src/main/java/com/doumee/api/web/mall/PaymentCallback.java
@@ -115,7 +115,9 @@
                        goodsOrder.setPayOrderId(paymentNo);
                        goodsOrder.setStatus(Constants.OrderStatus.PAY_DONE.getKey());
                        //生成核销码
                        goodsOrder.setExchangeCode(Constants.equalsInteger(goodsOrder.getReceiveType(),Constants.ZERO)?null:Constants.getRandomNumber());
                        if(Constants.equalsInteger(goodsOrder.getReceiveType(),Constants.ONE)){
                            goodsOrder.setExchangeCode(goodsorderService.createExchangeCode());
                        }
                        goodsOrder.setPayMethod(Constants.ZERO);
                        goodsorderService.updateById(goodsOrder);
                        if(Objects.nonNull(goodsOrder.getPickUpShopId())){