diff --git a/src/main/java/com/ai/da/common/enums/OrderStatusEnum.java b/src/main/java/com/ai/da/common/enums/OrderStatusEnum.java index aac9719d..8f8699a6 100644 --- a/src/main/java/com/ai/da/common/enums/OrderStatusEnum.java +++ b/src/main/java/com/ai/da/common/enums/OrderStatusEnum.java @@ -17,6 +17,11 @@ public enum OrderStatusEnum { */ SUCCESS("支付成功"), + /** + * 支付失败 + */ + FAILURE("支付失败"), + /** * 已关闭 */ diff --git a/src/main/java/com/ai/da/common/utils/SendEmailUtil.java b/src/main/java/com/ai/da/common/utils/SendEmailUtil.java index c52d3d8c..c6d61e68 100644 --- a/src/main/java/com/ai/da/common/utils/SendEmailUtil.java +++ b/src/main/java/com/ai/da/common/utils/SendEmailUtil.java @@ -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()); diff --git a/src/main/java/com/ai/da/mapper/primary/entity/OrderInfo.java b/src/main/java/com/ai/da/mapper/primary/entity/OrderInfo.java index 98a020b9..e5bc0a98 100644 --- a/src/main/java/com/ai/da/mapper/primary/entity/OrderInfo.java +++ b/src/main/java/com/ai/da/mapper/primary/entity/OrderInfo.java @@ -21,5 +21,7 @@ public class OrderInfo extends BaseEntity{ private String orderStatus;//订单状态 + private String note; + private String paymentType;//支付方式 } diff --git a/src/main/java/com/ai/da/mapper/primary/entity/PaymentInfo.java b/src/main/java/com/ai/da/mapper/primary/entity/PaymentInfo.java index 3806d888..8172f4bd 100644 --- a/src/main/java/com/ai/da/mapper/primary/entity/PaymentInfo.java +++ b/src/main/java/com/ai/da/mapper/primary/entity/PaymentInfo.java @@ -26,4 +26,8 @@ public class PaymentInfo extends BaseEntity{ // 当前支付是否已邮件通知 0 || 1 private Integer notified; + + private String paymentMethod; + + private String last4; } diff --git a/src/main/java/com/ai/da/mapper/primary/entity/SubscriptionInfo.java b/src/main/java/com/ai/da/mapper/primary/entity/SubscriptionInfo.java index 2b61cf48..b7895c08 100644 --- a/src/main/java/com/ai/da/mapper/primary/entity/SubscriptionInfo.java +++ b/src/main/java/com/ai/da/mapper/primary/entity/SubscriptionInfo.java @@ -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; diff --git a/src/main/java/com/ai/da/model/dto/SubscriptionEmailParamsDTO.java b/src/main/java/com/ai/da/model/dto/SubscriptionEmailParamsDTO.java index 0020582f..9ecf0241 100644 --- a/src/main/java/com/ai/da/model/dto/SubscriptionEmailParamsDTO.java +++ b/src/main/java/com/ai/da/model/dto/SubscriptionEmailParamsDTO.java @@ -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; + } diff --git a/src/main/java/com/ai/da/service/PaymentInfoService.java b/src/main/java/com/ai/da/service/PaymentInfoService.java index fcc69d00..785fb286 100644 --- a/src/main/java/com/ai/da/service/PaymentInfoService.java +++ b/src/main/java/com/ai/da/service/PaymentInfoService.java @@ -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 { void createPaymentInfoForAliPayHK(AlipayHKCallbackDTO alipayHKCallbackDTO); - PaymentInfo createPaymentInfoForStripe(Invoice invoice); + PaymentInfo createOrUpdatePaymentInfoForStripe(Invoice invoice); + + PaymentInfo createOrUpdatePaymentInfoForStripe(Charge charge); PaymentInfo getPaymentInfoByOrderId(String orderId); diff --git a/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java b/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java index e78fd856..204a9ce4 100644 --- a/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java @@ -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 implements PaymentInfoService { + private final StripeServiceImpl stripeServiceImpl; + + public PaymentInfoServiceImpl(StripeServiceImpl stripeServiceImpl) { + this.stripeServiceImpl = stripeServiceImpl; + } + /** * 记录支付日志:微信支付 * @param plainText @@ -152,7 +160,7 @@ public class PaymentInfoServiceImpl extends ServiceImpl 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 paymentMethod = stripeServiceImpl.getPaymentMethodByInvoiceId(invoiceId); paymentInfo = new PaymentInfo(); paymentInfo.setOrderNo(orderNo); @@ -219,12 +234,84 @@ public class PaymentInfoServiceImpl extends ServiceImpl 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){ diff --git a/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java b/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java index fe903590..dba20370 100644 --- a/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java @@ -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 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 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 orderInfos = orderInfoService.getBaseMapper().selectList(queryWrapper); + if (orderInfos.isEmpty()) { + // 4、判断当前订单有没有订阅信息 + QueryWrapper 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 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 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 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 qwPI = new QueryWrapper<>(); + qwPI.eq("order_no", orderNo); + List 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();