支付优化

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("支付成功"), SUCCESS("支付成功"),
/**
* 支付失败
*/
FAILURE("支付失败"),
/** /**
* 已关闭 * 已关闭
*/ */

View File

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

View File

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

View File

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

View File

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

View File

@@ -28,6 +28,8 @@ public class SubscriptionEmailParamsDTO {
// 付款方式 // 付款方式
private String paymentMethod; private String paymentMethod;
private String last4;
// 订阅Id // 订阅Id
private String subscriptionId; private String subscriptionId;
@@ -43,5 +45,8 @@ public class SubscriptionEmailParamsDTO {
// 下次付款时间reminder // 下次付款时间reminder
private String renewalTime; 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.ai.da.model.dto.AlipayHKCallbackDTO;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
import com.paypal.orders.Order; import com.paypal.orders.Order;
import com.stripe.model.Charge;
import com.stripe.model.Invoice; import com.stripe.model.Invoice;
import java.util.Map; import java.util.Map;
@@ -18,7 +19,9 @@ public interface PaymentInfoService extends IService<PaymentInfo> {
void createPaymentInfoForAliPayHK(AlipayHKCallbackDTO alipayHKCallbackDTO); void createPaymentInfoForAliPayHK(AlipayHKCallbackDTO alipayHKCallbackDTO);
PaymentInfo createPaymentInfoForStripe(Invoice invoice); PaymentInfo createOrUpdatePaymentInfoForStripe(Invoice invoice);
PaymentInfo createOrUpdatePaymentInfoForStripe(Charge charge);
PaymentInfo getPaymentInfoByOrderId(String orderId); PaymentInfo getPaymentInfoByOrderId(String orderId);

View File

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

View File

@@ -271,6 +271,10 @@ public class StripeServiceImpl implements StripeService {
Session session = (Session) stripeObject; Session session = (Session) stripeObject;
if (event.getType().equals("checkout.session.completed")) { if (event.getType().equals("checkout.session.completed")) {
processOrder(session); processOrder(session);
}else if (event.getType().equals("checkout.session.expired")){
String orderNo = session.getMetadata().get("orderId");
// 会话过期 未支付 且之后没有支付成功的订单
processExpiredOrder(orderNo);
} }
} else if (stripeObject instanceof Subscription){ } else if (stripeObject instanceof Subscription){
Subscription subscription = (Subscription) stripeObject; Subscription subscription = (Subscription) stripeObject;
@@ -280,25 +284,30 @@ public class StripeServiceImpl implements StripeService {
log.info("创建连续订阅"); log.info("创建连续订阅");
} else if (event.getType().equals("customer.subscription.updated")){ } else if (event.getType().equals("customer.subscription.updated")){
// 更新订阅信息 // 更新订阅信息
response = updateSubscription(subscription); updateSubscription(subscription);
log.info("订阅更新"); log.info("订阅更新");
if (subscription.getStatus().equals("active")){ if (subscription.getStatus().equals("active")){
response = sendEmail(subscription.getId(), null); response = sendEmail(subscription.getId(), null);
} }
} else if (event.getType().equals("customer.subscription.deleted")){ } else if (event.getType().equals("customer.subscription.deleted")){
response = updateSubscription(subscription); SubscriptionInfo subscriptionInfo = updateSubscription(subscription);
log.info("用户取消连续订阅"); 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); updateSubscription(subscription);
} else if (event.getType().equals("customer.subscription.resumed")){ } else if (event.getType().equals("customer.subscription.resumed")){
updateSubscription(subscription); updateSubscription(subscription);
log.info("用户订阅恢复"); log.info("用户订阅恢复");
} }*/
} else if (stripeObject instanceof Invoice) { } else if (stripeObject instanceof Invoice) {
Invoice invoice = (Invoice) stripeObject; Invoice invoice = (Invoice) stripeObject;
if (event.getType().equals("invoice.paid")) { if (event.getType().equals("invoice.paid")) {
// 新增支付成功的信息,返回orderNo表示该回调第一次被记录 // 新增支付成功的信息,返回orderNo表示该回调第一次被记录
PaymentInfo paymentInfo = paymentInfoService.createPaymentInfoForStripe(invoice); PaymentInfo paymentInfo = paymentInfoService.createOrUpdatePaymentInfoForStripe(invoice);
// 当前支付没有被通知时才需要发送通知邮件 // 当前支付没有被通知时才需要发送通知邮件
if (paymentInfo.getNotified().equals(0)) { if (paymentInfo.getNotified().equals(0)) {
@@ -311,6 +320,43 @@ public class StripeServiceImpl implements StripeService {
response = sendEmail(invoice.getSubscription(), "renewal"); 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; 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) @Transactional(rollbackFor = Exception.class)
public SubscriptionInfo createSubscription(Subscription subscription){ public SubscriptionInfo createSubscription(Subscription subscription){
// 确认当前subscription是否已经记录 // 确认当前subscription是否已经记录
@@ -366,7 +442,6 @@ public class StripeServiceImpl implements StripeService {
// 从回调信息中获取recurring type // 从回调信息中获取recurring type
SubscriptionItem subscriptionItem = subscription.getItems().getData().get(0); SubscriptionItem subscriptionItem = subscription.getItems().getData().get(0);
String interval = subscriptionItem.getPrice().getRecurring().getInterval(); String interval = subscriptionItem.getPrice().getRecurring().getInterval();
Map<String, String> paymentMethod = getPaymentMethodByInvoiceId(subscription.getLatestInvoice());
subscriptionInfo = new SubscriptionInfo(); subscriptionInfo = new SubscriptionInfo();
subscriptionInfo.setAccountId(orderInfo.getAccountId()); subscriptionInfo.setAccountId(orderInfo.getAccountId());
@@ -374,8 +449,6 @@ public class StripeServiceImpl implements StripeService {
subscriptionInfo.setSubscriptionId(subscription.getId()); subscriptionInfo.setSubscriptionId(subscription.getId());
subscriptionInfo.setType(interval); subscriptionInfo.setType(interval);
subscriptionInfo.setStatus(subscription.getStatus()); 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.setNextPayDate(changeTimeStampFormat(subscription.getCurrentPeriodEnd(), "seconds", CommonConstant.TIME_FORMAT_MMM_dd_yyyy_EEEE));
subscriptionInfo.setCurrentPeriodStart(subscription.getCurrentPeriodStart()); subscriptionInfo.setCurrentPeriodStart(subscription.getCurrentPeriodStart());
subscriptionInfo.setCurrentPeriodEnd(subscription.getCurrentPeriodEnd()); subscriptionInfo.setCurrentPeriodEnd(subscription.getCurrentPeriodEnd());
@@ -406,7 +479,7 @@ public class StripeServiceImpl implements StripeService {
} }
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public Boolean updateSubscription(Subscription subscription){ public SubscriptionInfo updateSubscription(Subscription subscription){
// 获取当前是否有已经记录的subscriptionInfo // 获取当前是否有已经记录的subscriptionInfo
SubscriptionInfo subscriptionInfo = createSubscription(subscription); SubscriptionInfo subscriptionInfo = createSubscription(subscription);
// 用于标志数据有没有变动,避免在没有改动的情况下频繁的更新数据库 // 用于标志数据有没有变动,避免在没有改动的情况下频繁的更新数据库
@@ -415,9 +488,6 @@ public class StripeServiceImpl implements StripeService {
subscriptionInfo.setStatus(subscription.getStatus()); subscriptionInfo.setStatus(subscription.getStatus());
flag = true; flag = true;
} }
if (subscription.getStatus().equals("canceled")){
subscriptionInfo.setAutoRenewal((byte) 0);
}
if (!subscriptionInfo.getCurrentPeriodStart().equals(subscription.getCurrentPeriodStart())){ if (!subscriptionInfo.getCurrentPeriodStart().equals(subscription.getCurrentPeriodStart())){
subscriptionInfo.setCurrentPeriodStart(subscription.getCurrentPeriodStart()); subscriptionInfo.setCurrentPeriodStart(subscription.getCurrentPeriodStart());
flag = true; flag = true;
@@ -432,10 +502,9 @@ public class StripeServiceImpl implements StripeService {
} }
if (flag){ if (flag){
subscriptionInfo.setUpdateTime(LocalDateTime.now()); subscriptionInfo.setUpdateTime(LocalDateTime.now());
// todo 这里需要再检查支付方式吗?
subscriptionInfoMapper.updateById(subscriptionInfo); subscriptionInfoMapper.updateById(subscriptionInfo);
} }
return true; return subscriptionInfo;
} }
private void updateAccountValidity(Long accountId, Long currentPeriodEnd){ private void updateAccountValidity(Long accountId, Long currentPeriodEnd){
@@ -633,6 +702,7 @@ public class StripeServiceImpl implements StripeService {
switch (retrieve.getType()){ switch (retrieve.getType()){
case "alipay": case "alipay":
paymentMethod = "Alipay"; paymentMethod = "Alipay";
last4 = "N/A";
break; break;
case "bancontact": case "bancontact":
paymentMethod = "BanContact"; paymentMethod = "BanContact";
@@ -647,17 +717,24 @@ public class StripeServiceImpl implements StripeService {
case "eps": case "eps":
PaymentMethod.Eps eps = retrieve.getEps(); PaymentMethod.Eps eps = retrieve.getEps();
paymentMethod = eps.getBank(); paymentMethod = eps.getBank();
last4 = "N/A";
break; break;
case "giropay": case "giropay":
paymentMethod = "GiroPay"; paymentMethod = "GiroPay";
last4 = "N/A";
break; break;
case "ideal": case "ideal":
PaymentMethod.Ideal ideal = retrieve.getIdeal(); PaymentMethod.Ideal ideal = retrieve.getIdeal();
paymentMethod = ideal.getBank(); paymentMethod = ideal.getBank();
last4 = "N/A";
break; break;
case "link": case "link":
paymentMethod = "Link"; paymentMethod = "Link";
last4 = "N/A";
break; break;
default:
paymentMethod = "N/A";
last4 = "N/A";
} }
HashMap<String, String> resp = new HashMap<>(); HashMap<String, String> resp = new HashMap<>();
resp.put("paymentMethod", paymentMethod); resp.put("paymentMethod", paymentMethod);
@@ -669,7 +746,7 @@ public class StripeServiceImpl implements StripeService {
// return null; // return null;
} }
public boolean sendEmail(String subscriptionId, String type){ public boolean sendEmail(String subscriptionId, String type) {
SubscriptionEmailParamsDTO emailParamsDTO = new SubscriptionEmailParamsDTO(); SubscriptionEmailParamsDTO emailParamsDTO = new SubscriptionEmailParamsDTO();
QueryWrapper<SubscriptionInfo> qwSI = new QueryWrapper<>(); QueryWrapper<SubscriptionInfo> qwSI = new QueryWrapper<>();
@@ -688,9 +765,9 @@ public class StripeServiceImpl implements StripeService {
if (StringUtil.isNullOrEmpty(type)){ if (StringUtil.isNullOrEmpty(type)){
// 如果没有传入type,则使用paymentInfo中记录的类型 // 如果没有传入type,则使用paymentInfo中记录的类型
// 其实这里也可以通过invoiceId查询stripe但是记录在自己的db中可以不用每次都查且方便查看 // 其实这里也可以通过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; return true;
} }
@@ -707,8 +784,10 @@ public class StripeServiceImpl implements StripeService {
emailParamsDTO.setTotalFee(paymentInfo.getPayerTotal().toString()); emailParamsDTO.setTotalFee(paymentInfo.getPayerTotal().toString());
emailParamsDTO.setLastOrderDate(changeTimeStampFormat(subscriptionInfo.getCurrentPeriodStart(), "seconds", CommonConstant.TIME_FORMAT_MMM_dd_yyyy)); 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.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.setSubscriptionId(subscriptionInfo.getId().toString());
emailParamsDTO.setFailMessage(orderByOrderNo.getNote());
emailParamsDTO.setSubscriptionType(subscriptionInfo.getType()); emailParamsDTO.setSubscriptionType(subscriptionInfo.getType());
emailParamsDTO.setStartDate(changeTimeStampFormat(orderByOrderNo.getCreateTime())); emailParamsDTO.setStartDate(changeTimeStampFormat(orderByOrderNo.getCreateTime()));
emailParamsDTO.setNextPayDate(changeTimeStampFormat(subscriptionInfo.getCurrentPeriodEnd(), "seconds", CommonConstant.TIME_FORMAT_MMM_dd_yyyy)); 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()); SendEmailUtil.subscriptionEmailReminder(type, emailParamsDTO, language, account.getUserEmail());
// 邮件通知成功后,更新标志 // 邮件通知成功后,更新标志
if (!type.equals("reminder")){ if (!type.equals("reminder") && !type.equals("cancel")){
PaymentInfo payment = new PaymentInfo(); PaymentInfo payment = new PaymentInfo();
payment.setId(paymentInfo.getId()); payment.setId(paymentInfo.getId());
payment.setNotified(1); payment.setNotified(1);
@@ -727,6 +806,40 @@ public class StripeServiceImpl implements StripeService {
return true; 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(){ public void subscriptionReminder(){
// 提前7天的 00:00:00 和 23:59:59 // 提前7天的 00:00:00 和 23:59:59
LocalDateTime startOfDay = LocalDateTime.now().plusDays(7).toLocalDate().atStartOfDay(); LocalDateTime startOfDay = LocalDateTime.now().plusDays(7).toLocalDate().atStartOfDay();