Authored by Lixiaodi

支付超过100万修改

... ... @@ -50,5 +50,17 @@ public class TradeBills {
//打款关联id
private Integer dealRelateId = 0;
public static enum Status {
TRANSFER_WAITING(90);
private Status(int code) {
this.code = code;
}
private int code;
public int getCode() {
return code;
}
}
}
... ...
... ... @@ -90,6 +90,8 @@ public class AlipayConfig {
public static final String BLK_ALI_RSA_PUBLIC = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCnxj/9qwVfgoUh/y2W89L6BkRAFljhNhgPdyPuBV64bfQNN1PjbCzkIM6qRdKBoLPXmKKMiFYnkd6rAoprih3/PrQEB/VsW8OoM8fxn67UDYuyBTqA23MML9q1+ilIZwBC2AQ2UBVOrFXfFl75p6/B5KsiNG9zpgmLCUYuLkxpLQIDAQAB";
/********************/ //OUYIN
public static final String OUYIN_EMAIL = "ouyin@yoho.cn";
public static final String OUYIN_USER_NAME = "欧印南京贸易有限公司";
public static final String OUYIN_PARTNER = "2088421850636193";
public static final String OUYIN_APPID = "2016091401906455";
... ...
... ... @@ -29,6 +29,7 @@ import com.yohoufo.order.model.NotifyResponse;
import com.yohoufo.order.model.PayQueryBo;
import com.yohoufo.order.model.PayRefundBo;
import com.yohoufo.order.model.PaymentData;
import com.yohoufo.order.model.TransferData;
import com.yohoufo.order.model.request.PaymentRequest;
import com.yohoufo.order.model.response.PaymentConfirmRsp;
import com.yohoufo.order.model.response.PrepayResponse;
... ... @@ -259,6 +260,44 @@ public class PaymentController {
logger.info("[{}] reply success to alipay", out_trade_no);
response.getWriter().print("success");
}
@IgnoreSignature
@IgnoreSession
@RequestMapping(value = "/ufo_alipay_transfer_notify", method = RequestMethod.POST)
public void notifyAliTransferPayment(HttpServletRequest request, HttpServletResponse response) throws IOException {
alipayLogger.info("\n\n\n************************* Notify ufo_alipay_transfer_notify");
Map<String, String> params = parseParams(request.getParameterMap());
alipayLogger.info("[{}] ufo_alipay_transfer_notify Request params: {}", params);
String batch_no = params.get("batch_no");
alipayLogger.info("[{}] ufo_alipay_transfer_notify notification received", batch_no);
//回调验证
if(!alipayService.notifyVerify(params)) {
alipayLogger.error("[{}] ufo_alipay_transfer_notify notification verify failed", batch_no);
return ;
}
TransferData data = null;
try {
TransferData success = alipayService.getTransferData(params.get("success_details"));
TransferData fail = alipayService.getTransferData(params.get("fail_details"));
alipayLogger.info("method {} ufo_alipay_transfer_notify data is {},{}", batch_no, success, fail);
if((success==null && fail==null) ||(success!=null &&fail!=null)) {
alipayLogger.info("method {} ufo_alipay_transfer_notify success 和 fail 歧义", batch_no);
}
data = (fail == null) ? success : fail;
paymentService.transferSuccess(data);
} catch (Exception e) {
alipayLogger.error("[{}] ufo_alipay_transfer_notify notify process failed, ex: {}", batch_no, e);
return ;
}
logger.info("[{}] ufo_alipay_transfer_notify reply success to alipay", batch_no);
response.getWriter().print("success");
}
/* @RequestMapping(params = "method=ufo.order.transferMon")
public ApiResponse transferMon(@RequestParam(name = "buyerOrderCode") long buyerOrderCode,
... ...
package com.yohoufo.order.model;
import lombok.Data;
import lombok.ToString;
@Data
@ToString
public class TransferData {
private String orderCode;
private Integer transferId;
private Integer tradeBillsId;
private String receiveAccount;
private String receiveUserName;
private String money;
private String status;
private String message;
/** 支付宝内部流水号. */
private String alipayTradeId;
private String time;
}
... ...
... ... @@ -4,6 +4,7 @@ package com.yohoufo.order.service;
import com.yohobuy.ufo.model.order.req.ManualDealRequest;
import com.yohoufo.order.model.PayRefundBo;
import com.yohoufo.order.model.PaymentData;
import com.yohoufo.order.model.TransferData;
import com.yohoufo.order.model.request.PaymentRequest;
import com.yohoufo.order.model.request.TransferMoneyRequest;
import com.yohoufo.order.model.response.PaymentConfirmRsp;
... ... @@ -47,6 +48,7 @@ public interface IPaymentService {
*/
void paySuccess(PaymentData paymentData);
void transferSuccess(TransferData transferData);
/**
* 订单退款
... ...
... ... @@ -23,6 +23,7 @@ import com.yohoufo.order.constants.RefundContant;
import com.yohoufo.order.model.PayQueryBo;
import com.yohoufo.order.model.PayRefundBo;
import com.yohoufo.order.model.PaymentData;
import com.yohoufo.order.model.TransferData;
import com.yohoufo.order.model.request.PaymentRequest;
import com.yohoufo.order.model.request.TranseferCellNode;
import com.yohoufo.order.model.request.TransferMoneyRequest;
... ... @@ -53,6 +54,7 @@ import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.Date;
import java.util.Map;
import java.util.Objects;
import java.util.function.BiFunction;
... ... @@ -329,6 +331,71 @@ public class PaymentServiceImpl implements IPaymentService {
logger.info("paySuccess finished. orderCode is {}", orderCode);
abstractOrderService.processAfterPay(orderInfo);
}
@Override
public void transferSuccess(TransferData transferData) {
int now = (int) (System.currentTimeMillis()/1000);
Integer tradeBillsId = transferData.getTradeBillsId();
Integer transferId = transferData.getTransferId();
String orderCode = transferData.getOrderCode();
TradeBills tradeBills = tradeBillsMapper.selectByPrimaryKey(tradeBillsId);
if (tradeBills == null) {
throw new ServiceException(400, "transferSuccess:流水不存在");
}
if (tradeBills.getTradeStatus() != TradeBills.Status.TRANSFER_WAITING.getCode()) {
throw new ServiceException(400, "transferSuccess:该流水不是异步转账的");
}
OrdersPayTransfer transfer = ordersPayTransferMapper.selectByPrimaryKey(transferId);
if (transfer == null) {
throw new ServiceException(400, "transferSuccess:转账记录不存在");
}
if (transfer.getStatus() == 1) {
throw new ServiceException(400, "transferSuccess:转账记录已经成功");
}
logger.info("transferSuccess 参数 tradeBillsId={}, tradeBillsId={}, orderCode={}", tradeBillsId, tradeBillsId, orderCode);
if(StringUtils.equals("S", transferData.getStatus())) {
// 更新成OK
TradeBills success = new TradeBills();
success.setId(tradeBills.getId());
success.setDealStatus(1);
if (tradeBillsMapper.updateToOkByPrimaryKey(success) == 0) {
logger.warn("transferSuccess 流水已经被并发处理过 tradeBillsId={}, tradeBillsId={}, orderCode={}", tradeBillsId, tradeBillsId, orderCode);
return;
}
logger.info("transferSuccess 旧流水更新成功,准备加新流水 tradeBillsId={}, tradeBillsId={}, orderCode={}", tradeBillsId, tradeBillsId, orderCode);
// 加新流水
tradeBills.setDealRelateId(tradeBills.getId());
tradeBills.setId(null);
tradeBills.setTradeStatus(100);
tradeBills.setCreateTime(now);
addTradeBills(tradeBills);
logger.info("transferSuccess 加新流水成功,准备修改转账状态 tradeBillsId={}, tradeBillsId={}, orderCode={}", tradeBillsId, tradeBillsId, orderCode);
OrdersPayTransfer newTransfer = new OrdersPayTransfer();
newTransfer.setId(transfer.getId());
newTransfer.setStatus(1);
newTransfer.setUpdateTime(now);
ordersPayTransferMapper.updateByPrimaryKeySelective(newTransfer);
logger.info("transferSuccess 修改转账状态成功 tradeBillsId={}, tradeBillsId={}, orderCode={}", tradeBillsId, tradeBillsId, orderCode);
} else {
TradeBills fail = new TradeBills();
fail.setId(tradeBills.getId());
fail.setDealStatus(0);
fail.setTradeStatus(299);
tradeBillsMapper.updateToOkByPrimaryKey(fail);
logger.info("transferSuccess 旧流水(失败)更新成功,准备改转账表 tradeBillsId={}, tradeBillsId={}, orderCode={}", tradeBillsId, tradeBillsId, orderCode);
OrdersPayTransfer newTransfer = new OrdersPayTransfer();
newTransfer.setId(transfer.getId());
newTransfer.setStatus(3);
newTransfer.setUpdateTime(now);
ordersPayTransferMapper.updateByPrimaryKeySelective(newTransfer);
logger.info("transferSuccess 转账表(失败)更新成功 tradeBillsId={}, tradeBillsId={}, orderCode={}", tradeBillsId, tradeBillsId, orderCode);
}
}
private OrdersPay saveOrdersPay(PaymentData paymentData, long orderType, OrderInfo orderInfo) {
... ... @@ -553,30 +620,8 @@ public class PaymentServiceImpl implements IPaymentService {
}
int now = (int) (System.currentTimeMillis()/1000);
// 查看是否已经有转账记录
OrdersPayTransfer exist = ordersPayTransferMapper.selectByBuyerOrderCode(buyerOrderCode);
if (exist != null) {
logger.warn("transferMonErr OrdersPayTransfer has exist, orderCode is {}", buyerOrderCode);
throw new ServiceException(400, "订单已经处理过");
}
OrdersPayTransfer transfer = new OrdersPayTransfer();
transfer.setBuyerOrderCode(buyerOrderCode);
transfer.setSellerOrderCode(sellerOrderCode);
transfer.setAlipayTradeId("");
transfer.setAlipayTradeResult("");
transfer.setTransferType(transferCase.getCode());
transfer.setUid(targetUid);
transfer.setAmount(BigDecimal.ZERO);
transfer.setCreateTime(now);
transfer.setStatus(0);
try {
logger.info("transferMon插入初始化转账信息buyerOrderCode is {}, sellerOrderCode is {}", buyerOrderCode, sellerOrderCode);
ordersPayTransferMapper.insert(transfer);
} catch (Exception e) {
logger.warn("transferMonErr insert ordersPayTransfer failed, orderCode is {}, msg is {}", buyerOrderCode, e.getMessage());
throw new ServiceException(400, "交易记录创建失败");
}
checkTransferExist(buyerOrderCode);
OrdersPayTransfer transfer = createTransfer(buyerOrderCode, sellerOrderCode, transferCase.getCode(), null, targetUid, BigDecimal.ZERO, now);
// 增加流水记录
TradeBills record = new TradeBills();
... ... @@ -686,31 +731,8 @@ public class PaymentServiceImpl implements IPaymentService {
int now = (int) (System.currentTimeMillis()/1000);
// 查看是否已经有转账记录
OrdersPayTransfer exist = ordersPayTransferMapper.selectByBuyerOrderCode(orderCode);
if (exist != null) {
logger.warn("transAllEarnestErr OrdersPayTransfer has exist, orderCode is {}", orderCode);
throw new ServiceException(400, "订单已经处理过");
}
OrdersPayTransfer transfer = new OrdersPayTransfer();
transfer.setBuyerOrderCode(orderCode);
transfer.setSellerOrderCode(orderCode);
transfer.setAlipayTradeId("");
transfer.setAlipayTradeResult("");
transfer.setAlipayAccount(alipayAccount);
transfer.setTransferType(6);
transfer.setUid(uid);
transfer.setAmount(amount);
transfer.setCreateTime(now);
transfer.setStatus(0);
try {
logger.info("transAllEarnest插入初始化转账信息orderCode is {}", orderCode);
ordersPayTransferMapper.insert(transfer);
} catch (Exception e) {
logger.warn("transAllEarnestErr insert ordersPayTransfer failed, orderCode is {}, msg is {}", orderCode, e.getMessage());
throw new ServiceException(400, "交易记录创建失败");
}
checkTransferExist(orderCode);
OrdersPayTransfer transfer = createTransfer(orderCode, orderCode, 6, alipayAccount, uid, amount, now);
// 增加流水记录
TradeBills record = new TradeBills();
... ... @@ -986,7 +1008,18 @@ public class PaymentServiceImpl implements IPaymentService {
if (transfer == null || transfer.getStatus() == 1) {
throw new ServiceException(400, "转账记录已成功转账,流水id=" + tradeBillsId);
}
if(exceedMillion()) {
Map<String, String> mapResult = transferWhenExceedMillion(transfer.getId(), preSuccess, orderCode, account, amount, now);
String resultStr = JSON.toJSONString(mapResult);
jsonObject = JSON.parseObject(resultStr);
if(!StringUtils.equals("T", mapResult.get("is_success"))) {
throw new ServiceException(500, "转账失败:返回={}" + resultStr);
} else {
return;
}
}
jsonObject = alipayService.transferMoney(Long.toString(orderCode), account.getAlipayId(), account.getAlipayAccount(), amount);
if (jsonObject == null) {
logger.warn("manualDeal 转账失败 , req is {}", req);
... ... @@ -1007,6 +1040,15 @@ public class PaymentServiceImpl implements IPaymentService {
tradeBills.setTradeStatus(100);
tradeBills.setCreateTime(now);
addTradeBills(tradeBills);
} else if(exceedMillion(jsonObject)) {
Map<String, String> mapResult = transferWhenExceedMillion(transfer.getId(), tradeBills, orderCode, account, amount, now);
String resultStr = JSON.toJSONString(mapResult);
jsonObject = JSON.parseObject(resultStr);
if(!StringUtils.equals("T", mapResult.get("is_success"))) {
throw new ServiceException(500, "转账失败:返回={}" + resultStr);
} else {
return;
}
} else {
logger.warn("manualDealErr 返回code或者order_id不是成功状态,code={}, orderId={}", code, orderId);
// 上报
... ... @@ -1031,6 +1073,81 @@ public class PaymentServiceImpl implements IPaymentService {
logger.info("manualDeal转账结束, tradeBillsId is {}!", tradeBillsId);
}
}
private Map<String, String> transferWhenExceedMillion(Integer transferId, TradeBills tradeBills, long orderCode, AuthorizeResultRespVO account,
BigDecimal amount, int now) throws Exception {
Map<String, String> mapResult = alipayService.transferMoneyWhenExceedMillion(Long.toString(orderCode),
transferId + "_" + tradeBills.getId(), account.getAlipayId(), account.getAlipayAccount(),
account.getCertName(), amount);
logger.info("manualDeal 转账阿里接口(超过100万)返回 {}", mapResult);
// success to wait
if (StringUtils.equals("T", mapResult.get("is_success"))) {
// TODO 加新流水
tradeBills.setDealRelateId(tradeBills.getId());
tradeBills.setId(null);
tradeBills.setTradeStatus(100);
tradeBills.setCreateTime(now);
addTradeBills(tradeBills);
tradeBills.setDealStatus(0);
tradeBills.setTradeStatus(99);
// wait
tradeBillsMapper.updateToOkByPrimaryKey(tradeBills);
}
return mapResult;
}
private boolean exceedMillion(JSONObject jsonObject) {
// {"msg":"Business Failed","code":"40004","sub_msg":"单日最多可转100万元","sub_code":"EXCEED_LIMIT_DM_MAX_AMOUNT"}
if (StringUtils.equals("40004", jsonObject.getString("code"))
&& StringUtils.equals("EXCEED_LIMIT_DM_MAX_AMOUNT", jsonObject.getString("sub_code"))) {
exceedMillion = true;
return true;
}
return false;
}
private boolean exceedMillion() {
return exceedMillion;
}
private volatile boolean exceedMillion = false;
private void checkTransferExist(long orderCode) {
// 查看是否已经有转账记录
OrdersPayTransfer exist = ordersPayTransferMapper.selectByBuyerOrderCode(orderCode);
if (exist != null) {
logger.warn("OrdersPayTransfer has exist, orderCode is {}", orderCode);
throw new ServiceException(400, "订单已经处理过");
}
}
private OrdersPayTransfer createTransfer(long buyerOrderCode, long sellerOrderCode, Integer transferType, String alipayAccount,
Integer uid, BigDecimal amount, int time) {
OrdersPayTransfer transfer = new OrdersPayTransfer();
transfer.setBuyerOrderCode(buyerOrderCode);
transfer.setSellerOrderCode(sellerOrderCode);
transfer.setAlipayTradeId("");
transfer.setAlipayTradeResult("");
transfer.setAlipayAccount(alipayAccount);
transfer.setTransferType(transferType);
transfer.setUid(uid);
transfer.setAmount(amount);
transfer.setCreateTime(time);
transfer.setStatus(0);
try {
logger.info("转账 插入初始化转账信息 buyerOrderCode is {},sellerOrderCode is {}", buyerOrderCode, sellerOrderCode);
ordersPayTransferMapper.insert(transfer);
return transfer;
} catch (Exception e) {
logger.warn(
"transferCreateErr insert ordersPayTransfer failed, buyerOrderCode is {},sellerOrderCode is {}, msg is {}",
buyerOrderCode, sellerOrderCode, e.getMessage());
throw new ServiceException(400, "交易记录创建失败");
}
}
public PayQueryBo queryTransferResult(String buyerOrderCode) {
return alipayService.transferQuery(buyerOrderCode);
... ...
... ... @@ -31,7 +31,15 @@ public class AlipayOuyinService extends AlipayServiceAbstract {
return AlipayConfig.OUYIN_APPID;
}
@Override
protected String getAccountUserName() {
return AlipayConfig.OUYIN_USER_NAME;
}
@Override
protected String getAccountEmail() {
return AlipayConfig.OUYIN_EMAIL;
}
}
... ...
... ... @@ -9,6 +9,7 @@ import com.yohoufo.common.utils.DateUtil;
import com.yohoufo.common.utils.HttpClient;
import com.yohoufo.common.utils.MD5Utils;
import com.yohoufo.common.utils.RSAUtils;
import com.yohoufo.common.utils.WXUtil;
import com.yohoufo.order.config.AlipayConfig;
import com.yohoufo.order.constants.RefundContant;
import com.yohoufo.order.model.*;
... ... @@ -22,6 +23,7 @@ import org.springframework.beans.factory.annotation.Value;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.*;
public abstract class AlipayServiceAbstract extends AbstractPayService {
... ... @@ -41,11 +43,22 @@ public abstract class AlipayServiceAbstract extends AbstractPayService {
protected abstract String getAppId();
protected abstract String getPartnerId();
protected String getAccountUserName() {
return "";
}
protected String getAccountEmail() {
return "";
}
@Value("${alipay.notifyurl}")
private String notifyURL;
@Value("${alipay.transfer.notifyurl}")
private String transferNotifyURL;
// public JSONObject prepayRequest(OrderInfo orderInfo){
... ... @@ -155,6 +168,29 @@ public abstract class AlipayServiceAbstract extends AbstractPayService {
return result;
}
/**
* 转账功能
* @param transferOrderCode
* @param alipayAccount
* @param transferAmount
* @return
* @throws Exception
*/
public Map<String, String> transferMoneyWhenExceedMillion(String transferOrderCode, String businessId, String alipayUid, String alipayAccount, String userName, BigDecimal transferAmount) throws Exception{
Map<String, String> queryParams = buildTransferParamsWhenExceedMillion(transferOrderCode, businessId, alipayUid, alipayAccount, userName, transferAmount);
String respTxt = sendOpenApiRequestWithException(transferOrderCode, queryParams);
Map<String, String> result;
if (StringUtils.isNotBlank(respTxt)){
result = WXUtil.parseWXPayXml(respTxt);
} else {
result = new HashMap<>();
}
return result;
}
public PayQueryBo transferQuery(String buyerOrderCode) {
String tradeNo = buyerOrderCode;
Map<String, String> queryParams = buildAlipayTransferQueryParams(tradeNo);
... ... @@ -313,6 +349,45 @@ public abstract class AlipayServiceAbstract extends AbstractPayService {
params.put("sign", RSAUtils.sign(preSignStr, getRsaPrivateKey(), AlipayConfig.input_charset));
return params;
}
/**
* 单笔转账
* @param orderData
* @return
*/
private Map<String, String> buildTransferParamsWhenExceedMillion(String transferOrderCode, String businessId, String alipayUid, String alipayAccount, String userName, BigDecimal transferAmount) {
Map<String, String> params = new HashMap<String, String>();
params.put("service", "batch_trans_notify_no_pwd");
params.put("partner", getPartnerId());
params.put("_input_charset", AlipayConfig.input_charset);
params.put("notify_url", transferNotifyURL);
params.put("account_name", getAccountUserName());
params.put("batch_no", transferOrderCode);
params.put("batch_num", "1");
params.put("batch_fee", transferAmount.toString());
params.put("email", getAccountEmail());
StringBuilder detailAppender = new StringBuilder();
detailAppender.append(businessId).append("^");
if (StringUtils.isNotBlank(alipayUid)) {
// 流水号1^收款方UserId1^付款金额1^备注说明1
params.put("detail_version", "1.1");
detailAppender.append(alipayUid).append("^");
} else {
// 流水号1^收款方账号1^收款账号姓名1^付款金额1^备注说明1
params.put("detail_version", "1.0");
detailAppender.append(alipayAccount).append("^").append(userName).append("^");
}
params.put("detail_data", detailAppender.toString());
detailAppender.append(transferAmount).append("^UFO_ORDER");
String preSignStr = getOpenApiSignString(params);
params.put("sign", RSAUtils.sign(preSignStr, getRsaPrivateKey(), AlipayConfig.input_charset));
params.put("sign_type", "RSA");
return params;
}
/**
... ... @@ -405,6 +480,38 @@ public abstract class AlipayServiceAbstract extends AbstractPayService {
}
return payData;
}
public TransferData getTransferData(String data) {
if (StringUtils.isBlank(data)) {
return null;
}
if (data.endsWith("|")) {
data = data.substring(0, data.length() - 1);
}
String[] dataArray = data.split("^");
if (dataArray.length != 8) {
logger.error("[{}] getTransferData 支付宝回调数据字段个数有误", data);
return null;
}
// 1流水号^2收款方账号^3收款账号姓名^4付款金额^5成功标识(S)^6成功原因(null)^7支付宝内部流水号^8完成时间
try {
TransferData transferData = new TransferData();
String[] transferIdAndTradeBillId = dataArray[0].split("_");
transferData.setTransferId(new Integer(transferIdAndTradeBillId[0]));
transferData.setTradeBillsId(new Integer(transferIdAndTradeBillId[1]));
transferData.setReceiveAccount(dataArray[1]);
transferData.setReceiveUserName(dataArray[2]);
transferData.setMoney(dataArray[3]);
transferData.setStatus(dataArray[4]);
transferData.setMessage(dataArray[5]);
transferData.setAlipayTradeId(dataArray[6]);
transferData.setTime(dataArray[7]);
return transferData;
} catch (NumberFormatException e) {
logger.error("[{}] getTransferData 支付宝回调数据格式有误", data);
return null;
}
}
public boolean notifyVerify(Map<String, String> paramsMap) {
... ...
... ... @@ -81,6 +81,8 @@ wechat.notifyurl=http://testapi.yohops.com/payment/weixin_notify
alipay.notifyurl=http://testapi.yohops.com/payment/alipay_notify
alipay.transfer.notifyurl=http://testapi.yohops.com/payment/alipay_transfer_notify
erp-gateway.url=http://java-yoho-erp-gateway.test3.ingress.dev.yohocorp.com/erp-gateway
redis.readonly.proxy.address=192.168.102.45
... ... @@ -119,7 +121,7 @@ uic.url=http://java-yoho-uic.test3.ingress.dev.yohocorp.com/uic
yoho.message.controller.url=http://message-controller.yohoops.org/yoho-message-controller
#rabbit address for transaction compensate
rabbit_host=192.168.102.45:5672
rabbit_host=192.168.104.199:30005
rabbit_user=yoho
rabbit_password=yoho
... ...
... ... @@ -62,6 +62,7 @@ wechat.app.appid=wx049fdaa3ba9cdd7a
wechat.notifyurl=${wechat.notifyurl}
alipay.notifyurl=${alipay.notifyurl}
alipay.transfer.notifyurl=${alipay.transfer.notifyurl}
order.seller.earnestmoney.min=${order.seller.earnestmoney.min}
order.seller.earnestmoney.max=${order.seller.earnestmoney.max}
... ...