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;
@Autowired
private IOrdersService iOrdersService;
@Autowired
private IStripeOrderService iStripeOrderService;
@Autowired
private 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
*/
@Transactional
public 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 + "订单申请扣费成功=============");
}
} |