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

This commit is contained in:
shahaibo
2025-02-07 10:25:20 +08:00
12 changed files with 118 additions and 66 deletions

View File

@@ -220,7 +220,7 @@ public interface AccountService extends IService<Account> {
Boolean unbindGoogle();
void updateAccountValidity(Long accountId, Long currentPeriodEnd);
boolean updateAccountValidity(Long accountId, Long currentPeriodEnd);
void updateUserRoleAndCredits(Long accountId, String type);

View File

@@ -36,4 +36,6 @@ public interface CreditsService extends IService<CreditsDetail> {
void preInsert(Long accountId, String changeEventName, String taskId, Boolean isPreInsert, String changedCredits);
void updateChangedCredits(String accountId, String taskId);
CreditsDetail queryDetailByTaskId(String taskId);
}

View File

@@ -1335,7 +1335,7 @@ public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> impl
config.addDataSourceProperty("cachePrepStmts", "true");
config.addDataSourceProperty("prepStmtCacheSize", "250");
config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
config.addDataSourceProperty("maxLifetime", 300000);
config.addDataSourceProperty("maxLifetime", 50000);
dataSource = new HikariDataSource(config);
}
@@ -2745,12 +2745,16 @@ public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> impl
return result;
}
public void updateAccountValidity(Long accountId, Long currentPeriodEnd){
public boolean updateAccountValidity(Long accountId, Long currentPeriodEnd){
// 不管当前用户的账号是否到期,都根据付款信息重置账号到期时间
Account account = accountMapper.selectById(accountId);
account.setValidEndTime(currentPeriodEnd * 1000);
accountMapper.updateById(account);
if (account.getValidEndTime().equals(currentPeriodEnd * 1000)){
return false;
}else {
account.setValidEndTime(currentPeriodEnd * 1000);
accountMapper.updateById(account);
}
return true;
}
public void updateUserRoleAndCredits(Long accountId, String type){

View File

@@ -76,9 +76,9 @@ public class AffiliateServiceImpl extends ServiceImpl<AffiliateMapper, Affiliate
affiliate.setPromotionMethod(promotionMethod);
baseMapper.insert(affiliate);
// 邮件通知审批者
// String merchantEmail = "kimwong@code-create.com.hk";
String merchantEmail = "kimwong@code-create.com.hk";
String developer = "xupei3360@163.com";
String[] receiverEmail = {/*merchantEmail, */developer};
String[] receiverEmail = {merchantEmail, developer};
SendEmailUtil.affiliateEmailReminder(receiverEmail, new AffiliateEmailParamsDTO(userHolder.getUsername(), promotionMethod), "new");
}else {
throw new BusinessException("You have registered an Affiliate", ResultEnum.PROMPT.getCode());
@@ -313,9 +313,9 @@ public class AffiliateServiceImpl extends ServiceImpl<AffiliateMapper, Affiliate
affiliateEmailParamsDTO.setUnpaidEarnings(totalCommission.toString());
affiliateEmailParamsDTO.setPaidEarnings("0");
// String merchantEmail = "kimwong@code-create.com.hk";
String merchantEmail = "kimwong@code-create.com.hk";
String developer = "xupei3360@163.com";
String[] receiverEmail = {/*merchantEmail, */developer};
String[] receiverEmail = {merchantEmail, developer};
// 邮件通知
SendEmailUtil.affiliateEmailReminder(receiverEmail, affiliateEmailParamsDTO, "summary");
}

View File

@@ -318,4 +318,10 @@ public class CreditsServiceImpl extends ServiceImpl<CreditsDetailMapper, Credits
}
public CreditsDetail queryDetailByTaskId(String taskId) {
QueryWrapper<CreditsDetail> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("task_id", taskId);
return baseMapper.selectOne(queryWrapper);
}
}

View File

@@ -9,10 +9,7 @@ import com.ai.da.common.utils.SendEmailUtil;
import com.ai.da.mapper.primary.AccountMapper;
import com.ai.da.mapper.primary.PaymentInfoMapper;
import com.ai.da.mapper.primary.SubscriptionInfoMapper;
import com.ai.da.mapper.primary.entity.OrderInfo;
import com.ai.da.mapper.primary.entity.PaymentInfo;
import com.ai.da.mapper.primary.entity.RefundInfo;
import com.ai.da.mapper.primary.entity.SubscriptionInfo;
import com.ai.da.mapper.primary.entity.*;
import com.ai.da.model.dto.ProductPurchaseDTO;
import com.ai.da.model.dto.SubscriptionEmailParamsDTO;
import com.ai.da.service.*;
@@ -24,6 +21,7 @@ import com.stripe.Stripe;
import com.stripe.exception.SignatureVerificationException;
import com.stripe.exception.StripeException;
import com.stripe.model.*;
import com.stripe.model.Product;
import com.stripe.model.checkout.Session;
import com.stripe.net.Webhook;
import com.stripe.param.*;
@@ -42,6 +40,7 @@ import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.*;
import java.util.stream.Collectors;
@SuppressWarnings("LoggingSimilarMessage")
@Service
@@ -140,6 +139,9 @@ public class StripeServiceImpl implements StripeService {
// one-time 手动创建发票;订阅会自动创建invoice
sessionBuilder.setInvoiceCreation(SessionCreateParams.InvoiceCreation.builder().setEnabled(Boolean.TRUE).build());
}
// sessionBuilder.setPaymentMethodConfiguration("pmc_1QIKyq02n1TEydyNKVEYvhW7");
// sessionBuilder.addPaymentMethodType(SessionCreateParams.PaymentMethodType.ALIPAY);
// sessionBuilder.addPaymentMethodType(SessionCreateParams.PaymentMethodType.CARD);
sessionBuilder.setCustomer(customerId);
sessionBuilder.setSuccessUrl(productPurchaseDTO.getReturnUrl());//可自定义成功页面
sessionBuilder.setLocale(account.getLanguage().equals("CHINESE_SIMPLIFIED") ? SessionCreateParams.Locale.ZH : SessionCreateParams.Locale.EN);
@@ -151,7 +153,12 @@ public class StripeServiceImpl implements StripeService {
sessionBuilder.putMetadata("orderId", orderId); //通过订单号关联用于检索支付信息(可选)
Session session = Session.create(sessionBuilder.build());
log.info("sessionId:" + session.getId()); //退款方式1拿到sessionId入库退款的时候根据这个id找到PaymentIntent的id然后发起退款
List<String> paymentMethodTypes = session.getPaymentMethodTypes();
log.info("paymentMethodTypes: {}", paymentMethodTypes);
Session.PaymentMethodConfigurationDetails paymentMethodConfigurationDetails = session.getPaymentMethodConfigurationDetails();
log.info("paymentMethodConfigurationDetails ID: {}", paymentMethodConfigurationDetails.getId());
log.info("sessionId:{}", session.getId()); //退款方式1拿到sessionId入库退款的时候根据这个id找到PaymentIntent的id然后发起退款
// 更新order信息
orderInfoService.updateOrderNoById(orderInfo.getId(), orderId);
@@ -350,6 +357,11 @@ public class StripeServiceImpl implements StripeService {
// 发送续订失败邮件
response = sendRenewalFailEmail(invoice.getId(), null, paymentInfo.getOrderNo());
}else {
// 新增支付信息
PaymentInfo paymentInfoFail = paymentInfoService.createOrUpdatePaymentInfoForStripe(invoice);
// 发送新订阅失败邮件
response = sendEmail(paymentInfoFail.getOrderNo());
}
}
}else if (stripeObject instanceof Charge) {
@@ -387,22 +399,26 @@ public class StripeServiceImpl implements StripeService {
// 当订单状态处于未支付或超时已关闭时,更新订单状态,其他状态均不更新订单状态
if (!OrderStatusEnum.NOT_PAY.getType().equals(orderStatus) && !OrderStatusEnum.TIMEOUT_CLOSED.getType().equals(orderStatus)) {
log.info("订单状态 : {}", orderStatus);
return;
}else {
//更新订单状态
orderInfoService.updateStatusByOrderNo(orderId, OrderStatusEnum.SUCCESS);
log.info("Stripe 订单:{} 状态更新成功", orderId);
}
//更新订单状态
orderInfoService.updateStatusByOrderNo(orderId, OrderStatusEnum.SUCCESS);
log.info("Stripe 订单:{} 状态更新成功", orderId);
if (orderByOrderNo.getTitle().startsWith("积分购买")){
float quantity = totalAmount / ProductEnum.CreditsProduct.getPrice();
// 更新积分
creditsService.buyCredits(orderByOrderNo.getAccountId(), quantity);
// 添加积分变更记录
creditsService.insertToCreditsDetail(orderByOrderNo.getAccountId(),
CreditsEventsEnum.BUY_CREDITS.getName() + "--Stripe",
String.valueOf((Long.parseLong(CreditsEventsEnum.BUY_CREDITS.getValue()) * quantity)),
"positive", orderId);
log.info("用户:{} 积分信息更新成功", orderByOrderNo.getAccountId());
// 查询当前订单的积分是否已添加
CreditsDetail creditsDetail = creditsService.queryDetailByTaskId(orderId);
if (Objects.isNull(creditsDetail)){
float quantity = totalAmount / ProductEnum.CreditsProduct.getPrice();
// 更新积分
creditsService.buyCredits(orderByOrderNo.getAccountId(), quantity);
// 添加积分变更记录
creditsService.insertToCreditsDetail(orderByOrderNo.getAccountId(),
CreditsEventsEnum.BUY_CREDITS.getName() + "--Stripe",
String.valueOf((Long.parseLong(CreditsEventsEnum.BUY_CREDITS.getValue()) * quantity)),
"positive", orderId);
log.info("用户:{} 积分信息更新成功", orderByOrderNo.getAccountId());
}
}
} catch (Exception e) {
log.info(e.getMessage());
@@ -468,11 +484,13 @@ public class StripeServiceImpl implements StripeService {
subscriptionInfo.setCreateTime(LocalDateTime.now());
subscriptionInfoMapper.insert(subscriptionInfo);
// 更新账号到期时间
accountService.updateAccountValidity(subscriptionInfo.getAccountId(), subscriptionInfo.getCurrentPeriodEnd());
// 更新账号身份和积分
accountService.updateUserRoleAndCredits(subscriptionInfo.getAccountId(), interval);
if (subscriptionInfo.getStatus().equals("active")){
log.info("创建订阅更新账号信息");
// 更新账号到期时间
boolean b = accountService.updateAccountValidity(subscriptionInfo.getAccountId(), subscriptionInfo.getCurrentPeriodEnd());
// 更新账号身份和积分
if (b) accountService.updateUserRoleAndCredits(subscriptionInfo.getAccountId(), interval);
}
}
return subscriptionInfo;
}
@@ -498,7 +516,7 @@ public class StripeServiceImpl implements StripeService {
public SubscriptionInfo getLatestSubscriptionInfoByAccountId(Long accountId){
QueryWrapper<SubscriptionInfo> qw = new QueryWrapper<>();
qw.eq("account_id", accountId);
qw.eq("account_id", accountId).orderByDesc("id");
List<SubscriptionInfo> subscriptionInfos = subscriptionInfoMapper.selectList(qw);
if (subscriptionInfos.isEmpty()){
return null;
@@ -524,6 +542,7 @@ public class StripeServiceImpl implements StripeService {
if (!subscriptionInfo.getCurrentPeriodEnd().equals(subscription.getCurrentPeriodEnd())){
subscriptionInfo.setCurrentPeriodEnd(subscription.getCurrentPeriodEnd());
subscriptionInfo.setNextPayDate(DateUtil.changeTimeStampFormat(subscription.getCurrentPeriodEnd(), "seconds", CommonConstant.TIME_FORMAT_MMM_dd_yyyy_EEEE));
log.info("更新订阅更新账号信息");
// 更新账号到期时间
accountService.updateAccountValidity(subscriptionInfo.getAccountId(), subscriptionInfo.getCurrentPeriodEnd());
// 更新账号身份和积分
@@ -531,6 +550,12 @@ public class StripeServiceImpl implements StripeService {
log.info("更新 {} 账号到期时间为:{}", subscriptionInfo.getAccountId(), DateUtil.changeTimeStampFormat(subscriptionInfo.getCurrentPeriodEnd(), "seconds", CommonConstant.TIME_FORMAT_MMM_dd_yyyy_EEEE));
flag = true;
}
if (subscriptionInfo.getStatus().equals("active")){
// 更新账号到期时间
boolean b = accountService.updateAccountValidity(subscriptionInfo.getAccountId(), subscriptionInfo.getCurrentPeriodEnd());
// 更新账号身份和积分
if (b) accountService.updateUserRoleAndCredits(subscriptionInfo.getAccountId(), subscriptionInfo.getType());
}
if (flag){
subscriptionInfo.setUpdateTime(LocalDateTime.now());
subscriptionInfoMapper.updateById(subscriptionInfo);
@@ -541,8 +566,8 @@ public class StripeServiceImpl implements StripeService {
// 取消连续订阅 将订阅从pause状态转为cancel状态使用定时器定期检索DB中过期且不续订的订阅
public void cancelSubscription(String subscriptionId, String cancelReason) {
Stripe.apiKey = privateKey;
log.info("cancel subscription");
Long accountId = UserContext.getUserHolder().getId();
log.info("用户 {} 申请取消连续订阅 {}", accountId, subscriptionId);
com.ai.da.mapper.primary.entity.Account account = accountMapper.selectById(accountId);
List<Subscription> subscriptions = getSubscription(account.getUserName(), account.getUserEmail());
// 获取status = active的订阅
@@ -551,7 +576,7 @@ public class StripeServiceImpl implements StripeService {
try {
Subscription cancel = subscription.cancel();
cancel.getStatus();
log.info("用户 {} 申请取消连续订阅 {}", accountId, subscriptionId);
// 更新数据库
updateCancelReason(subscriptionId, cancelReason);
} catch (StripeException e) {
@@ -809,10 +834,20 @@ public class StripeServiceImpl implements StripeService {
SubscriptionEmailParamsDTO emailParamsDTO = new SubscriptionEmailParamsDTO();
QueryWrapper<SubscriptionInfo> qwSI = new QueryWrapper<>();
qwSI.eq("subscription_id", subscriptionId);
SubscriptionInfo subscriptionInfo = subscriptionInfoMapper.selectOne(qwSI);
if (Objects.isNull(subscriptionInfo)) {
List<SubscriptionInfo> subscriptionInfoList = subscriptionInfoMapper.selectList(qwSI);
SubscriptionInfo subscriptionInfo;
if (subscriptionInfoList.isEmpty()){
return false;
}else {
List<SubscriptionInfo> activeSubscriptions = subscriptionInfoList.stream()
.filter(subscription -> "active".equals(subscription.getStatus()))
.collect(Collectors.toList());
if (activeSubscriptions.isEmpty()){
return false;
}
subscriptionInfo = activeSubscriptions.get(0);
}
QueryWrapper<PaymentInfo> qwPI = new QueryWrapper<>();
qwPI.eq("order_no", subscriptionInfo.getOrderNo()).orderByDesc("id");
List<PaymentInfo> paymentInfos = paymentInfoMapper.selectList(qwPI);