1.关闭续订前七天邮件提醒

2.优化订阅邮件提醒,向redis存储已发送的邮件类型
This commit is contained in:
2025-05-23 17:16:19 +08:00
parent 3b6b0c7e2c
commit 5c66ece467
7 changed files with 51 additions and 29 deletions

View File

@@ -13,6 +13,8 @@ public class CommonConstant {
public static final Integer MINIO_IMAGE_EXPIRE_TIME = 24 * 60; public static final Integer MINIO_IMAGE_EXPIRE_TIME = 24 * 60;
// 单位 秒 一天过期 in redis // 单位 秒 一天过期 in redis
public static final Long GENERATE_RESULT_EXPIRE_TIME = 24 * 60 * 60L; public static final Long GENERATE_RESULT_EXPIRE_TIME = 24 * 60 * 60L;
// 单位 秒 7天过期
public static final Long REDIS_SET_EXPIRE_TIME = 24 * 60 * 60 * 7L;
public static class Numbers{ public static class Numbers{
public static final Integer NUMBER_10 = 10; public static final Integer NUMBER_10 = 10;

View File

@@ -84,8 +84,9 @@ public class PaymentTask {
}*/ }*/
} }
// !!关闭此定时器,改为提前三天站内信提醒!!
// 提前7天向用户发送提醒邮件,每天早上8点执行 // 提前7天向用户发送提醒邮件,每天早上8点执行
@Scheduled(cron = "0 0 8 * * ?") // @Scheduled(cron = "0 0 8 * * ?")
public void subscriptionReminder(){ public void subscriptionReminder(){
stripeService.subscriptionReminder(); stripeService.subscriptionReminder();
} }
@@ -113,7 +114,7 @@ public class PaymentTask {
} }
} }
@Scheduled(cron = "0 */5 * * * *") // Run every 5 minutes @Scheduled(cron = "0 */5 * * * *") // Run every 5 minutes
public void calcCouponsCommission(){ public void calcCouponsCommission(){
// log.info("优惠券佣金计算定时器"); // log.info("优惠券佣金计算定时器");
affiliateService.calcCouponsCommission(); affiliateService.calcCouponsCommission();

View File

@@ -84,8 +84,10 @@ public class RedisUtil {
/** /**
* 将数据放入set缓存 * 将数据放入set缓存
*/ */
public void addToSet(String key, String value) { public void addToSet(String key, String value, Long expiresIn) {
redisTemplate.opsForSet().add(key, value); redisTemplate.opsForSet().add(key, value);
// 设置过期时间
redisTemplate.expire(key, expiresIn, TimeUnit.SECONDS);
} }
/** /**
@@ -302,4 +304,5 @@ public class RedisUtil {
} }
public final static String STRIPE_EXCEPTION_LOG = "StripeException:"; public final static String STRIPE_EXCEPTION_LOG = "StripeException:";
public final static String SUBSCRIPTION_SENT_EMAIL_TYPE = "SubscriptionEmailSentType:";
} }

View File

@@ -343,17 +343,19 @@ public class AffiliateServiceImpl extends ServiceImpl<AffiliateMapper, Affiliate
} }
public void calcCouponsCommission(){ public void calcCouponsCommission(){
// id存redis
String lastTime = redisUtil.getFromString(RedisUtil.PAYMENT_INFO_LAST_SCAN_TIME); String lastTime = redisUtil.getFromString(RedisUtil.PAYMENT_INFO_LAST_SCAN_TIME);
log.info("优惠券佣金计算,上次执行时间:{}", lastTime);
String currentTime = LocalDateTime.now().toString(); String currentTime = LocalDateTime.now().toString();
// 1、查上次更新之后有无使用了优惠券的新订单 // 1、查上次更新之后有无使用了优惠券的新订单
QueryWrapper<PaymentInfo> queryWrapper = new QueryWrapper<>(); QueryWrapper<PaymentInfo> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("trade_state","paid")
.lt("create_time", currentTime)
.isNotNull("promotion_code");
if (!StringUtil.isNullOrEmpty(lastTime)){ if (!StringUtil.isNullOrEmpty(lastTime)){
queryWrapper.gt("create_time", lastTime) queryWrapper.gt("create_time", lastTime);
.lt("create_time", currentTime)
.isNotNull("promotion_code");
} }
List<PaymentInfo> paymentInfos = paymentInfoService.getBaseMapper().selectList(queryWrapper); List<PaymentInfo> paymentInfos = paymentInfoService.getBaseMapper().selectList(queryWrapper);
log.info("目前,新增使用优惠券的订单数:{}", paymentInfos.size());
// key:推广码, value:用户支付的金额 // key:推广码, value:用户支付的金额
HashMap<String, Float> codeAmount = new HashMap<>(); HashMap<String, Float> codeAmount = new HashMap<>();

View File

@@ -701,7 +701,7 @@ public class GenerateServiceImpl extends ServiceImpl<GenerateMapper, Generate> i
// todo 取消待优化 // todo 取消待优化
uniqueIdList.forEach(uniqueId -> { uniqueIdList.forEach(uniqueId -> {
// 1、将需要取消的唯一id加入redis以便及时取消生成 // 1、将需要取消的唯一id加入redis以便及时取消生成
redisUtil.addToSet(cancelSetKey, uniqueId); redisUtil.addToSet(cancelSetKey, uniqueId, CommonConstant.REDIS_SET_EXPIRE_TIME);
/*// 1、确认当前消息是否还在排队中 /*// 1、确认当前消息是否还在排队中
Boolean exists = redisUtil.isElementExistsInZSet(consumptionOrderKey, uniqueId); Boolean exists = redisUtil.isElementExistsInZSet(consumptionOrderKey, uniqueId);

View File

@@ -310,6 +310,7 @@ public class PaymentInfoServiceImpl extends ServiceImpl<PaymentInfoMapper, Payme
public PaymentInfo createOrUpdatePaymentInfoForStripe(Charge charge){ public PaymentInfo createOrUpdatePaymentInfoForStripe(Charge charge){
Stripe.apiKey = privateKey; Stripe.apiKey = privateKey;
QueryWrapper<PaymentInfo> qw = new QueryWrapper<>(); QueryWrapper<PaymentInfo> qw = new QueryWrapper<>();
// todo 首次支付失败没有invoiceId所以如果这个order之后成功支付后会有多条paymentInfo 是否需要优化??
qw.eq("transaction_id", charge.getInvoice()); qw.eq("transaction_id", charge.getInvoice());
PaymentInfo paymentInfo = baseMapper.selectOne(qw); PaymentInfo paymentInfo = baseMapper.selectOne(qw);
Charge.PaymentMethodDetails paymentMethodDetails = charge.getPaymentMethodDetails(); Charge.PaymentMethodDetails paymentMethodDetails = charge.getPaymentMethodDetails();

View File

@@ -5,6 +5,7 @@ import com.ai.da.common.constant.CommonConstant;
import com.ai.da.common.context.UserContext; import com.ai.da.common.context.UserContext;
import com.ai.da.common.enums.*; import com.ai.da.common.enums.*;
import com.ai.da.common.utils.DateUtil; import com.ai.da.common.utils.DateUtil;
import com.ai.da.common.utils.RedisUtil;
import com.ai.da.common.utils.SendEmailUtil; import com.ai.da.common.utils.SendEmailUtil;
import com.ai.da.mapper.primary.AccountMapper; import com.ai.da.mapper.primary.AccountMapper;
import com.ai.da.mapper.primary.PaymentInfoMapper; import com.ai.da.mapper.primary.PaymentInfoMapper;
@@ -67,7 +68,6 @@ public class StripeServiceImpl implements StripeService {
private RefundInfoService refundInfoService; private RefundInfoService refundInfoService;
@Resource @Resource
private AccountService accountService; private AccountService accountService;
@Resource @Resource
private AccountMapper accountMapper; private AccountMapper accountMapper;
@Resource @Resource
@@ -76,6 +76,8 @@ public class StripeServiceImpl implements StripeService {
private PaymentInfoMapper paymentInfoMapper; private PaymentInfoMapper paymentInfoMapper;
@Resource @Resource
private ProductCouponsMapper productCouponsMapper; private ProductCouponsMapper productCouponsMapper;
@Resource
private RedisUtil redisUtil;
@Value("${stripe.private-key}") @Value("${stripe.private-key}")
private String privateKey; private String privateKey;
@@ -368,28 +370,31 @@ public class StripeServiceImpl implements StripeService {
// 新增支付成功的信息,返回orderNo表示该回调第一次被记录 // 新增支付成功的信息,返回orderNo表示该回调第一次被记录
PaymentInfo paymentInfo = paymentInfoService.createOrUpdatePaymentInfoForStripe(invoice); PaymentInfo paymentInfo = paymentInfoService.createOrUpdatePaymentInfoForStripe(invoice);
/* 在sendEmail方法中有做判断这里的判断取消
// 当前支付没有被通知时才需要发送通知邮件 // 当前支付没有被通知时才需要发送通知邮件
if (paymentInfo.getNotified().equals(0)) { if (paymentInfo.getNotified().equals(0)) {
// 更新t_order_info中的total_fee,记录该订单的累计付款金额
orderInfoService.updateTotalFeeByOrderNo(paymentInfo.getOrderNo()); }*/
// 邮件通知商家和用户 // 更新t_order_info中的total_fee,记录该订单的累计付款金额
String billingReason = invoice.getBillingReason(); orderInfoService.updateTotalFeeByOrderNo(paymentInfo.getOrderNo());
switch (billingReason) { // 邮件通知商家和用户
case "subscription_create": String billingReason = invoice.getBillingReason();
response = sendEmail(invoice.getSubscription(), "new", null); switch (billingReason) {
break; case "subscription_create":
case "subscription_cycle": response = sendEmail(invoice.getSubscription(), "new", null);
response = sendEmail(invoice.getSubscription(), "renewal", null); break;
break; case "subscription_cycle":
case "manual": response = sendEmail(invoice.getSubscription(), "renewal", null);
boolean b = invoice.getLines().getData().get(0).getDescription().endsWith("Subscription"); break;
if (b) { case "manual":
// 非自动续订式订阅Stripe不会创建Subscription,所以invoice中不会有subscriptionId boolean b = invoice.getLines().getData().get(0).getDescription().endsWith("Subscription");
response = sendEmail(null, "new", paymentInfo.getOrderNo()); if (b) {
} // 非自动续订式订阅Stripe不会创建Subscription,所以invoice中不会有subscriptionId
break; response = sendEmail(null, "new", paymentInfo.getOrderNo());
} }
break;
} }
} else if (event.getType().equals("invoice.payment_failed")) { } else if (event.getType().equals("invoice.payment_failed")) {
// 更新支付信息 // 更新支付信息
QueryWrapper<PaymentInfo> queryWrapper = new QueryWrapper<>(); QueryWrapper<PaymentInfo> queryWrapper = new QueryWrapper<>();
@@ -1011,7 +1016,12 @@ public class StripeServiceImpl implements StripeService {
// 其实这里也可以通过invoiceId查询stripe但是记录在自己的db中可以不用每次都查且方便查看 // 其实这里也可以通过invoiceId查询stripe但是记录在自己的db中可以不用每次都查且方便查看
type = StringUtil.isNullOrEmpty(paymentInfo.getType()) ? "new" : paymentInfo.getType(); type = StringUtil.isNullOrEmpty(paymentInfo.getType()) ? "new" : paymentInfo.getType();
} }
if (!type.equals("reminder") && !type.equals("cancel") && paymentInfo.getNotified() == 1){
// todo 之后这种改成通过email-log来判断
String key = RedisUtil.SUBSCRIPTION_SENT_EMAIL_TYPE + subscriptionInfo.getId();
// 先判断当前订单 这个类型的邮件是否已发送过
Boolean elementExistsInSet = redisUtil.isElementExistsInSet(key, type);
if (!type.equals("reminder") && !type.equals("cancel") && paymentInfo.getNotified() == 1 && elementExistsInSet){
// 已经邮件通知过,直接返回 // 已经邮件通知过,直接返回
log.info("不发送邮件原因【type为{}order_no为{},已经进行邮件通知】", type, orderNo); log.info("不发送邮件原因【type为{}order_no为{},已经进行邮件通知】", type, orderNo);
return true; return true;
@@ -1044,6 +1054,9 @@ public class StripeServiceImpl implements StripeService {
payment.setUpdateTime(LocalDateTime.now()); payment.setUpdateTime(LocalDateTime.now());
paymentInfoMapper.updateById(payment); paymentInfoMapper.updateById(payment);
} }
// 将发成功的邮件类型存入redis 避免同一个订阅重复发送相同类型的邮件 subIdtype
redisUtil.addToSet(key, type, CommonConstant.REDIS_SET_EXPIRE_TIME);
return true; return true;
} }