|
|
@@ -23,6 +23,7 @@ import shop.alien.store.config.WebSocketProcess;
|
|
|
import shop.alien.store.service.LifeDiscountCouponStoreFriendService;
|
|
|
import shop.alien.util.common.constant.DiscountCouponEnum;
|
|
|
import shop.alien.util.coupon.DiscountCouponExpirationUtil;
|
|
|
+import shop.alien.util.coupon.LifeDiscountCouponStock;
|
|
|
|
|
|
import java.math.BigDecimal;
|
|
|
import java.math.RoundingMode;
|
|
|
@@ -35,31 +36,33 @@ import java.util.HashMap;
|
|
|
import java.util.LinkedHashMap;
|
|
|
import java.util.List;
|
|
|
import java.util.Map;
|
|
|
+import java.util.Objects;
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
/**
|
|
|
- * <p>
|
|
|
- * 优惠券商户发放好友优惠券关系表 服务实现类
|
|
|
- * </p>
|
|
|
- *
|
|
|
- * @author ssk
|
|
|
- * @since 2025-02-19
|
|
|
+ * 好友赠券领域:配置可赠券、执行赠送(扣库存 + 写 ldcsf)、消费后发券、赠券历史查询等。
|
|
|
*/
|
|
|
@Slf4j
|
|
|
@Service
|
|
|
@RequiredArgsConstructor
|
|
|
public class LifeDiscountCouponStoreFriendServiceImpl extends ServiceImpl<LifeDiscountCouponStoreFriendMapper, LifeDiscountCouponStoreFriend> implements LifeDiscountCouponStoreFriendService {
|
|
|
|
|
|
+ /** {@link #getReceivedSendFriendCouponList} 的 queryType:我收到的 */
|
|
|
+ private static final int GIFT_HISTORY_QUERY_RECEIVED = 1;
|
|
|
+ /** {@link #getReceivedSendFriendCouponList} 的 queryType:我送出的 */
|
|
|
+ private static final int GIFT_HISTORY_QUERY_SENT = 2;
|
|
|
+
|
|
|
final String STORE_PREFIX = "store_";
|
|
|
|
|
|
+ /** 单次好评发券的张数上限,防止运营误填特大数字 */
|
|
|
+ private static final int GOOD_RATING_ISSUE_COPIES_HARD_CAP = 50;
|
|
|
+
|
|
|
private final StoreUserMapper storeUserMapper;
|
|
|
|
|
|
private final LifeFansMapper lifeFansMapper;
|
|
|
|
|
|
private final LifeDiscountCouponMapper lifeDiscountCouponMapper;
|
|
|
|
|
|
- private final LifeCouponMapper lifeCouponMapper;
|
|
|
-
|
|
|
private final LifeDiscountCouponStoreFriendMapper lifeDiscountCouponStoreFriendMapper;
|
|
|
|
|
|
private final LifeDiscountCouponUserMapper lifeDiscountCouponUserMapper;
|
|
|
@@ -145,14 +148,10 @@ public class LifeDiscountCouponStoreFriendServiceImpl extends ServiceImpl<LifeDi
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
- @Override
|
|
|
/**
|
|
|
- * 为好友设置优惠券,涉及优惠券库存检查、发放记录处理和库存更新等操作。
|
|
|
- *
|
|
|
- * @param userLoginInfo 当前用户的登录信息
|
|
|
- * @param lifeDiscountCouponStoreFriendDto 包含要设置的优惠券信息的 DTO 对象
|
|
|
- * @return 如果所有优惠券都成功设置,返回 true;否则返回 false
|
|
|
+ * 向好友店铺赠送优惠券:按券列表逐笔调用 {@link #handleDiscountFriendCoupon}(库存 + ldcsf)。
|
|
|
*/
|
|
|
+ @Override
|
|
|
public boolean setFriendCoupon(UserLoginInfo userLoginInfo, LifeDiscountCouponStoreFriendDto lifeDiscountCouponStoreFriendDto) {
|
|
|
try {
|
|
|
List<LifeDiscountCouponStoreFriendDto> coupons = lifeDiscountCouponStoreFriendDto.getCouponIds();
|
|
|
@@ -160,16 +159,9 @@ public class LifeDiscountCouponStoreFriendServiceImpl extends ServiceImpl<LifeDi
|
|
|
return true;
|
|
|
}
|
|
|
for (LifeDiscountCouponStoreFriendDto couponDto : coupons) {
|
|
|
- if (StringUtils.isNotEmpty(couponDto.getVoucherId())) {
|
|
|
- // 代金券:入参为 voucherId,对应 life_coupon 表
|
|
|
- if (!handleVoucherFriendCoupon(userLoginInfo, lifeDiscountCouponStoreFriendDto, couponDto)) {
|
|
|
- return false;
|
|
|
- }
|
|
|
- } else if (couponDto.getCouponId() != null) {
|
|
|
- // 优惠券:入参为 couponId,对应 life_discount_coupon 表
|
|
|
- if (!handleDiscountFriendCoupon(userLoginInfo, lifeDiscountCouponStoreFriendDto, couponDto)) {
|
|
|
- return false;
|
|
|
- }
|
|
|
+ if (couponDto.getCouponId() != null
|
|
|
+ && !handleDiscountFriendCoupon(userLoginInfo, lifeDiscountCouponStoreFriendDto, couponDto)) {
|
|
|
+ return false;
|
|
|
}
|
|
|
}
|
|
|
return true;
|
|
|
@@ -179,91 +171,154 @@ public class LifeDiscountCouponStoreFriendServiceImpl extends ServiceImpl<LifeDi
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- /** 处理代金券(life_coupon)发放好友 */
|
|
|
- private boolean handleVoucherFriendCoupon(UserLoginInfo userLoginInfo, LifeDiscountCouponStoreFriendDto dto, LifeDiscountCouponStoreFriendDto couponDto) {
|
|
|
- LifeCoupon lifeCoupon = lifeCouponMapper.selectById(couponDto.getVoucherId());
|
|
|
- if (lifeCoupon == null) {
|
|
|
- return false;
|
|
|
+ private static Integer parseStoreIdInt(String raw) {
|
|
|
+ if (raw == null) {
|
|
|
+ return null;
|
|
|
}
|
|
|
- int qty = couponDto.getSingleQty() != null ? couponDto.getSingleQty() : 0;
|
|
|
- if (lifeCoupon.getSingleQty() == null || (lifeCoupon.getSingleQty() - qty) < 0) {
|
|
|
- return false;
|
|
|
+ String t = raw.trim();
|
|
|
+ if (t.isEmpty()) {
|
|
|
+ return null;
|
|
|
}
|
|
|
- StoreUser storeUser = storeUserMapper.selectOne(new LambdaQueryWrapper<StoreUser>().eq(StoreUser::getStoreId, lifeCoupon.getStoreId()));
|
|
|
- if (storeUser == null) {
|
|
|
- return false;
|
|
|
+ try {
|
|
|
+ return Integer.parseInt(t);
|
|
|
+ } catch (NumberFormatException e) {
|
|
|
+ return null;
|
|
|
}
|
|
|
- LambdaQueryWrapper<LifeDiscountCouponStoreFriend> wrapper = new LambdaQueryWrapper<LifeDiscountCouponStoreFriend>()
|
|
|
- .eq(LifeDiscountCouponStoreFriend::getVoucherId, couponDto.getVoucherId())
|
|
|
- .eq(LifeDiscountCouponStoreFriend::getStoreUserId, dto.getFriendStoreUserId())
|
|
|
- .eq(LifeDiscountCouponStoreFriend::getFriendStoreUserId, userLoginInfo.getUserId());
|
|
|
- LifeDiscountCouponStoreFriend friend = lifeDiscountCouponStoreFriendMapper.selectOne(wrapper);
|
|
|
-
|
|
|
- if (friend == null) {
|
|
|
- friend = new LifeDiscountCouponStoreFriend();
|
|
|
- friend.setVoucherId(couponDto.getVoucherId());
|
|
|
- friend.setCouponId(null);
|
|
|
- friend.setExpirationDate(lifeCoupon.getExpirationDate());
|
|
|
- if (lifeCoupon.getStartDate() != null) {
|
|
|
- friend.setStartDate(lifeCoupon.getStartDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDate());
|
|
|
- }
|
|
|
- if (lifeCoupon.getEndDate() != null) {
|
|
|
- friend.setEndDate(lifeCoupon.getEndDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDate());
|
|
|
- }
|
|
|
- friend.setFriendStoreUserId(storeUser.getId());
|
|
|
- friend.setSingleQty(qty);
|
|
|
- friend.setStoreUserId(dto.getFriendStoreUserId());
|
|
|
- friend.setReleaseType(1);
|
|
|
- lifeDiscountCouponStoreFriendMapper.insert(friend);
|
|
|
- } else {
|
|
|
- friend.setSingleQty(friend.getSingleQty() + qty);
|
|
|
- lifeDiscountCouponStoreFriendMapper.updateById(friend);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 同券同赠送人同接收店铺:新旧列任一命中即合并 single_qty(仅 life_discount_coupon 优惠券模板)。
|
|
|
+ */
|
|
|
+ private LambdaQueryWrapper<LifeDiscountCouponStoreFriend> duplicateGiftRowWrapper(
|
|
|
+ Integer couponId, Integer receiverStoreId, int senderUserId) {
|
|
|
+ LambdaQueryWrapper<LifeDiscountCouponStoreFriend> w = new LambdaQueryWrapper<>();
|
|
|
+ if (couponId == null) {
|
|
|
+ w.eq(LifeDiscountCouponStoreFriend::getId, -1);
|
|
|
+ return w;
|
|
|
}
|
|
|
- lifeCoupon.setSingleQty(lifeCoupon.getSingleQty() - qty);
|
|
|
- lifeCouponMapper.updateById(lifeCoupon);
|
|
|
- sendFriendCouponNotice(dto.getFriendStoreUserId(), userLoginInfo, qty, true);
|
|
|
- return true;
|
|
|
+ w.eq(LifeDiscountCouponStoreFriend::getCouponId, couponId)
|
|
|
+ .isNull(LifeDiscountCouponStoreFriend::getVoucherId);
|
|
|
+ w.apply("( (receiver_store_id = {0} AND sender_user_id = {1}) OR (receiver_store_id IS NULL AND store_user_id = {0} AND friend_store_user_id = {1}) )",
|
|
|
+ receiverStoreId, senderUserId);
|
|
|
+ return w;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 赠送方 / 接收方新旧列对齐:receiver/store_user_id、sender/friend_store_user_id 同源,便于历史脚本与 Mapper 仍可读。
|
|
|
+ */
|
|
|
+ private void applyGiftParties(LifeDiscountCouponStoreFriend row, int senderUserId, Integer receiverStoreId, Integer receiverUserId) {
|
|
|
+ StoreUser sender = storeUserMapper.selectById(senderUserId);
|
|
|
+ Integer senderStoreId = sender != null ? sender.getStoreId() : null;
|
|
|
+ row.setSenderUserId(senderUserId);
|
|
|
+ row.setSenderStoreId(senderStoreId);
|
|
|
+ row.setReceiverStoreId(receiverStoreId);
|
|
|
+ row.setReceiverUserId(receiverUserId);
|
|
|
+ row.setFriendStoreUserId(senderUserId);
|
|
|
+ row.setStoreUserId(receiverStoreId);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 写入/更新 {@link LifeDiscountCouponStoreFriend} 时,有效期相关字段仅以「按 couponId 查到的」{@link LifeDiscountCoupon} 为准(请求体 DTO 对应属性已 JsonIgnore)。
|
|
|
+ */
|
|
|
+ private static void applyGiftValiditySnapshotFromTemplate(LifeDiscountCouponStoreFriend row, LifeDiscountCoupon template) {
|
|
|
+ row.setExpirationDate(template.getExpirationDate());
|
|
|
+ row.setLongTermValid(template.getLongTermValid());
|
|
|
+ row.setStartDate(template.getStartDate());
|
|
|
+ row.setEndDate(template.getEndDate());
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 接收方商户用户:请求体显式传入优先;未传时按接收方店铺取一条未删除的商户账号(与赠券通知选取逻辑一致,便于四字段落库)。
|
|
|
+ */
|
|
|
+ private Integer resolveReceiverUserId(Integer receiverStoreId, Integer explicitReceiverUserId) {
|
|
|
+ if (explicitReceiverUserId != null) {
|
|
|
+ return explicitReceiverUserId;
|
|
|
+ }
|
|
|
+ if (receiverStoreId == null) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ List<StoreUser> list = storeUserMapper.selectList(new LambdaQueryWrapper<StoreUser>()
|
|
|
+ .eq(StoreUser::getStoreId, receiverStoreId)
|
|
|
+ .eq(StoreUser::getDeleteFlag, 0)
|
|
|
+ .orderByAsc(StoreUser::getId)
|
|
|
+ .last("LIMIT 1"));
|
|
|
+ if (CollectionUtils.isEmpty(list)) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ return list.get(0).getId();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 接收方维度筛选:优先 {@code receiver_store_id},兼容旧列 {@code store_user_id}(均为 store_info.id)。
|
|
|
+ */
|
|
|
+ private void applyLdcsfReceiverStoreFilter(QueryWrapper<?> q, int receiverStoreInfoId) {
|
|
|
+ q.and(w -> w.eq("ldcsf.receiver_store_id", receiverStoreInfoId)
|
|
|
+ .or(sub -> sub.isNull("ldcsf.receiver_store_id").eq("ldcsf.store_user_id", receiverStoreInfoId)));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 赠送方维度筛选:优先 {@code sender_user_id},兼容旧列 {@code friend_store_user_id}(均为 store_user.id)。
|
|
|
+ */
|
|
|
+ private void applyLdcsfSenderMerchantFilter(QueryWrapper<?> q, int senderStoreUserId) {
|
|
|
+ q.and(w -> w.eq("ldcsf.sender_user_id", senderStoreUserId)
|
|
|
+ .or(sub -> sub.isNull("ldcsf.sender_user_id").eq("ldcsf.friend_store_user_id", senderStoreUserId)));
|
|
|
}
|
|
|
|
|
|
/** 处理优惠券(life_discount_coupon)发放好友 */
|
|
|
private boolean handleDiscountFriendCoupon(UserLoginInfo userLoginInfo, LifeDiscountCouponStoreFriendDto lifeDiscountCouponStoreFriendDto, LifeDiscountCouponStoreFriendDto couponDto) {
|
|
|
LifeDiscountCoupon lifeDiscountCoupon = lifeDiscountCouponMapper.selectById(couponDto.getCouponId());
|
|
|
- if (lifeDiscountCoupon == null || (lifeDiscountCoupon.getSingleQty() - couponDto.getSingleQty()) < 0) {
|
|
|
+ Integer receiverStoreId = lifeDiscountCouponStoreFriendDto.getFriendStoreUserId();
|
|
|
+ if (lifeDiscountCoupon == null || receiverStoreId == null) {
|
|
|
return false;
|
|
|
}
|
|
|
- StoreUser storeUser = storeUserMapper.selectOne(new LambdaQueryWrapper<StoreUser>().eq(StoreUser::getStoreId, lifeDiscountCoupon.getStoreId()));
|
|
|
+ Integer receiverUserId = resolveReceiverUserId(receiverStoreId, lifeDiscountCouponStoreFriendDto.getReceiverUserId());
|
|
|
+ int sendQty = couponDto.getSingleQty() != null ? couponDto.getSingleQty() : 0;
|
|
|
+ if (!LifeDiscountCouponStock.isUnlimitedQty(lifeDiscountCoupon.getUnlimitedQty())) {
|
|
|
+ if (lifeDiscountCoupon.getSingleQty() == null
|
|
|
+ || (lifeDiscountCoupon.getSingleQty() - sendQty) < 0) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ Integer tplStoreId = parseStoreIdInt(lifeDiscountCoupon.getStoreId());
|
|
|
+ if (tplStoreId == null) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ Integer tplMerchantCount = storeUserMapper.selectCount(new LambdaQueryWrapper<StoreUser>()
|
|
|
+ .eq(StoreUser::getStoreId, tplStoreId).eq(StoreUser::getDeleteFlag, 0));
|
|
|
+ if (tplMerchantCount == null || tplMerchantCount == 0) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
LifeDiscountCouponStoreFriend lifeDiscountCouponStoreFriend = lifeDiscountCouponStoreFriendMapper.selectOne(
|
|
|
- new LambdaQueryWrapper<LifeDiscountCouponStoreFriend>()
|
|
|
- .eq(LifeDiscountCouponStoreFriend::getCouponId, couponDto.getCouponId())
|
|
|
- .eq(LifeDiscountCouponStoreFriend::getStoreUserId, lifeDiscountCouponStoreFriendDto.getFriendStoreUserId())
|
|
|
- .eq(LifeDiscountCouponStoreFriend::getFriendStoreUserId, userLoginInfo.getUserId())
|
|
|
+ duplicateGiftRowWrapper(couponDto.getCouponId(), receiverStoreId, userLoginInfo.getUserId())
|
|
|
);
|
|
|
|
|
|
if (lifeDiscountCouponStoreFriend == null) {
|
|
|
lifeDiscountCouponStoreFriend = new LifeDiscountCouponStoreFriend();
|
|
|
- BeanUtils.copyProperties(lifeDiscountCouponStoreFriendDto, lifeDiscountCouponStoreFriend);
|
|
|
lifeDiscountCouponStoreFriend.setCouponId(couponDto.getCouponId());
|
|
|
lifeDiscountCouponStoreFriend.setVoucherId(null);
|
|
|
- lifeDiscountCouponStoreFriend.setExpirationDate(lifeDiscountCoupon.getExpirationDate());
|
|
|
- lifeDiscountCouponStoreFriend.setStartDate(lifeDiscountCoupon.getStartDate());
|
|
|
- lifeDiscountCouponStoreFriend.setEndDate(lifeDiscountCoupon.getEndDate());
|
|
|
- lifeDiscountCouponStoreFriend.setFriendStoreUserId(storeUser.getId());
|
|
|
+ applyGiftValiditySnapshotFromTemplate(lifeDiscountCouponStoreFriend, lifeDiscountCoupon);
|
|
|
lifeDiscountCouponStoreFriend.setSingleQty(couponDto.getSingleQty());
|
|
|
- lifeDiscountCouponStoreFriend.setStoreUserId(lifeDiscountCouponStoreFriendDto.getFriendStoreUserId());
|
|
|
lifeDiscountCouponStoreFriend.setReleaseType(1);
|
|
|
+ applyGiftParties(lifeDiscountCouponStoreFriend, userLoginInfo.getUserId(), receiverStoreId, receiverUserId);
|
|
|
lifeDiscountCouponStoreFriendMapper.insert(lifeDiscountCouponStoreFriend);
|
|
|
} else {
|
|
|
+ applyGiftParties(lifeDiscountCouponStoreFriend, userLoginInfo.getUserId(), receiverStoreId, receiverUserId);
|
|
|
+ applyGiftValiditySnapshotFromTemplate(lifeDiscountCouponStoreFriend, lifeDiscountCoupon);
|
|
|
lifeDiscountCouponStoreFriend.setSingleQty(lifeDiscountCouponStoreFriend.getSingleQty() + couponDto.getSingleQty());
|
|
|
lifeDiscountCouponStoreFriendMapper.updateById(lifeDiscountCouponStoreFriend);
|
|
|
}
|
|
|
- lifeDiscountCoupon.setSingleQty(lifeDiscountCoupon.getSingleQty() - couponDto.getSingleQty());
|
|
|
+ if (!LifeDiscountCouponStock.isUnlimitedQty(lifeDiscountCoupon.getUnlimitedQty())
|
|
|
+ && lifeDiscountCoupon.getSingleQty() != null) {
|
|
|
+ lifeDiscountCoupon.setSingleQty(lifeDiscountCoupon.getSingleQty() - sendQty);
|
|
|
+ }
|
|
|
lifeDiscountCouponMapper.updateById(lifeDiscountCoupon);
|
|
|
- sendFriendCouponNotice(lifeDiscountCouponStoreFriendDto.getFriendStoreUserId(), userLoginInfo, couponDto.getSingleQty(), false);
|
|
|
+ sendFriendCouponNotice(lifeDiscountCouponStoreFriendDto.getFriendStoreUserId(), userLoginInfo, couponDto.getSingleQty());
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
- /** 发送赠券通知:isVoucher true=代金券,false=优惠券 */
|
|
|
- private void sendFriendCouponNotice(Integer friendStoreUserId, UserLoginInfo userLoginInfo, int qty, boolean isVoucher) {
|
|
|
+ /** 发送赠券通知 */
|
|
|
+ private void sendFriendCouponNotice(Integer friendStoreUserId, UserLoginInfo userLoginInfo, int qty) {
|
|
|
if (friendStoreUserId == null) {
|
|
|
return;
|
|
|
}
|
|
|
@@ -287,8 +342,7 @@ public class LifeDiscountCouponStoreFriendServiceImpl extends ServiceImpl<LifeDi
|
|
|
}
|
|
|
}
|
|
|
LifeNotice lifeMessage = new LifeNotice();
|
|
|
- String couponTypeName = isVoucher ? "代金券" : "优惠券";
|
|
|
- String text = "您的好友" + storeName + "送了您" + qty + "张" + couponTypeName + ",快去使用吧!";
|
|
|
+ String text = "您的好友" + storeName + "送了您" + qty + "张优惠券,快去使用吧!";
|
|
|
JSONObject jsonObject = new JSONObject();
|
|
|
jsonObject.put("message", text);
|
|
|
lifeMessage.setReceiverId("store_" + friendPhone);
|
|
|
@@ -351,8 +405,10 @@ public class LifeDiscountCouponStoreFriendServiceImpl extends ServiceImpl<LifeDi
|
|
|
|
|
|
// 根据店铺ID从数据库中查询该店铺为好友设定的所有优惠券信息
|
|
|
List<LifeDiscountCouponStoreFriend> lifeDiscountCouponStoreFriends = lifeDiscountCouponStoreFriendMapper.selectList(
|
|
|
- // 使用LambdaQueryWrapper构建查询条件,筛选出店铺ID等于指定店铺ID的优惠券记录,并且发布状态为已发布
|
|
|
- new LambdaQueryWrapper<LifeDiscountCouponStoreFriend>().eq(LifeDiscountCouponStoreFriend::getStoreUserId, storeId)
|
|
|
+ new LambdaQueryWrapper<LifeDiscountCouponStoreFriend>()
|
|
|
+ .and(w -> w.eq(LifeDiscountCouponStoreFriend::getReceiverStoreId, storeId)
|
|
|
+ .or(sub -> sub.isNull(LifeDiscountCouponStoreFriend::getReceiverStoreId)
|
|
|
+ .eq(LifeDiscountCouponStoreFriend::getStoreUserId, storeId)))
|
|
|
.eq(LifeDiscountCouponStoreFriend::getReleaseType, 1)
|
|
|
.in(LifeDiscountCouponStoreFriend::getCouponId, couponList));
|
|
|
|
|
|
@@ -370,7 +426,9 @@ public class LifeDiscountCouponStoreFriendServiceImpl extends ServiceImpl<LifeDi
|
|
|
// 设置查询条件:优惠券的结束日期大于等于当前日期,即优惠券在有效期内
|
|
|
queryWrapper.ge(LifeDiscountCoupon::getValidDate, currentDate);
|
|
|
// 设置查询条件:优惠券还有库存
|
|
|
- queryWrapper.gt(LifeDiscountCoupon::getSingleQty, 0);
|
|
|
+ queryWrapper.and(w -> w.eq(LifeDiscountCoupon::getUnlimitedQty, 1)
|
|
|
+ .or()
|
|
|
+ .gt(LifeDiscountCoupon::getSingleQty, 0));
|
|
|
|
|
|
// 根据上述查询条件从数据库中查询符合条件的优惠券信息
|
|
|
LifeDiscountCoupon lifeDiscountCoupon = lifeDiscountCouponMapper.selectOne(queryWrapper);
|
|
|
@@ -392,6 +450,7 @@ public class LifeDiscountCouponStoreFriendServiceImpl extends ServiceImpl<LifeDi
|
|
|
lifeDiscountCouponUser.setReceiveTime(new Date());
|
|
|
lifeDiscountCouponUser.setExpirationTime(DiscountCouponExpirationUtil.resolveLifeDiscountCouponExpiration(
|
|
|
lifeDiscountCouponUser.getReceiveTime(),
|
|
|
+ lifeDiscountCoupon.getLongTermValid(),
|
|
|
lifeDiscountCoupon.getSpecifiedDay(),
|
|
|
lifeDiscountCoupon.getExpirationDate(),
|
|
|
lifeDiscountCoupon.getValidDate(),
|
|
|
@@ -509,9 +568,12 @@ public class LifeDiscountCouponStoreFriendServiceImpl extends ServiceImpl<LifeDi
|
|
|
|
|
|
// 根据店铺ID从数据库中查询该店铺为好友设定的所有优惠券信息
|
|
|
List<LifeDiscountCouponStoreFriend> lifeDiscountCouponStoreFriends = lifeDiscountCouponStoreFriendMapper.selectList(
|
|
|
- // 使用LambdaQueryWrapper构建查询条件,筛选出店铺ID等于指定店铺ID的优惠券记录,并且发布状态为已发布
|
|
|
- new LambdaQueryWrapper<LifeDiscountCouponStoreFriend>().eq(LifeDiscountCouponStoreFriend::getStoreUserId, storeId)
|
|
|
+ new LambdaQueryWrapper<LifeDiscountCouponStoreFriend>()
|
|
|
+ .and(w -> w.eq(LifeDiscountCouponStoreFriend::getReceiverStoreId, storeId)
|
|
|
+ .or(sub -> sub.isNull(LifeDiscountCouponStoreFriend::getReceiverStoreId)
|
|
|
+ .eq(LifeDiscountCouponStoreFriend::getStoreUserId, storeId)))
|
|
|
.eq(LifeDiscountCouponStoreFriend::getReleaseType, 1)
|
|
|
+ .gt(LifeDiscountCouponStoreFriend::getSingleQty, 0)
|
|
|
// .in(LifeDiscountCouponStoreFriend::getCouponId, couponList)
|
|
|
);
|
|
|
|
|
|
@@ -527,15 +589,17 @@ public class LifeDiscountCouponStoreFriendServiceImpl extends ServiceImpl<LifeDi
|
|
|
// 设置查询条件:优惠券的ID等于当前遍历到的优惠券ID
|
|
|
queryWrapper.eq(LifeDiscountCoupon::getId, coupon.getCouponId());
|
|
|
// 设置查询条件:优惠券的结束日期大于等于当前日期,即优惠券在有效期内
|
|
|
- queryWrapper.ge(LifeDiscountCoupon::getValidDate, currentDate);
|
|
|
+// queryWrapper.ge(LifeDiscountCoupon::getValidDate, currentDate);
|
|
|
// 设置查询条件:优惠券还有库存
|
|
|
- queryWrapper.gt(LifeDiscountCoupon::getSingleQty, 0);
|
|
|
+ queryWrapper.and(w -> w.eq(LifeDiscountCoupon::getUnlimitedQty, 1)
|
|
|
+ .or()
|
|
|
+ .gt(LifeDiscountCoupon::getSingleQty, 0));
|
|
|
|
|
|
// 根据上述查询条件从数据库中查询符合条件的优惠券信息
|
|
|
LifeDiscountCoupon lifeDiscountCoupon = lifeDiscountCouponMapper.selectOne(queryWrapper);
|
|
|
|
|
|
// 如果查询到符合条件的优惠券,说明该优惠券可领
|
|
|
- if (lifeDiscountCoupon != null) {
|
|
|
+ if (lifeDiscountCoupon != null ) {
|
|
|
// 设定本次领取优惠券的数量,这里固定为1张
|
|
|
Integer receiveQuantity = 1;
|
|
|
|
|
|
@@ -650,14 +714,9 @@ public class LifeDiscountCouponStoreFriendServiceImpl extends ServiceImpl<LifeDi
|
|
|
@Override
|
|
|
public LifeDiscountCouponFriendRuleVo saveFriendCouponRule(LifeDiscountCouponFriendRule lifeDiscountCouponFriendRule) {
|
|
|
List<LifeDiscountCouponFriendRuleDetail> details = lifeDiscountCouponFriendRule.getDetails();
|
|
|
- // 按列表中是否传入代金券id区分:有 voucherId 走代金券逻辑,否则走优惠券逻辑
|
|
|
if (ObjectUtils.isNotEmpty(details)) {
|
|
|
for (LifeDiscountCouponFriendRuleDetail detail : details) {
|
|
|
- if (detail.getVoucherId() != null && !detail.getVoucherId().trim().isEmpty()) {
|
|
|
- detail.setCouponId(null);
|
|
|
- } else {
|
|
|
- detail.setVoucherId(null);
|
|
|
- }
|
|
|
+ detail.setVoucherId(null);
|
|
|
}
|
|
|
}
|
|
|
if (ObjectUtils.isNotEmpty(lifeDiscountCouponFriendRule.getId())) {
|
|
|
@@ -698,21 +757,17 @@ public class LifeDiscountCouponStoreFriendServiceImpl extends ServiceImpl<LifeDi
|
|
|
*/
|
|
|
@Override
|
|
|
public List<LifeDiscountCouponFriendRuleDetailVo> getReceivedFriendCouponList(String storeId, String friendStoreUserId, Integer type, Integer couponType) {
|
|
|
- QueryWrapper<LifeDiscountCouponFriendRuleDetailVo> queryWrapper = new QueryWrapper<>();
|
|
|
- queryWrapper.eq("ldcsf.store_user_id", storeId);
|
|
|
- queryWrapper.eq("ldcsf.delete_flag", 0);
|
|
|
if (Integer.valueOf(4).equals(type)) {
|
|
|
- // 代金券:创建时为启用状态 2,需查出 release_type=1 与 2 的 LifeDiscountCouponStoreFriend 数据
|
|
|
- queryWrapper.in("ldcsf.release_type", 1, 2);
|
|
|
- queryWrapper.isNotNull("ldcsf.voucher_id");
|
|
|
- if (StringUtils.isEmpty(friendStoreUserId)) {
|
|
|
- queryWrapper.groupBy("ldcsf.friend_store_user_id").orderByDesc("couponNum");
|
|
|
- } else {
|
|
|
- queryWrapper.eq("ldcsf.friend_store_user_id", friendStoreUserId).groupBy("ldcsf.voucher_id").orderByDesc("couponNum");
|
|
|
- }
|
|
|
- return lifeDiscountCouponFriendRuleDetailMapper.getReceivedFriendVoucherList(queryWrapper);
|
|
|
+ return new ArrayList<>();
|
|
|
+ }
|
|
|
+ QueryWrapper<LifeDiscountCouponFriendRuleDetailVo> queryWrapper = new QueryWrapper<>();
|
|
|
+ try {
|
|
|
+ applyLdcsfReceiverStoreFilter(queryWrapper, Integer.parseInt(storeId.trim()));
|
|
|
+ } catch (NumberFormatException e) {
|
|
|
+ log.warn("getReceivedFriendCouponList 非法 storeId={}", storeId);
|
|
|
+ return new ArrayList<>();
|
|
|
}
|
|
|
- // 优惠券:保持原逻辑,只查 release_type=1
|
|
|
+ queryWrapper.eq("ldcsf.delete_flag", 0);
|
|
|
queryWrapper.eq("ldcsf.release_type", 1);
|
|
|
queryWrapper.isNotNull("ldcsf.coupon_id");
|
|
|
//如果指定了优惠券类型(满减券或折扣券),添加筛选条件
|
|
|
@@ -720,9 +775,10 @@ public class LifeDiscountCouponStoreFriendServiceImpl extends ServiceImpl<LifeDi
|
|
|
queryWrapper.eq("ldc.coupon_type", couponType);
|
|
|
}
|
|
|
if (StringUtils.isEmpty(friendStoreUserId)) {
|
|
|
- queryWrapper.groupBy("ldcsf.friend_store_user_id").orderByDesc("couponNum");
|
|
|
+ queryWrapper.groupBy("COALESCE(ldcsf.sender_user_id, ldcsf.friend_store_user_id)").orderByDesc("couponNum");
|
|
|
} else {
|
|
|
- queryWrapper.eq("ldcsf.friend_store_user_id", friendStoreUserId).groupBy("ldcsf.coupon_id").orderByDesc("couponNum");
|
|
|
+ appendFriendSenderFilter(queryWrapper, friendStoreUserId);
|
|
|
+ queryWrapper.groupBy("ldcsf.coupon_id").orderByDesc("couponNum");
|
|
|
}
|
|
|
return lifeDiscountCouponFriendRuleDetailMapper.getReceivedFriendCouponList(queryWrapper);
|
|
|
}
|
|
|
@@ -796,7 +852,6 @@ public class LifeDiscountCouponStoreFriendServiceImpl extends ServiceImpl<LifeDi
|
|
|
|
|
|
// 如果规则表中没有 couponType,尝试从关联的优惠券中获取
|
|
|
if (ruleVo.getCouponType() == null && ObjectUtils.isNotEmpty(lifeDiscountCouponFriendRuleDetails)) {
|
|
|
- // 查找第一个优惠券(非代金券)的 couponType
|
|
|
for (LifeDiscountCouponFriendRuleDetailVo detail : lifeDiscountCouponFriendRuleDetails) {
|
|
|
if (detail.getCouponId() != null && detail.getCouponType() != null) {
|
|
|
ruleVo.setCouponType(detail.getCouponType());
|
|
|
@@ -809,189 +864,241 @@ public class LifeDiscountCouponStoreFriendServiceImpl extends ServiceImpl<LifeDi
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 代金券类型常量
|
|
|
+ * 赠券历史(GET /getReceivedSendFriendCouponList):根据「我收到 / 我送出」筛 ldcsf,再补模板与头像。
|
|
|
*/
|
|
|
- private static final Integer TYPE_VOUCHER = 4;
|
|
|
-
|
|
|
@Override
|
|
|
public List<LifeDiscountCouponFriendRuleVo> getReceivedSendFriendCouponList(String storeUserId, Integer queryType, String storeName, Integer type, Integer couponType) {
|
|
|
- // 参数校验
|
|
|
- if (StringUtils.isEmpty(storeUserId)) {
|
|
|
- log.warn("getReceivedSendFriendCouponList 参数错误:storeUserId 不能为空");
|
|
|
- return new ArrayList<>();
|
|
|
- }
|
|
|
- if (queryType == null || (queryType != 1 && queryType != 2)) {
|
|
|
- log.warn("getReceivedSendFriendCouponList 参数错误:queryType 必须为 1 或 2,当前值={}", queryType);
|
|
|
+ if (!validateGiftHistoryQueryParams(storeUserId, queryType, couponType)) {
|
|
|
return new ArrayList<>();
|
|
|
}
|
|
|
- // 校验couponType参数(1=满减券,2=折扣券)
|
|
|
- if (couponType != null && couponType != 1 && couponType != 2) {
|
|
|
- log.warn("getReceivedSendFriendCouponList 参数错误:couponType 必须为 1(满减券)或 2(折扣券),当前值={}", couponType);
|
|
|
+
|
|
|
+ if (Integer.valueOf(4).equals(type)) {
|
|
|
return new ArrayList<>();
|
|
|
}
|
|
|
|
|
|
- // 判断是否仅查询代金券
|
|
|
- boolean voucherOnly = TYPE_VOUCHER.equals(type);
|
|
|
+ boolean isReceivedByMe = (queryType == GIFT_HISTORY_QUERY_RECEIVED);
|
|
|
+ return queryCouponList(isReceivedByMe, storeUserId, storeName, couponType);
|
|
|
+ }
|
|
|
|
|
|
- // 确定查询类型
|
|
|
- // 根据表结构(实体类注释):
|
|
|
- // store_user_id: store_info的ID(店铺ID),收到券的店铺
|
|
|
- // friend_store_user_id: store_user的ID(店铺用户ID),送券的用户
|
|
|
- // 前端传入的 storeUserId 是当前登录账号的 store_user.id(店铺用户ID)
|
|
|
- // queryType = 1: 我收到的(所有好友赠送给我的)-> store_user_id = 我的店铺ID(我是收到券的店铺,需要从店铺用户ID转换为店铺ID)
|
|
|
- // queryType = 2: 我送出的(我送给所有好友的)-> friend_store_user_id = 我的店铺用户ID(我是送券的用户)
|
|
|
- boolean isReceivedByMe = (queryType == 1);
|
|
|
+ private boolean validateGiftHistoryQueryParams(String storeUserId, Integer queryType, Integer couponType) {
|
|
|
+ if (StringUtils.isEmpty(storeUserId)) {
|
|
|
+ log.error("getReceivedSendFriendCouponList 参数错误:storeUserId 不能为空");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if (queryType == null || (queryType != GIFT_HISTORY_QUERY_RECEIVED && queryType != GIFT_HISTORY_QUERY_SENT)) {
|
|
|
+ log.error("getReceivedSendFriendCouponList 参数错误:queryType 必须为 {} 或 {},当前值={}", GIFT_HISTORY_QUERY_RECEIVED, GIFT_HISTORY_QUERY_SENT, queryType);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if (couponType != null && couponType != 1 && couponType != 2) {
|
|
|
+ log.error("getReceivedSendFriendCouponList 参数错误:couponType 必须为 1(满减券)或 2(折扣券),当前值={}", couponType);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
|
|
|
- return queryCouponList(isReceivedByMe, storeUserId, storeName, type, voucherOnly, couponType);
|
|
|
+ /**
|
|
|
+ * 仅优惠券模板(coupon_id):拼条件 → 查列表 → 含逻辑删模板补全 → 对方头像 → 按 ldcsf.created_time 倒序(新的在前)。
|
|
|
+ */
|
|
|
+ private List<LifeDiscountCouponFriendRuleVo> queryCouponList(boolean isReceivedByMe, String storeUserId, String storeName, Integer couponType) {
|
|
|
+ QueryWrapper<LifeDiscountCouponFriendRuleVo> couponQuery = buildBaseQueryWrapper(isReceivedByMe, storeUserId, storeName);
|
|
|
+ couponQuery.isNotNull("ldcsf.coupon_id");
|
|
|
+ // couponType:须保留「模板已逻辑删除导致 JOIN 不到 ldc」的记录,改为用含删除快照的批量查询再筛
|
|
|
+ if (couponType != null) {
|
|
|
+ couponQuery.and(w -> w.eq("ldc.coupon_type", couponType)
|
|
|
+ .or(sub -> sub.isNull("ldc.id").isNotNull("ldcsf.coupon_id")));
|
|
|
+ }
|
|
|
+ couponQuery.orderByDesc("ldcsf.created_time");
|
|
|
+ List<LifeDiscountCouponFriendRuleVo> couponList = isReceivedByMe
|
|
|
+ ? lifeDiscountCouponStoreFriendMapper.getReceivedSendFriendCouponList(couponQuery)
|
|
|
+ : lifeDiscountCouponStoreFriendMapper.getReceivedSendFriendCouponListwzhy(couponQuery);
|
|
|
+
|
|
|
+ mergeCouponTemplatesIncludeDeleted(couponList, couponType);
|
|
|
+ fillStoreAvatar(couponList);
|
|
|
+ return couponList;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 查询赠券列表(抽取公共方法,减少代码重复)
|
|
|
- *
|
|
|
- * @param isReceivedByMe true=我收到的(所有好友赠送给我的),false=我送出的(我送给所有好友的)
|
|
|
- * @param storeUserId 当前登录店铺用户ID
|
|
|
- * @param storeName 店铺名称(模糊查询)
|
|
|
- * @param type 类型参数(4=代金券,其他=优惠券,null=全部)
|
|
|
- * @param voucherOnly 是否仅查询代金券
|
|
|
- * @param couponType 优惠券类型(1=满减券,2=折扣券,null=全部优惠券)
|
|
|
- * @return 赠券列表
|
|
|
+ * 使用单表直查(含 delete_flag=1 的已删模板),覆盖/补全列表中的券属性,避免商家逻辑删除模板后好友记录无法展示券信息。
|
|
|
+ * 当传入 couponTypeFilter 时,在补全后按模板真实 coupon_type 再过滤(兼容 JOIN 不到 ldc 的行)。
|
|
|
*/
|
|
|
- private List<LifeDiscountCouponFriendRuleVo> queryCouponList(boolean isReceivedByMe, String storeUserId, String storeName, Integer type, boolean voucherOnly, Integer couponType) {
|
|
|
- List<LifeDiscountCouponFriendRuleVo> result;
|
|
|
-
|
|
|
- // 仅查询代金券
|
|
|
- if (voucherOnly) {
|
|
|
- QueryWrapper<LifeDiscountCouponFriendRuleVo> queryWrapper = buildBaseQueryWrapper(isReceivedByMe, storeUserId, storeName);
|
|
|
- queryWrapper.isNotNull("ldcsf.voucher_id");
|
|
|
- result = isReceivedByMe
|
|
|
- ? lifeDiscountCouponStoreFriendMapper.getReceivedSendFriendCouponListVoucher(queryWrapper)
|
|
|
- : lifeDiscountCouponStoreFriendMapper.getReceivedSendFriendCouponListwzhyVoucher(queryWrapper);
|
|
|
- } else {
|
|
|
- // 查询优惠券
|
|
|
- QueryWrapper<LifeDiscountCouponFriendRuleVo> couponQuery = buildBaseQueryWrapper(isReceivedByMe, storeUserId, storeName);
|
|
|
- couponQuery.isNotNull("ldcsf.coupon_id");
|
|
|
- // 如果指定了优惠券类型(满减券或折扣券),添加筛选条件
|
|
|
- if (couponType != null) {
|
|
|
- couponQuery.eq("ldc.coupon_type", couponType);
|
|
|
+ private void mergeCouponTemplatesIncludeDeleted(List<LifeDiscountCouponFriendRuleVo> list, Integer couponTypeFilter) {
|
|
|
+ if (CollectionUtils.isEmpty(list)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ List<Integer> couponIds = list.stream()
|
|
|
+ .map(LifeDiscountCouponFriendRuleVo::getCouponId)
|
|
|
+ .filter(Objects::nonNull)
|
|
|
+ .distinct()
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ if (couponIds.isEmpty()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ List<LifeDiscountCoupon> templates = lifeDiscountCouponMapper.selectByIdsIncludeDeleted(couponIds);
|
|
|
+ Map<Integer, LifeDiscountCoupon> byId = templates.stream()
|
|
|
+ .collect(Collectors.toMap(LifeDiscountCoupon::getId, t -> t, (a, b) -> a));
|
|
|
+ for (LifeDiscountCouponFriendRuleVo vo : list) {
|
|
|
+ Integer cid = vo.getCouponId();
|
|
|
+ if (cid == null) {
|
|
|
+ continue;
|
|
|
}
|
|
|
- List<LifeDiscountCouponFriendRuleVo> couponList = isReceivedByMe
|
|
|
- ? lifeDiscountCouponStoreFriendMapper.getReceivedSendFriendCouponList(couponQuery)
|
|
|
- : lifeDiscountCouponStoreFriendMapper.getReceivedSendFriendCouponListwzhy(couponQuery);
|
|
|
-
|
|
|
- // 如果 type 不为 null,说明只查询优惠券,直接返回
|
|
|
- if (type != null) {
|
|
|
- result = couponList;
|
|
|
- } else {
|
|
|
- // type 为 null,需要合并优惠券和代金券
|
|
|
- QueryWrapper<LifeDiscountCouponFriendRuleVo> voucherQuery = buildBaseQueryWrapper(isReceivedByMe, storeUserId, storeName);
|
|
|
- voucherQuery.isNotNull("ldcsf.voucher_id");
|
|
|
- List<LifeDiscountCouponFriendRuleVo> voucherList = isReceivedByMe
|
|
|
- ? lifeDiscountCouponStoreFriendMapper.getReceivedSendFriendCouponListVoucher(voucherQuery)
|
|
|
- : lifeDiscountCouponStoreFriendMapper.getReceivedSendFriendCouponListwzhyVoucher(voucherQuery);
|
|
|
-
|
|
|
- // 合并列表
|
|
|
- result = new ArrayList<>(couponList);
|
|
|
- result.addAll(voucherList);
|
|
|
+ LifeDiscountCoupon t = byId.get(cid);
|
|
|
+ if (t != null) {
|
|
|
+ applyDiscountCouponTemplateToFriendRuleVo(vo, t);
|
|
|
}
|
|
|
}
|
|
|
+ if (couponTypeFilter != null) {
|
|
|
+ list.removeIf(vo -> {
|
|
|
+ LifeDiscountCoupon t = byId.get(vo.getCouponId());
|
|
|
+ return t == null || !couponTypeFilter.equals(t.getCouponType());
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- // 批量查询商户头像并填充
|
|
|
- fillStoreAvatar(result);
|
|
|
-
|
|
|
- // 排序
|
|
|
- return sortByEndDate(result);
|
|
|
+ private void applyDiscountCouponTemplateToFriendRuleVo(LifeDiscountCouponFriendRuleVo vo, LifeDiscountCoupon t) {
|
|
|
+ vo.setCouponName(t.getName());
|
|
|
+ vo.setNominalValue(t.getNominalValue());
|
|
|
+ vo.setMinimumSpendingAmount(t.getMinimumSpendingAmount());
|
|
|
+ vo.setExpirationDate(t.getExpirationDate());
|
|
|
+ vo.setLongTermValid(t.getLongTermValid());
|
|
|
+ vo.setCouponType(t.getCouponType());
|
|
|
+ vo.setDiscountRate(t.getDiscountRate());
|
|
|
+ Date valid = localDateToDate(t.getValidDate());
|
|
|
+ vo.setEndDate(valid);
|
|
|
+ vo.setValidDate(valid);
|
|
|
+ vo.setBeginGetDate(localDateToDate(t.getBeginGetDate()));
|
|
|
+ vo.setEndGetDate(localDateToDate(t.getEndGetDate()));
|
|
|
+ }
|
|
|
+
|
|
|
+ private static Date localDateToDate(LocalDate d) {
|
|
|
+ if (d == null) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ return Date.from(d.atStartOfDay(ZoneId.systemDefault()).toInstant());
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 批量查询商户头像并填充到结果中
|
|
|
- * 只从 store_user.head_img 获取商户头像,不涉及店铺信息表(store_info)
|
|
|
- *
|
|
|
- * @param couponList 券列表
|
|
|
+ * 批量查询商户头像并填充到结果中(对方店铺展示对方商户头像,不展示当前登录人自己)
|
|
|
+ * 优先按「对方 store_user.id」取 head_img;缺失时再按对方店铺 id 取店内主号等头像。
|
|
|
*/
|
|
|
private void fillStoreAvatar(List<LifeDiscountCouponFriendRuleVo> couponList) {
|
|
|
if (CollectionUtils.isEmpty(couponList)) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- // 收集所有的店铺ID(storeId是Integer类型)
|
|
|
- List<Integer> storeIds = couponList.stream()
|
|
|
- .map(LifeDiscountCouponFriendRuleVo::getStoreId)
|
|
|
- .filter(storeId -> storeId != null)
|
|
|
+ List<Integer> counterpartyUserIds = couponList.stream()
|
|
|
+ .map(LifeDiscountCouponFriendRuleVo::getCounterpartyStoreUserId)
|
|
|
+ .filter(Objects::nonNull)
|
|
|
.distinct()
|
|
|
.collect(Collectors.toList());
|
|
|
|
|
|
- if (storeIds.isEmpty()) {
|
|
|
- log.warn("没有有效的店铺ID,无法查询商户头像");
|
|
|
- return;
|
|
|
+ Map<Integer, String> userIdToHeadImg = new HashMap<>();
|
|
|
+ if (!counterpartyUserIds.isEmpty()) {
|
|
|
+ LambdaQueryWrapper<StoreUser> byId = new LambdaQueryWrapper<>();
|
|
|
+ byId.in(StoreUser::getId, counterpartyUserIds).eq(StoreUser::getDeleteFlag, 0);
|
|
|
+ for (StoreUser u : storeUserMapper.selectList(byId)) {
|
|
|
+ if (u.getHeadImg() != null && !u.getHeadImg().trim().isEmpty()) {
|
|
|
+ userIdToHeadImg.put(u.getId(), u.getHeadImg());
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- // 批量查询商户头像(只从 store_user.head_img 获取,优先取主账号头像)
|
|
|
- LambdaQueryWrapper<StoreUser> userWrapper = new LambdaQueryWrapper<>();
|
|
|
- userWrapper.in(StoreUser::getStoreId, storeIds)
|
|
|
- .eq(StoreUser::getDeleteFlag, 0)
|
|
|
- .isNotNull(StoreUser::getHeadImg)
|
|
|
- .ne(StoreUser::getHeadImg, "")
|
|
|
- .orderByAsc(StoreUser::getAccountType) // 主账号(1)排在前面,null值排在最后
|
|
|
- .orderByAsc(StoreUser::getId);
|
|
|
- List<StoreUser> storeUsers = storeUserMapper.selectList(userWrapper);
|
|
|
+ List<Integer> storeIdsForFallback = couponList.stream()
|
|
|
+ .filter(vo -> {
|
|
|
+ Integer uid = vo.getCounterpartyStoreUserId();
|
|
|
+ if (uid != null && userIdToHeadImg.containsKey(uid)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ return vo.getStoreId() != null;
|
|
|
+ })
|
|
|
+ .map(LifeDiscountCouponFriendRuleVo::getStoreId)
|
|
|
+ .filter(Objects::nonNull)
|
|
|
+ .distinct()
|
|
|
+ .collect(Collectors.toList());
|
|
|
|
|
|
- // 构建店铺ID -> 头像的映射(优先主账号)
|
|
|
Map<Integer, String> storeAvatarMap = new HashMap<>();
|
|
|
- for (StoreUser user : storeUsers) {
|
|
|
- if (user.getStoreId() != null && user.getHeadImg() != null && !user.getHeadImg().trim().isEmpty()) {
|
|
|
+ if (!storeIdsForFallback.isEmpty()) {
|
|
|
+ LambdaQueryWrapper<StoreUser> userWrapper = new LambdaQueryWrapper<>();
|
|
|
+ userWrapper.in(StoreUser::getStoreId, storeIdsForFallback)
|
|
|
+ .eq(StoreUser::getDeleteFlag, 0)
|
|
|
+ .isNotNull(StoreUser::getHeadImg)
|
|
|
+ .ne(StoreUser::getHeadImg, "")
|
|
|
+ .orderByAsc(StoreUser::getAccountType)
|
|
|
+ .orderByAsc(StoreUser::getId);
|
|
|
+ for (StoreUser user : storeUserMapper.selectList(userWrapper)) {
|
|
|
+ if (user.getStoreId() == null || user.getHeadImg() == null || user.getHeadImg().trim().isEmpty()) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
Integer storeId = user.getStoreId();
|
|
|
- // 如果该店铺还没有头像,或者当前用户是主账号(account_type = 1),则设置头像
|
|
|
- // 主账号优先:如果已存在头像但当前是主账号,则覆盖
|
|
|
if (!storeAvatarMap.containsKey(storeId)) {
|
|
|
- // 该店铺还没有头像,直接设置
|
|
|
storeAvatarMap.put(storeId, user.getHeadImg());
|
|
|
} else if (user.getAccountType() != null && user.getAccountType() == 1) {
|
|
|
- // 该店铺已有头像,但当前是主账号,优先使用主账号头像
|
|
|
storeAvatarMap.put(storeId, user.getHeadImg());
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // 填充头像到结果中
|
|
|
for (LifeDiscountCouponFriendRuleVo vo : couponList) {
|
|
|
+ Integer uid = vo.getCounterpartyStoreUserId();
|
|
|
+ if (uid != null) {
|
|
|
+ String byUser = userIdToHeadImg.get(uid);
|
|
|
+ if (byUser != null) {
|
|
|
+ vo.setImgUrl(byUser);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ }
|
|
|
if (vo.getStoreId() != null) {
|
|
|
- String avatar = storeAvatarMap.get(vo.getStoreId());
|
|
|
- if (avatar != null) {
|
|
|
- vo.setImgUrl(avatar);
|
|
|
+ String byStore = storeAvatarMap.get(vo.getStoreId());
|
|
|
+ if (byStore != null) {
|
|
|
+ vo.setImgUrl(byStore);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ private void appendFriendSenderFilter(QueryWrapper<LifeDiscountCouponFriendRuleDetailVo> queryWrapper, String friendStoreUserId) {
|
|
|
+ if (friendStoreUserId == null) {
|
|
|
+ queryWrapper.eq("1", "0");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ String t = friendStoreUserId.trim();
|
|
|
+ if (t.isEmpty()) {
|
|
|
+ queryWrapper.eq("1", "0");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ applyLdcsfSenderMerchantFilter(queryWrapper, Integer.parseInt(t));
|
|
|
+ } catch (NumberFormatException e) {
|
|
|
+ queryWrapper.eq("1", "0");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
- * 构建基础查询条件
|
|
|
+ * 构建基础查询条件(与 {@code life_discount_coupon_store_friend} 四列语义对齐:
|
|
|
+ * 我收到的 → {@code receiver_store_id} 或旧列 {@code store_user_id};
|
|
|
+ * 我送出的 → {@code sender_user_id} 或旧列 {@code friend_store_user_id})。
|
|
|
*
|
|
|
- * @param isReceivedByMe true=我收到的(所有好友赠送给我的),false=我送出的(我送给所有好友的)
|
|
|
- * @param storeUserId 当前登录店铺用户ID
|
|
|
- * @param storeName 店铺名称(模糊查询)
|
|
|
+ * @param isReceivedByMe true=我收到的,false=我送出的
|
|
|
+ * @param storeUserId 当前登录账号 store_user.id
|
|
|
+ * @param storeName 对方店铺名称(模糊,对应联表 si.store_name)
|
|
|
* @return QueryWrapper
|
|
|
*/
|
|
|
private QueryWrapper<LifeDiscountCouponFriendRuleVo> buildBaseQueryWrapper(boolean isReceivedByMe, String storeUserId, String storeName) {
|
|
|
QueryWrapper<LifeDiscountCouponFriendRuleVo> queryWrapper = new QueryWrapper<>();
|
|
|
- // 根据表结构(实体类注释):
|
|
|
- // store_user_id: store_info的ID(店铺ID),收到券的店铺
|
|
|
- // friend_store_user_id: store_user的ID(店铺用户ID),送券的用户
|
|
|
- // 前端传入的 storeUserId 是当前登录账号的 store_user.id(店铺用户ID)
|
|
|
if (isReceivedByMe) {
|
|
|
- // 我收到的:查询所有好友赠送给我的券(我是收到券的店铺)
|
|
|
- // store_user_id = 我的店铺ID(store_info.id),需要从店铺用户ID转换为店铺ID
|
|
|
StoreUser storeUser = storeUserMapper.selectById(storeUserId);
|
|
|
if (storeUser != null && storeUser.getStoreId() != null) {
|
|
|
- queryWrapper.eq("ldcsf.store_user_id", storeUser.getStoreId());
|
|
|
+ applyLdcsfReceiverStoreFilter(queryWrapper, storeUser.getStoreId());
|
|
|
} else {
|
|
|
- // 如果查询不到店铺用户,返回空结果
|
|
|
- queryWrapper.eq("1", "0"); // 永远不匹配的条件
|
|
|
- log.warn("buildBaseQueryWrapper 查询不到店铺用户,storeUserId={}", storeUserId);
|
|
|
+ queryWrapper.eq("1", "0");
|
|
|
+ log.error("buildBaseQueryWrapper 查询不到店铺用户,storeUserId={}", storeUserId);
|
|
|
}
|
|
|
} else {
|
|
|
- // 我送出的:查询我送给所有好友的券(我是送券的用户)
|
|
|
- // friend_store_user_id = 我的店铺用户ID(store_user.id)
|
|
|
- queryWrapper.eq("ldcsf.friend_store_user_id", storeUserId);
|
|
|
+ try {
|
|
|
+ applyLdcsfSenderMerchantFilter(queryWrapper, Integer.parseInt(storeUserId.trim()));
|
|
|
+ } catch (NumberFormatException e) {
|
|
|
+ queryWrapper.eq("1", "0");
|
|
|
+ log.error("buildBaseQueryWrapper 非法 storeUserId={}", storeUserId);
|
|
|
+ }
|
|
|
}
|
|
|
queryWrapper.eq("ldcsf.delete_flag", 0);
|
|
|
// 店铺名称模糊查询
|
|
|
@@ -1002,55 +1109,11 @@ public class LifeDiscountCouponStoreFriendServiceImpl extends ServiceImpl<LifeDi
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 按有效期降序排序(null 值排在最后),如果有效期为 null 则按创建时间降序排序
|
|
|
- *
|
|
|
- * @param list 待排序列表
|
|
|
- * @return 排序后的列表
|
|
|
- */
|
|
|
- private List<LifeDiscountCouponFriendRuleVo> sortByEndDate(List<LifeDiscountCouponFriendRuleVo> list) {
|
|
|
- if (CollectionUtils.isEmpty(list)) {
|
|
|
- return list;
|
|
|
- }
|
|
|
- list.sort((a, b) -> {
|
|
|
- // 优先按有效期(validDate)排序,如果为 null 则按创建时间(endDate)排序
|
|
|
- Date validDateA = a.getValidDate();
|
|
|
- Date validDateB = b.getValidDate();
|
|
|
- Date endDateA = a.getEndDate();
|
|
|
- Date endDateB = b.getEndDate();
|
|
|
-
|
|
|
- // 如果两个都有有效期,按有效期排序
|
|
|
- if (validDateA != null && validDateB != null) {
|
|
|
- return validDateB.compareTo(validDateA); // 降序:有效期晚的在前
|
|
|
- }
|
|
|
- // 如果只有一个有有效期,有有效期的排在前面
|
|
|
- if (validDateA != null) {
|
|
|
- return -1;
|
|
|
- }
|
|
|
- if (validDateB != null) {
|
|
|
- return 1;
|
|
|
- }
|
|
|
- // 如果都没有有效期,按创建时间排序
|
|
|
- if (endDateA == null && endDateB == null) {
|
|
|
- return 0;
|
|
|
- }
|
|
|
- if (endDateA == null) {
|
|
|
- return 1;
|
|
|
- }
|
|
|
- if (endDateB == null) {
|
|
|
- return -1;
|
|
|
- }
|
|
|
- // 降序排序(最新的在前)
|
|
|
- return endDateB.compareTo(endDateA);
|
|
|
- });
|
|
|
- return list;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 好评送券:用户好评且AI审核通过后,按运营活动配置的优惠券/代金券ID发放到用户券包,发放成功后扣减库存;按券类型发送对应通知。
|
|
|
+ * 好评送券:用户好评且AI审核通过后,按运营活动配置的优惠券发放到用户券包。
|
|
|
*
|
|
|
* @param userId 评价用户ID(life用户)
|
|
|
* @param storeId 店铺ID(businessId)
|
|
|
- * @return 发放数量(优惠券+代金券),0表示未发放
|
|
|
+ * @return 发放张数,0 表示未发放
|
|
|
*/
|
|
|
@Override
|
|
|
public int issueCouponForGoodRating(Integer userId, Integer storeId) {
|
|
|
@@ -1068,7 +1131,7 @@ public class LifeDiscountCouponStoreFriendServiceImpl extends ServiceImpl<LifeDi
|
|
|
.orderByDesc(StoreOperationalActivity::getId)
|
|
|
.last("LIMIT 1");
|
|
|
StoreOperationalActivity activity = storeOperationalActivityMapper.selectOne(activityWrapper);
|
|
|
- if (activity == null || (activity.getCouponId() == null && activity.getVoucherId() == null)) {
|
|
|
+ if (activity == null || activity.getCouponId() == null || activity.getCouponId() <= 0) {
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
@@ -1078,222 +1141,193 @@ public class LifeDiscountCouponStoreFriendServiceImpl extends ServiceImpl<LifeDi
|
|
|
// 只统计活动开始时间之后的好评,活动开始前的评论不计入参与次数
|
|
|
int passedCount = commonRatingMapper.countPassedGoodRatingsByUserAndStore(
|
|
|
Long.valueOf(userId), storeId, activity.getStartTime());
|
|
|
- if (passedCount >= limit) {
|
|
|
+ if (passedCount > limit) {
|
|
|
log.info("issueCouponForGoodRating 好评送券跳过:超过运营活动参与次数 participation_limit={}, count={}, userId={}, storeId={}, activityStartTime={}",
|
|
|
limit, passedCount, userId, storeId, activity.getStartTime());
|
|
|
return 0;
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- // 调用4参数方法进行发放
|
|
|
- return issueCouponForGoodRating(userId, storeId, activity.getCouponId(), activity.getVoucherId());
|
|
|
+
|
|
|
+ return issueCouponForGoodRating(userId, storeId, activity.getCouponId(), activity.getCouponQuantity());
|
|
|
+ }
|
|
|
+
|
|
|
+ private static int resolveGoodRatingCouponCopies(Integer couponQuantity) {
|
|
|
+ if (couponQuantity == null) {
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ if (couponQuantity < 1) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ return Math.min(couponQuantity, GOOD_RATING_ISSUE_COPIES_HARD_CAP);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 好评送券:按优惠券/代金券ID发放到用户券包,发放成功后扣减库存;根据是优惠券还是代金券发送对应通知。
|
|
|
+ * 好评送券:按优惠券模板 ID 发放到用户券包,扣减库存并通知。
|
|
|
*/
|
|
|
- public int issueCouponForGoodRating(Integer userId, Integer storeId, Integer couponId, Integer voucherId) {
|
|
|
+ @Override
|
|
|
+ public int issueCouponForGoodRating(Integer userId, Integer storeId, Integer couponId) {
|
|
|
+ return issueCouponForGoodRating(userId, storeId, couponId, null);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public int issueCouponForGoodRating(Integer userId, Integer storeId, Integer couponId, Integer couponQuantity) {
|
|
|
if (userId == null || storeId == null) {
|
|
|
return 0;
|
|
|
}
|
|
|
- if ((couponId == null || couponId <= 0) && (voucherId == null || voucherId <= 0)) {
|
|
|
+ if (couponId == null || couponId <= 0) {
|
|
|
return 0;
|
|
|
}
|
|
|
int commenterUserId = userId.intValue();
|
|
|
+ int copiesWanted = resolveGoodRatingCouponCopies(couponQuantity);
|
|
|
+
|
|
|
StoreInfo storeInfo = storeInfoMapper.selectById(storeId);
|
|
|
LifeUser lifeUser = lifeUserMapper.selectById(commenterUserId);
|
|
|
- int grantedCoupon = 0;
|
|
|
- int grantedVoucher = 0;
|
|
|
- String couponName = null; // 优惠券名称
|
|
|
- String voucherName = null; // 代金券名称
|
|
|
- LifeDiscountCoupon lifeDiscountCoupon = null; // 保存优惠券对象,用于通知消息
|
|
|
-
|
|
|
- // 按优惠券ID发放:发放1张,扣减库存,发优惠券通知
|
|
|
- if (couponId != null && couponId > 0) {
|
|
|
- LifeDiscountCoupon coupon = lifeDiscountCouponMapper.selectById(couponId);
|
|
|
- if (coupon != null && String.valueOf(storeId).equals(coupon.getStoreId())
|
|
|
- && coupon.getSingleQty() != null && coupon.getSingleQty() > 0) {
|
|
|
- try {
|
|
|
- LifeDiscountCouponUser lifeDiscountCouponUser = new LifeDiscountCouponUser();
|
|
|
- lifeDiscountCouponUser.setCouponId(coupon.getId());
|
|
|
- lifeDiscountCouponUser.setUserId(commenterUserId);
|
|
|
- lifeDiscountCouponUser.setReceiveTime(new Date());
|
|
|
- lifeDiscountCouponUser.setExpirationTime(DiscountCouponExpirationUtil.resolveLifeDiscountCouponExpiration(
|
|
|
- lifeDiscountCouponUser.getReceiveTime(),
|
|
|
- coupon.getSpecifiedDay(),
|
|
|
- coupon.getExpirationDate(),
|
|
|
- coupon.getValidDate(),
|
|
|
- coupon.getEndDate(),
|
|
|
- ZoneId.systemDefault()));
|
|
|
- lifeDiscountCouponUser.setStatus(Integer.parseInt(DiscountCouponEnum.WAITING_USED.getValue()));
|
|
|
- lifeDiscountCouponUser.setDeleteFlag(0);
|
|
|
- lifeDiscountCouponUser.setIssueSource(3); // 3-好评送券
|
|
|
- lifeDiscountCouponUserMapper.insert(lifeDiscountCouponUser);
|
|
|
- coupon.setSingleQty(coupon.getSingleQty() - 1);
|
|
|
-// 1. 获取开始日期
|
|
|
- LocalDate beginDate = coupon.getBeginGetDate();
|
|
|
-// 2. 获取字符串类型的天数
|
|
|
- String specifiedDayStr = coupon.getSpecifiedDay();
|
|
|
-
|
|
|
-// 3. 基础校验
|
|
|
- if (beginDate == null) {
|
|
|
- throw new IllegalArgumentException("优惠券开始日期不能为空");
|
|
|
- }
|
|
|
- if (specifiedDayStr == null || specifiedDayStr.isEmpty()) {
|
|
|
- throw new IllegalArgumentException("有效天数不能为空");
|
|
|
- }
|
|
|
|
|
|
-// 4. 字符串转整数 + 合法性校验
|
|
|
- int days;
|
|
|
- try {
|
|
|
- days = Integer.parseInt(specifiedDayStr);
|
|
|
- } catch (NumberFormatException e) {
|
|
|
- throw new IllegalArgumentException("有效天数必须是纯数字:" + specifiedDayStr);
|
|
|
- }
|
|
|
- if (days <= 0) {
|
|
|
- throw new IllegalArgumentException("有效天数必须大于0");
|
|
|
- }
|
|
|
+ LifeDiscountCoupon coupon = lifeDiscountCouponMapper.selectById(couponId);
|
|
|
+ if (coupon == null || !String.valueOf(storeId).equals(coupon.getStoreId())) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ if (!LifeDiscountCouponStock.hasTemplateStockRemaining(coupon.getUnlimitedQty(), coupon.getSingleQty())) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
|
|
|
-// 5. 计算结束日期并赋值
|
|
|
- LocalDate endDate = beginDate.plusDays(days);
|
|
|
- coupon.setEndGetDate(endDate);
|
|
|
- lifeDiscountCouponMapper.updateById(coupon);
|
|
|
- grantedCoupon = 1;
|
|
|
- couponName = coupon.getName(); // 保存优惠券名称
|
|
|
- lifeDiscountCoupon = coupon; // 保存优惠券对象,用于通知消息
|
|
|
- } catch (Exception e) {
|
|
|
- log.error("发放优惠券失败,userId={}, storeId={}, couponId={}, error={}", userId, storeId, couponId, e.getMessage(), e);
|
|
|
- }
|
|
|
+ ZoneId zone = ZoneId.systemDefault();
|
|
|
+ if (!Integer.valueOf(1).equals(coupon.getLongTermValid())) {
|
|
|
+ LocalDate beginDate = coupon.getBeginGetDate();
|
|
|
+ if (beginDate == null) {
|
|
|
+ beginDate = LocalDate.now(zone);
|
|
|
+ coupon.setBeginGetDate(beginDate);
|
|
|
+ }
|
|
|
+ String specifiedDayStr = coupon.getSpecifiedDay();
|
|
|
+ if (specifiedDayStr == null || specifiedDayStr.isEmpty()) {
|
|
|
+ log.error("发放优惠券失败(非长期券缺少有效天数),userId={}, storeId={}, couponId={}", userId, storeId, couponId);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ int days;
|
|
|
+ try {
|
|
|
+ days = Integer.parseInt(specifiedDayStr.trim());
|
|
|
+ } catch (NumberFormatException e) {
|
|
|
+ log.error("发放优惠券失败(有效天数非法),userId={}, storeId={}, couponId={}, specifiedDay={}",
|
|
|
+ userId, storeId, couponId, specifiedDayStr, e);
|
|
|
+ return 0;
|
|
|
}
|
|
|
+ if (days <= 0) {
|
|
|
+ log.error("发放优惠券失败(有效天数须>0),userId={}, storeId={}, couponId={}", userId, storeId, couponId);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ coupon.setEndGetDate(beginDate.plusDays(days));
|
|
|
}
|
|
|
|
|
|
- // 按代金券ID发放:发放1张,扣减库存,发代金券通知
|
|
|
- if (voucherId != null && voucherId > 0) {
|
|
|
- LifeCoupon lifeCoupon = lifeCouponMapper.selectById(voucherId);
|
|
|
- if (lifeCoupon != null && String.valueOf(storeId).equals(lifeCoupon.getStoreId())
|
|
|
- && lifeCoupon.getSingleQty() != null && lifeCoupon.getSingleQty() > 0) {
|
|
|
- try {
|
|
|
- LifeDiscountCouponUser lifeDiscountCouponUser = new LifeDiscountCouponUser();
|
|
|
- lifeDiscountCouponUser.setVoucherId(lifeCoupon.getId());
|
|
|
- lifeDiscountCouponUser.setUserId(commenterUserId);
|
|
|
- lifeDiscountCouponUser.setReceiveTime(new Date());
|
|
|
- lifeDiscountCouponUser.setExpirationTime(DiscountCouponExpirationUtil.resolveLifeCouponVoucherExpiration(
|
|
|
- lifeDiscountCouponUser.getReceiveTime(),
|
|
|
- lifeCoupon.getExpirationDate(),
|
|
|
- lifeCoupon.getEndDate(),
|
|
|
- ZoneId.systemDefault()));
|
|
|
- lifeDiscountCouponUser.setStatus(Integer.parseInt(DiscountCouponEnum.WAITING_USED.getValue()));
|
|
|
- lifeDiscountCouponUser.setDeleteFlag(0);
|
|
|
- lifeDiscountCouponUser.setIssueSource(3); // 3-好评送券(代金券)
|
|
|
- lifeDiscountCouponUserMapper.insert(lifeDiscountCouponUser);
|
|
|
- lifeCoupon.setSingleQty(lifeCoupon.getSingleQty() - 1);
|
|
|
- lifeCouponMapper.updateById(lifeCoupon);
|
|
|
- grantedVoucher = 1;
|
|
|
- voucherName = lifeCoupon.getName(); // 保存代金券名称
|
|
|
- } catch (Exception e) {
|
|
|
- log.error("发放代金券失败,userId={}, storeId={}, voucherId={}, error={}", userId, storeId, voucherId, e.getMessage(), e);
|
|
|
+ int grantedCoupon = 0;
|
|
|
+ for (int i = 0; i < copiesWanted; i++) {
|
|
|
+ if (!LifeDiscountCouponStock.hasTemplateStockRemaining(coupon.getUnlimitedQty(), coupon.getSingleQty())) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ Date receiveTime = new Date();
|
|
|
+ LifeDiscountCouponUser lifeDiscountCouponUser = new LifeDiscountCouponUser();
|
|
|
+ lifeDiscountCouponUser.setCouponId(coupon.getId());
|
|
|
+ lifeDiscountCouponUser.setUserId(commenterUserId);
|
|
|
+ lifeDiscountCouponUser.setReceiveTime(receiveTime);
|
|
|
+ lifeDiscountCouponUser.setExpirationTime(DiscountCouponExpirationUtil.resolveLifeDiscountCouponExpiration(
|
|
|
+ receiveTime,
|
|
|
+ coupon.getLongTermValid(),
|
|
|
+ coupon.getSpecifiedDay(),
|
|
|
+ coupon.getExpirationDate(),
|
|
|
+ coupon.getValidDate(),
|
|
|
+ coupon.getEndDate(),
|
|
|
+ zone));
|
|
|
+ lifeDiscountCouponUser.setStatus(Integer.parseInt(DiscountCouponEnum.WAITING_USED.getValue()));
|
|
|
+ lifeDiscountCouponUser.setDeleteFlag(0);
|
|
|
+ lifeDiscountCouponUser.setIssueSource(3); // 3-好评送券
|
|
|
+ lifeDiscountCouponUserMapper.insert(lifeDiscountCouponUser);
|
|
|
+ if (!LifeDiscountCouponStock.isUnlimitedQty(coupon.getUnlimitedQty())
|
|
|
+ && coupon.getSingleQty() != null) {
|
|
|
+ coupon.setSingleQty(coupon.getSingleQty() - 1);
|
|
|
}
|
|
|
+ grantedCoupon++;
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("发放优惠券失败,userId={}, storeId={}, couponId={}, index={}, error={}",
|
|
|
+ userId, storeId, couponId, i, e.getMessage(), e);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (grantedCoupon > 0) {
|
|
|
+ try {
|
|
|
+ lifeDiscountCouponMapper.updateById(coupon);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("更新优惠券模板失败 userId={}, storeId={}, couponId={}, error={}", userId, storeId, couponId, e.getMessage(), e);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // 根据发放的是优惠券还是代金券发送对应通知(明确区分券类型和名称)
|
|
|
- if (lifeUser != null && storeInfo != null) {
|
|
|
- if (grantedCoupon > 0 && couponName != null) {
|
|
|
- LifeNotice couponNotice = new LifeNotice();
|
|
|
- couponNotice.setSenderId("system");
|
|
|
- couponNotice.setReceiverId("user_" + lifeUser.getUserPhone());
|
|
|
-
|
|
|
- // 构建优惠券详情信息
|
|
|
- String couponDetailText = "";
|
|
|
- if (lifeDiscountCoupon != null) {
|
|
|
- Integer couponType = lifeDiscountCoupon.getCouponType();
|
|
|
- if (couponType != null && couponType == 2) {
|
|
|
- // 折扣券:discountRate 为实付比例 0-100,与券模板一致(10=付10%=1折,80=8折)
|
|
|
- BigDecimal discountRate = lifeDiscountCoupon.getDiscountRate();
|
|
|
- if (discountRate != null) {
|
|
|
- BigDecimal zheShu = discountRate.divide(BigDecimal.TEN, 2, RoundingMode.HALF_UP);
|
|
|
- String zheShuText = zheShu.stripTrailingZeros().toPlainString();
|
|
|
- couponDetailText = "(" + zheShuText + "折";
|
|
|
- if (lifeDiscountCoupon.getMinimumSpendingAmount() != null) {
|
|
|
- couponDetailText += ",满" + lifeDiscountCoupon.getMinimumSpendingAmount() + "可用";
|
|
|
- }
|
|
|
- couponDetailText += ")";
|
|
|
+ LifeDiscountCoupon lifeDiscountCoupon = grantedCoupon > 0 ? coupon : null;
|
|
|
+ String couponName = grantedCoupon > 0 ? coupon.getName() : null;
|
|
|
+
|
|
|
+ if (lifeUser != null && storeInfo != null && grantedCoupon > 0 && couponName != null) {
|
|
|
+ LifeNotice couponNotice = new LifeNotice();
|
|
|
+ couponNotice.setSenderId("system");
|
|
|
+ couponNotice.setReceiverId("user_" + lifeUser.getUserPhone());
|
|
|
+
|
|
|
+ String couponDetailText = "";
|
|
|
+ if (lifeDiscountCoupon != null) {
|
|
|
+ Integer cType = lifeDiscountCoupon.getCouponType();
|
|
|
+ if (cType != null && cType == 2) {
|
|
|
+ BigDecimal discountRate = lifeDiscountCoupon.getDiscountRate();
|
|
|
+ if (discountRate != null) {
|
|
|
+ BigDecimal zheShu = discountRate.divide(BigDecimal.TEN, 2, RoundingMode.HALF_UP);
|
|
|
+ String zheShuText = zheShu.stripTrailingZeros().toPlainString();
|
|
|
+ couponDetailText = "(" + zheShuText + "折";
|
|
|
+ if (lifeDiscountCoupon.getMinimumSpendingAmount() != null) {
|
|
|
+ couponDetailText += ",满" + lifeDiscountCoupon.getMinimumSpendingAmount() + "可用";
|
|
|
}
|
|
|
- } else {
|
|
|
- // 满减券(默认)
|
|
|
- if (lifeDiscountCoupon.getNominalValue() != null) {
|
|
|
- couponDetailText = "(满减" + lifeDiscountCoupon.getNominalValue() + "元";
|
|
|
- if (lifeDiscountCoupon.getMinimumSpendingAmount() != null) {
|
|
|
- couponDetailText += ",满" + lifeDiscountCoupon.getMinimumSpendingAmount() + "可用";
|
|
|
- }
|
|
|
- couponDetailText += ")";
|
|
|
+ couponDetailText += ")";
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (lifeDiscountCoupon.getNominalValue() != null) {
|
|
|
+ couponDetailText = "(满减" + lifeDiscountCoupon.getNominalValue() + "元";
|
|
|
+ if (lifeDiscountCoupon.getMinimumSpendingAmount() != null) {
|
|
|
+ couponDetailText += ",满" + lifeDiscountCoupon.getMinimumSpendingAmount() + "可用";
|
|
|
}
|
|
|
+ couponDetailText += ")";
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- // 明确标注是优惠券,并包含券的具体名称和详情
|
|
|
- String couponText = "您对店铺「" + storeInfo.getStoreName() + "」的好评已通过审核,已为您发放优惠券「" + couponName + "」" + couponDetailText + ",快去我的券包查看吧~";
|
|
|
- JSONObject couponJson = new JSONObject();
|
|
|
- couponJson.put("message", couponText);
|
|
|
- couponJson.put("couponType", "优惠券"); // 明确标识券类型
|
|
|
- couponJson.put("couponName", couponName); // 券名称
|
|
|
- if (lifeDiscountCoupon != null) {
|
|
|
- couponJson.put("couponTypeValue", lifeDiscountCoupon.getCouponType()); // 优惠券类型值(1-满减券,2-折扣券)
|
|
|
- }
|
|
|
- couponNotice.setContext(couponJson.toJSONString());
|
|
|
- couponNotice.setNoticeType(1);
|
|
|
- couponNotice.setTitle("好评送优惠券"); // 标题明确标注是优惠券
|
|
|
- couponNotice.setIsRead(0);
|
|
|
- couponNotice.setDeleteFlag(0);
|
|
|
- lifeNoticeMapper.insert(couponNotice);
|
|
|
-
|
|
|
- // WebSocket 实时推送通知
|
|
|
- try {
|
|
|
- WebSocketVo websocketVo = new WebSocketVo();
|
|
|
- websocketVo.setSenderId("system");
|
|
|
- websocketVo.setReceiverId("user_" + lifeUser.getUserPhone());
|
|
|
- websocketVo.setCategory("notice");
|
|
|
- websocketVo.setNoticeType("1");
|
|
|
- websocketVo.setIsRead(0);
|
|
|
- websocketVo.setText(JSONObject.from(couponNotice).toJSONString());
|
|
|
- webSocketProcess.sendMessage("user_" + lifeUser.getUserPhone(), JSONObject.from(websocketVo).toJSONString());
|
|
|
- } catch (Exception e) {
|
|
|
- log.error("好评送优惠券 WebSocket 推送失败,userId={}, storeId={}, couponId={}, error={}", userId, storeId, couponId, e.getMessage(), e);
|
|
|
- }
|
|
|
}
|
|
|
- if (grantedVoucher > 0 && voucherName != null) {
|
|
|
- LifeNotice voucherNotice = new LifeNotice();
|
|
|
- voucherNotice.setSenderId("system");
|
|
|
- voucherNotice.setReceiverId("user_" + lifeUser.getUserPhone());
|
|
|
- // 明确标注是代金券,并包含券的具体名称
|
|
|
- String voucherText = "您对店铺「" + storeInfo.getStoreName() + "」的好评已通过审核,已为您发放代金券「" + voucherName + "」,快去我的券包查看吧~";
|
|
|
- JSONObject voucherJson = new JSONObject();
|
|
|
- voucherJson.put("message", voucherText);
|
|
|
- voucherJson.put("couponType", "代金券"); // 明确标识券类型
|
|
|
- voucherJson.put("couponName", voucherName); // 券名称
|
|
|
- voucherNotice.setContext(voucherJson.toJSONString());
|
|
|
- voucherNotice.setNoticeType(1);
|
|
|
- voucherNotice.setTitle("好评送代金券"); // 标题明确标注是代金券
|
|
|
- voucherNotice.setIsRead(0);
|
|
|
- voucherNotice.setDeleteFlag(0);
|
|
|
- lifeNoticeMapper.insert(voucherNotice);
|
|
|
-
|
|
|
- // WebSocket 实时推送通知
|
|
|
- try {
|
|
|
- WebSocketVo websocketVo = new WebSocketVo();
|
|
|
- websocketVo.setSenderId("system");
|
|
|
- websocketVo.setReceiverId("user_" + lifeUser.getUserPhone());
|
|
|
- websocketVo.setCategory("notice");
|
|
|
- websocketVo.setNoticeType("1");
|
|
|
- websocketVo.setIsRead(0);
|
|
|
- websocketVo.setText(JSONObject.from(voucherNotice).toJSONString());
|
|
|
- webSocketProcess.sendMessage("user_" + lifeUser.getUserPhone(), JSONObject.from(websocketVo).toJSONString());
|
|
|
- } catch (Exception e) {
|
|
|
- log.error("好评送代金券 WebSocket 推送失败,userId={}, storeId={}, voucherId={}, error={}", userId, storeId, voucherId, e.getMessage(), e);
|
|
|
- }
|
|
|
+
|
|
|
+ String couponText = grantedCoupon > 1
|
|
|
+ ? "您对店铺「" + storeInfo.getStoreName() + "」的好评已通过审核,已为您发放优惠券「" + couponName + "」"
|
|
|
+ + couponDetailText + "共" + grantedCoupon + "张,快去我的券包查看吧~"
|
|
|
+ : "您对店铺「" + storeInfo.getStoreName() + "」的好评已通过审核,已为您发放优惠券「" + couponName + "」"
|
|
|
+ + couponDetailText + ",快去我的券包查看吧~";
|
|
|
+ JSONObject couponJson = new JSONObject();
|
|
|
+ couponJson.put("message", couponText);
|
|
|
+ couponJson.put("couponType", "优惠券");
|
|
|
+ couponJson.put("couponName", couponName);
|
|
|
+ couponJson.put("grantCount", grantedCoupon);
|
|
|
+ if (lifeDiscountCoupon != null) {
|
|
|
+ couponJson.put("couponTypeValue", lifeDiscountCoupon.getCouponType());
|
|
|
+ }
|
|
|
+ couponNotice.setContext(couponJson.toJSONString());
|
|
|
+ couponNotice.setNoticeType(1);
|
|
|
+ couponNotice.setTitle("好评送优惠券");
|
|
|
+ couponNotice.setIsRead(0);
|
|
|
+ couponNotice.setDeleteFlag(0);
|
|
|
+ lifeNoticeMapper.insert(couponNotice);
|
|
|
+
|
|
|
+ try {
|
|
|
+ WebSocketVo websocketVo = new WebSocketVo();
|
|
|
+ websocketVo.setSenderId("system");
|
|
|
+ websocketVo.setReceiverId("user_" + lifeUser.getUserPhone());
|
|
|
+ websocketVo.setCategory("notice");
|
|
|
+ websocketVo.setNoticeType("1");
|
|
|
+ websocketVo.setIsRead(0);
|
|
|
+ websocketVo.setText(JSONObject.from(couponNotice).toJSONString());
|
|
|
+ webSocketProcess.sendMessage("user_" + lifeUser.getUserPhone(), JSONObject.from(websocketVo).toJSONString());
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("好评送优惠券 WebSocket 推送失败,userId={}, storeId={}, couponId={}, error={}", userId, storeId, couponId, e.getMessage(), e);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- return grantedCoupon + grantedVoucher;
|
|
|
+ return grantedCoupon;
|
|
|
}
|
|
|
}
|