Merge remote-tracking branch 'origin/test' into test

This commit is contained in:
wangw 2025-10-22 10:37:09 +08:00
commit 7e175d8c6d
11 changed files with 238 additions and 11 deletions

View File

@ -58,9 +58,8 @@ public class CouponRedemptionController {
*/
@SaAdminCheckPermission(value = "couponRedemption:detail", name = "券兑换码列表")
@GetMapping
public CzgResult<MkCouponRedemptionConfigVO> detail(@RequestParam Integer id) {
return CzgResult.success(configService.getOneAs(new QueryWrapper().eq(MkCouponRedemptionConfig::getId, id)
.eq(MkCouponRedemptionConfig::getMainShopId, StpKit.USER.getMainShopId()), MkCouponRedemptionConfigVO.class));
public CzgResult<MkCouponRedemptionConfigVO> detail(@RequestParam Long id) {
return CzgResult.success(configService.detail(StpKit.USER.getMainShopId(), id));
}
/**

View File

@ -0,0 +1,40 @@
package com.czg.controller.user;
import com.czg.market.dto.MkRedemptionDTO;
import com.czg.market.service.MkCouponRedemptionConfigService;
import com.czg.market.service.MkEnableConfigService;
import com.czg.market.service.MkRechargeRedemptionConfigService;
import com.czg.resp.CzgResult;
import com.czg.sa.StpKit;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
/**
*
* 兑换码相关
* @author Administrator
*/
@RestController
@RequestMapping("/user/redemption")
public class URedemptionController {
@Resource
private MkRechargeRedemptionConfigService rechargeRedemptionConfigService;
@Resource
private MkCouponRedemptionConfigService couponRedemptionConfigService;
/**
* 使用券码
*/
@PostMapping("/exchange")
public CzgResult<Boolean> exchange(@Validated @RequestBody MkRedemptionDTO dto) {
if ("recharge".equals(dto.getType())) {
rechargeRedemptionConfigService.exchange(StpKit.USER.getLoginIdAsLong(), dto);
}else {
couponRedemptionConfigService.exchange(StpKit.USER.getLoginIdAsLong(), dto);
}
return CzgResult.success();
}
}

View File

@ -0,0 +1,42 @@
package com.czg.market.dto;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serial;
import java.io.Serializable;
/**
*
* @author ww
* @since 2025-09-12
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class MkRedemptionDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* recharge充值码 coupon券兑换码
*/
@NotBlank(message = "类型不为空")
private String type;
/**
* 券码
*/
@NotBlank(message = "券码不为空")
private String code;
/**
* 门店id
*/
@NotNull(message = "门店不为空")
private Long shopId;
}

View File

@ -1,6 +1,7 @@
package com.czg.market.service;
import com.czg.market.dto.MkCouponRedemptionConfigDTO;
import com.czg.market.dto.MkRedemptionDTO;
import com.czg.market.vo.MkCouponRedemptionCodeVO;
import com.czg.market.vo.MkCouponRedemptionConfigVO;
import com.mybatisflex.core.paginate.Page;
@ -16,7 +17,7 @@ import jakarta.servlet.http.HttpServletResponse;
* @since 2025-10-22
*/
public interface MkCouponRedemptionConfigService extends IService<MkCouponRedemptionConfig> {
MkCouponRedemptionConfigVO detail(Long mainShopId);
MkCouponRedemptionConfigVO detail(Long mainShopId, Long id);
Boolean edit(Long shopId, MkCouponRedemptionConfigDTO dto);
@ -27,4 +28,6 @@ public interface MkCouponRedemptionConfigService extends IService<MkCouponRedemp
Page<MkCouponRedemptionCodeVO> codeList(Long mainShopId, Long id, String code, Integer status);
void exportCodeList(Long mainShopId, Long redemptionId, String code, Integer status, HttpServletResponse response, HttpServletRequest request);
void exchange(long userId, MkRedemptionDTO dto);
}

View File

@ -5,6 +5,7 @@ import com.czg.market.dto.MkEnableConfigDTO;
import com.czg.market.vo.MkEnableConfigVO;
import com.mybatisflex.core.service.IService;
import com.czg.market.entity.MkEnableConfig;
import jakarta.validation.constraints.NotNull;
/**
* 兑换码明细 服务层
@ -16,4 +17,6 @@ public interface MkEnableConfigService extends IService<MkEnableConfig> {
Boolean upEnable(Long mainShopId, Long shopId, MkEnableConfigDTO dto, TableValueConstant.EnableConfig.Type type);
MkEnableConfigVO detail(Long mainShopId, Long shopId, TableValueConstant.EnableConfig.Type type);
void checkEnable(Long mainShopId, @NotNull(message = "门店不为空") Long shopId, TableValueConstant.EnableConfig.Type type, boolean masterMange);
}

View File

@ -1,6 +1,7 @@
package com.czg.market.service;
import com.czg.market.dto.MkRechargeRedemptionConfigDTO;
import com.czg.market.dto.MkRedemptionDTO;
import com.czg.market.vo.MkRechargeRedemptionCodeVO;
import com.czg.market.vo.MkRechargeRedemptionConfigVO;
import com.mybatisflex.core.paginate.Page;
@ -28,4 +29,6 @@ public interface MkRechargeRedemptionConfigService extends IService<MkRechargeRe
Page<MkRechargeRedemptionCodeVO> codeList(Long mainShopId, Long id, String code, Integer status);
void exportCodeList(Long mainShopId, Long redemptionId, String code, Integer status, HttpServletResponse response, HttpServletRequest request);
void exchange(long userId, MkRedemptionDTO dto);
}

View File

@ -1,5 +1,6 @@
package com.czg.market.vo;
import com.czg.market.dto.CouponInfoDTO;
import com.czg.market.entity.MkRechargeRedemptionConfig;
import com.mybatisflex.annotation.Column;
import com.mybatisflex.annotation.Id;
@ -32,7 +33,7 @@ public class MkCouponRedemptionConfigVO implements Serializable {
/**
* 赠送金额
*/
private List<CouponInfoVO> couponInfoList;
private List<CouponInfoDTO> couponInfoList;
/**
* 优惠券数量
*/

View File

@ -30,6 +30,7 @@ public enum ShopUserFlowBizEnum {
// ADMIN_REFUND("adminRefund"),
//adminOut
ADMIN_OUT("adminOut", "管理员退款充值"),
RECHARGE_REDEMPTION("rechargeRedemption", "充值兑换码"),
//adminInOut
// ADMIN_IN_OUT("adminInOut"),
;

View File

@ -6,12 +6,24 @@ import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.alibaba.fastjson2.JSONArray;
import com.czg.account.dto.shopuser.ShopUserMoneyEditDTO;
import com.czg.account.entity.ShopUser;
import com.czg.account.service.ShopInfoService;
import com.czg.account.service.ShopUserService;
import com.czg.constant.TableValueConstant;
import com.czg.enums.ShopUserFlowBizEnum;
import com.czg.exception.CzgException;
import com.czg.market.dto.CouponInfoDTO;
import com.czg.market.dto.MkCouponRedemptionConfigDTO;
import com.czg.market.dto.MkRedemptionDTO;
import com.czg.market.dto.MkShopCouponGiftDTO;
import com.czg.market.entity.MkCouponRedemptionCode;
import com.czg.market.entity.MkCouponRedemptionConfig;
import com.czg.market.entity.MkRechargeRedemptionCode;
import com.czg.market.entity.MkRechargeRedemptionConfig;
import com.czg.market.service.MkCouponRedemptionCodeService;
import com.czg.market.service.MkEnableConfigService;
import com.czg.market.service.MkShopCouponRecordService;
import com.czg.market.vo.CouponInfoVO;
import com.czg.market.vo.MkCouponRedemptionConfigVO;
import com.czg.market.vo.MkCouponRedemptionCodeVO;
@ -26,7 +38,9 @@ import com.czg.service.market.mapper.MkCouponRedemptionConfigMapper;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
@ -42,18 +56,27 @@ import java.util.*;
public class MkCouponRedemptionConfigServiceImpl extends ServiceImpl<MkCouponRedemptionConfigMapper, MkCouponRedemptionConfig> implements MkCouponRedemptionConfigService{
@Resource
private MkCouponRedemptionCodeService codeService;
@Resource
private MkEnableConfigService enableConfigService;
@Resource
private MkShopCouponRecordService shopCouponRecordService;
@DubboReference
private ShopInfoService shopInfoService;
@DubboReference
private ShopUserService shopUserService;
@Override
public MkCouponRedemptionConfigVO detail(Long mainShopId) {
MkCouponRedemptionConfig redemptionConfig = getOne(new QueryWrapper().eq(MkCouponRedemptionConfig::getMainShopId, mainShopId));
public MkCouponRedemptionConfigVO detail(Long mainShopId, Long id) {
MkCouponRedemptionConfig redemptionConfig = getOne(new QueryWrapper().eq(MkCouponRedemptionConfig::getMainShopId, mainShopId).eq(MkCouponRedemptionConfig::getId, id));
if (redemptionConfig == null) {
return null;
}
MkCouponRedemptionConfigVO infoList = BeanUtil.copyProperties(redemptionConfig, MkCouponRedemptionConfigVO.class, "couponInfoList");
if (StrUtil.isNotBlank(redemptionConfig.getCouponInfoList())) {
infoList.setCouponInfoList(JSONArray.parseArray(redemptionConfig.getCouponInfoList(), CouponInfoVO.class));
infoList.setCouponInfoList(JSONArray.parseArray(redemptionConfig.getCouponInfoList(), CouponInfoDTO.class));
}
return infoList;
@ -82,8 +105,8 @@ public class MkCouponRedemptionConfigServiceImpl extends ServiceImpl<MkCouponRed
MkCouponRedemptionConfigVO config = BeanUtil.copyProperties(item, MkCouponRedemptionConfigVO.class, "couponInfoList");
if (StrUtil.isNotBlank(item.getCouponInfoList())) {
config.setCouponInfoList(JSONArray.parseArray(item.getCouponInfoList(), CouponInfoVO.class));
config.setCouponNum(config.getCouponInfoList().stream().map(CouponInfoVO::getNum).reduce(0, Integer::sum));
config.setCouponInfoList(JSONArray.parseArray(item.getCouponInfoList(), CouponInfoDTO.class));
config.setCouponNum(config.getCouponInfoList().stream().map(CouponInfoDTO::getNum).reduce(0, Integer::sum));
}
configList.add(config);
});
@ -199,6 +222,50 @@ public class MkCouponRedemptionConfigServiceImpl extends ServiceImpl<MkCouponRed
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void exchange(long userId, MkRedemptionDTO dto) {
Long mainShopId = shopInfoService.getMainIdByShopId(dto.getShopId());
enableConfigService.checkEnable(mainShopId, dto.getShopId(), TableValueConstant.EnableConfig.Type.RECHARGE_REDEMPTION, true);
ShopUser shopUserInfo = shopUserService.getShopUserInfo(dto.getShopId(), userId);
MkCouponRedemptionCode redemptionCode = codeService.getOne(new QueryWrapper().eq(MkCouponRedemptionCode::getMainShopId, mainShopId).eq(MkCouponRedemptionCode::getCode, dto.getCode()));
AssertUtil.isNull(redemptionCode, "兑换码不存在");
AssertUtil.isTrue(redemptionCode.getStatus() != 0, "兑换码不存在");
MkCouponRedemptionConfigVO config = detail(mainShopId, redemptionCode.getId());
AssertUtil.isNull(config, "兑换配置不存在");
AssertUtil.isTrue(config.getStock() <= 0, "兑换码可兑换库存不足");
if (config.getStartTime() != null) {
AssertUtil.isTrue(config.getStartTime().isAfter(DateUtil.date().toLocalDateTime()), "兑换活动未开始");
}
if (config.getEndTime() != null) {
AssertUtil.isTrue(config.getEndTime().isBefore(DateUtil.date().toLocalDateTime()), "兑换活动已结束");
}
if (config.getCouponInfoList() != null && !config.getCouponInfoList().isEmpty()) {
config.getCouponInfoList().forEach(item -> {
MkShopCouponGiftDTO giftDTO = new MkShopCouponGiftDTO().setCouponId(item.getId())
.setShopId(mainShopId)
.setSourceId(redemptionCode.getId())
.setShopUserId(shopUserInfo.getId())
.setSource("兑换码兑换");
shopCouponRecordService.receiveCoupon(giftDTO, item.getNum(), false);
});
}
redemptionCode.setStatus(1);
redemptionCode.setUserId(shopUserInfo.getUserId());
redemptionCode.setShopUserId(shopUserInfo.getId());
redemptionCode.setRedemptionTime(DateUtil.date().toLocalDateTime());
codeService.updateById(redemptionCode);
boolean update = updateChain().eq(MkRechargeRedemptionConfig::getId, config.getId()).setRaw(MkRechargeRedemptionConfig::getStock, "stock - 1")
.where("stock - 1 >= 0").update();
AssertUtil.isTrue(!update, "库存不足");
}
}

View File

@ -5,6 +5,7 @@ import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.czg.constant.TableValueConstant;
import com.czg.exception.CzgException;
import com.czg.market.dto.MkEnableConfigDTO;
import com.czg.market.vo.MkEnableConfigVO;
import com.mybatisflex.core.query.QueryWrapper;
@ -62,4 +63,12 @@ public class MkEnableConfigServiceImpl extends ServiceImpl<MkEnableConfigMapper,
one.setUseType(dto.getUseType());
return updateById(one);
}
@Override
public void checkEnable(Long mainShopId, Long shopId, TableValueConstant.EnableConfig.Type type, boolean masterMange) {
MkEnableConfigVO detail = detail(mainShopId, shopId, type);
if (detail.getIsEnable() != 1) {
throw new CzgException("模块未开启");
}
}
}

View File

@ -6,10 +6,18 @@ import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.czg.account.dto.shopuser.ShopUserMoneyEditDTO;
import com.czg.account.entity.ShopUser;
import com.czg.account.service.ShopInfoService;
import com.czg.account.service.ShopUserService;
import com.czg.account.service.UserInfoService;
import com.czg.constant.TableValueConstant;
import com.czg.enums.ShopUserFlowBizEnum;
import com.czg.exception.CzgException;
import com.czg.market.dto.MkRechargeRedemptionConfigDTO;
import com.czg.market.dto.MkRedemptionDTO;
import com.czg.market.entity.MkRechargeRedemptionCode;
import com.czg.market.service.MkEnableConfigService;
import com.czg.market.service.MkRechargeRedemptionCodeService;
import com.czg.market.vo.MkRechargeRedemptionCodeVO;
import com.czg.market.vo.MkRechargeRedemptionConfigVO;
@ -25,7 +33,9 @@ import com.czg.service.market.mapper.MkRechargeRedemptionConfigMapper;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
@ -41,6 +51,14 @@ import java.util.*;
public class MkRechargeRedemptionConfigServiceImpl extends ServiceImpl<MkRechargeRedemptionConfigMapper, MkRechargeRedemptionConfig> implements MkRechargeRedemptionConfigService{
@Resource
private MkRechargeRedemptionCodeService codeService;
@Resource
private MkEnableConfigService enableConfigService;
@DubboReference
private ShopInfoService shopInfoService;
@DubboReference
private ShopUserService shopUserService;
/**
* 生成指定活动的兑换码集合
@ -229,8 +247,49 @@ public class MkRechargeRedemptionConfigServiceImpl extends ServiceImpl<MkRecharg
// 5. 输出到浏览器
writer.flush(response.getOutputStream(), true);
} catch (Exception e) {
throw new RuntimeException(e);
throw new RuntimeException(e);
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void exchange(long userId, MkRedemptionDTO dto) {
Long mainShopId = shopInfoService.getMainIdByShopId(dto.getShopId());
enableConfigService.checkEnable(mainShopId, dto.getShopId(), TableValueConstant.EnableConfig.Type.RECHARGE_REDEMPTION, true);
ShopUser shopUserInfo = shopUserService.getShopUserInfo(dto.getShopId(), userId);
MkRechargeRedemptionCode redemptionCode = codeService.getOne(new QueryWrapper().eq(MkRechargeRedemptionCode::getMainShopId, mainShopId).eq(MkRechargeRedemptionCode::getCode, dto.getCode()));
AssertUtil.isNull(redemptionCode, "兑换码不存在");
AssertUtil.isTrue(redemptionCode.getStatus() != 0, "兑换码不存在");
MkRechargeRedemptionConfig config = getOne(new QueryWrapper().eq(MkRechargeRedemptionConfig::getId, redemptionCode.getRedemptionId()).eq(MkRechargeRedemptionConfig::getMainShopId, mainShopId));
AssertUtil.isNull(config, "兑换配置不存在");
AssertUtil.isTrue(config.getStock() <= 0, "兑换码可兑换库存不足");
if (config.getStartTime() != null) {
AssertUtil.isTrue(config.getStartTime().isAfter(DateUtil.date().toLocalDateTime()), "兑换活动未开始");
}
if (config.getEndTime() != null) {
AssertUtil.isTrue(config.getEndTime().isBefore(DateUtil.date().toLocalDateTime()), "兑换活动已结束");
}
ShopUserMoneyEditDTO shopUserMoneyEditDTO = new ShopUserMoneyEditDTO()
.setId(shopUserInfo.getId())
.setMoney(config.getAmount())
.setType(1)
.setBizEnum(ShopUserFlowBizEnum.RECHARGE_REDEMPTION)
.setRelationId(redemptionCode.getId());
shopUserService.updateMoney(shopUserMoneyEditDTO);
redemptionCode.setStatus(1);
redemptionCode.setUserId(shopUserInfo.getUserId());
redemptionCode.setShopUserId(shopUserInfo.getId());
redemptionCode.setRedemptionTime(DateUtil.date().toLocalDateTime());
codeService.updateById(redemptionCode);
boolean update = updateChain().eq(MkRechargeRedemptionConfig::getId, config.getId()).setRaw(MkRechargeRedemptionConfig::getStock, "stock - 1")
.where("stock - 1 >= 0").update();
AssertUtil.isTrue(!update, "库存不足");
}
}