支付优化

This commit is contained in:
2024-11-25 10:53:09 +08:00
parent 2ea19dcf03
commit 5019fbd3fc
9 changed files with 257 additions and 35 deletions

View File

@@ -17,6 +17,11 @@ public enum OrderStatusEnum {
*/
SUCCESS("支付成功"),
/**
* 支付失败
*/
FAILURE("支付失败"),
/**
* 已关闭
*/

View File

@@ -779,6 +779,8 @@ public class SendEmailUtil {
private final static Long RENEWAL_USER_CN = 130726L;
private final static Long RENEWAL_REMINDER_USER_EN = 130727L;
private final static Long RENEWAL_REMINDER_USER_CN = 130728L;
private final static Long PAYMENT_FAILED_NEW_MERCHANT_EN = 131230L;
private final static Long PAYMENT_FAILED_RENEWAL_MERCHANT_EN = 131225L;
public static void subscriptionEmailReminder(String type, SubscriptionEmailParamsDTO subscriptionEmailParamsDTO, String language, String receiverAddress){
try{
@@ -807,6 +809,14 @@ public class SendEmailUtil {
merchant.setSubject("[Code-Create] Subscription Cancelled");
templateMerchant.setTemplateID(CANCEL_MERCHANT_EN);
break;
case "fail_new":
merchant.setSubject("[Code-Create] Payment Failed : New Order (" + subscriptionEmailParamsDTO.getOrderId() + ")");
templateMerchant.setTemplateID(PAYMENT_FAILED_NEW_MERCHANT_EN);
break;
case "fail_renewal":
merchant.setSubject("[Code-Create] Payment Failed : Renewal Order (" + subscriptionEmailParamsDTO.getOrderId() + ")");
templateMerchant.setTemplateID(PAYMENT_FAILED_RENEWAL_MERCHANT_EN);
break;
case "new":
merchant.setSubject("[Code-Create] New Order(" + subscriptionEmailParamsDTO.getOrderId() + ")");
templateMerchant.setTemplateID(NEW_MERCHANT_EN);
@@ -849,14 +859,14 @@ public class SendEmailUtil {
templateMerchant.setTemplateData(JSON.toJSONString(subscriptionEmailParamsDTO));
merchant.setTemplate(templateMerchant);
if (!type.equals("cancel")){
if (!type.equals("cancel") && !type.equals("fail_new") && !type.equals("fail_renewal") ){
// 返回的resp是一个SendEmailResponse的实例与请求对象对应
SendEmailResponse respUser = client.SendEmail(user);
log.info("邮件发送结果toUser###{}", SendEmailResponse.toJsonString(respUser));
log.info("邮件主题:{}发送结果toUser###{}", user.getSubject(), SendEmailResponse.toJsonString(respUser));
}
if (!type.equals("reminder")){
SendEmailResponse respMerchant = client.SendEmail(merchant);
log.info("邮件发送结果toMerchant###{}", SendEmailResponse.toJsonString(respMerchant));
log.info("邮件主题:{}发送结果toMerchant###{}", merchant.getSubject(), SendEmailResponse.toJsonString(respMerchant));
}
} catch (TencentCloudSDKException e) {
log.info("邮件发送失败###{}", e.toString());

View File

@@ -21,5 +21,7 @@ public class OrderInfo extends BaseEntity{
private String orderStatus;//订单状态
private String note;
private String paymentType;//支付方式
}

View File

@@ -26,4 +26,8 @@ public class PaymentInfo extends BaseEntity{
// 当前支付是否已邮件通知 0 || 1
private Integer notified;
private String paymentMethod;
private String last4;
}

View File

@@ -22,14 +22,7 @@ public class SubscriptionInfo extends BaseEntity{
// active || expired
private String status = "active";
// 是否自动续订
private byte autoRenewal = (byte)1;
// 支付方式
private String paymentMethod;
// 如果是用卡支付,可以看到银行卡最后四位
private String last4;
private byte cancelNotified = (byte)0;
// 续订的下一个付款日
private String nextPayDate;

View File

@@ -28,6 +28,8 @@ public class SubscriptionEmailParamsDTO {
// 付款方式
private String paymentMethod;
private String last4;
// 订阅Id
private String subscriptionId;
@@ -43,5 +45,8 @@ public class SubscriptionEmailParamsDTO {
// 下次付款时间reminder
private String renewalTime;
// 付款失败原因
private String failMessage;
}

View File

@@ -4,6 +4,7 @@ import com.ai.da.mapper.primary.entity.PaymentInfo;
import com.ai.da.model.dto.AlipayHKCallbackDTO;
import com.baomidou.mybatisplus.extension.service.IService;
import com.paypal.orders.Order;
import com.stripe.model.Charge;
import com.stripe.model.Invoice;
import java.util.Map;
@@ -18,7 +19,9 @@ public interface PaymentInfoService extends IService<PaymentInfo> {
void createPaymentInfoForAliPayHK(AlipayHKCallbackDTO alipayHKCallbackDTO);
PaymentInfo createPaymentInfoForStripe(Invoice invoice);
PaymentInfo createOrUpdatePaymentInfoForStripe(Invoice invoice);
PaymentInfo createOrUpdatePaymentInfoForStripe(Charge charge);
PaymentInfo getPaymentInfoByOrderId(String orderId);

View File

@@ -11,6 +11,7 @@ import com.google.gson.Gson;
import com.paypal.orders.Order;
import com.stripe.Stripe;
import com.stripe.exception.StripeException;
import com.stripe.model.Charge;
import com.stripe.model.Invoice;
import com.stripe.model.Subscription;
import com.stripe.model.checkout.Session;
@@ -20,6 +21,7 @@ import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
@@ -28,6 +30,12 @@ import java.util.Objects;
@Slf4j
public class PaymentInfoServiceImpl extends ServiceImpl<PaymentInfoMapper, PaymentInfo> implements PaymentInfoService {
private final StripeServiceImpl stripeServiceImpl;
public PaymentInfoServiceImpl(StripeServiceImpl stripeServiceImpl) {
this.stripeServiceImpl = stripeServiceImpl;
}
/**
* 记录支付日志:微信支付
* @param plainText
@@ -152,7 +160,7 @@ public class PaymentInfoServiceImpl extends ServiceImpl<PaymentInfoMapper, Payme
baseMapper.insert(paymentInfo);
}
public void createPaymentInfoForStripe(Session session){
public void createOrUpdatePaymentInfoForStripe(Session session){
String orderId = session.getMetadata().get("orderId");
String status = session.getStatus();
// 获取transactionId,从sessionId更改为invoiceId
@@ -176,7 +184,7 @@ public class PaymentInfoServiceImpl extends ServiceImpl<PaymentInfoMapper, Payme
@Value("${stripe.private-key}")
private String privateKey;
public PaymentInfo createPaymentInfoForStripe(Invoice invoice){
public PaymentInfo createOrUpdatePaymentInfoForStripe(Invoice invoice){
Stripe.apiKey = privateKey;
// 获取transactionId,从sessionId更改为invoiceId
String invoiceId = invoice.getId();
@@ -184,6 +192,7 @@ public class PaymentInfoServiceImpl extends ServiceImpl<PaymentInfoMapper, Payme
QueryWrapper<PaymentInfo> qw = new QueryWrapper<>();
qw.eq("transaction_id", invoiceId);
PaymentInfo paymentInfo = baseMapper.selectOne(qw);
String status = invoice.getStatus();
// 判断当前支付是否已经被记录,确保同一个支付不会被重复记录
if (Objects.isNull(paymentInfo)){
String orderNo;
@@ -199,13 +208,19 @@ public class PaymentInfoServiceImpl extends ServiceImpl<PaymentInfoMapper, Payme
} catch (StripeException e) {
throw new RuntimeException(e);
}
String status = invoice.getStatus();
Long amountTotal = invoice.getAmountPaid();
Long amountTotal;
if (status.equals("paid")){
amountTotal = invoice.getAmountPaid();
}else {
amountTotal = invoice.getAmountDue();
}
// stripe 的支付金额单位是分,在我们数据库中金额单位为 元
Float divide = new BigDecimal(amountTotal).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP).floatValue();
String type = invoice.getBillingReason().equals("subscription_create") ? "new" :
invoice.getBillingReason().equals("subscription_cycle") ? "renewal" : invoice.getBillingReason();
Map<String, String> paymentMethod = stripeServiceImpl.getPaymentMethodByInvoiceId(invoiceId);
paymentInfo = new PaymentInfo();
paymentInfo.setOrderNo(orderNo);
@@ -219,12 +234,84 @@ public class PaymentInfoServiceImpl extends ServiceImpl<PaymentInfoMapper, Payme
paymentInfo.setContent(json);
paymentInfo.setType(type);
paymentInfo.setNotified(0);
paymentInfo.setPaymentMethod(paymentMethod.get("paymentMethod"));
paymentInfo.setLast4(paymentMethod.get("last4"));
paymentInfo.setCreateTime(LocalDateTime.now());
baseMapper.insert(paymentInfo);
}else {
paymentInfo.setTradeState(status);
paymentInfo.setUpdateTime(LocalDateTime.now());
baseMapper.updateById(paymentInfo);
}
return paymentInfo;
}
public PaymentInfo createOrUpdatePaymentInfoForStripe(Charge charge){
Stripe.apiKey = privateKey;
QueryWrapper<PaymentInfo> qw = new QueryWrapper<>();
qw.eq("transaction_id", charge.getInvoice());
PaymentInfo paymentInfo = baseMapper.selectOne(qw);
Charge.PaymentMethodDetails paymentMethodDetails = charge.getPaymentMethodDetails();
String paymentMethod;
String last4 = "N/A";
switch (paymentMethodDetails.getType()){
case "alipay":
paymentMethod = "Alipay";
break;
case "bancontact":
paymentMethod = "BanContact";
break;
case "card":
Charge.PaymentMethodDetails.Card card = paymentMethodDetails.getCard();
String brand = card.getBrand();
brand = brand.substring(0, 1).toUpperCase() + brand.substring(1);
paymentMethod = brand + " " + card.getFunding() + "card";
last4 = card.getLast4();
break;
case "eps":
Charge.PaymentMethodDetails.Eps eps = paymentMethodDetails.getEps();
paymentMethod = eps.getBank();
break;
case "giropay":
paymentMethod = "GiroPay";
break;
case "ideal":
Charge.PaymentMethodDetails.Ideal ideal = paymentMethodDetails.getIdeal();
paymentMethod = ideal.getBank();
break;
case "link":
paymentMethod = "Link";
break;
default:
paymentMethod = "N/A";
}
if (Objects.isNull(paymentInfo)){
Stripe.apiKey = privateKey;
Float divide = new BigDecimal(charge.getAmount()).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP).floatValue();
paymentInfo = new PaymentInfo();
paymentInfo.setOrderNo(charge.getDescription().replace("AiDA - ", ""));
paymentInfo.setTransactionId(charge.getInvoice());
paymentInfo.setPaymentType(PayTypeEnum.STRIPE.getType());
paymentInfo.setTradeState(charge.getStatus());
paymentInfo.setPayerTotal(divide);
paymentInfo.setNotified(0);
paymentInfo.setPaymentMethod(paymentMethod);
paymentInfo.setLast4(last4);
paymentInfo.setCreateTime(LocalDateTime.now());
baseMapper.insert(paymentInfo);
}else {
paymentInfo.setTradeState(charge.getStatus());
paymentInfo.setPaymentMethod(paymentMethod);
paymentInfo.setLast4(last4);
paymentInfo.setUpdateTime(LocalDateTime.now());
baseMapper.updateById(paymentInfo);
}
return paymentInfo;
}
@Override
public PaymentInfo getPaymentInfoByOrderId(String orderId){

View File

@@ -271,6 +271,10 @@ public class StripeServiceImpl implements StripeService {
Session session = (Session) stripeObject;
if (event.getType().equals("checkout.session.completed")) {
processOrder(session);
}else if (event.getType().equals("checkout.session.expired")){
String orderNo = session.getMetadata().get("orderId");
// 会话过期 未支付 且之后没有支付成功的订单
processExpiredOrder(orderNo);
}
} else if (stripeObject instanceof Subscription){
Subscription subscription = (Subscription) stripeObject;
@@ -280,25 +284,30 @@ public class StripeServiceImpl implements StripeService {
log.info("创建连续订阅");
} else if (event.getType().equals("customer.subscription.updated")){
// 更新订阅信息
response = updateSubscription(subscription);
updateSubscription(subscription);
log.info("订阅更新");
if (subscription.getStatus().equals("active")){
response = sendEmail(subscription.getId(), null);
}
} else if (event.getType().equals("customer.subscription.deleted")){
response = updateSubscription(subscription);
SubscriptionInfo subscriptionInfo = updateSubscription(subscription);
log.info("用户取消连续订阅");
} else if (event.getType().equals("customer.subscription.paused")){
if (subscriptionInfo.getCancelNotified() == (byte)0){
response = sendEmail(subscription.getId(), "cancel");
}
subscriptionInfo.setCancelNotified((byte)1);
subscriptionInfoMapper.updateById(subscriptionInfo);
}/* else if (event.getType().equals("customer.subscription.paused")){
updateSubscription(subscription);
} else if (event.getType().equals("customer.subscription.resumed")){
updateSubscription(subscription);
log.info("用户订阅恢复");
}
}*/
} else if (stripeObject instanceof Invoice) {
Invoice invoice = (Invoice) stripeObject;
if (event.getType().equals("invoice.paid")) {
// 新增支付成功的信息,返回orderNo表示该回调第一次被记录
PaymentInfo paymentInfo = paymentInfoService.createPaymentInfoForStripe(invoice);
PaymentInfo paymentInfo = paymentInfoService.createOrUpdatePaymentInfoForStripe(invoice);
// 当前支付没有被通知时才需要发送通知邮件
if (paymentInfo.getNotified().equals(0)) {
@@ -311,6 +320,43 @@ public class StripeServiceImpl implements StripeService {
response = sendEmail(invoice.getSubscription(), "renewal");
}
}
} else if (event.getType().equals("invoice.payment_failed")) {
// 更新支付信息
QueryWrapper<PaymentInfo> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("transaction_id", invoice.getId());
PaymentInfo paymentInfo = paymentInfoService.getBaseMapper().selectOne(queryWrapper);
if (!Objects.isNull(paymentInfo)){
String type = invoice.getBillingReason().equals("subscription_create") ? "new" :
invoice.getBillingReason().equals("subscription_cycle") ? "renewal" : invoice.getBillingReason();
Gson gson = new Gson();
String json = gson.toJson(invoice);
paymentInfo.setContent(json);
paymentInfo.setType(type);
paymentInfoService.updateById(paymentInfo);
}
/*// 支付失败 通知商家的条件 1、会话过期 2、支付失败 3、这个用户在这个支付失败后再无支付成功的订阅
if (invoice.getBillingReason().equals("subscription_create")){
response = sendEmail(paymentInfo.getOrderNo());
} else if (invoice.getBillingReason().equals("subscription_cycle")){
response = sendEmail(invoice.getSubscription(), "fail_renewal");
}*/
}
}else if (stripeObject instanceof Charge) {
Charge charge = (Charge) stripeObject;
String orderNo = charge.getDescription().replace("AiDA - ", "");
OrderInfo orderInfo = orderInfoService.getOrderByOrderNo(orderNo);
if (event.getType().equals("charge.failed")){
// 添加支付信息 && 更新支付信息
// 支付失败时无法通过invoice_id获取支付方式所以使用charge.failed回调添加支付信息
paymentInfoService.createOrUpdatePaymentInfoForStripe(charge);
orderInfo.setOrderStatus(OrderStatusEnum.FAILURE.getType());
orderInfo.setNote(charge.getFailureMessage());
orderInfoService.updateById(orderInfo);
}else if (event.getType().equals("charge.succeeded")){
orderInfo.setOrderStatus(OrderStatusEnum.SUCCESS.getType());
orderInfo.setNote("");
orderInfoService.updateById(orderInfo);
}
}
return response;
@@ -351,6 +397,36 @@ public class StripeServiceImpl implements StripeService {
}
}
private void processExpiredOrder(String orderNo) {
// 支付失败 通知商家的条件 1、会话过期 2、支付失败 3、这个用户在这个支付失败后再无支付成功的订阅
// 1、获取当前订单的支付状态
// String orderNo = session.getMetadata().get("orderId");
OrderInfo orderByOrderNo = orderInfoService.getOrderByOrderNo(orderNo);
// 2、确认订单状态为支付失败
if (orderByOrderNo.getOrderStatus().equals(OrderStatusEnum.FAILURE.getType())) {
// 3、判断失败订单之后再无成功的订单
QueryWrapper<OrderInfo> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("account_id", orderByOrderNo.getAccountId());
queryWrapper.gt("create_time", orderByOrderNo.getCreateTime());
queryWrapper.eq("order_status", OrderStatusEnum.SUCCESS.getType());
queryWrapper.likeLeft("title", "Subscription");
List<OrderInfo> orderInfos = orderInfoService.getBaseMapper().selectList(queryWrapper);
if (orderInfos.isEmpty()) {
// 4、判断当前订单有没有订阅信息
QueryWrapper<SubscriptionInfo> qw = new QueryWrapper<>();
qw.eq("order_no", orderNo);
SubscriptionInfo subscriptionInfo = subscriptionInfoMapper.selectOne(qw);
// 发送邮件通知商家用户支付失败
if (Objects.isNull(subscriptionInfo) || subscriptionInfo.getStatus().equals("incomplete")) {
sendEmail(orderNo);
}else {
sendEmail(subscriptionInfo.getSubscriptionId(), "fail_renewal");
}
}
}
}
@Transactional(rollbackFor = Exception.class)
public SubscriptionInfo createSubscription(Subscription subscription){
// 确认当前subscription是否已经记录
@@ -366,7 +442,6 @@ public class StripeServiceImpl implements StripeService {
// 从回调信息中获取recurring type
SubscriptionItem subscriptionItem = subscription.getItems().getData().get(0);
String interval = subscriptionItem.getPrice().getRecurring().getInterval();
Map<String, String> paymentMethod = getPaymentMethodByInvoiceId(subscription.getLatestInvoice());
subscriptionInfo = new SubscriptionInfo();
subscriptionInfo.setAccountId(orderInfo.getAccountId());
@@ -374,8 +449,6 @@ public class StripeServiceImpl implements StripeService {
subscriptionInfo.setSubscriptionId(subscription.getId());
subscriptionInfo.setType(interval);
subscriptionInfo.setStatus(subscription.getStatus());
subscriptionInfo.setPaymentMethod(paymentMethod.get("paymentMethod"));
subscriptionInfo.setLast4(paymentMethod.get("last4"));
subscriptionInfo.setNextPayDate(changeTimeStampFormat(subscription.getCurrentPeriodEnd(), "seconds", CommonConstant.TIME_FORMAT_MMM_dd_yyyy_EEEE));
subscriptionInfo.setCurrentPeriodStart(subscription.getCurrentPeriodStart());
subscriptionInfo.setCurrentPeriodEnd(subscription.getCurrentPeriodEnd());
@@ -406,7 +479,7 @@ public class StripeServiceImpl implements StripeService {
}
@Transactional(rollbackFor = Exception.class)
public Boolean updateSubscription(Subscription subscription){
public SubscriptionInfo updateSubscription(Subscription subscription){
// 获取当前是否有已经记录的subscriptionInfo
SubscriptionInfo subscriptionInfo = createSubscription(subscription);
// 用于标志数据有没有变动,避免在没有改动的情况下频繁的更新数据库
@@ -415,9 +488,6 @@ public class StripeServiceImpl implements StripeService {
subscriptionInfo.setStatus(subscription.getStatus());
flag = true;
}
if (subscription.getStatus().equals("canceled")){
subscriptionInfo.setAutoRenewal((byte) 0);
}
if (!subscriptionInfo.getCurrentPeriodStart().equals(subscription.getCurrentPeriodStart())){
subscriptionInfo.setCurrentPeriodStart(subscription.getCurrentPeriodStart());
flag = true;
@@ -432,10 +502,9 @@ public class StripeServiceImpl implements StripeService {
}
if (flag){
subscriptionInfo.setUpdateTime(LocalDateTime.now());
// todo 这里需要再检查支付方式吗?
subscriptionInfoMapper.updateById(subscriptionInfo);
}
return true;
return subscriptionInfo;
}
private void updateAccountValidity(Long accountId, Long currentPeriodEnd){
@@ -633,6 +702,7 @@ public class StripeServiceImpl implements StripeService {
switch (retrieve.getType()){
case "alipay":
paymentMethod = "Alipay";
last4 = "N/A";
break;
case "bancontact":
paymentMethod = "BanContact";
@@ -647,17 +717,24 @@ public class StripeServiceImpl implements StripeService {
case "eps":
PaymentMethod.Eps eps = retrieve.getEps();
paymentMethod = eps.getBank();
last4 = "N/A";
break;
case "giropay":
paymentMethod = "GiroPay";
last4 = "N/A";
break;
case "ideal":
PaymentMethod.Ideal ideal = retrieve.getIdeal();
paymentMethod = ideal.getBank();
last4 = "N/A";
break;
case "link":
paymentMethod = "Link";
last4 = "N/A";
break;
default:
paymentMethod = "N/A";
last4 = "N/A";
}
HashMap<String, String> resp = new HashMap<>();
resp.put("paymentMethod", paymentMethod);
@@ -669,7 +746,7 @@ public class StripeServiceImpl implements StripeService {
// return null;
}
public boolean sendEmail(String subscriptionId, String type){
public boolean sendEmail(String subscriptionId, String type) {
SubscriptionEmailParamsDTO emailParamsDTO = new SubscriptionEmailParamsDTO();
QueryWrapper<SubscriptionInfo> qwSI = new QueryWrapper<>();
@@ -688,9 +765,9 @@ public class StripeServiceImpl implements StripeService {
if (StringUtil.isNullOrEmpty(type)){
// 如果没有传入type,则使用paymentInfo中记录的类型
// 其实这里也可以通过invoiceId查询stripe但是记录在自己的db中可以不用每次都查且方便查看
type = paymentInfo.getType();
type = StringUtil.isNullOrEmpty(paymentInfo.getType()) ? "new" : paymentInfo.getType();
}
if (!type.equals("reminder") && paymentInfo.getNotified() == 1){
if (!type.equals("reminder") && !type.equals("cancel") && paymentInfo.getNotified() == 1){
// 已经邮件通知过,直接返回
return true;
}
@@ -707,8 +784,10 @@ public class StripeServiceImpl implements StripeService {
emailParamsDTO.setTotalFee(paymentInfo.getPayerTotal().toString());
emailParamsDTO.setLastOrderDate(changeTimeStampFormat(subscriptionInfo.getCurrentPeriodStart(), "seconds", CommonConstant.TIME_FORMAT_MMM_dd_yyyy));
emailParamsDTO.setEndOfPrepaidTerm(changeTimeStampFormat(subscriptionInfo.getCurrentPeriodEnd(), "seconds", CommonConstant.TIME_FORMAT_MMM_dd_yyyy));
emailParamsDTO.setPaymentMethod(subscriptionInfo.getPaymentMethod());
emailParamsDTO.setPaymentMethod(paymentInfo.getPaymentMethod());
emailParamsDTO.setLast4(paymentInfo.getLast4());
emailParamsDTO.setSubscriptionId(subscriptionInfo.getId().toString());
emailParamsDTO.setFailMessage(orderByOrderNo.getNote());
emailParamsDTO.setSubscriptionType(subscriptionInfo.getType());
emailParamsDTO.setStartDate(changeTimeStampFormat(orderByOrderNo.getCreateTime()));
emailParamsDTO.setNextPayDate(changeTimeStampFormat(subscriptionInfo.getCurrentPeriodEnd(), "seconds", CommonConstant.TIME_FORMAT_MMM_dd_yyyy));
@@ -717,7 +796,7 @@ public class StripeServiceImpl implements StripeService {
SendEmailUtil.subscriptionEmailReminder(type, emailParamsDTO, language, account.getUserEmail());
// 邮件通知成功后,更新标志
if (!type.equals("reminder")){
if (!type.equals("reminder") && !type.equals("cancel")){
PaymentInfo payment = new PaymentInfo();
payment.setId(paymentInfo.getId());
payment.setNotified(1);
@@ -727,6 +806,40 @@ public class StripeServiceImpl implements StripeService {
return true;
}
public boolean sendEmail(String orderNo){
SubscriptionEmailParamsDTO emailParamsDTO = new SubscriptionEmailParamsDTO();
OrderInfo orderInfo = orderInfoService.getOrderByOrderNo(orderNo);
com.ai.da.mapper.primary.entity.Account account = accountMapper.selectById(orderInfo.getAccountId());
String userName = account.getUserName();
String language = account.getLanguage();
QueryWrapper<PaymentInfo> qwPI = new QueryWrapper<>();
qwPI.eq("order_no", orderNo);
List<PaymentInfo> paymentInfos = paymentInfoMapper.selectList(qwPI);
if (paymentInfos.isEmpty()) {
return false;
}
PaymentInfo paymentInfo = paymentInfos.get(0);
emailParamsDTO.setUsername(userName);
emailParamsDTO.setOrderId(paymentInfo.getId().toString());
emailParamsDTO.setCreateDate(String.valueOf(paymentInfo.getCreateTime()).replace("T", " "));
emailParamsDTO.setQuantity(String.valueOf(1));
emailParamsDTO.setTotalFee(paymentInfo.getPayerTotal().toString());
emailParamsDTO.setFailMessage(orderInfo.getNote());
emailParamsDTO.setPaymentMethod(paymentInfo.getPaymentMethod());
emailParamsDTO.setLast4(paymentInfo.getLast4());
SendEmailUtil.subscriptionEmailReminder("fail_new", emailParamsDTO, language, account.getUserEmail());
// 邮件通知成功后,更新标志
PaymentInfo payment = new PaymentInfo();
payment.setId(paymentInfo.getId());
payment.setNotified(1);
payment.setUpdateTime(LocalDateTime.now());
paymentInfoMapper.updateById(payment);
return true;
}
public void subscriptionReminder(){
// 提前7天的 00:00:00 和 23:59:59
LocalDateTime startOfDay = LocalDateTime.now().plusDays(7).toLocalDate().atStartOfDay();