支付优化-续订失败邮件通知

This commit is contained in:
2024-11-28 10:43:06 +08:00
parent 5019fbd3fc
commit 1b15aed6a2
9 changed files with 269 additions and 42 deletions

View File

@@ -236,6 +236,7 @@ public class PaymentInfoServiceImpl extends ServiceImpl<PaymentInfoMapper, Payme
paymentInfo.setNotified(0);
paymentInfo.setPaymentMethod(paymentMethod.get("paymentMethod"));
paymentInfo.setLast4(paymentMethod.get("last4"));
paymentInfo.setHostedInvoiceUrl(invoice.getHostedInvoiceUrl());
paymentInfo.setCreateTime(LocalDateTime.now());
baseMapper.insert(paymentInfo);

View File

@@ -284,19 +284,27 @@ public class StripeServiceImpl implements StripeService {
log.info("创建连续订阅");
} else if (event.getType().equals("customer.subscription.updated")){
// 更新订阅信息
updateSubscription(subscription);
SubscriptionInfo subscriptionInfo = updateSubscription(subscription);
log.info("订阅更新");
if (subscription.getStatus().equals("active")){
response = sendEmail(subscription.getId(), null);
}
// 续订支付失败,邮件通知用户
if (subscription.getStatus().equals("past_due")){
// 发送续订失败邮件
response = sendRenewalFailEmail(null, subscription.getId(), subscriptionInfo.getOrderNo());
}
} else if (event.getType().equals("customer.subscription.deleted")){
SubscriptionInfo subscriptionInfo = updateSubscription(subscription);
log.info("用户取消连续订阅");
log.info("用户 {} 取消连续订阅 {}", subscriptionInfo.getAccountId(), subscription.getId());
if (subscriptionInfo.getCancelNotified() == (byte)0){
log.info("取消订阅 邮件通知商家");
response = sendEmail(subscription.getId(), "cancel");
subscriptionInfo.setCancelNotified((byte)1);
subscriptionInfoMapper.updateById(subscriptionInfo);
}
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")){
@@ -332,14 +340,13 @@ public class StripeServiceImpl implements StripeService {
String json = gson.toJson(invoice);
paymentInfo.setContent(json);
paymentInfo.setType(type);
paymentInfo.setHostedInvoiceUrl(invoice.getHostedInvoiceUrl());
paymentInfoService.updateById(paymentInfo);
// 发送续订失败邮件
response = sendRenewalFailEmail(invoice.getId(), null, paymentInfo.getOrderNo());
}
/*// 支付失败 通知商家的条件 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;
@@ -417,9 +424,12 @@ public class StripeServiceImpl implements StripeService {
qw.eq("order_no", orderNo);
SubscriptionInfo subscriptionInfo = subscriptionInfoMapper.selectOne(qw);
// 发送邮件通知商家用户支付失败
if (Objects.isNull(subscriptionInfo) || subscriptionInfo.getStatus().equals("incomplete")) {
if (Objects.isNull(subscriptionInfo)
|| subscriptionInfo.getStatus().equals("incomplete")
|| subscriptionInfo.getStatus().equals("incomplete_expired")) {
sendEmail(orderNo);
}else {
// todo 续订失败 应该不会走这里
sendEmail(subscriptionInfo.getSubscriptionId(), "fail_renewal");
}
}
@@ -535,6 +545,18 @@ public class StripeServiceImpl implements StripeService {
});
}
public void cancelSubscriptionTemp(String subscriptionId) {
Stripe.apiKey = privateKey;
try {
log.info("申请取消连续订阅 {}", subscriptionId);
Subscription subscription = Subscription.retrieve(subscriptionId);
Subscription cancel = subscription.cancel();
cancel.getStatus();
} catch (StripeException e) {
throw new RuntimeException(e);
}
}
public String refund(String amount, String orderNo, String reason) {
Refund refund;
RefundInfo refundByOrderNo = refundInfoService.createRefundByOrderNo(orderNo, reason);
@@ -630,7 +652,6 @@ public class StripeServiceImpl implements StripeService {
}
// 获取所有订阅
public List<Subscription> getSubscription(String username, String userEmail) {
Stripe.apiKey = privateKey;
String customerId = null;
@@ -642,6 +663,25 @@ public class StripeServiceImpl implements StripeService {
} catch (StripeException e) {
throw new RuntimeException(e);
}
}
// 获取所有订阅
public List<String> getSubscriptionIds(String username, String userEmail) {
Stripe.apiKey = privateKey;
String customerId = null;
try {
customerId = getCustomer(username, userEmail);
SubscriptionCollection list = Subscription.list(SubscriptionListParams.builder()
.setCustomer(customerId).build());
List<Subscription> data = list.getData();
ArrayList<String> subscriptionIds = new ArrayList<>();
data.forEach(subscription -> {
subscriptionIds.add(subscription.getId());
});
return subscriptionIds;
} catch (StripeException e) {
throw new RuntimeException(e);
}
}
@@ -747,7 +787,6 @@ public class StripeServiceImpl implements StripeService {
}
public boolean sendEmail(String subscriptionId, String type) {
SubscriptionEmailParamsDTO emailParamsDTO = new SubscriptionEmailParamsDTO();
QueryWrapper<SubscriptionInfo> qwSI = new QueryWrapper<>();
qwSI.eq("subscription_id", subscriptionId);
@@ -784,14 +823,7 @@ 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(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));
emailParamsDTO.setRenewalTime(changeTimeStampFormat(subscriptionInfo.getCurrentPeriodEnd(), "seconds", CommonConstant.TIME_FORMAT_MMM_dd_yyyy));
setSubscriptionParams(paymentInfo, subscriptionInfo, orderByOrderNo, emailParamsDTO);
SendEmailUtil.subscriptionEmailReminder(type, emailParamsDTO, language, account.getUserEmail());
@@ -840,6 +872,79 @@ public class StripeServiceImpl implements StripeService {
return true;
}
public boolean sendRenewalFailEmail(String invoiceId, String subscriptionId, String orderNo){
// 1、确认当前订单最后一笔支付为fail
// 更新支付信息
PaymentInfo paymentInfo;
QueryWrapper<PaymentInfo> queryWrapper = new QueryWrapper<>();
if (StringUtil.isNullOrEmpty(invoiceId)){
queryWrapper.eq("order_no", orderNo).orderByDesc("id");
List<PaymentInfo> paymentInfos = paymentInfoService.getBaseMapper().selectList(queryWrapper);
if (paymentInfos.isEmpty() || !paymentInfos.get(0).getTradeState().equals("failed")){
return false;
}else {
paymentInfo = paymentInfos.get(0);
}
}else {
queryWrapper.eq("transaction_id", invoiceId);
paymentInfo = paymentInfoService.getBaseMapper().selectOne(queryWrapper);
if (Objects.isNull(paymentInfo)
|| !paymentInfo.getTradeState().equals("failed")
|| paymentInfo.getNotified().equals(1)){
return false;
}
}
// 2、确认当前订阅的状态为past_due
SubscriptionInfo subscriptionInfo;
QueryWrapper<SubscriptionInfo> qwSI = new QueryWrapper<>();
if (StringUtil.isNullOrEmpty(subscriptionId)){
qwSI.eq("order_no", orderNo);
}else {
qwSI.eq("subscription_id", subscriptionId);
}
subscriptionInfo = subscriptionInfoMapper.selectOne(qwSI);
if (Objects.isNull(subscriptionInfo) || !subscriptionInfo.getStatus().equals("past_due")){
return false;
}
// 3、组参数
com.ai.da.mapper.primary.entity.Account account = accountMapper.selectById(subscriptionInfo.getAccountId());
String userName = account.getUserName();
String language = account.getLanguage();
OrderInfo orderByOrderNo = orderInfoService.getOrderByOrderNo(subscriptionInfo.getOrderNo());
SubscriptionEmailParamsDTO emailParamsDTO = new SubscriptionEmailParamsDTO();
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());
setSubscriptionParams(paymentInfo, subscriptionInfo, orderByOrderNo, emailParamsDTO);
// todo
emailParamsDTO.setAccountPageRef("\"https://www.aida.com.hk/home/homePage\"");
// 4、发邮件
SendEmailUtil.subscriptionEmailReminder("fail_renewal", emailParamsDTO, language, account.getUserEmail());
PaymentInfo payment = new PaymentInfo();
payment.setId(paymentInfo.getId());
payment.setNotified(1);
payment.setUpdateTime(LocalDateTime.now());
paymentInfoMapper.updateById(payment);
return true;
}
private void setSubscriptionParams(PaymentInfo paymentInfo, SubscriptionInfo subscriptionInfo, OrderInfo orderByOrderNo, SubscriptionEmailParamsDTO emailParamsDTO) {
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));
emailParamsDTO.setRenewalTime(changeTimeStampFormat(subscriptionInfo.getCurrentPeriodEnd(), "seconds", CommonConstant.TIME_FORMAT_MMM_dd_yyyy));
}
public void subscriptionReminder(){
// 提前7天的 00:00:00 和 23:59:59
LocalDateTime startOfDay = LocalDateTime.now().plusDays(7).toLocalDate().atStartOfDay();
@@ -876,4 +981,87 @@ public class StripeServiceImpl implements StripeService {
}
}
// todo 新建一个订阅 使用不会成功的付款方式
public String createSubscriptionTemp(String name, String email){
Stripe.apiKey = privateKey;
try {
OrderInfo orderInfo = orderInfoService.createOrderByProductId(1, PayTypeEnum.STRIPE.getType(), ProductEnum.DailySubscription);
String paymentMethodCode = "pm_card_mastercard";
PaymentMethod paymentMethod = PaymentMethod.retrieve(paymentMethodCode);
String customerId = getCustomer(name, email);
log.info("customerId: {}", customerId);
PaymentMethodAttachParams attachParams = PaymentMethodAttachParams.builder()
.setCustomer(customerId)
.build();
paymentMethod.attach(attachParams);
// 设置默认付款方式
Customer updatedCustomer = Customer.retrieve(customerId);
CustomerUpdateParams params = CustomerUpdateParams.builder()
.setInvoiceSettings(
CustomerUpdateParams.InvoiceSettings.builder()
.setDefaultPaymentMethod(paymentMethod.getId())
.build()
)
.build();
updatedCustomer.update(params);
// 3. 创建订阅
SubscriptionCreateParams subscriptionParams = SubscriptionCreateParams.builder()
.setCustomer(customerId)
.addItem(
SubscriptionCreateParams.Item.builder()
.setPrice("price_1QFXkf02n1TEydyNtA4TQ3Yz") // 替换为实际的价格 ID
.build()
)
.setDescription("AiDA - " + orderInfo.getOrderNo())
.build();
Subscription subscription = Subscription.create(subscriptionParams);
// 打印订阅 ID
System.out.println("Subscription created: " + subscription.getId());
return subscription.getId();
} catch (StripeException e) {
throw new RuntimeException(e);
}
}
public String changeCustomerPayment(String name, String email){
Stripe.apiKey = privateKey;
String paymentMethodCode = "pm_card_chargeCustomerFail";
try {
PaymentMethod paymentMethod = PaymentMethod.retrieve(paymentMethodCode);
String customerId = getCustomer(name, email);
log.info("customerId: {}", customerId);
// 附加支付方式到客户
PaymentMethodAttachParams attachParams = PaymentMethodAttachParams.builder()
.setCustomer(customerId)
.build();
paymentMethod.attach(attachParams);
// 更新客户的默认支付方式
CustomerUpdateParams params = CustomerUpdateParams.builder()
.setInvoiceSettings(
CustomerUpdateParams.InvoiceSettings.builder()
.setDefaultPaymentMethod(paymentMethod.getId())
.build()
)
.build();
// 更新客户信息
Customer customer = Customer.retrieve(customerId);
customer.update(params);
return paymentMethod.getId();
} catch (StripeException e) {
throw new RuntimeException(e);
}
}
}