diff --git a/src/main/java/com/ai/da/common/enums/CreditsEventsEnum.java b/src/main/java/com/ai/da/common/enums/CreditsEventsEnum.java index 64ada86f..fbf43e60 100644 --- a/src/main/java/com/ai/da/common/enums/CreditsEventsEnum.java +++ b/src/main/java/com/ai/da/common/enums/CreditsEventsEnum.java @@ -11,6 +11,8 @@ public enum CreditsEventsEnum { // PRICE("price","0.1"), BUY_CREDITS("Buy Credits","60"), + + REFUND("Refund","60"), // BUY_CREDITS("Buy Credits","10"), // 每月更新 diff --git a/src/main/java/com/ai/da/common/enums/PayTypeEnum.java b/src/main/java/com/ai/da/common/enums/PayTypeEnum.java index 5bc14b21..390d2b49 100644 --- a/src/main/java/com/ai/da/common/enums/PayTypeEnum.java +++ b/src/main/java/com/ai/da/common/enums/PayTypeEnum.java @@ -24,7 +24,12 @@ public enum PayTypeEnum { /** * 香港支付宝 */ - ALIPAY_HK("Alipay-HK"); + ALIPAY_HK("Alipay-HK"), + + /** + * Stripe + */ + STRIPE("Stripe"); /** * 类型 diff --git a/src/main/java/com/ai/da/common/task/StripeTask.java b/src/main/java/com/ai/da/common/task/StripeTask.java new file mode 100644 index 00000000..d4a6fbaf --- /dev/null +++ b/src/main/java/com/ai/da/common/task/StripeTask.java @@ -0,0 +1,40 @@ +package com.ai.da.common.task; + +import com.ai.da.common.enums.PayTypeEnum; +import com.ai.da.mapper.primary.entity.OrderInfo; +import com.ai.da.service.OrderInfoService; +import com.ai.da.service.StripeService; +import com.paypal.http.exceptions.SerializeException; +import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.List; + +@Slf4j +@Component +public class StripeTask { + + @Resource + private OrderInfoService orderInfoService; + + @Resource + private StripeService stripeService; + +// @Scheduled(cron = "0/30 * * * * ?") + public void orderConfirm() throws SerializeException { + + // 查看超过30分钟以上仍未支付的订单 置为超时订单 + List orderInfoList = orderInfoService.getNoPayOrderByDuration(30, PayTypeEnum.STRIPE.getType()); + + for (OrderInfo orderInfo : orderInfoList) { + String orderNo = orderInfo.getOrderNo(); + log.warn("超时订单 ===> {}", orderNo); + + //核实订单状态:调用支付宝查单接口 + stripeService.checkOrderStatus(orderNo); + + } + } +} diff --git a/src/main/java/com/ai/da/controller/StripeController.java b/src/main/java/com/ai/da/controller/StripeController.java index a7f8f76c..70430fab 100644 --- a/src/main/java/com/ai/da/controller/StripeController.java +++ b/src/main/java/com/ai/da/controller/StripeController.java @@ -2,6 +2,8 @@ package com.ai.da.controller; import com.ai.da.common.response.Response; import com.ai.da.service.StripeService; +import com.paypal.http.HttpResponse; +import com.paypal.payments.Refund; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; @@ -10,7 +12,6 @@ import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; import java.io.IOException; @Api(tags = "Stripe模块") @@ -24,8 +25,8 @@ public class StripeController { @ApiOperation("创建支付链接") @PostMapping("/createOrder/{amount}") - public Response pay(@PathVariable Integer amount) { - return Response.success(stripeService.pay(amount)); + public Response pay(@PathVariable Integer amount, @RequestParam String returnUrl) { + return Response.success(stripeService.pay(amount, returnUrl)); } @ApiOperation("支付通知") @@ -38,4 +39,16 @@ public class StripeController { return Response.fail(400,"failure"); } } + + @ApiOperation("申请退款") + @PostMapping("/trade/refund/{orderNo}/{reason}") + public Response> refund(@PathVariable String orderNo, @PathVariable String reason) throws IOException { + String response = stripeService.refund(null,orderNo,reason); + if (response.equals("退款成功")){ + return Response.success(); + }else { + return Response.fail("Request for refund failed."); + } + } + } diff --git a/src/main/java/com/ai/da/service/PaymentInfoService.java b/src/main/java/com/ai/da/service/PaymentInfoService.java index de9526b1..74492683 100644 --- a/src/main/java/com/ai/da/service/PaymentInfoService.java +++ b/src/main/java/com/ai/da/service/PaymentInfoService.java @@ -1,7 +1,9 @@ package com.ai.da.service; +import com.ai.da.mapper.primary.entity.PaymentInfo; import com.ai.da.model.dto.AlipayHKCallbackDTO; import com.paypal.orders.Order; +import com.stripe.model.checkout.Session; import java.util.Map; @@ -14,4 +16,10 @@ public interface PaymentInfoService { void createPaymentInfoForPayPal(Order order); void createPaymentInfoForAliPayHK(AlipayHKCallbackDTO alipayHKCallbackDTO); + + void createPaymentInfoForStripe(Session session); + + PaymentInfo getPaymentInfoByOrderId(String orderId); + + void updatePaymentStatusById(Long id, String status, String content); } diff --git a/src/main/java/com/ai/da/service/StripeService.java b/src/main/java/com/ai/da/service/StripeService.java index c4a09be1..98709597 100644 --- a/src/main/java/com/ai/da/service/StripeService.java +++ b/src/main/java/com/ai/da/service/StripeService.java @@ -5,7 +5,11 @@ import javax.servlet.http.HttpServletResponse; public interface StripeService { - String pay(Integer quantity); + String pay(Integer quantity, String returnUrl); Boolean notify(HttpServletRequest request); + + String refund(String amount, String orderId, String reason); + + void checkOrderStatus(String orderNo); } diff --git a/src/main/java/com/ai/da/service/impl/AliPayServiceImpl.java b/src/main/java/com/ai/da/service/impl/AliPayServiceImpl.java index 61f8b1d2..ccbd47d2 100644 --- a/src/main/java/com/ai/da/service/impl/AliPayServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AliPayServiceImpl.java @@ -210,12 +210,13 @@ public class AliPayServiceImpl implements AliPayService { orderInfoService.updateStatusByOrderNo(orderNo, OrderStatusEnum.SUCCESS); //记录支付日志 paymentInfoService.createPaymentInfoForAliPay(params); + float quantity = Float.parseFloat(totalAmount) / Float.parseFloat(CreditsEventsEnum.PRICE.getValue()); // 更新积分 - creditsService.buyCredits(orderByOrderNo.getAccountId(),Float.parseFloat(totalAmount) / Float.parseFloat(CreditsEventsEnum.PRICE.getValue())); + creditsService.buyCredits(orderByOrderNo.getAccountId(), quantity); // 添加积分变更记录 creditsService.insertToCreditsDetail(orderByOrderNo.getAccountId(), CreditsEventsEnum.BUY_CREDITS.getName() + "--Alipay", - CreditsEventsEnum.BUY_CREDITS.getValue(), + String.valueOf((Long.parseLong(CreditsEventsEnum.BUY_CREDITS.getValue()) * quantity)), "positive"); } finally { //要主动释放锁 @@ -312,12 +313,13 @@ public class AliPayServiceImpl implements AliPayService { orderInfoService.updateStatusByOrderNo(orderNo, OrderStatusEnum.SUCCESS); //并记录支付日志 paymentInfoService.createPaymentInfoForAliPay(alipayTradeQueryResponse); + float quantity = orderByOrderNo.getTotalFee() / Float.parseFloat(CreditsEventsEnum.PRICE.getValue()); // 更新积分 - creditsService.buyCredits(orderByOrderNo.getAccountId(),orderByOrderNo.getTotalFee() / Float.parseFloat(CreditsEventsEnum.PRICE.getValue())); + creditsService.buyCredits(orderByOrderNo.getAccountId(), quantity); // 添加积分变更记录 creditsService.insertToCreditsDetail(orderByOrderNo.getAccountId(), CreditsEventsEnum.BUY_CREDITS.getName() + "--Alipay", - CreditsEventsEnum.BUY_CREDITS.getValue(), + String.valueOf((Long.parseLong(CreditsEventsEnum.BUY_CREDITS.getValue()) * quantity)), "positive"); } diff --git a/src/main/java/com/ai/da/service/impl/AlipayHKServiceImpl.java b/src/main/java/com/ai/da/service/impl/AlipayHKServiceImpl.java index 208f82d8..f20d7350 100644 --- a/src/main/java/com/ai/da/service/impl/AlipayHKServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AlipayHKServiceImpl.java @@ -241,12 +241,13 @@ public class AlipayHKServiceImpl implements AlipayHKService { //记录支付日志 paymentInfoService.createPaymentInfoForAliPayHK(alipayHKCallbackDTO); log.info("Alipay-HK 订单:{} 支付信息状态更新成功",orderNo); + float quantity = Float.parseFloat(totalAmount) / Float.parseFloat(CreditsEventsEnum.PRICE.getValue()); // 更新积分 - creditsService.buyCredits(orderByOrderNo.getAccountId(),Float.parseFloat(totalAmount) / Float.parseFloat(CreditsEventsEnum.PRICE.getValue())); + creditsService.buyCredits(orderByOrderNo.getAccountId(), quantity); // 添加积分变更记录 creditsService.insertToCreditsDetail(orderByOrderNo.getAccountId(), CreditsEventsEnum.BUY_CREDITS.getName() + "--AlipayHK", - CreditsEventsEnum.BUY_CREDITS.getValue(), + String.valueOf((Long.parseLong(CreditsEventsEnum.BUY_CREDITS.getValue()) * quantity)), "positive"); log.info("用户:{} 积分信息更新成功",orderByOrderNo.getAccountId()); } finally { diff --git a/src/main/java/com/ai/da/service/impl/CreditsServiceImpl.java b/src/main/java/com/ai/da/service/impl/CreditsServiceImpl.java index bb7adbaf..013451a6 100644 --- a/src/main/java/com/ai/da/service/impl/CreditsServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/CreditsServiceImpl.java @@ -104,7 +104,14 @@ public class CreditsServiceImpl extends ServiceImpl qw = new QueryWrapper<>(); + qw.eq("order_no", orderId); + + return baseMapper.selectOne(qw); + } + + @Override + public void updatePaymentStatusById(Long id, String status, String content){ + PaymentInfo paymentInfo = new PaymentInfo(); + paymentInfo.setId(id); + paymentInfo.setTradeState(status); + paymentInfo.setContent(content); + + baseMapper.updateById(paymentInfo); + } } 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 a984048d..fd6b3295 100644 --- a/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java @@ -1,27 +1,36 @@ package com.ai.da.service.impl; -import com.ai.da.service.PayPalCheckoutService; -import com.ai.da.service.StripeService; +import com.ai.da.common.enums.AliPayTradeStateEnum; +import com.ai.da.common.enums.CreditsEventsEnum; +import com.ai.da.common.enums.OrderStatusEnum; +import com.ai.da.common.enums.PayTypeEnum; +import com.ai.da.common.utils.OrderNoUtils; +import com.ai.da.mapper.primary.entity.OrderInfo; +import com.ai.da.mapper.primary.entity.PaymentInfo; +import com.ai.da.mapper.primary.entity.RefundInfo; +import com.ai.da.service.*; +import com.baomidou.mybatisplus.core.toolkit.StringUtils; +import com.google.gson.Gson; import com.stripe.Stripe; import com.stripe.exception.SignatureVerificationException; import com.stripe.exception.StripeException; import com.stripe.model.*; import com.stripe.model.checkout.Session; -import com.stripe.model.issuing.Card; import com.stripe.net.Webhook; import com.stripe.param.*; import com.stripe.param.checkout.SessionCreateParams; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; import java.math.BigDecimal; +import java.math.RoundingMode; import java.text.SimpleDateFormat; -import java.util.Date; import java.util.HashMap; import java.util.Map; +import java.util.Objects; @Service @Slf4j @@ -30,7 +39,257 @@ public class StripeServiceImpl implements StripeService { private static final String privateKey = "sk_test_51P4ZZL02n1TEydyN8qQHjOA9imsFU7Oxs2HMHGy2urHnnQgSHnZuu5vVP6pKhEACwUpsKNyrbZpdcg5TJWJLRHcY008dEO1fn2"; // private static final String privateKey = "pk_test_51P4ZZL02n1TEydyNluht6VDxnBMoBw8S524otzlXV3CMCZI8HmkcUr3CKy8Z0eQ2WssSJ9sAaZnIQJI04fARHHJi00pcIB4sKU"; + @Resource + private OrderInfoService orderInfoService; + @Resource + private PayPalCheckoutService payPalCheckoutService; + @Resource + private PaymentInfoService paymentInfoService; + @Resource + private CreditsService creditsService; + @Resource + private RefundInfoService refundInfoService; + @Override + @Transactional(rollbackFor = Exception.class) + public String pay(Integer quantity, String returnUrl) { + Stripe.apiKey = privateKey; + log.info("生成订单"); + OrderInfo orderInfo = orderInfoService.createOrderByProductId(quantity, PayTypeEnum.STRIPE.getType()); + + try { + //创建产品 + Map params = new HashMap<>(); + params.put("name", "AiDA credits purchase"); + Product product = Product.create(params); + String orderId = OrderNoUtils.getOrderNo(); + + BigDecimal actualAmount = new BigDecimal(Long.parseLong(CreditsEventsEnum.PRICE.getValue()) * 100); //stripe的默认单位是分,即传入的amount实际上小数点会被左移两位 + //给price绑定元数据并更新price用于检索 + Map metadata = new HashMap<>(); + metadata.put("orderId", orderId); + //创建价格 + Map priceParams = new HashMap<>(); + priceParams.put("metadata", metadata); //通过订单号关联用于检索price信息(可选) + priceParams.put("unit_amount", actualAmount.intValue()); + priceParams.put("currency", "HKD"); + priceParams.put("product", product.getId()); + Price price = Price.create(priceParams); + + //创建支付信息得到url + SessionCreateParams params3 = SessionCreateParams.builder() + .setMode(SessionCreateParams.Mode.PAYMENT) + .setSuccessUrl(returnUrl) //可自定义成功页面 + .addLineItem( + SessionCreateParams.LineItem.builder() + .setQuantity(Long.valueOf(quantity)) + .setPrice(price.getId()) + .build()) + .putMetadata("orderId", orderId) //通过订单号关联用于检索支付信息(可选) + .build(); + Session session = Session.create(params3); + log.info("sessionId:" + session.getId()); //退款方式1:拿到sessionId入库,退款的时候根据这个id找到PaymentIntent的id然后发起退款 + + // 更新order信息 + orderInfoService.updateOrderNoById(orderInfo.getId(), orderId); + //记录支付日志 + paymentInfoService.createPaymentInfoForStripe(session); + return session.getUrl(); + } catch (Exception e) { + log.error("创建支付会话出现异常:", e); + } + return ""; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean notify(HttpServletRequest request) { + log.info("stripe异步通知进行中"); + String payload = null; + String sigHeader = null; + String endpointSecret = "whsec_e0dBiJngx6qqgJj6yPyJ2A9ouh1Cjv5w";//webhook秘钥签名 + try { + sigHeader = request.getHeader("Stripe-Signature"); + payload = payPalCheckoutService.getBody(request); + } catch (Exception e) { + log.info("stripe 支付回调参数解析异常:errorMsg {}", e.getMessage()); + log.info("request sigHeader = {}", sigHeader); + log.info("request body = {}", payload); + e.printStackTrace(); + return Boolean.FALSE; + } + + Event event = null; + try { + assert sigHeader != null; + event = Webhook.constructEvent(payload, sigHeader, endpointSecret); + } catch (SignatureVerificationException e) { + log.info("stripe 验签,获取事件异常, errorMsg=" + e.getMessage()); + log.info("request sigHeader = {}", sigHeader); + log.info("request body = {}", payload); + e.printStackTrace(); + return Boolean.FALSE; + } + + //获取自定义参数 + // Deserialize the nested object inside the event + assert event != null; + EventDataObjectDeserializer dataObjectDeserializer = event.getDataObjectDeserializer(); + StripeObject stripeObject = null; + if (dataObjectDeserializer.getObject().isPresent()) { + stripeObject = dataObjectDeserializer.getObject().get(); + } else { + log.info("stripe 验签失败!"); + log.info("request sigHeader = {}", sigHeader); + log.info("request body = {}", payload); + return Boolean.FALSE; + } + log.info("stripe验签成功"); + + if (event.getType().equals("checkout.session.completed")) { + Session session = (Session) stripeObject; + processOrder(session); + } + + return Boolean.TRUE; + } + + public void processOrder(Session session) { + String orderId = session.getMetadata().get("orderId"); + float totalAmount = new BigDecimal(session.getAmountTotal()).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP).floatValue(); + + try { + //处理重复通知 + //接口调用的幂等性:无论接口被调用多少次,以下业务执行一次 +// String orderStatus = orderInfoService.getOrderStatus(orderNo); + OrderInfo orderByOrderNo = orderInfoService.getOrderByOrderNo(orderId); + String orderStatus = orderByOrderNo.getOrderStatus(); + // 当订单状态处于未支付或超时已关闭时,更新订单状态,其他状态均不更新订单状态 + if (!OrderStatusEnum.NOT_PAY.getType().equals(orderStatus) && !OrderStatusEnum.TIMEOUT_CLOSED.getType().equals(orderStatus)) { + log.info("订单状态 : {}", orderStatus); + return; + } + //更新订单状态 + orderInfoService.updateStatusByOrderNo(orderId, OrderStatusEnum.SUCCESS); + log.info("Stripe 订单:{} 状态更新成功", orderId); + + // 更新支付日志 + paymentInfoService.updatePaymentStatusById( + paymentInfoService.getPaymentInfoByOrderId(orderId).getId(), + session.getStatus(), + new Gson().toJson(session)); + + log.info("Stripe 订单:{} 支付信息状态更新成功", orderId); + float quantity = totalAmount / Float.parseFloat(CreditsEventsEnum.PRICE.getValue()); + // 更新积分 + creditsService.buyCredits(orderByOrderNo.getAccountId(), quantity); + // 添加积分变更记录 + creditsService.insertToCreditsDetail(orderByOrderNo.getAccountId(), + CreditsEventsEnum.BUY_CREDITS.getName() + "--Stripe", + String.valueOf((Long.parseLong(CreditsEventsEnum.BUY_CREDITS.getValue()) * quantity)), + "positive"); + log.info("用户:{} 积分信息更新成功", orderByOrderNo.getAccountId()); + }catch (Exception e){ + log.info(e.getMessage()); + } + } + + + + public String refund(String amount, String orderId, String reason) { + Refund refund ; + RefundInfo refundByOrderNo = refundInfoService.createRefundByOrderNo(orderId, reason); + + try { + Stripe.apiKey = privateKey; + // 根据orderId找到对应的sessionId + String sessionId = paymentInfoService.getPaymentInfoByOrderId(orderId).getTransactionId(); + + if (StringUtils.isNotEmpty(sessionId)) { //根据会话编号退款 + Session session = Session.retrieve(sessionId); + RefundCreateParams params; + if (amount != null && !amount.equals("0")) { //指定退款金额 + BigDecimal actualAmount = new BigDecimal(amount).multiply(BigDecimal.valueOf(100)); //api默认单位分 + params = RefundCreateParams.builder() + .setPaymentIntent(session.getPaymentIntent()) + .setAmount(actualAmount.longValue()) + .build(); + } else { //全额退款 + params = RefundCreateParams.builder() + .setPaymentIntent(session.getPaymentIntent()) + .build(); + } + refund = Refund.create(params); + log.info("根据会话编号退款成功"); + + }else { + log.error("当前订单不存在"); + return "退款异常"; + } + } catch (Exception e) { + //e.getMessage.contain("charge_already_refunded") 已退款 + //e.getMessage.contain("resource_missing") 退款编号错误 + //e.getMessage.contain("amount on charge ($n)") 金额应小于n + log.error("退款异常:", e); + return "退款异常"; + } + + if ("succeeded".equals(refund.getStatus())) { + //进行数据库操作,修改状态为已退款(配合回调和退款查询确定退款成功) + //更新订单状态 + orderInfoService.updateStatusByOrderNo(orderId, OrderStatusEnum.REFUND_SUCCESS); + + refundInfoService.updateRefundForPayPal( + refundByOrderNo.getId(), + refund.getId(), + new Gson().toJson(refund), + AliPayTradeStateEnum.REFUND_SUCCESS.getType()); //退款成功 + + // 更新积分状态 + OrderInfo orderByOrderNo = orderInfoService.getOrderByOrderNo(orderId); + creditsService.creditsRefund(orderByOrderNo.getAccountId(), (int)(orderByOrderNo.getTotalFee() / Float.parseFloat(CreditsEventsEnum.PRICE.getValue()))); + } else { + //更新订单状态 + orderInfoService.updateStatusByOrderNo(orderId, OrderStatusEnum.REFUND_ABNORMAL); + + //更新退款单 + refundInfoService.updateRefundForPayPal( + refundByOrderNo.getId(), + refund.getId(), + new Gson().toJson(refund), + AliPayTradeStateEnum.REFUND_ERROR.getType()); //退款失败 + } + log.info("记录退款订单"); + return "退款成功"; + } + + public void checkOrderStatus(String orderNo){ + Stripe.apiKey = privateKey; + // 1、通过orderNo 查询sessionId + PaymentInfo paymentInfo = paymentInfoService.getPaymentInfoByOrderId(orderNo); + try { + Session session = Session.retrieve(paymentInfo.getTransactionId()); + if (Objects.isNull(session)){ + log.warn("核实订单未创建 ===> {}", orderNo); + return; + } else if (session.getStatus().equals("open") || session.getStatus().equals("expired")){ + // 订单未支付 || 订单过期 ---> 均设置为超时未支付 + log.info("订单超时未支付 ===> {}", orderNo); + //更新本地订单状态 + orderInfoService.updateStatusByOrderNo(orderNo, OrderStatusEnum.TIMEOUT_CLOSED); + paymentInfoService.updatePaymentStatusById(paymentInfo.getId(), + session.getStatus(), + new Gson().toJson(session)); + } else if (session.getStatus().equals("complete")) { + // 订单已完成 + processOrder(session); + } + } catch (StripeException e) { + log.error("根据sessionId获取Stripe Session失败"); + throw new RuntimeException(e); + } + + } // 1、创建customer,获取customerId // 2、创建客户支付方式 (从前端获取) @@ -72,25 +331,6 @@ public class StripeServiceImpl implements StripeService { .build(); PaymentMethod paymentMethod = PaymentMethod.create(params); - - /*try{ - Map card = new HashMap<>(); - card.put("exp_month",8L); - card.put("exp_year",2026L); - card.put("number","4242 4242 4242 42422"); - card.put("cvc","314"); - Map params = new HashMap<>(); - params.put("type", "card"); - params.put("card", card); - PaymentMethod paymentMethod = PaymentMethod.create(params); - Map params2 = new HashMap<>(); - params2.put("customer", customerId); - paymentMethod.attach(params2); - return paymentMethod.getId(); - }catch (Exception e){ - e.printStackTrace(); - }*/ -// return null; return paymentMethod.getId(); } @@ -142,144 +382,5 @@ public class StripeServiceImpl implements StripeService { return null; } - public static void main(String[] args) throws StripeException { -// String customerId = createCustomer(); -// log.info(customerId); - String paymentMethodId = createPaymentMethod("cus_Pvc92hQPBgLE2t"); - log.info(paymentMethodId); -// String substring = paymentMethodId.substring(0, paymentMethodId.lastIndexOf("_")); -// log.info(substring); -// log.info(substring.substring(0, substring.lastIndexOf("_"))); -// String paymentIntentId = createPaymentIntent(null, "cus_Pvc92hQPBgLE2t"); -// log.info(paymentIntentId); - -// confirmPaymentIntent("pi_3P5lr002n1TEydyN0caeqdfq"); - - } - - public String pay(Integer quantity) { - Stripe.apiKey = privateKey; - try { - //创建产品 - Map params = new HashMap<>(); - params.put("name", "AiDA 积分"); -// PriceCreateParams.ProductData productData = new PriceCreateParams.ProductData.Builder().setName("AiDA 积分").build(); - Product product = Product.create(params); - SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss"); - String format = simpleDateFormat.format(new Date()); - - //创建价格 - Map priceParams = new HashMap<>(); -// BigDecimal actualAmount = createOrderEntity.getAmount().multiply(BigDecimal.valueOf(100)); //stripe的默认单位是分,即传入的amount实际上小数点会被左移两位 - BigDecimal actualAmount = new BigDecimal("600"); //stripe的默认单位是分,即传入的amount实际上小数点会被左移两位 - //给price绑定元数据并更新price用于检索 - Map metadata = new HashMap<>(); - metadata.put("orderId", format); - priceParams.put("metadata", metadata); //通过订单号关联用于检索price信息(可选) - priceParams.put("unit_amount", actualAmount.intValue()); - priceParams.put("currency", "HKD"); - priceParams.put("product", product.getId()); -// priceParams.put("product_data", product.getId()); -// PriceCreateParams priceParam = PriceCreateParams.builder().setCurrency("HKD").setProductData(productData).setUnitAmount(Long.valueOf("6")).build(); - Price price = Price.create(priceParams); - - //创建支付信息得到url - SessionCreateParams params3 = SessionCreateParams.builder() - .setMode(SessionCreateParams.Mode.PAYMENT) - .setSuccessUrl("https://www.example.com") //可自定义成功页面 - .setCancelUrl("https://www.example.com") - .addLineItem( - SessionCreateParams.LineItem.builder() - .setQuantity(Long.valueOf(quantity)) - /*.setPriceData( - new SessionCreateParams.LineItem.PriceData.Builder() - .setCurrency("HKD") - .setUnitAmount(Long.valueOf("600")) - .setProductData( - new SessionCreateParams.LineItem.PriceData.ProductData.Builder() - .setName("AiDaA 积分") - .build()) - .build())*/ - .setPrice(price.getId()) - .build()) - .putMetadata("orderId",format) //通过订单号关联用于检索支付信息(可选) - .build(); - Session session = Session.create(params3); - System.out.println("sessionId:" +session.getId()); - String sessionId = session.getId(); //退款方式1:拿到sessionId入库,退款的时候根据这个id找到PaymentIntent的id然后发起退款 - return session.getUrl(); - }catch (Exception e){ - log.error("创建支付会话出现异常:",e); - } - return ""; - } - - @Resource - private PayPalCheckoutService payPalCheckoutService; - - @Override - public Boolean notify(HttpServletRequest request){ - log.info("stripe异步通知进行中"); - String payload = null; - String sigHeader= null; -// String endpointSecret = "whsec_xxxgx92OjXdBf1lc2c";//webhook秘钥签名 - String endpointSecret = "whsec_e0dBiJngx6qqgJj6yPyJ2A9ouh1Cjv5w";//webhook秘钥签名 - try { - sigHeader = request.getHeader("Stripe-Signature"); - payload = payPalCheckoutService.getBody(request); - } catch (Exception e) { - log.info("stripe 支付回调参数解析异常:errorMsg {}", e.getMessage()); - log.info("request sigHeader = {}", sigHeader); - log.info("request body = {}", payload); - e.printStackTrace(); - return Boolean.FALSE; -// response.setStatus(400); - } - - Event event = null; - try { - assert sigHeader != null; - event = Webhook.constructEvent(payload, sigHeader, endpointSecret); - } catch (SignatureVerificationException e) { - log.info("stripe 验签,获取事件异常, errorMsg=" + e.getMessage()); - log.info("request sigHeader = {}", sigHeader); - log.info("request body = {}", payload); - e.printStackTrace(); - return Boolean.FALSE; -// response.setStatus(400); - } - - - //获取自定义参数 - // Deserialize the nested object inside the event - assert event != null; - EventDataObjectDeserializer dataObjectDeserializer = event.getDataObjectDeserializer(); - StripeObject stripeObject = null; - if (dataObjectDeserializer.getObject().isPresent()) { - stripeObject = dataObjectDeserializer.getObject().get(); - - } else { - log.info("stripe 验签失败!"); - log.info("request sigHeader = {}", sigHeader); - log.info("request body = {}", payload); - return Boolean.FALSE; -// response.setStatus(400); - } - - if (event.getType().equals("checkout.session.completed")){ - - } - log.info("stripe验签成功"); - return Boolean.TRUE; -// response.setStatus(200); - - - // 1、验签 - - // 2、处理订单 - // 2.1 更新订单状态 - // 2.2 添加积分 - } - }