支付优化
This commit is contained in:
@@ -17,6 +17,11 @@ public enum OrderStatusEnum {
|
|||||||
*/
|
*/
|
||||||
SUCCESS("支付成功"),
|
SUCCESS("支付成功"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付失败
|
||||||
|
*/
|
||||||
|
FAILURE("支付失败"),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 已关闭
|
* 已关闭
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -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());
|
||||||
|
|||||||
@@ -21,5 +21,7 @@ public class OrderInfo extends BaseEntity{
|
|||||||
|
|
||||||
private String orderStatus;//订单状态
|
private String orderStatus;//订单状态
|
||||||
|
|
||||||
|
private String note;
|
||||||
|
|
||||||
private String paymentType;//支付方式
|
private String paymentType;//支付方式
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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){
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
Reference in New Issue
Block a user