From 37c866f665fc1d2255f0442f92516c686c6c9edf Mon Sep 17 00:00:00 2001
From: kong <sunuping1@sina.com>
Date: 星期日, 12 四月 2026 16:55:52 +0800
Subject: [PATCH] add 优惠券切换
---
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/service/impl/XpAppUserCouponServiceImpl.java | 148 +++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 148 insertions(+), 0 deletions(-)
diff --git a/xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/service/impl/XpAppUserCouponServiceImpl.java b/xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/service/impl/XpAppUserCouponServiceImpl.java
index 2332280..220a92c 100644
--- a/xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/service/impl/XpAppUserCouponServiceImpl.java
+++ b/xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/service/impl/XpAppUserCouponServiceImpl.java
@@ -15,7 +15,11 @@
import com.xiaopeng.account.model.vo.XpAppUserCouponVo;
import com.xiaopeng.account.service.IXpAppUserCouponService;
import com.xiaopeng.account.util.holiday.HolidayUtil;
+import com.xiaopeng.api.dto.account.NavigationCouponPickerRequest;
import com.xiaopeng.api.dto.account.UcUserInfo;
+import com.xiaopeng.api.enums.NavigationCouponBubbleType;
+import com.xiaopeng.api.vo.account.NavigationCouponItemVo;
+import com.xiaopeng.api.vo.account.NavigationCouponPickerVo;
import com.xiaopeng.api.feignClient.account.UserResourcesClient;
import com.xiaopeng.api.feignClient.operation.XpCouponClient;
import com.xiaopeng.api.feignClient.operation.XpWhiteListClient;
@@ -27,9 +31,13 @@
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
+import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
+import java.util.Comparator;
import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
/**
* <p>
@@ -225,4 +233,144 @@
return false;
}
+ @Override
+ public NavigationCouponPickerVo navigationCouponPicker(Long userId, NavigationCouponPickerRequest req) {
+ NavigationCouponPickerVo vo = new NavigationCouponPickerVo();
+ double orderAmount = req.getOrderAmount() == null ? 0d : req.getOrderAmount();
+ List<XpAppUserCoupon> couponList = baseMapper.selectList(new LambdaQueryWrapper<XpAppUserCoupon>()
+ .eq(XpAppUserCoupon::getStatus, 1)
+ .eq(XpAppUserCoupon::getAppUserId, userId)
+ .apply("(FIND_IN_SET({0}, open_city_id) or open_city_id='0')", req.getOpenCityId()));
+ couponList = timeRule(couponList);
+
+ Long bestId = null;
+ double bestEff = -1d;
+ LocalDateTime bestExp = null;
+ for (XpAppUserCoupon c : couponList) {
+ if (!couponAmountAvailable(c, orderAmount)) {
+ continue;
+ }
+ double eff = effectiveDiscountAmount(c, orderAmount);
+ if (eff <= 0) {
+ continue;
+ }
+ LocalDateTime exp = c.getExpirationTime();
+ if (bestId == null || eff > bestEff + 1e-6
+ || (Math.abs(eff - bestEff) < 1e-6 && exp != null && bestExp != null && exp.isBefore(bestExp))
+ || (Math.abs(eff - bestEff) < 1e-6 && bestExp == null && exp != null)) {
+ bestId = c.getId();
+ bestEff = eff;
+ bestExp = exp;
+ }
+ }
+ vo.setRecommendedUserCouponId(bestId);
+
+ Long selected = req.getSelectedUserCouponId();
+ Long applied;
+ if (selected != null && selected == 0L) {
+ applied = null;
+ } else if (selected != null && selected > 0L) {
+ XpAppUserCoupon chosen = couponList.stream().filter(c -> selected.equals(c.getId())).findFirst().orElse(null);
+ if (chosen != null && couponAmountAvailable(chosen, orderAmount)) {
+ applied = selected;
+ } else {
+ applied = null;
+ }
+ } else {
+ applied = bestId;
+ }
+ vo.setAppliedUserCouponId(applied);
+
+ long availCount = couponList.stream().filter(c -> couponAmountAvailable(c, orderAmount)).count();
+ if (availCount == 0) {
+ vo.setBubbleType(NavigationCouponBubbleType.HIDDEN);
+ List<NavigationCouponItemVo> hiddenItems = buildNavigationItems(couponList, orderAmount, bestId, applied);
+ vo.setItems(hiddenItems);
+ vo.setListTotalCount(hiddenItems.size());
+ return vo;
+ }
+ if (applied == null) {
+ vo.setBubbleType(NavigationCouponBubbleType.MULTI_AVAILABLE);
+ vo.setAvailableCouponCount((int) availCount);
+ } else {
+ vo.setBubbleType(NavigationCouponBubbleType.SELECTED);
+ XpAppUserCoupon ap = couponList.stream().filter(c -> applied.equals(c.getId())).findFirst().orElse(null);
+ vo.setSelectedDiscountAmount(ap != null ? effectiveDiscountAmount(ap, orderAmount) : 0d);
+ }
+ List<NavigationCouponItemVo> items = buildNavigationItems(couponList, orderAmount, bestId, applied);
+ vo.setItems(items);
+ vo.setListTotalCount(items.size());
+ return vo;
+ }
+
+ private List<NavigationCouponItemVo> buildNavigationItems(List<XpAppUserCoupon> couponList, double orderAmount,
+ Long bestId, Long appliedId) {
+ List<NavigationCouponItemVo> raw = new ArrayList<>();
+ for (XpAppUserCoupon c : couponList) {
+ NavigationCouponItemVo it = new NavigationCouponItemVo();
+ it.setUserCouponId(c.getId());
+ it.setCouponName(c.getCouponName());
+ it.setCouponType(c.getCouponType());
+ it.setDiscountMoney(c.getMoney() != null ? c.getMoney().doubleValue() : 0d);
+ it.setFullMoney(c.getFullMoney() != null ? c.getFullMoney().doubleValue() : null);
+ it.setExpireTime(c.getExpirationTime());
+ boolean ok = couponAmountAvailable(c, orderAmount);
+ it.setAvailable(ok);
+ if (c.getCouponType() != null && c.getCouponType() == 2) {
+ it.setThresholdLabel("满" + moneyStr(c.getFullMoney()) + "元可用");
+ if (!ok) {
+ it.setUnavailableReason("未满足使用门槛");
+ }
+ } else {
+ it.setThresholdLabel("无门槛");
+ }
+ it.setBestOffer(bestId != null && bestId.equals(c.getId()));
+ it.setSelected(appliedId != null && appliedId.equals(c.getId()));
+ raw.add(it);
+ }
+ List<NavigationCouponItemVo> available = raw.stream().filter(x -> Boolean.TRUE.equals(x.getAvailable()))
+ .sorted(Comparator
+ .comparing((NavigationCouponItemVo x) -> !Boolean.TRUE.equals(x.getBestOffer()))
+ .thenComparing((NavigationCouponItemVo x) -> -effectiveDiscountAmount(findCoupon(couponList, x.getUserCouponId()), orderAmount))
+ .thenComparing(NavigationCouponItemVo::getExpireTime, Comparator.nullsLast(Comparator.naturalOrder())))
+ .collect(Collectors.toList());
+ List<NavigationCouponItemVo> unavailable = raw.stream().filter(x -> !Boolean.TRUE.equals(x.getAvailable()))
+ .sorted(Comparator.comparing(NavigationCouponItemVo::getExpireTime, Comparator.nullsLast(Comparator.naturalOrder())))
+ .collect(Collectors.toList());
+ available.addAll(unavailable);
+ return available;
+ }
+
+ private static XpAppUserCoupon findCoupon(List<XpAppUserCoupon> list, Long id) {
+ return list.stream().filter(c -> Objects.equals(c.getId(), id)).findFirst().orElse(null);
+ }
+
+ private static String moneyStr(BigDecimal b) {
+ if (b == null) {
+ return "0";
+ }
+ return b.stripTrailingZeros().toPlainString();
+ }
+
+ private static boolean couponAmountAvailable(XpAppUserCoupon c, double orderAmount) {
+ if (c.getCouponType() == null || c.getCouponType() == 1) {
+ return true;
+ }
+ if (c.getCouponType() == 2) {
+ return c.getFullMoney() != null && orderAmount >= c.getFullMoney().doubleValue();
+ }
+ return true;
+ }
+
+ private static double effectiveDiscountAmount(XpAppUserCoupon c, double orderAmount) {
+ if (c == null || c.getMoney() == null) {
+ return 0d;
+ }
+ double m = c.getMoney().doubleValue();
+ if (!couponAmountAvailable(c, orderAmount)) {
+ return 0d;
+ }
+ return Math.min(orderAmount, m);
+ }
+
}
--
Gitblit v1.7.1