Authored by LUOXC

Merge branch 'dev6.9.7' into test6.9.7

# Conflicts:
#	order/src/main/java/com/yohoufo/order/service/impl/PaymentServiceImpl.java
... ... @@ -26,5 +26,7 @@ public interface BuyerOrderGoodsMapper {
BuyerOrderGoods selectOnlyByOrderCode(@Param("orderCode") long orderCode);
List<BuyerOrderGoods> selectByOrderCodes(@Param("orderCodes") List<Long> orderCodes);
}
\ No newline at end of file
... ...
... ... @@ -32,4 +32,12 @@ public interface TradeBillsMapper {
TradeBills selectByDealRelateId(Integer dealRelateId);
List<TradeBills> selectByKeyProps(TradeBills condition);
int updateLockOfUidTradeStatusAndDealTime(Integer uid, Integer tradeStatus, Integer dealTime,
Integer tagTradeStatus, Integer tagDealTime);
List<TradeBills> selectByUidTradeStatusAndDealTime(Integer uid, Integer tradeStatus, Integer dealTime);
}
... ...
... ... @@ -4,6 +4,8 @@ import java.math.BigDecimal;
public class OrdersPayTransfer {
public static final Integer INTERFACE_TYPE_TRANSFER_NON_EXCEED_MILLION = 1;
public static final Integer INTERFACE_TYPE_TRANSFER_WHEN_EXCEED_MILLION = 2;
private Integer id;
... ...
... ... @@ -151,4 +151,14 @@
limit 1
</select>
<select id="selectByOrderCodes" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from buyer_order_goods
where order_code IN
<foreach collection="orderCodes" item="orderCode" open="(" separator="," close=")">
#{orderCode,jdbcType=BIGINT}
</foreach>
</select>
</mapper>
\ No newline at end of file
... ...
... ... @@ -202,4 +202,23 @@
and trade_type = #{tradeType,jdbcType=INTEGER}
</if>
</select>
<update id="updateLockOfUidTradeStatusAndDealTime" >
update trade_bills
set trade_status = #{tagTradeStatus,jdbcType=INTEGER},deal_time = #{tagDealTime,jdbcType=INTEGER}
where
uid = #{uid,jdbcType=INTEGER}
and trade_status = #{tradeStatus,jdbcType=INTEGER}
and deal_time = #{dealTime,jdbcType=INTEGER}
</update>
<select id="selectByUidTradeStatusAndDealTime" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from trade_bills
where
uid = #{uid,jdbcType=INTEGER}
and trade_status = #{tradeStatus,jdbcType=INTEGER}
and deal_time = #{dealTime,jdbcType=INTEGER}
</select>
</mapper>
\ No newline at end of file
... ...
... ... @@ -5,11 +5,15 @@ package com.yohoufo.order.common;
* Created by chao.chen on 2018/10/24.
*/
public enum BillTradeStatus {
NEW(0),
TRANSFER_WAITING(90),
SUCCESS(100),
FAIL(200),
NOT_EXIST_ALI_ACCOUNT(201),
NOT_EXIST_ALIPAY_ACCOUNT(201),
AMOUNT_IS_ILLEGAL(202),
HK_AMOUNT_WAIT_PAYMENT(203),
YOHO_STORE_AMOUNT_WAIT_PAYMENT(204),
HK_AMOUNT_PAYING(213),
TRANSFER_FAIL(299);
int code;
... ...
... ... @@ -54,6 +54,8 @@ public interface TopicConstants {
String ORDER_NOT_DELIVER_NOTICE = "order.notDeliver";
//String ORDER_NOT_DELIVER_NOTICE_108 = "order.notDeliver_108";
String HK_AMOUNT_WAIT_PAYMENT = "order.hkAmountWaitPayment";
}
... ...
package com.yohoufo.order.mq.consumer;
import com.alibaba.fastjson.JSONObject;
import com.yoho.core.rabbitmq.YhConsumer;
import com.yohoufo.order.event.BuyerConfirmEvent;
import com.yohoufo.order.model.request.OrderRequest;
import com.yohoufo.order.service.transfer.HkAccountSettlement;
import com.yohoufo.order.utils.LoggerUtils;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class HkAmountWaitPaymentMessageConsummer implements YhConsumer {
final Logger logger = LoggerUtils.getMqConsumerLogger();
@Autowired
HkAccountSettlement hkAccountSettlement;
@Override
public void handleMessage(Object o) throws Exception {
logger.info("handler hk amount wait payment message, msg {} ", o);
try {
JSONObject message = JSONObject.parseObject(o.toString());
Integer uid = message.getInteger("uid");
hkAccountSettlement.settle(uid);
logger.info("handler hk amount wait payment message success, msg {} ", o);
} catch (Exception e) {
logger.info("handler hk amount wait payment message fail, msg {} ", o, e);
}
}
}
... ...
package com.yohoufo.order.service.handler.transfer;
import com.alibaba.fastjson.JSONObject;
import com.yoho.core.config.ConfigReader;
import com.yohoufo.dal.order.model.OrdersPayTransfer;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.text.SimpleDateFormat;
import java.util.Date;
@Slf4j
@Service
public class AlipayTransferChancelSelector {
private volatile String lastTransferDate = null;
@Autowired
private ConfigReader configReader;
public boolean isTransferWithAlipayExceedMillionTransfer() {
boolean value = configReader.getBoolean("ufo.order.pay.exceedSwitch", false);
if (value) {
log.info("use exceed million ufo.order.pay.exceedSwitch={}", value);
return true;
}
String nowDate = new SimpleDateFormat("yyyyMMdd").format(new Date());
return StringUtils.equals(lastTransferDate, nowDate);
}
public boolean isExceedMillion(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"))) {
lastTransferDate = new SimpleDateFormat("yyyyMMdd").format(new Date());
log.info("transferWhenExceedMillion 转账阿里接口返回 {},进入商家转账模式 lastTransferDate={}", jsonObject, lastTransferDate);
return true;
}
return false;
}
public boolean isTransferWithAlipayExceedMillionTransfer(Integer interfaceType) {
return OrdersPayTransfer.INTERFACE_TYPE_TRANSFER_WHEN_EXCEED_MILLION.equals(interfaceType);
}
}
... ...
... ... @@ -2,7 +2,6 @@ package com.yohoufo.order.service.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.yoho.core.config.ConfigReader;
import com.yoho.core.dal.datasource.annotation.Database;
import com.yoho.error.ServiceError;
import com.yoho.error.exception.ServiceException;
... ... @@ -29,12 +28,19 @@ 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;
import com.yohoufo.order.model.response.PaymentConfirmRsp;
import com.yohoufo.order.model.response.PrepayResponse;
import com.yohoufo.order.service.*;
import com.yohoufo.order.mq.TopicConstants;
import com.yohoufo.order.mq.producer.TradeMqSender;
import com.yohoufo.order.service.AbstractOrderPaymentService;
import com.yohoufo.order.service.BuyerOrderPaymentService;
import com.yohoufo.order.service.IPaymentService;
import com.yohoufo.order.service.MerchantOrderPaymentService;
import com.yohoufo.order.service.SellerOrderPaymentService;
import com.yohoufo.order.service.handler.BuyerOrderPayDiffTimeHandler;
import com.yohoufo.order.service.handler.transfer.AlipayTransferChancelSelector;
import com.yohoufo.order.service.pay.AbstractPayService;
import com.yohoufo.order.service.pay.alipay.AlipayOuyinService;
import com.yohoufo.order.service.pay.wallet.WalletPayService;
... ... @@ -53,12 +59,12 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Collections;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import static com.yohoufo.order.common.TransferCase.EARNEST_MONEY_TO_BUYER;
... ... @@ -143,11 +149,14 @@ public class PaymentServiceImpl implements IPaymentService {
BuyerOrderPayDiffTimeHandler buyerOrderPayDiffTimeHandler;
@Autowired
private OrdersPayHbfqMapper ordersPayHbfqDao;
private AlipayTransferChancelSelector alipayTransferChancelSelector;
@Autowired
private TradeBillsService tradeBillsService;
@Autowired
private TradeMqSender tradeMqSender;
/**
* 获取主场的订单service
* @param codeMeta
... ... @@ -322,8 +331,6 @@ public class PaymentServiceImpl implements IPaymentService {
// 记录支付成功记录
saveOrdersPay(paymentData, codeMeta.getType(), orderInfo);
abstractOrderService.processAfterPay(orderInfo);
logger.info("paySuccess finished. orderCode is {}", orderCode);
}
... ... @@ -575,195 +582,97 @@ public class PaymentServiceImpl implements IPaymentService {
*/
@Database(ForceMaster = true)
public void transferMon(TransferMoneyRequest request){
logger.info("transferMon转账开始,request = {}", request);
long buyerOrderCode = request.getBuyerOrderCode();
logger.info("transferMon参数检查");
// 订单号check
if (buyerOrderCode < 1L) {
logger.warn("transferMonErr orderCode empty");
throw new ServiceException(ServiceError.ORDER_REQUEST_PARM_IS_EMPTY);
}
// 类型检查
TransferCase transferCase = TransferCase.getTransferCase(request.getType());
if (transferCase == null) {
logger.warn("transferMonErr transferType invalid");
throw new ServiceException(ServiceError.ORDER_REQUEST_PARM_IS_EMPTY);
}
TransferMoneyModel transferMoneyModel = new TransferMoneyModel(request).invoke();
String logTag = transferMoneyModel.getLogTag();
long buyerOrderCode = transferMoneyModel.getBuyerOrderCode();
TransferCase transferCase = transferMoneyModel.getTransferCase();
SellerOrder sellerOrder = transferMoneyModel.getSellerOrder();
long sellerOrderCode = transferMoneyModel.getSellerOrderCode();
Integer targetUid = transferMoneyModel.getTargetUid();
int now = transferMoneyModel.getNow();
// 买家订单检查
BuyerOrder buyerOrder = buyerOrderMapper.selectByOrderCode(buyerOrderCode);
if (buyerOrder == null) {
logger.warn("transferMonErr getOrderInfo buyer order not exist, orderCode is {}", buyerOrderCode);
throw new ServiceException(ServiceError.ORDER_NULL);
}
BuyerOrderGoods buyerOrderGoods = buyerOrderGoodsMapper.selectByOrderCode(buyerOrder.getUid(), buyerOrderCode);
if (buyerOrderGoods == null) {
logger.warn("transferMonErr buyerOrderGoods not exist, orderCode is {}", buyerOrderCode);
throw new ServiceException(ServiceError.ORDER_NULL);
}
// 卖家订单检查
Integer skup = buyerOrderGoods.getSkup();
SellerOrder sellerOrder = sellerOrderMapper.selectBySkup(skup);
if (sellerOrder == null){
logger.warn("transferMonErr getOrderInfo seller order not exist, skup is {}", buyerOrderGoods.getSkup());
throw new ServiceException(ServiceError.ORDER_NULL);
}
Integer sellerUid = sellerOrder.getUid();
long sellerOrderCode = sellerOrder.getOrderCode();
penaltyEarnestIfWalletSellerOrder(request.getPenaltyEarnestFunction(), request.getSwdType(), sellerOrder);
val targetUserType = transferCase == EARNEST_MONEY_TO_BUYER ? TargetUserType.buyer : TargetUserType.seller;
val targetUid = targetUserType == TargetUserType.buyer ? buyerOrder.getUid() : sellerUid;
if (targetUid == null || targetUid < 1) {
logger.warn("transferMonErr uid {} 不合法", targetUid);
throw new ServiceException(400, "uid[" + targetUid + "]不合法");
}
int now = (int) (System.currentTimeMillis()/1000);
// 查看是否已经有转账记录
checkTransferExist(buyerOrderCode);
OrdersPayTransfer transfer = createTransfer(buyerOrderCode, sellerOrderCode, transferCase.getCode(), null, targetUid, BigDecimal.ZERO, now);
// 增加流水记录
TradeBills record = new TradeBills();
record.setUid(targetUid);
record.setOrderCode(buyerOrderCode);
record.setUserType(targetUserType.getCode());
record.setPayType(1);
// 如果[全部货款->卖家],否则[补偿款->卖家或买家] 2:货款;3:补偿款
record.setTradeType(transferCase == TransferCase.ALL_GOODS_MONEY_TO_SELLER ? 2 : 3);
record.setIncomeOutcome(1);
record.setTradeStatus(0);
record.setCreateTime(now);
TradeBills record = transferMoneyModel.newTradeBills();
logger.info("transferMon参数检查成功!插入初始化转账信息成功,接下来计算费用");
TranseferCellNode transeferCellNode = request.getTranseferCellNode();
// 算费
BigDecimal transferAmount = transeferCellNode.getAmount();
logger.info("transferMon计算费用结果为 {}", transferAmount);
if (transferAmount == null) {
logger.warn("transferMonErr transferMon计算费用结果为 null, 不合法的金额");
alarm("转账金额不合法", "ufo.order.transferMon", "订单号:" + buyerOrderCode + "操作类型(" + transferCase.getCode() + ")计算金额结果为null");
record.setTradeStatus(BillTradeStatus.AMOUNT_IS_ILLEGAL.getCode());
addTradeBills(record);
throw new ServiceException(400, "计算金额错误!:");
}
transfer.setAmount(transferAmount);
// 转账费
BigDecimal transferAmount = request.getTranseferCellNode().getAmount();
if (transferAmount == null) {
logger.warn("{}, transfer amount is null", logTag);
alarm("转账金额不合法", "ufo.order.transferMon", "订单号:" + buyerOrderCode + "操作类型(" + transferCase.getCode() + ")计算金额结果为空");
record.setTradeStatus(BillTradeStatus.AMOUNT_IS_ILLEGAL.getCode());
addTradeBills(record);
throw new ServiceException(400, "计算金额错误!:");
}
logger.info("{}, transfer amount is {}", logTag, transferAmount);
record.setAmount(transferAmount);
// 因为转账支付宝扣费累计计算,使用转账额
// ???因为转账支付宝扣费累计计算,使用转账额
record.setSystemAmount(transferAmount.multiply(new BigDecimal("-1")));
if (transferAmount.compareTo(new BigDecimal("0.1")) < 0) {
logger.warn("transferMonErr transferMon计算费用结果为 {}, 小于0.1", transferAmount);
logger.info("{}, transfer amount is {}, it less than 0.1", logTag, transferAmount);
alarm("转账金额小于0.1", "ufo.order.transferMon", "订单号:" + buyerOrderCode + "操作类型(" + transferCase.getCode() + ")计算金额结果为" + transferAmount);
record.setTradeStatus(BillTradeStatus.AMOUNT_IS_ILLEGAL.getCode());
addTradeBills(record);
throw new ServiceException(400, "不合法的金额:" + transferAmount);
}
AuthorizeResultRespVO account = getOneValidAlipayAccount(targetUid);
if (account == null ) {
logger.warn("transferMonErr uid {} 没有获取到有效的支付宝账号", targetUid);
record.setTradeStatus(BillTradeStatus.NOT_EXIST_ALI_ACCOUNT.getCode());
addTradeBills(record);
throw new ServiceException(400, "uid[" + targetUid + "]没有获取到有效的支付宝账号");
}
if(StringUtils.isNotBlank(account.getAlipayId())) {
logger.info("transferMon uid {} 支付宝账号uid有值优先使用{}", targetUid, account.getAlipayId());
transfer.setAlipayAccount(account.getAlipayId());
} else if(StringUtils.isNotBlank(account.getAlipayAccount())) {
logger.info("transferMon uid {} 支付宝账号uid无值使用账号{}", targetUid, account.getAlipayAccount());
transfer.setAlipayAccount(account.getAlipayAccount());
}
transfer.setUpdateTime(now);
tradeBillsMapper.insert(record);
AuthorizeResultRespVO account = getOneValidAlipayAccountOr(targetUid, invalidAccount -> {
if ("invalid".equals(invalidAccount)) {
record.setTradeStatus(BillTradeStatus.YOHO_STORE_AMOUNT_WAIT_PAYMENT.getCode());
} else if ("invalid_hk".equals(invalidAccount)) {
record.setTradeStatus(BillTradeStatus.HK_AMOUNT_WAIT_PAYMENT.getCode());
tradeMqSender.send(TopicConstants.HK_AMOUNT_WAIT_PAYMENT, Collections.singletonMap("uid", record.getUid()));
} else {
record.setTradeStatus(BillTradeStatus.NOT_EXIST_ALIPAY_ACCOUNT.getCode());
}
addTradeBills(record);
throw new ServiceException(400, "uid[" + targetUid + "]没有获取到有效的支付宝账号");
});
tradeBillsMapper.insert(record);
String alipayAccount = StringUtils.isNotBlank(account.getAlipayId()) ? account.getAlipayId() : account.getAlipayAccount();
transfer.setAlipayAccount(alipayAccount);
transfer.setUpdateTime(now);
transfer.setAmount(transferAmount);
String alipayAccount = transfer.getAlipayAccount();
JSONObject jsonObject = null;
boolean exceedMillionAndSuccess = false;
// 转账
try {
logger.info("transferMon开始调用阿里接口参数buyerOrderCode={}, alipayAccount={}, transferAmount={}", buyerOrderCode, alipayAccount, transferAmount);
if(exceedMillion()) {
transfer.setInterfaceType(2);
ordersPayTransferMapper.updateByPrimaryKeySelective(transfer);
Map<String, String> mapResult = transferWhenExceedMillion(transfer.getId(), record, buyerOrderCode, account, transferAmount, now);
String resultStr = JSON.toJSONString(mapResult);
jsonObject = JSON.parseObject(resultStr);
if(!StringUtils.equals("T", mapResult.get("is_success"))) {
throw new ServiceException(500, "转账失败:返回={}" + resultStr);
} else {
exceedMillionAndSuccess = true;
return;
}
}
transfer.setInterfaceType(1);
ordersPayTransferMapper.updateByPrimaryKeySelective(transfer);
jsonObject = alipayService.transferMoney(Long.toString(buyerOrderCode), account.getAlipayId(), account.getAlipayAccount(), transferAmount);
if (jsonObject == null) {
logger.warn("transferMonErr 转账失败 , orderCode is {}", buyerOrderCode);
transfer.setStatus(3);
throw new ServiceException(500, "转账失败:阿里接口返回null");
}
transfer.setAlipayTradeResult(jsonObject.toJSONString());
// 成功
Integer code = null;
String orderId = null;
if (jsonObject.containsKey("code")
&& (code = jsonObject.getInteger("code")) == 10000
&& jsonObject.containsKey("order_id")
&& StringUtils.isNotBlank(orderId = jsonObject.getString("order_id"))) {
logger.info("转账成功,targeAccount is {}, amount is {}", alipayAccount, transferAmount);
transfer.setAlipayTradeId(orderId);
transfer.setStatus(1);
} else if(exceedMillion(jsonObject)) {
transfer.setInterfaceType(2);
ordersPayTransferMapper.updateByPrimaryKeySelective(transfer);
Map<String, String> mapResult = transferWhenExceedMillion(transfer.getId(), record, buyerOrderCode, account, transferAmount, now);
String resultStr = JSON.toJSONString(mapResult);
jsonObject = JSON.parseObject(resultStr);
if(!StringUtils.equals("T", mapResult.get("is_success"))) {
throw new ServiceException(500, "转账失败:返回={}" + resultStr);
} else {
exceedMillionAndSuccess = true;
return;
}
} else {
logger.warn("transferMonErr 返回code或者order_id不是成功状态,code={}, orderId={}", code, orderId);
throw new ServiceException(500, "转账失败:code或者order_id不是成功状态");
}
} catch (Exception e) {
logger.warn("transferMonErr 转账失败 , orderCode is {}, msg is {}", buyerOrderCode, e.getMessage());
String alarmMsg = "订单号:" + buyerOrderCode + ",操作类型:" + transferCase.getInfo() + ",msg=" + e.getMessage();
if (jsonObject != null) {
alarmMsg += ",阿里返回DETAIL=" + jsonObject.toJSONString();
}
logger.info("transferMonErr 转账失败 , alarmMsg is {}", alarmMsg);
alarm("转账失败", "ufo.order.transferMon", alarmMsg);
transfer.setStatus(3);
if(e instanceof ServiceException) {
throw new ServiceException(((ServiceException) e).getCode(), e.getMessage());
} else {
throw new ServiceException(500, "转账失败");
}
} finally {
if(exceedMillionAndSuccess) {
logger.info("transferMon exceedMillion,转账结束,等待回调 buyerOrderCode is {}!", buyerOrderCode);
return;
}
logger.info("transferMon最后更新状态 status= {}", transfer.getStatus());
ordersPayTransferMapper.updateByPrimaryKeySelective(transfer);
// 100:成功;201:没有支付宝账号;202:金额不合法;299:转账失败
BillTradeStatus bts = transfer.getStatus() == 1 ? BillTradeStatus.SUCCESS : BillTradeStatus.TRANSFER_FAIL;
record.setTradeStatus(bts.getCode());
// 转账
try {
logger.info("{}, transfer alipayAccount={}, transferAmount={}", logTag, alipayAccount, transferAmount);
if (alipayTransferChancelSelector.isTransferWithAlipayExceedMillionTransfer()) {
transfer.setInterfaceType(OrdersPayTransfer.INTERFACE_TYPE_TRANSFER_WHEN_EXCEED_MILLION);
ordersPayTransferMapper.updateByPrimaryKeySelective(transfer);
transferWithAlipayExceedMillionTransfer(logTag, record, buyerOrderCode, account, transferAmount, transfer);
} else {
transfer.setInterfaceType(OrdersPayTransfer.INTERFACE_TYPE_TRANSFER_NON_EXCEED_MILLION);
ordersPayTransferMapper.updateByPrimaryKeySelective(transfer);
transferWithAlipayTransfer(logTag, record, buyerOrderCode, account, transferAmount, transfer);
}
logger.info("{}, transfer success ", logTag);
} catch (Exception e) {
logger.warn("{}, transfer fail", logTag, e);
String alarmMsg = "订单号:" + buyerOrderCode + ",操作类型:" + transferCase.getInfo() + ",msg=" + e.getMessage();
alarm("转账失败", "ufo.order.transferMon", alarmMsg);
transfer.setStatus(3);
ordersPayTransferMapper.updateByPrimaryKeySelective(transfer);
logger.warn("{}, transfer fail orders pay transfer status is updated", logTag);
record.setTradeStatus(BillTradeStatus.TRANSFER_FAIL.getCode());
tradeBillsMapper.updateSelectiveByPrimaryKey(record);
logger.info("transferMon最后更新状态完成,转账结束, buyerOrderCode is {}!", buyerOrderCode);
}
logger.warn("{}, transfer fail trade bills status is updated", logTag);
if (e instanceof ServiceException) {
throw e;
} else {
throw new ServiceException(500, "转账失败");
}
}
}
@Database(ForceMaster = true)
@Database(ForceMaster = true)
public boolean transAllEarnest(long orderCode, Integer uid, BigDecimal amount, AuthorizeResultRespVO aliPayAccount){
logger.info("退还商家所有保证金,转账开始,orderCode = {}, uid={}, amount={}, alipayAccount={}", orderCode, uid, amount, aliPayAccount);
... ... @@ -802,7 +711,7 @@ public class PaymentServiceImpl implements IPaymentService {
if (StringUtils.isBlank(aliPayAccount.getAlipayAccount()) && StringUtils.isBlank(aliPayAccount.getAlipayId()) ) {
logger.warn("transAllEarnestErr uid {} 支付宝账号不合法", account);
record.setTradeStatus(BillTradeStatus.NOT_EXIST_ALI_ACCOUNT.getCode());
record.setTradeStatus(BillTradeStatus.NOT_EXIST_ALIPAY_ACCOUNT.getCode());
addTradeBills(record);
throw new ServiceException(400, "uid[" + uid + "]支付宝账号不合法");
}
... ... @@ -816,7 +725,7 @@ public class PaymentServiceImpl implements IPaymentService {
try {
logger.info("transAllEarnest开始调用阿里接口参数buyerOrderCode={}, alipayAccount={}, transferAmount={}", orderCode, account, amount);
if(exceedMillion()) {
if(alipayTransferChancelSelector.isTransferWithAlipayExceedMillionTransfer()) {
transfer.setInterfaceType(2);
ordersPayTransferMapper.updateByPrimaryKeySelective(transfer);
Map<String, String> mapResult = transferWhenExceedMillion(transfer.getId(), record, orderCode, aliPayAccount, amount, now);
... ... @@ -850,7 +759,7 @@ public class PaymentServiceImpl implements IPaymentService {
transfer.setAlipayTradeId(orderId);
transfer.setStatus(1);
return true;
} else if(exceedMillion(jsonObject)) {
} else if(alipayTransferChancelSelector.isExceedMillion(jsonObject)) {
transfer.setInterfaceType(2);
ordersPayTransferMapper.updateByPrimaryKeySelective(transfer);
Map<String, String> mapResult = transferWhenExceedMillion(transfer.getId(), record, orderCode, aliPayAccount, amount, now);
... ... @@ -985,7 +894,7 @@ public class PaymentServiceImpl implements IPaymentService {
TradeBills lockKey = new TradeBills();
lockKey.setId(tradeBills.getId());
lockKey.setDealTime((int) (System.currentTimeMillis() / 1000));
lockKey.setDealTime(DateUtil.getCurrentTimeSecond());
lockKey.setDealStatus(1);
lockKey.setDealUid(req.getOperateUid());
lockKey.setDealUserName(req.getOperateUname());
... ... @@ -1147,10 +1056,10 @@ public class PaymentServiceImpl implements IPaymentService {
400, "转账记录已成功转账,请不要重复操作。");
Integer interfaceType = transfer.getInterfaceType();
logger.info("{}, transfer channel router {}", logTag, interfaceType);
if (OrdersPayTransfer.INTERFACE_TYPE_TRANSFER_WHEN_EXCEED_MILLION.equals(interfaceType)) {
transferWithAlipayExceedMillionTransfer(tradeBills, orderCode, logTag, account, amount, transfer);
if (alipayTransferChancelSelector.isTransferWithAlipayExceedMillionTransfer(interfaceType)) {
transferWithAlipayExceedMillionTransfer(logTag, tradeBills, orderCode, account, amount, transfer);
} else {
transferWithAlipayTransfer(logTag, tradeBills, orderCode, account, amount, transfer);
transferWithAlipayTransferAndAddSuccessTradeBills(logTag, tradeBills, orderCode, account, amount, transfer);
}
logger.info("{}, transfer success.", logTag);
} catch (Exception e) {
... ... @@ -1188,7 +1097,7 @@ public class PaymentServiceImpl implements IPaymentService {
addTradeBills(tradeBills);
}
private void transferWithAlipayTransfer(String logTag, TradeBills tradeBills, long orderCode, AuthorizeResultRespVO account, BigDecimal amount, OrdersPayTransfer transfer) {
private void transferWithAlipayTransferAndAddSuccessTradeBills(String logTag, TradeBills tradeBills, long orderCode, AuthorizeResultRespVO account, BigDecimal amount, OrdersPayTransfer transfer) {
TransferResult transferResult = alipayService.newAlipayTransfer()
.transferOrderCode(Long.toString(orderCode))
.alipayUid(account.getAlipayId())
... ... @@ -1213,7 +1122,32 @@ public class PaymentServiceImpl implements IPaymentService {
}
private void transferWithAlipayExceedMillionTransfer(TradeBills tradeBills, long orderCode, String logTag, AuthorizeResultRespVO account, BigDecimal amount, OrdersPayTransfer transfer) {
private void transferWithAlipayTransfer(String logTag, TradeBills tradeBills, long orderCode, AuthorizeResultRespVO account, BigDecimal amount, OrdersPayTransfer transfer) {
TransferResult transferResult = alipayService.newAlipayTransfer()
.transferOrderCode(Long.toString(orderCode))
.alipayUid(account.getAlipayId())
.alipayAccount(account.getAlipayAccount())
.transferAmount(amount)
.transfer();
if (transferResult.getCode() == 200) {
logger.info("{}, transfer success and out trade no is {}", logTag, orderCode);
// 更新流水
tradeBills.setTradeStatus(BillTradeStatus.SUCCESS.getCode());
tradeBillsMapper.updateSelectiveByPrimaryKey(tradeBills);
// ?
OrdersPayTransfer transferSuccess = new OrdersPayTransfer();
transferSuccess.setId(transfer.getId());
transferSuccess.setAlipayTradeId(transferResult.getTradeNo());
transferSuccess.setStatus(1);
transferSuccess.setUpdateTime(DateUtil.getCurrentTimeSecond());
ordersPayTransferMapper.updateByPrimaryKeySelective(transferSuccess);
}else {
logger.warn("{}, transfer fail {}", logTag,transferResult);
throwServiceException(transferResult.getCode(), transferResult.getMsg());
}
}
private void transferWithAlipayExceedMillionTransfer(String logTag, TradeBills tradeBills, long orderCode, AuthorizeResultRespVO account, BigDecimal amount, OrdersPayTransfer transfer) {
String businessId = transfer.getId() + "_" + tradeBills.getId();
TransferResult transferResult = alipayService.newAlipayExceedMillionTransfer()
.transferOrderCode( Long.toString(orderCode))
... ... @@ -1258,32 +1192,6 @@ public class PaymentServiceImpl implements IPaymentService {
}
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"))) {
lastTransferDate = new SimpleDateFormat("yyyyMMdd").format(new Date());
logger.info("transferWhenExceedMillion 转账阿里接口返回 {},进入商家转账模式 lastTransferDate={}", jsonObject, lastTransferDate);
return true;
}
return false;
}
private boolean exceedMillion() {
boolean zkValue = configReader.getBoolean("ufo.order.pay.exceedSwitch", false);
logger.info("transferWhenExceedMillion ufo.order.pay.exceedSwitch={}", zkValue);
if (zkValue) {
return true;
}
String nowDate = new SimpleDateFormat("yyyyMMdd").format(new Date());
return StringUtils.equals(lastTransferDate, nowDate);
}
private volatile String lastTransferDate = null;
@Autowired
private ConfigReader configReader;
private OrdersPayTransfer checkTransferExist(long orderCode) {
// 查看是否已经有转账记录
... ... @@ -1325,28 +1233,45 @@ public class PaymentServiceImpl implements IPaymentService {
public PayQueryBo queryTransferResult(String buyerOrderCode) {
return alipayService.transferQuery(buyerOrderCode);
}
private void addTradeBills(TradeBills record) {
tradeBillsService.addTradeBills(record);
}
private AuthorizeResultRespVO getOneValidAlipayAccount(int targetUid) {
return getOneValidAlipayAccountOr(targetUid, invalidAccount -> {});
}
private AuthorizeResultRespVO getOneValidAlipayAccount(int targetUid) {
private AuthorizeResultRespVO getOneValidAlipayAccountOr(int targetUid, Consumer<String> invalidAccountHandler) {
ApiResponse<AuthorizeResultRespVO> resp = ufoServiceCaller.call("ufo.user.aliPayAccountQuery", ApiResponse.class, targetUid);
AuthorizeResultRespVO account = null;
if (resp != null) {
account = (AuthorizeResultRespVO) resp.getData();
}
if (account == null ||
(StringUtils.isBlank(account.getAlipayAccount()) && StringUtils.isBlank(account.getAlipayId()))
|| StringUtils.equals("invalid", account.getAlipayAccount())
|| StringUtils.equals("invalid", account.getAlipayId())) {
// 账户不存在
if (account == null) {
invalidAccountHandler.accept(null);
return null;
}
// 账户不存在
else if ((StringUtils.isBlank(account.getAlipayAccount()) && StringUtils.isBlank(account.getAlipayId()))) {
invalidAccountHandler.accept(null);
return null;
}
// 无效的支付宝账号
else if (StringUtils.contains(account.getAlipayAccount(), "invalid")) {
invalidAccountHandler.accept(account.getAlipayAccount());
return null;
}
return account;
// 无效的支付宝账号
else if (StringUtils.contains(account.getAlipayId(), "invalid")) {
invalidAccountHandler.accept(account.getAlipayId());
return null;
} else {
return account;
}
}
... ... @@ -1483,4 +1408,120 @@ public class PaymentServiceImpl implements IPaymentService {
}
private class TransferMoneyModel {
private TransferMoneyRequest request;
private long buyerOrderCode;
private String logTag;
private TransferCase transferCase;
private SellerOrder sellerOrder;
private long sellerOrderCode;
private TargetUserType targetUserType;
private Integer targetUid;
private int now;
public TransferMoneyModel(TransferMoneyRequest request) {
this.request = request;
}
public long getBuyerOrderCode() {
return buyerOrderCode;
}
public String getLogTag() {
return logTag;
}
public TransferCase getTransferCase() {
return transferCase;
}
public SellerOrder getSellerOrder() {
return sellerOrder;
}
public long getSellerOrderCode() {
return sellerOrderCode;
}
public TargetUserType getTargetUserType() {
return targetUserType;
}
public Integer getTargetUid() {
return targetUid;
}
public int getNow() {
return now;
}
public TransferMoneyModel invoke() {
logger.info("transferMon转账开始,request = {}", request);
buyerOrderCode = request.getBuyerOrderCode();
logTag = String.format("transfer money orderCode is %s", buyerOrderCode);
logger.info("transferMon参数检查");
// 订单号check
if (buyerOrderCode < 1L) {
logger.warn("transferMonErr orderCode empty");
throw new ServiceException(ServiceError.ORDER_REQUEST_PARM_IS_EMPTY);
}
// 类型检查
transferCase = TransferCase.getTransferCase(request.getType());
if (transferCase == null) {
logger.warn("transferMonErr transferType invalid");
throw new ServiceException(ServiceError.ORDER_REQUEST_PARM_IS_EMPTY);
}
// 买家订单检查
BuyerOrder buyerOrder = buyerOrderMapper.selectByOrderCode(buyerOrderCode);
if (buyerOrder == null) {
logger.warn("transferMonErr getOrderInfo buyer order not exist, orderCode is {}", buyerOrderCode);
throw new ServiceException(ServiceError.ORDER_NULL);
}
BuyerOrderGoods buyerOrderGoods = buyerOrderGoodsMapper.selectByOrderCode(buyerOrder.getUid(), buyerOrderCode);
if (buyerOrderGoods == null) {
logger.warn("transferMonErr buyerOrderGoods not exist, orderCode is {}", buyerOrderCode);
throw new ServiceException(ServiceError.ORDER_NULL);
}
// 卖家订单检查
Integer skup = buyerOrderGoods.getSkup();
sellerOrder = sellerOrderMapper.selectBySkup(skup);
if (sellerOrder == null){
logger.warn("transferMonErr getOrderInfo seller order not exist, skup is {}", buyerOrderGoods.getSkup());
throw new ServiceException(ServiceError.ORDER_NULL);
}
Integer sellerUid = sellerOrder.getUid();
sellerOrderCode = sellerOrder.getOrderCode();
targetUserType = transferCase == EARNEST_MONEY_TO_BUYER ? TargetUserType.buyer : TargetUserType.seller;
targetUid = targetUserType == TargetUserType.buyer ? buyerOrder.getUid() : sellerUid;
if (targetUid == null || targetUid < 1) {
logger.warn("transferMonErr uid {} 不合法", targetUid);
throw new ServiceException(400, "uid[" + targetUid + "]不合法");
}
now = (int) (System.currentTimeMillis() / 1000);
// 查看是否已经有转账记录
checkTransferExist(buyerOrderCode);
return this;
}
public TradeBills newTradeBills(){
// 增加流水记录
TradeBills record = new TradeBills();
record.setUid(targetUid);
record.setOrderCode(buyerOrderCode);
record.setUserType(targetUserType.getCode());
record.setPayType(1);
// 如果[全部货款->卖家],否则[补偿款->卖家或买家] 2:货款;3:补偿款
record.setTradeType(transferCase == TransferCase.ALL_GOODS_MONEY_TO_SELLER ? 2 : 3);
record.setIncomeOutcome(1);
record.setTradeStatus(BillTradeStatus.NEW.getCode());
record.setCreateTime(now);
return record;
}
}
}
... ...
package com.yohoufo.order.service.transfer;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.yoho.core.redis.cluster.annotation.Redis;
import com.yoho.core.redis.cluster.operations.nosync.YHValueOperations;
import com.yoho.core.redis.cluster.operations.serializer.RedisKeyBuilder;
import com.yohoufo.common.utils.DateUtil;
import com.yohoufo.dal.order.BuyerOrderGoodsMapper;
import com.yohoufo.dal.order.TradeBillsMapper;
import com.yohoufo.dal.order.model.BuyerOrderGoods;
import com.yohoufo.dal.order.model.TradeBills;
import com.yohoufo.dal.product.ProductMapper;
import com.yohoufo.dal.product.StoragePriceMapper;
import com.yohoufo.dal.product.model.Product;
import com.yohoufo.dal.product.model.StoragePrice;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import static com.yohoufo.order.common.BillTradeStatus.HK_AMOUNT_PAYING;
import static com.yohoufo.order.common.BillTradeStatus.HK_AMOUNT_WAIT_PAYMENT;
@Slf4j
@Service
public class HkAccountSettlement {
@Autowired
private TradeBillsMapper tradeBillsMapper;
@Autowired
private BuyerOrderGoodsMapper buyerOrderGoodsMapper;
@Autowired
private StoragePriceMapper storagePriceMapper;
@Autowired
private ProductMapper productMapper;
@Redis("gwNoSyncRedis")
private YHValueOperations valueOperations;
public void settle(Integer uid) {
log.info("{} settle start", uid);
int dealTime = DateUtil.getCurrentTimeSecond();
RedisKeyBuilder redisLockKey = RedisKeyBuilder.newInstance()
.appendFixed("ufo:order:hkAccount:settle:")
.appendVar(uid + "-" + dealTime);
String redisLockValue = "Y";
if (redisLockValue.equals(valueOperations.get(redisLockKey))) {
log.info("{} settle fail, it already in the process", uid);
return;
}
valueOperations.set(redisLockKey, redisLockValue, 5, TimeUnit.SECONDS);
// 没有要打款的账单
if (!tryLock(uid, dealTime)) {
log.info("{} settle fail, it already in the process", uid);
return;
}
List<TradeBills> tradeBills = tradeBillsMapper.selectByUidTradeStatusAndDealTime(uid, HK_AMOUNT_PAYING.getCode(), dealTime);
Integer sumIncome = tradeBills.stream().mapToInt(TradeBills::getIncomeOutcome).sum();
log.info("{} settle, sum income is {}", uid, sumIncome);
// 满足打款条件,通知财务打款
if (sumIncome > 100) {
try {
log.info("{} settle, send email", uid, sumIncome);
List<TradeBillResult> tradeBillResults = getTradeBillResults(uid, tradeBills);
// 差异订单
Set<Long> tradeBillOrderCodes = tradeBills.stream().map(TradeBills::getOrderCode).collect(Collectors.toSet());
Set<Long> tradeBillResultOrderCodes = tradeBillResults.stream().map(TradeBillResult::getOrderCode).collect(Collectors.toSet());
Sets.SetView<Long> difference = Sets.difference(tradeBillOrderCodes, tradeBillResultOrderCodes);
log.info("{} settle, difference is {}", uid, difference);
// 通知财务打款
tradeBillResults.forEach(tradeBillResult -> log.info("{} settle, item {}", uid, tradeBillResult));
} catch (Exception e) {
// 通知失败
log.info("{} settle, send email fail", uid, sumIncome);
releaseLockWithRetry(uid, dealTime);
}
}
// 不满足打款条件
else {
releaseLockWithRetry(uid, dealTime);
}
}
private List<TradeBillResult> getTradeBillResults(Integer uid, List<TradeBills> tradeBills) {
List<Long> orderCodes = tradeBills.stream().map(TradeBills::getOrderCode).collect(Collectors.toList());
List<BuyerOrderGoods> buyerOrderGoodsList = buyerOrderGoodsMapper.selectByOrderCodes(orderCodes);
List<Integer> skups = buyerOrderGoodsList.stream().map(BuyerOrderGoods::getSkup).collect(Collectors.toList());
List<StoragePrice> storagePrices = storagePriceMapper.selectBySkupList(skups);
List<Integer> productIds = storagePrices.stream().map(StoragePrice::getProductId).collect(Collectors.toList());
List<Product> products = productMapper.selectByIds(productIds);
List<TradeBillResult> tradeBillResults = Lists.newArrayList();
tradeBills.forEach(tradeBill -> {
getBuyerOrderGoods(tradeBill, buyerOrderGoodsList)
.ifPresent(buyerOrderGoods -> {
getStoragePrice(buyerOrderGoods, storagePrices).ifPresent(storagePrice -> {
getProduct(storagePrice, products).ifPresent(product -> {
TradeBillResult billResult = TradeBillResult.builder()
.uid(uid)
.orderCode(buyerOrderGoods.getOrderCode())
.productNo(product.getProductCode())
.productName(product.getProductName())
.rate(BigDecimal.ZERO)
.platformServiceAmount(tradeBill.getSystemAmount())
.payAmount(BigDecimal.valueOf(tradeBill.getIncomeOutcome()))
.payType(tradeBill.getTradeType() == 1 ? "保证金"
: tradeBill.getTradeType() == 2 ? "货款"
: tradeBill.getTradeType() == 3 ? "补偿款" : "")
.build();
tradeBillResults.add(billResult);
});
});
});
});
return tradeBillResults;
}
@Getter
@Setter
@Builder
private static class TradeBillResult {
private Integer uid;
// 订单编号
private Long orderCode;
// 商品货号
private String productNo;
// 商品名称
private String productName;
// 税费
private BigDecimal rate;
//平台服务费
private BigDecimal platformServiceAmount;
// 打款金额
private BigDecimal payAmount;
// 金额类型:货款
private String payType;
}
private Optional<BuyerOrderGoods> getBuyerOrderGoods(TradeBills tradeBills, List<BuyerOrderGoods> buyerOrderGoodsList) {
return buyerOrderGoodsList.stream()
.filter(e -> e.getOrderCode().equals(tradeBills.getOrderCode()))
.findAny();
}
private Optional<StoragePrice> getStoragePrice(BuyerOrderGoods buyerOrderGoods, List<StoragePrice> storagePrices) {
return storagePrices.stream()
.filter(e -> e.getSkup().equals(buyerOrderGoods.getSkup()))
.findAny();
}
private Optional<Product> getProduct(StoragePrice storagePrice, List<Product> products) {
return products.stream()
.filter(e -> e.getId().equals(storagePrice.getProductId()))
.findAny();
}
private boolean tryLock(Integer uid, int dealTime) {
return tradeBillsMapper.updateLockOfUidTradeStatusAndDealTime(
uid,
HK_AMOUNT_WAIT_PAYMENT.getCode(), 0,
HK_AMOUNT_PAYING.getCode(), dealTime) > 0;
}
private void releaseLock(Integer uid, int dealTime) {
tradeBillsMapper.updateLockOfUidTradeStatusAndDealTime(
uid,
HK_AMOUNT_PAYING.getCode(), dealTime,
HK_AMOUNT_WAIT_PAYMENT.getCode(), 0);
}
private void releaseLockWithRetry(Integer uid, int dealTime) {
try {
releaseLock(uid, dealTime);
} catch (Exception e) {
try {
releaseLock(uid, dealTime);
} catch (Exception e1) {
log.info("{} settle, release lock fail deal time is {}", uid, dealTime);
}
}
}
}
... ...
... ... @@ -69,6 +69,11 @@ consumer:
topic: ufo.couponSendWithTradeMqNotify
ratelimit: 20
# 香港卖家待结算
- class: com.yohoufo.order.mq.consumer.HkAmountWaitPaymentMessageConsummer
topic: order.hkAmountWaitPayment
ratelimit: 20
- address: ${rabbit_ufo}
username: ${rabbit_ufo_user}
... ...