模板名称 异步发放优惠券

This commit is contained in:
wangw 2025-10-17 11:28:24 +08:00
parent 17d872e7c4
commit 0afcba22df
6 changed files with 167 additions and 17 deletions

View File

@ -3,11 +3,10 @@ package com.czg.account.service;
import com.czg.account.dto.shopuser.*;
import com.czg.account.entity.ShopUser;
import com.czg.market.entity.SmsPushEventUser;
import com.czg.resp.CzgResult;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.service.IService;
import java.math.BigDecimal;
import java.util.List;
/**
* 商户储值会员 服务层
@ -22,6 +21,8 @@ public interface AShopUserService {
Page<ShopUserDTO> getPage(String key, Integer isVip, BigDecimal amount);
Page<ShopUser> getPushEventUser(SmsPushEventUser smsPushEventUser);
List<ShopUser> getPushEventUserList(SmsPushEventUser smsPushEventUser);
Boolean add(Long shopId, ShopUserAddDTO shopUserAddDTO);
Boolean updateInfo(Long shopId, ShopUserEditDTO shopUserEditDTO);

View File

@ -1,6 +1,7 @@
package com.czg.market.service;
import com.czg.account.dto.QueryReceiveDto;
import com.czg.account.entity.ShopUser;
import com.czg.account.vo.CouponReceiveVo;
import com.czg.account.vo.UserCouponVo;
import com.czg.market.dto.MkRewardCouponDTO;
@ -47,6 +48,13 @@ public interface MkShopCouponRecordService extends IService<MkShopCouponRecord>
*/
void receiveCoupon(MkShopCouponGiftDTO giftDTO, Integer number, boolean isLimit);
/**
* 发放券 批量发放 不计限领
* 检查优惠券状态 检查店铺ID是否存在且与发放店铺一致 检查优惠券是否失效
* @param giftDTO sourceFlowId shopUserId外 全必填 如果有 也填
* @param number 发放数量
*/
void batchReceiveCoupon(MkShopCouponGiftDTO giftDTO, Integer number, List<ShopUser> userList);
/**
* 用户优惠券 失效/删除

View File

@ -35,6 +35,7 @@ import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
@ -102,12 +103,23 @@ public class AShopUserServiceImpl implements AShopUserService {
List<ShopUser> shopUsers = shopUserMapper.selectPushEventUser(mainShopId,
smsPushEventUser.getShopId(), smsPushEventUser);
return PageUtil.convert(new PageInfo<>(shopUsers));
}catch (Exception e){
} catch (Exception e) {
log.info("获取营销推送任务用户列表失败{},{}", smsPushEventUser, e.getMessage());
return PageUtil.convert(new PageInfo<>());
}
}
@Override
public List<ShopUser> getPushEventUserList(SmsPushEventUser smsPushEventUser) {
List<Long> shopUserIds = new ArrayList<>();
Long mainShopId = shopInfoService.getMainIdByShopId(smsPushEventUser.getShopId());
smsPushEventUser.checkIsAll();
// 调用Mapper层查询
List<ShopUser> shopUsers = shopUserMapper.selectPushEventUser(mainShopId,
smsPushEventUser.getShopId(), smsPushEventUser);
return shopUsers;
}
@Override
public Boolean updateInfo(Long shopId, ShopUserEditDTO shopUserEditDTO) {
if (StrUtil.isNotBlank(shopUserEditDTO.getPhone())) {

View File

@ -1,11 +1,9 @@
package com.czg.service.market.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONObject;
import com.czg.account.dto.QueryReceiveDto;
import com.czg.account.entity.PictureGallery;
import com.czg.account.entity.ShopInfo;
import com.czg.account.entity.ShopUser;
import com.czg.account.entity.UserInfo;
@ -21,7 +19,6 @@ import com.czg.market.dto.MkShopCouponRecordDTO;
import com.czg.market.entity.MkShopCouponRecord;
import com.czg.market.entity.ShopCoupon;
import com.czg.market.service.MkShopCouponRecordService;
import com.czg.market.service.ShopCouponService;
import com.czg.market.vo.UserCouponVO;
import com.czg.service.market.mapper.MkShopCouponRecordMapper;
import com.czg.service.market.mapper.ShopCouponMapper;
@ -30,7 +27,6 @@ import com.czg.utils.CzgStrUtils;
import com.czg.utils.PageUtil;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.update.UpdateWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import org.apache.dubbo.config.annotation.DubboReference;
@ -39,10 +35,8 @@ import org.apache.dubbo.config.annotation.DubboService;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.temporal.ChronoUnit;
import java.util.HashMap;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* 优惠券发放记录表 服务层实现
@ -126,6 +120,7 @@ public class MkShopCouponRecordServiceImpl extends ServiceImpl<MkShopCouponRecor
}
return recordPage;
}
@Override
public Page<MkShopCouponRecordDTO> getConsumerRecord(MkShopCouponRecordDTO mkShopCouponRecordDTO, String startTime, String endTime) {
QueryWrapper recordQueryWrapper = new QueryWrapper();
@ -276,6 +271,93 @@ public class MkShopCouponRecordServiceImpl extends ServiceImpl<MkShopCouponRecor
}
@Override
public void batchReceiveCoupon(MkShopCouponGiftDTO giftDTO, Integer number, List<ShopUser> userList) {
if (number == null || number <= 0) {
throw new CzgException("发放数量不能小于0");
}
AssertUtil.isNull(giftDTO.getShopId(), "店铺id不能为空");
AssertUtil.isNull(giftDTO.getCouponId(), "优惠券id不能为空");
AssertUtil.isNull(giftDTO.getSourceId(), "来源活动id不能为空");
AssertUtil.isBlank(giftDTO.getSource(), "来源描述不能为空");
ShopInfo shopInfo = shopInfoService.getById(giftDTO.getShopId());
AssertUtil.isNull(shopInfo, "店铺不存在");
ShopCoupon coupon = couponService.selectOneById(giftDTO.getCouponId());
AssertUtil.isNull(coupon, "优惠券不存在");
// 检查优惠券状态
if (coupon.getIsDel() != 0) {
// 状态异常直接返回
return;
}
// 检查店铺ID是否存在且与发放店铺一致
if (coupon.getShopId() == null || !coupon.getShopId().equals(giftDTO.getShopId())) {
return;
}
// 检查优惠券是否失效
if (coupon.getStatus() != 1) {
return;
}
coupon.setGiftNum(coupon.getGiftNum() + userList.size() * number);
String couponJson = JSONObject.toJSONString(coupon);
LocalDateTime start = LocalDateTime.now().with(LocalTime.MIN);
LocalDateTime end = null;
if ("fixed".equals(coupon.getValidType())) {
//固定时间
if (coupon.getDaysToTakeEffect() != null && coupon.getDaysToTakeEffect() > 0) {
start = LocalDateTimeUtil.offset(start, coupon.getDaysToTakeEffect(), ChronoUnit.DAYS).with(LocalTime.MIN);
}
end = LocalDateTimeUtil.offset(start, coupon.getValidDays(), ChronoUnit.DAYS).with(LocalTime.MAX).truncatedTo(ChronoUnit.SECONDS);
} else if ("custom".equals(coupon.getValidType())) {
//自定义时间
start = coupon.getValidStartTime();
end = coupon.getValidEndTime();
}
List<MkShopCouponRecord> recordList = new ArrayList<>();
for (int i = 0; i < number; i++) {
for (ShopUser shopUser : userList) {
MkShopCouponRecord record = new MkShopCouponRecord();
record.setShopId(giftDTO.getShopId());
record.setShopUserId(shopUser.getId());
record.setUserId(shopUser.getUserId());
record.setCouponId(giftDTO.getCouponId());
record.setCouponSyncId(coupon.getSyncId());
record.setSourceId(giftDTO.getSourceId());
record.setSourceFlowId(giftDTO.getSourceFlowId());
record.setSource(giftDTO.getSource());
record.setStatus(0);
record.setType(coupon.getCouponType());
record.setFullAmount(coupon.getFullAmount());
record.setDiscountAmount(coupon.getDiscountAmount());
record.setDiscountRate(coupon.getDiscountRate());
record.setMaxDiscountAmount(coupon.getMaxDiscountAmount());
record.setCreateTime(LocalDateTime.now());
record.setIsDel(0);
record.setCouponJson(couponJson);
record.setName(coupon.getTitle());
record.setUseStartTime(start);
record.setUseEndTime(end);
recordList.add(record);
}
}
saveBatch(recordList);
QueryWrapper queryWrapper = new QueryWrapper();
ShopCoupon newCoupon = new ShopCoupon();
newCoupon.setGiftNum(coupon.getGiftNum());
if (coupon.getSyncId() != null) {
queryWrapper.and(q -> {
q.eq(ShopCoupon::getId, coupon.getSyncId()).or(q1 -> {
q1.eq(ShopCoupon::getSyncId, coupon.getSyncId());
});
});
couponService.updateByQuery(newCoupon, queryWrapper);
} else {
queryWrapper.eq(ShopCoupon::getId, coupon.getId());
couponService.update(coupon, true);
}
}
@Override
public void deleteRecord(Long id) {
// updateById(new MkShopCouponRecord().setId(id).setIsDel(1), true);

View File

@ -1,11 +1,19 @@
package com.czg.service.market.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.czg.account.entity.ShopUser;
import com.czg.account.service.AShopUserService;
import com.czg.config.RabbitPublisher;
import com.czg.exception.CzgException;
import com.czg.market.dto.MkShopCouponGiftDTO;
import com.czg.market.dto.SmsPushEventDTO;
import com.czg.market.entity.SmsPushEvent;
import com.czg.market.entity.SmsPushEventUser;
import com.czg.market.service.MkShopCouponRecordService;
import com.czg.market.service.SmsPushEventService;
import com.czg.service.market.mapper.SmsPushEventMapper;
import com.czg.service.market.mapper.SmsPushEventUserMapper;
@ -14,10 +22,14 @@ import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.CompletableFuture;
/**
* 营销推送发送记录 服务层实现
@ -25,12 +37,17 @@ import java.time.LocalDateTime;
* @author ww
* @since 2025-10-14
*/
@Slf4j
@Service
public class SmsPushEventServiceImpl extends ServiceImpl<SmsPushEventMapper, SmsPushEvent> implements SmsPushEventService {
@Resource
private SmsPushEventUserMapper eventUserMapper;
@Resource
private MkShopCouponRecordService couponRecordService;
@DubboReference
private AShopUserService shopUserService;
@Resource
private RabbitPublisher rabbitPublisher;
@Override
@ -79,6 +96,39 @@ public class SmsPushEventServiceImpl extends ServiceImpl<SmsPushEventMapper, Sms
}
// 推送消息 进行 消息发送
rabbitPublisher.sendApplySmsMsg(pushEvent.getShopId() + "," + pushEvent.getId(), "sendMarkSms");
//发放优惠券
CompletableFuture.runAsync(() -> {
try {
grantCoupon(param);
} catch (Exception e) {
log.error("异步发放优惠券失败", e);
}
});
}
// 发放优惠券
private void grantCoupon(SmsPushEventDTO param) {
if (StrUtil.isBlank(param.getCoupon())) {
return;
}
List<ShopUser> userList = shopUserService.getPushEventUserList(param.getSmsPushEventUser());
// 2. 将JSON字符串解析为JSONArray
JSONArray couponArray = JSON.parseArray(param.getCoupon());
// 3. 遍历JSONArray逐个获取JSONObject的字段值
for (int i = 0; i < couponArray.size(); i++) {
// 获取单个优惠券的JSONObject对象
JSONObject couponObj = couponArray.getJSONObject(i);
// 通过键名获取对应值需注意字段类型按需转换
Long id = couponObj.getLong("id");
Integer num = couponObj.getInteger("num");
MkShopCouponGiftDTO giftDTO = new MkShopCouponGiftDTO();
giftDTO.setShopId(param.getShopId());
giftDTO.setSourceId(param.getId());
giftDTO.setCouponId(id);
giftDTO.setSource("营销短信发放");
couponRecordService.batchReceiveCoupon(giftDTO, num, userList);
}
}
/**

View File

@ -82,13 +82,10 @@ public class SmsShopTemplateServiceImpl extends ServiceImpl<SmsShopTemplateMappe
public void addTemplate(SmsShopTemplateDTO param) {
SmsShopTemplate template = BeanUtil.toBean(param, SmsShopTemplate.class);
template.setStatus(0);
if (template.getShopId().equals(1L)) {
template.setSort(0);
template.setShopUse(1);
template.setStatus(2);
} else {
template.setTitle(template.getShopId() + param.getTitle());
}
template.setSort(0);
template.setShopUse(1);
template.setStatus(2);
save(template);
if (!template.getShopId().equals(1L)) {
sendApplyMsg(template.getShopId(), template.getId());