package com.otcbi.pay.service.impl;import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.gson.JsonSyntaxException;
import com.otcbi.coin.common.exception.ApiException;
import com.otcbi.coin.common.exception.ApiResponMessage;
import com.otcbi.constat.Consts;
import com.otcbi.pay.entity.StripeOrder;
import com.otcbi.pay.service.IGoodsOnlineService;
import com.otcbi.pay.service.IStripeOrderService;
import com.otcbi.pay.service.IStripeWebhookMessageService;
import com.otcbi.shop.dto.StripeCreateSourceDTO;
import com.otcbi.shop.entity.Orders;
import com.otcbi.shop.service.IOrdersService;
import com.stripe.Stripe;
import com.stripe.exception.SignatureVerificationException;
import com.stripe.model.Charge;
import com.stripe.model.Event;
import com.stripe.model.EventData;
import com.stripe.net.Webhook;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;@Service
public class IGoodsOnlineServiceImpl implements IGoodsOnlineService {private static final Logger logger = LoggerFactory.getLogger(IGoodsOnlineServiceImpl.class);@Value("${stripe.homeUrl}")private String homeUrl;@Value("${stripe.apiKey}")String stripeApiKey;@Value("${stripe.webhookSecret}")String stripeWebhookSecret;@Autowiredprivate IOrdersService iOrdersService;@Autowiredprivate IStripeOrderService iStripeOrderService;@Autowiredprivate IStripeWebhookMessageService iStripeWebhookMessageService;public StripeCreateSourceDTO createSource(Long ordersId) throws Exception {Orders orders = iOrdersService.getById(ordersId);if (orders == null) {throw new ApiException(ApiResponMessage.SHOP_ORDERS_EXIST, null);} else if (orders.getPayState() == 2) {throw new ApiException(ApiResponMessage.ORDERS_ALREADY_FINISHED, null);}StripeCreateSourceDTO source = new StripeCreateSourceDTO();source.setUserId(orders.getUserId());if (orders.getPayType() == 1) {source.setType("alipay");} else if (orders.getPayType() == 2) {source.setType("wechat");}source.setCurrency(orders.getCoin());source.setOrderNum(orders.getOrderNum());source.setReturnUrl(homeUrl + "/stripe/createSourceRetuenBack?orderNum=" + orders.getOrderNum());QueryWrapper<StripeOrder> wrapper = new QueryWrapper<>();wrapper.eq("is_deleted", "N");wrapper.eq("order_num", orders.getOrderNum());wrapper.eq("is_cancel", 0);StripeOrder stripeOrder = iStripeOrderService.getOne(wrapper);if (stripeOrder == null) {//创建stripe订单stripeOrder = new StripeOrder();stripeOrder.setIsDeleted("N");stripeOrder.setCreateTime(LocalDateTime.now());stripeOrder.setOrderNum(orders.getOrderNum());stripeOrder.setStatus(Consts.PAY_STRIPE_STATUS_PENDING);Integer realAmount = Integer.valueOf(new BigDecimal(orders.getActualPrice().toString()).multiply(new BigDecimal("100")).setScale(0, BigDecimal.ROUND_DOWN).toString());Integer amount = Integer.valueOf(realAmount.toString());source.setAmount(amount);stripeOrder.setAmount(realAmount);stripeOrder.setType(source.getType());stripeOrder.setUserId(orders.getUserId());stripeOrder.setCurrency(orders.getCoin());iStripeOrderService.save(stripeOrder);return source;} else {String status = stripeOrder.getStatus();if (Consts.PAY_STRIPE_STATUS_SUCCEEDED.equals(status)) {//已经完成throw new ApiException(ApiResponMessage.ORDERS_ALREADY_FINISHED, null);} else if (Consts.PAY_STRIPE_STATUS_CANCELED.equals(status) || Consts.PAY_STRIPE_STATUS_INSUFFICIENT_fUNDS.equals(status)|| Consts.PAY_STRIPE_STATUS_INVALID_AMOUNT.equals(status) || Consts.PAY_STRIPE_STATUS_CHARGE_ERROR.equals(status)) {//已经失效,删除原来订单,重新创建订单stripeOrder.setIsCancel(1);stripeOrder.setModifyTime(LocalDateTime.now());iStripeOrderService.updateById(stripeOrder);StripeOrder stripeOrderNew = new StripeOrder();stripeOrderNew.setIsDeleted("N");stripeOrderNew.setCreateTime(LocalDateTime.now());stripeOrderNew.setOrderNum(orders.getOrderNum());stripeOrderNew.setStatus(Consts.PAY_STRIPE_STATUS_PENDING);Integer realAmount = Integer.valueOf(new BigDecimal(orders.getActualPrice().toString()).multiply(new BigDecimal("100")).setScale(0, BigDecimal.ROUND_DOWN).toString());Integer amount = Integer.valueOf(realAmount.toString());source.setAmount(amount);stripeOrderNew.setAmount(realAmount);stripeOrderNew.setType(source.getType());stripeOrder.setUserId(orders.getUserId());stripeOrder.setCurrency(orders.getCoin());iStripeOrderService.save(stripeOrderNew);return source;} else {if (Consts.PAY_STRIPE_STATUS_PENDING.equals(status)) {//还未授权Integer amount = Integer.valueOf(new BigDecimal(stripeOrder.getAmount().toString()).setScale(0, BigDecimal.ROUND_DOWN).toString());source.setAmount(amount);return source;} else if (Consts.PAY_STRIPE_STATUS_CHARGEABLE.equals(status)) {//已经授权,按理来说这个时候已经完成了订单throw new ApiException(ApiResponMessage.SHOP_ORDERS_PLAYING_ERROR, null);} else if (Consts.PAY_STRIPE_STATUS_FAILED.equals(status)) {//拒绝授权支付,重新要求授权Integer amount = Integer.valueOf(new BigDecimal(stripeOrder.getAmount().toString()).setScale(0, BigDecimal.ROUND_DOWN).toString());source.setAmount(amount);return source;} else {throw new ApiException(ApiResponMessage.SHOP_GOODS_WEIXIN_PAY_ERROR, null);}}}}/*** 如果客户的支付宝账户被非法使用,支付宝和Stripe会在内部处理此问题。在支付宝的情况下,* 只有当客户对所提供的商品或服务有投诉时,付款才会有争议。* 如果发生争议,dispute.created则会发送webhook事件,Stripe会从您的Stripe余额中扣除争议金额。* <p>* 一个chargeable单一使用支付宝源必须在6小时内变得收费chargeable。如果不是,则其状态将自动转换为canceled* 您的集成并收到source.canceledwebhook事件。取消收费来源后,客户的授权支付宝付款将自动退还 -* 不会将任何款项转入您的帐户。因此,请确保您的订单已取消,并在收到source.canceled活动时通知客户。* 此外,pending如果不用于授权付款,则在一小时后取消资源,确保所有资源最终从pending状态转移到canceled状态(如果不使用)。** @param request* @param response* @throws Exception*/@Transactionalpublic synchronized void stripeCallBack(HttpServletRequest request, HttpServletResponse response) throws Exception {logger.info("============进入webhook回调=================");//验签Event event = attestation(request, response);if (event == null) {return;}/*不验签获得数据Event event = ApiResource.GSON.fromJson(request.getReader(), Event.class);*/String message = event.toJson();logger.info("收到内容为:" + message);String stripeType = event.getType();//把信息记录到表iStripeWebhookMessageService.saveWebHootMssage(event, message, stripeType);if (stripeType.equals("source." + Consts.PAY_STRIPE_STATUS_CHARGEABLE)) {//用户授权确认callBackPending(event, response);} else if (stripeType.equals("source." + Consts.PAY_STRIPE_STATUS_FAILED)) {//用户拒绝授权callBackFailed(event, response);} else if (stripeType.equals("source." + Consts.PAY_STRIPE_STATUS_CANCELED)) {//过期callBackCanceled(event, response);} else if (stripeType.equals("charge." + Consts.PAY_STRIPE_STATUS_SUCCEEDED)) {//stripe收款成功通知callBackSuccess(event, response);} else if (stripeType.equals("charge.dispute." + Consts.PAY_STRIPE_STATUS_CREATED)) {//客户投诉退款callBackCreated(event, response);} else {logger.error("获得未知状态" + stripeType);response.setStatus(500);logger.info("============webhook回调结束=================");return;}response.setStatus(200);logger.info("============webhook回调结束=================");}public Event attestation(HttpServletRequest request, HttpServletResponse response) throws Exception {String endpointSecret = stripeWebhookSecret;InputStream inputStream = request.getInputStream();byte[] bytes = IOUtils.toByteArray(inputStream);String payload = new String(bytes, "UTF-8");String sigHeader = request.getHeader("Stripe-Signature");Event event = null;try {event = Webhook.constructEvent(payload, sigHeader, endpointSecret);logger.info("验签成功");response.setStatus(200);return event;} catch (JsonSyntaxException e) {logger.error("验签失败");response.setStatus(400);} catch (SignatureVerificationException e) {logger.error("验签失败");e.printStackTrace();response.setStatus(400);}logger.info("============webhook回调结束=================");return null;}public void callBackPending(Event event, HttpServletResponse response) throws Exception {EventData eventData = event.getData();JSONObject json = JSONObject.parseObject(eventData.getObject().toJson());String client_secret = json.getString("client_secret");String orderNum = json.getString("statement_descriptor");String stripe_id = json.getString("id");String type = json.getString("type");String amount = json.getString("amount");String currency = json.getString("currency");String userId = json.getJSONObject("owner").getString("name");QueryWrapper<StripeOrder> wrapper = new QueryWrapper<>();wrapper.eq("is_deleted", "N");wrapper.eq("order_num", orderNum);wrapper.eq("is_cancel", 0);wrapper.eq("type", type);wrapper.eq("user_id", userId);StripeOrder stripeOrder = iStripeOrderService.getOne(wrapper);if (stripeOrder == null) {//订单不存在logger.error("Stripe收到不存在的订单回调" + orderNum);response.setStatus(500);} else {if (!stripeOrder.getStatus().equals(Consts.PAY_STRIPE_STATUS_PENDING)) {logger.error("Stripe收到违法订单" + orderNum);}if (!amount.equals(stripeOrder.getAmount().toString())) {logger.error("Stripe收到金额对不上的订单回调" + orderNum);response.setStatus(500);}//客户已经完成授权stripeOrder.setStripeId(stripe_id);stripeOrder.setStatus(Consts.PAY_STRIPE_STATUS_CHARGEABLE);stripeOrder.setClientSecret(client_secret);stripeOrder.setModifyTime(LocalDateTime.now());iStripeOrderService.updateById(stripeOrder);logger.info("===================" + orderNum + "订单授权成功=============");//创建支付订单try {createCharge(stripeOrder, Integer.valueOf(amount), currency, stripe_id, orderNum);} catch (Exception e) {e.printStackTrace();logger.error(orderNum + "stripe创建收费订单失败");}}}/*** 拒绝授权** @param event* @param response* @throws Exception*/public void callBackFailed(Event event, HttpServletResponse response) throws Exception {EventData eventData = event.getData();JSONObject json = JSONObject.parseObject(eventData.getObject().toJson());String client_secret = json.getString("client_secret");String orderNum = json.getString("statement_descriptor");String stripe_id = json.getString("id");String type = json.getString("type");String amount = json.getString("amount");String currency = json.getString("currency");String userId = json.getJSONObject("owner").getString("name");QueryWrapper<StripeOrder> wrapper = new QueryWrapper<>();wrapper.eq("is_deleted", "N");wrapper.eq("order_num", orderNum);wrapper.eq("is_cancel", 0);wrapper.eq("type", type);wrapper.eq("user_id", userId);StripeOrder stripeOrder = iStripeOrderService.getOne(wrapper);if (stripeOrder == null) {//订单不存在logger.error("Stripe收到不存在的订单回调" + orderNum);response.setStatus(500);} else {if (!stripeOrder.getStatus().equals(Consts.PAY_STRIPE_STATUS_PENDING)) {logger.error("Stripe收到违法订单" + orderNum);}if (!amount.equals(stripeOrder.getAmount().toString())) {logger.error("Stripe收到金额对不上的订单回调" + orderNum);response.setStatus(500);}//客户不授权删除订单stripeOrder.setStatus(Consts.PAY_STRIPE_STATUS_FAILED);stripeOrder.setClientSecret(client_secret);stripeOrder.setModifyTime(LocalDateTime.now());stripeOrder.setIsCancel(1);stripeOrder.setStripeId(stripe_id);iStripeOrderService.updateById(stripeOrder);logger.info("===================" + orderNum + "订单拒绝授权处理成功=============");}}/*** 过期订单** @param event* @param response* @throws Exception*/public void callBackCanceled(Event event, HttpServletResponse response) throws Exception {EventData eventData = event.getData();JSONObject json = JSONObject.parseObject(eventData.getObject().toJson());String client_secret = json.getString("client_secret");String orderNum = json.getString("statement_descriptor");String stripe_id = json.getString("id");String type = json.getString("type");String amount = json.getString("amount");String currency = json.getString("currency");String userId = json.getJSONObject("owner").getString("name");QueryWrapper<StripeOrder> wrapper = new QueryWrapper<>();wrapper.eq("is_deleted", "N");wrapper.eq("order_num", orderNum);wrapper.eq("is_cancel", 0);wrapper.eq("type", type);wrapper.eq("user_id", userId);wrapper.eq("stripe_id", stripe_id);StripeOrder stripeOrder = iStripeOrderService.getOne(wrapper);if (stripeOrder == null) {//订单不存在logger.error("Stripe收到不存在的订单回调" + orderNum);response.setStatus(500);} else {if (!stripeOrder.getStatus().equals(Consts.PAY_STRIPE_STATUS_PENDING)) {logger.error("Stripe收到违法订单" + orderNum);}if (!amount.equals(stripeOrder.getAmount().toString())) {logger.error("Stripe收到金额对不上的订单回调" + orderNum);response.setStatus(500);}//订单过期删除订单stripeOrder.setStatus(Consts.PAY_STRIPE_STATUS_CANCELED);stripeOrder.setClientSecret(client_secret);stripeOrder.setModifyTime(LocalDateTime.now());stripeOrder.setIsCancel(1);iStripeOrderService.updateById(stripeOrder);logger.info("===================" + orderNum + "订单过期处理成功=============");}}public void callBackCreated(Event event, HttpServletResponse response) throws Exception {EventData eventData = event.getData();//待写}public void callBackSuccess(Event event, HttpServletResponse response) throws Exception {EventData eventData = event.getData();JSONObject json = JSONObject.parseObject(eventData.getObject().toJson());String orderNum = json.getJSONObject("source").getString("statement_descriptor");String stripe_id = json.getJSONObject("source").getString("id");String type = json.getJSONObject("source").getString("type");String amount = json.getJSONObject("source").getString("amount");String userId = json.getJSONObject("source").getJSONObject("owner").getString("name");String payId = json.getString("id");QueryWrapper<StripeOrder> wrapper = new QueryWrapper<>();wrapper.eq("is_deleted", "N");wrapper.eq("order_num", orderNum);wrapper.eq("is_cancel", 0);wrapper.eq("type", type);wrapper.eq("user_id", userId);wrapper.eq("stripe_id", stripe_id);StripeOrder stripeOrder = iStripeOrderService.getOne(wrapper);if (stripeOrder == null) {//订单不存在logger.error("Stripe收到不存在的订单回调" + orderNum);response.setStatus(500);} else {if (!stripeOrder.getStatus().equals(Consts.PAY_STRIPE_STATUS_CHARGEABLE)) {logger.error("Stripe收到违法订单" + orderNum);}if (!amount.equals(stripeOrder.getAmount().toString())) {logger.error("Stripe收到金额对不上的订单回调" + orderNum);response.setStatus(500);}//客户付款成功stripeOrder.setStatus(Consts.PAY_STRIPE_STATUS_SUCCEEDED);stripeOrder.setModifyTime(LocalDateTime.now());stripeOrder.setPayId(payId);iStripeOrderService.updateById(stripeOrder);//更改订单状态QueryWrapper<Orders> orderWrapper = new QueryWrapper<>();orderWrapper.eq("order_num", orderNum);orderWrapper.eq("is_deleted", "N");Orders orders = iOrdersService.getOne(orderWrapper);orders.setModifyTime(LocalDateTime.now());orders.setPayState(2);iOrdersService.updateById(orders);logger.info("===================" + orderNum + "订单付款成功=============");}}/*** 创建收费订单** @param amount* @param currency* @param stripeId* @throws Exception 支付宝付款的费用创建可能会返回以下任何错误:* insufficient_funds 支付宝账户资金不足,无法完成购买。客户应为其帐户注资并重试,或使用其他付款方式。* invalid_amount 如果收费金额大于支付宝支持的费用,则会发生这种情况。*/public void createCharge(StripeOrder stripeOrder, Integer amount, String currency, String stripeId, String orderNum) throws Exception {Stripe.apiKey = stripeApiKey;Map<String, Object> chargeParams = new HashMap<String, Object>();chargeParams.put("amount", amount);chargeParams.put("currency", currency);chargeParams.put("source", stripeId);chargeParams.put("description", orderNum + " completion of payment");Charge charge = Charge.create(chargeParams);String errorMsg = charge.getFailureMessage();if (StringUtils.isEmpty(errorMsg)) {logger.info(orderNum + "订单请求支付成功");} else {if (errorMsg.equals("insufficient_funds")) {logger.error(orderNum + "订单用户支付宝余额不足");stripeOrder.setStatus(Consts.PAY_STRIPE_STATUS_INSUFFICIENT_fUNDS);stripeOrder.setModifyTime(LocalDateTime.now());} else if (errorMsg.equals("invalid_amount")) {logger.error(orderNum + "订单收费金额大于支付宝支持的费用");stripeOrder.setStatus(Consts.PAY_STRIPE_STATUS_INVALID_AMOUNT);stripeOrder.setModifyTime(LocalDateTime.now());} else {logger.error(orderNum + errorMsg);stripeOrder.setStatus(Consts.PAY_STRIPE_STATUS_CHARGE_ERROR);stripeOrder.setModifyTime(LocalDateTime.now());}iStripeOrderService.updateById(stripeOrder);}logger.info("===================" + orderNum + "订单申请扣费成功=============");}} |