Authored by LUOXC

Merge branch 'dev6.8.6' into test6.8.6

... ... @@ -14,7 +14,8 @@ public enum TransferCase {
ALL_GOODS_MONEY_TO_SELLER(1, "货款->卖家"),
EARNEST_MONEY_TO_BUYER(3,"保证金->买家"),
PART_GOODS_MONEY_TO_SELLER(6,"部分货款->卖家");
PART_GOODS_MONEY_TO_SELLER(6,"部分货款->卖家"),
PART_EARNEST_MONEY_TO_BUYER(7,"部分保证金->买家");
private int code;
private String info;
... ...
... ... @@ -10,6 +10,21 @@ import java.math.BigDecimal;
public class PenaltyResult {
private PenaltyRule penaltyRule;
/**
* 总金额
*/
private BigDecimal totalAmount;
/**
* 惩罚金额(包括服务费)
*/
private BigDecimal penaltyAmount;
/**
* 有货服务费
*/
private BigDecimal yhServiceAmount;
/**
* 剩余金额
*/
private BigDecimal leftAmount;
}
... ...
... ... @@ -27,6 +27,9 @@ public class SellerEarnestMoney2BuyerPenaltyCalculator implements PenaltyCalcula
@Setter
@Accessors(fluent = true)
private Supplier<Integer> diffTimeSupplier;
@Setter
@Accessors(fluent = true)
private boolean penaltyPartEarnestMoney;
SellerEarnestMoney2BuyerPenaltyCalculator(Integer uid, Integer skup, JSONObject fee) {
this.uid = uid;
... ... @@ -74,17 +77,23 @@ public class SellerEarnestMoney2BuyerPenaltyCalculator implements PenaltyCalcula
return new SellerEarnestMoney2BuyerPenaltyRuleSelector(uid, skup, fee)
.diffTimeSupplier(diffTimeSupplier)
.penaltyPartEarnestMoney(penaltyPartEarnestMoney)
.select()
.map(penaltyRule -> {
BigDecimal penaltyAmount = penaltyRule.getExt().getBigDecimal("prePenaltyAmount").multiply(penaltyRule.getPenaltyRate());
BigDecimal penaltyAmount = penaltyRule.getExt().getBigDecimal("prePenaltyAmount")
.multiply(penaltyRule.getPenaltyRate());
if (penaltyAmount.compareTo(minPenaltyAmount) < 0) {
penaltyAmount = minPenaltyAmount;
} else if (penaltyAmount.compareTo(maxPenaltyAmount) > 0) {
penaltyAmount = maxPenaltyAmount;
}
BigDecimal yhServiceRate = penaltyRule.getExt().getBigDecimal("yhServiceRate");
return PenaltyResult.builder()
.penaltyRule(penaltyRule)
.totalAmount(ensure.setScale(2, ROUND_HALF_UP))
.penaltyAmount(penaltyAmount.setScale(2, ROUND_HALF_UP))
.yhServiceAmount(penaltyAmount.multiply(yhServiceRate).setScale(2, ROUND_HALF_UP))
.leftAmount(ensure.subtract(penaltyAmount).setScale(2, ROUND_HALF_UP))
.penaltyRule(penaltyRule)
.build();
}
);
... ...
... ... @@ -6,6 +6,7 @@ import com.yohoufo.order.utils.LoggerUtils;
import lombok.Setter;
import lombok.experimental.Accessors;
import lombok.val;
import org.apache.commons.lang3.tuple.Pair;
import org.slf4j.Logger;
import java.math.BigDecimal;
... ... @@ -23,6 +24,9 @@ public class SellerEarnestMoney2BuyerPenaltyRuleSelector implements PenaltyRuleS
@Setter
@Accessors(fluent = true)
private Supplier<Integer> diffTimeSupplier;
@Setter
@Accessors(fluent = true)
private boolean penaltyPartEarnestMoney;
SellerEarnestMoney2BuyerPenaltyRuleSelector(Integer uid, Integer skup, JSONObject fee) {
this.uid = uid;
... ... @@ -38,8 +42,35 @@ public class SellerEarnestMoney2BuyerPenaltyRuleSelector implements PenaltyRuleS
*/
@Override
public Optional<PenaltyRule> select() {
BigDecimal penaltyRate;
BigDecimal prePenaltyAmount;
// 平台服务费
JSONObject serviceFeeRate = fee.getJSONObject("serviceFeeRate");
if (Objects.isNull(serviceFeeRate)) {
logger.warn("feeMeta serviceFeeRate is null, uid is {}, skup is {}", uid, skup);
return Optional.empty();
}
BigDecimal yhServiceRate = serviceFeeRate.getBigDecimal("earnestMoneyRate");
if (Objects.isNull(yhServiceRate) || yhServiceRate.compareTo(BigDecimal.ZERO) < 0 || yhServiceRate.compareTo(BigDecimal.ONE) > 0) {
logger.warn("feeMeta serviceFeeRate earnestMoneyRate err, uid is {}, skup is {}, rate is {}", uid, skup, yhServiceRate);
return Optional.empty();
}
return getPenaltyRate()
.map(penaltyRate -> PenaltyRule.builder()
.penaltyRate(penaltyRate.getRight())
.ext(new JSONObject()
.fluentPut("prePenaltyAmount", penaltyRate.getLeft())
.fluentPut("yhServiceRate", yhServiceRate))
.build());
}
private Optional<Pair<BigDecimal, BigDecimal>> getPenaltyRate() {
if (!penaltyPartEarnestMoney) {
val ensure = fee.getJSONObject("earnestMoney").getBigDecimal("earnestMoney");
if (Objects.isNull(ensure) || ensure.compareTo(BigDecimal.ZERO) < 0) {
logger.warn("calculate info err, uid is {}, skup is {}, ensure is {}", uid, skup, ensure);
return Optional.empty();
}
return Optional.of(Pair.of(ensure, BigDecimal.ONE));
}
JSONObject penaltyFeeRate = getPenaltyFeeRate();
if (Objects.nonNull(penaltyFeeRate)) {
val prdSalePrice = fee.getJSONObject("earnestMoney").getBigDecimal("prdSalePrice");
... ... @@ -47,37 +78,16 @@ public class SellerEarnestMoney2BuyerPenaltyRuleSelector implements PenaltyRuleS
logger.warn("calculate info err, uid is {}, skup is {}, sale price is {}", uid, skup, prdSalePrice);
return Optional.empty();
}
penaltyRate = penaltyFeeRate.getBigDecimal("rate");
prePenaltyAmount = prdSalePrice;
return Optional.of(Pair.of(prdSalePrice, penaltyFeeRate.getBigDecimal("rate")));
} else {
val ensure = fee.getJSONObject("earnestMoney").getBigDecimal("earnestMoney");
if (Objects.isNull(ensure) || ensure.compareTo(BigDecimal.ZERO) < 0) {
logger.warn("calculate info err, uid is {}, skup is {}, ensure is {}", uid, skup, ensure);
return Optional.empty();
}
penaltyRate = BigDecimal.ONE;
prePenaltyAmount = ensure;
}
if (Objects.isNull(penaltyRate)) {
logger.warn("feeMeta penaltyRate is null, uid is {}, skup is {}", uid, skup);
return Optional.empty();
return Optional.of(Pair.of(ensure, BigDecimal.ONE));
}
// 平台服务费
JSONObject serviceFeeRate = fee.getJSONObject("serviceFeeRate");
if (Objects.isNull(serviceFeeRate)) {
logger.warn("feeMeta serviceFeeRate is null, uid is {}, skup is {}", uid, skup);
return Optional.empty();
}
BigDecimal yhRate = serviceFeeRate.getBigDecimal("earnestMoneyRate");
if (Objects.isNull(yhRate) || yhRate.compareTo(BigDecimal.ZERO) < 0 || yhRate.compareTo(BigDecimal.ONE) > 0) {
logger.warn("feeMeta serviceFeeRate earnestMoneyRate err, uid is {}, skup is {}, rate is {}", uid, skup, yhRate);
return Optional.empty();
}
return Optional.of(penaltyRate.subtract(yhRate))
.map(realPenaltyRate -> PenaltyRule.builder()
.penaltyRate(realPenaltyRate)
.ext(new JSONObject().fluentPut("prePenaltyAmount", prePenaltyAmount))
.build());
}
private JSONObject getPenaltyFeeRate() {
... ...
... ... @@ -461,6 +461,7 @@ public class AppraiseService {
SellerOrderGoods sellerOrderGoods = updateSellerOrderStatusAndCleanCache(sellerUid ,sellerOrderCode,expectSOStatus,targetSoStatus,
skup, orderCode, buyerUid);
// TODO 卖家保证金分账给平台和买家
//将卖家的保证金分账给平台和买家
TransferCase transferCase = TransferCase.EARNEST_MONEY_TO_BUYER;
TransferMoneyRequest tmReq = TransferMoneyRequest.builder()
... ...
... ... @@ -218,6 +218,7 @@ class BuyerOrderCancelHandler {
if (Objects.isNull(transferService)) {
return;
}
// TODO 卖家保证金分账给平台和买家
val transferMoneyRequest = TransferMoneyRequest.builder()
.sellerUid(sellerUid)
.buyerOrderCode(orderCode)
... ...
... ... @@ -10,6 +10,7 @@ import com.yohobuy.ufo.model.order.bo.MerchantOrderAttachInfo;
import com.yohobuy.ufo.model.order.bo.OrderInfo;
import com.yohobuy.ufo.model.order.common.OrderAttributes;
import com.yohobuy.ufo.model.order.common.OrderCodeType;
import com.yohobuy.ufo.model.order.common.OrderStatus;
import com.yohobuy.ufo.model.order.constants.OrderConstant;
import com.yohobuy.ufo.model.order.req.ManualDealRequest;
import com.yohobuy.ufo.model.user.resp.AuthorizeResultRespVO;
... ... @@ -18,6 +19,7 @@ import com.yohoufo.common.caller.UfoServiceCaller;
import com.yohoufo.common.utils.TimeUtils;
import com.yohoufo.dal.order.*;
import com.yohoufo.dal.order.model.*;
import com.yohoufo.order.common.BillTradeStatus;
import com.yohoufo.order.common.Payment;
import com.yohoufo.order.common.TransferCase;
import com.yohoufo.order.constants.RefundContant;
... ... @@ -59,6 +61,7 @@ import java.util.Date;
import java.util.Objects;
import static com.yohoufo.order.common.TransferCase.EARNEST_MONEY_TO_BUYER;
import static com.yohoufo.order.common.TransferCase.PART_EARNEST_MONEY_TO_BUYER;
@Service
... ... @@ -141,6 +144,10 @@ public class PaymentServiceImpl implements IPaymentService {
@Autowired
BuyerOrderPayDiffTimeHandler buyerOrderPayDiffTimeHandler;
@Autowired
private TradeBillsService tradeBillsService;
/**
* 获取主场的订单service
* @param codeMeta
... ... @@ -535,7 +542,7 @@ public class PaymentServiceImpl implements IPaymentService {
Integer sellerUid = sellerOrder.getUid();
long sellerOrderCode = sellerOrder.getOrderCode();
punishEarnest(request.getSwdType(), sellerOrder);
val targetUserType = transferCase == EARNEST_MONEY_TO_BUYER ? TargetUserType.buyer : TargetUserType.seller;
val targetUserType = (transferCase == EARNEST_MONEY_TO_BUYER || transferCase == PART_EARNEST_MONEY_TO_BUYER) ? TargetUserType.buyer : TargetUserType.seller;
val targetUid = targetUserType == TargetUserType.buyer ? buyerOrder.getUid() : sellerUid;
if (targetUid == null || targetUid < 1) {
... ... @@ -584,8 +591,7 @@ public class PaymentServiceImpl implements IPaymentService {
logger.info("transferMon参数检查成功!插入初始化转账信息成功,接下来计算费用");
TranseferCellNode transeferCellNode = request.getTranseferCellNode();
// 算费
BigDecimal transferAmount = calcTransferAmount(buyerOrder,sellerOrder.getUid(),
sellerOrder.getSkup(), transferCase, transeferCellNode);
BigDecimal transferAmount = calcTransferAmount(buyerOrder,sellerOrder, transferCase, transeferCellNode);
logger.info("transferMon计算费用结果为 {}", transferAmount);
if (transferAmount == null) {
logger.warn("transferMonErr transferMon计算费用结果为 null, 不合法的金额");
... ... @@ -1161,31 +1167,44 @@ public class PaymentServiceImpl implements IPaymentService {
record.setCreateTime((int) (System.currentTimeMillis() / 1000));
addTradeBills(record);
}
private BigDecimal calcTransferAmount(BuyerOrder buyerOrder,Integer sellerUid, Integer skup,
TransferCase transferCase,TranseferCellNode transeferCellNode) {
private BigDecimal calcTransferAmount(BuyerOrder buyerOrder, SellerOrder sellerOrder,
TransferCase transferCase, TranseferCellNode transeferCellNode) {
Integer sellerUid = sellerOrder.getUid();
Integer skup = sellerOrder.getSkup();
if (transferCase == TransferCase.PART_GOODS_MONEY_TO_SELLER) {
return transeferCellNode.getAmount();
}
SellerOrderMeta meta = sellerOrderMetaMapper.selectByMetaKey(sellerUid, skup, "fee");
try {
// 交易成功的情况:货款->卖家
if (transferCase == TransferCase.ALL_GOODS_MONEY_TO_SELLER) {
}
SellerOrderMeta meta = sellerOrderMetaMapper.selectByMetaKey(sellerUid, skup, "fee");
try {
// 交易成功的情况:货款->卖家
if (transferCase == TransferCase.ALL_GOODS_MONEY_TO_SELLER) {
return getSaleIncome(sellerUid, skup, meta);
}
return SellerEarnestMoney2BuyerPenaltyCalculator.from(meta)
PenaltyResult penaltyResult = SellerEarnestMoney2BuyerPenaltyCalculator.from(meta)
.diffTimeSupplier(() -> buyerOrderPayDiffTimeHandler.diffTime(buyerOrder.getUid(), buyerOrder.getOrderCode()))
.penaltyPartEarnestMoney(transferCase == PART_EARNEST_MONEY_TO_BUYER)
.calculate()
.map(PenaltyResult::getPenaltyAmount)
.orElse(null);
} catch (Exception e) {
logger.warn("计费信息不完整, sellerUid is {}, skup is {}, err is {}", sellerUid, skup, e.getMessage());
throw new ServiceException(500, "计费信息不完整");
}
}
if (Objects.nonNull(penaltyResult)) {
// 退剩余保证金
BigDecimal backEarnestMoney = penaltyResult.getLeftAmount();
try {
tradeBillsService.backPayEnsureRecord(sellerUid, skup, sellerOrder.getOrderCode(), sellerOrder.getPayment(), BillTradeStatus.FAIL.getCode(), backEarnestMoney, meta);
} catch (Exception e) {
logger.warn("返回剩余保证金失败, sellerUid is {}, skup is {}, err is {}", sellerUid, skup, e.getMessage());
}
// 赔偿给买家的保证金金额
return penaltyResult.getPenaltyAmount().subtract(penaltyResult.getYhServiceAmount());
} else {
return null;
}
} catch (Exception e) {
logger.warn("计费信息不完整, sellerUid is {}, skup is {}, err is {}", sellerUid, skup, e.getMessage());
throw new ServiceException(500, "计费信息不完整");
}
}
private BigDecimal getSaleIncome(Integer sellerUid, Integer skup, SellerOrderMeta meta) {
if (meta == null) {
... ...
... ... @@ -490,7 +490,7 @@ public class SellerOrderCancelService {
.skup(sellerOrder.getSkup());
//分赃(分账) 有待考虑使用2比对
TransferCase transferCase = TransferCase.EARNEST_MONEY_TO_BUYER;
TransferCase transferCase = TransferCase.PART_EARNEST_MONEY_TO_BUYER;
TransferMoneyRequest tmReq = TransferMoneyRequest.builder()
.sellerUid(sellerUid)
.buyerOrderCode(buyerOrderCode)
... ...
... ... @@ -13,6 +13,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.Objects;
/**
* Created by chenchao on 2018/10/10.
... ... @@ -30,6 +31,7 @@ public class TradeBillsService {
/**
* 退保证金流水记录
*
* @param uid
* @param skup
* @param orderCode
... ... @@ -37,12 +39,20 @@ public class TradeBillsService {
* @param tradeStatus
*/
public void backPayEnsureRecord(Integer uid, Integer skup, Long orderCode,
Integer payType, Integer tradeStatus) {
if(payType != null && Payment.WALLET.getCode() == payType){
Integer payType, Integer tradeStatus) {
backPayEnsureRecord(uid, skup, orderCode, payType, tradeStatus, null, null);
}
public void backPayEnsureRecord(Integer uid, Integer skup, Long orderCode,
Integer payType, Integer tradeStatus,
BigDecimal backEarnestMoney, SellerOrderMeta meta) {
if (payType != null && Payment.WALLET.getCode() == payType) {
return;
}
SellerOrderMeta meta = sellerOrderMetaMapper.selectByMetaKey(uid, skup, "fee");
if (meta == null) {
if (Objects.isNull(meta)) {
meta = sellerOrderMetaMapper.selectByMetaKey(uid, skup, "fee");
}
if (Objects.isNull(meta)) {
logger.error("PayRecordErr记录交易到数据库出错 err=meta费率信息未查到, uid = {}, skup={}", uid, skup);
return;
}
... ... @@ -54,17 +64,17 @@ public class TradeBillsService {
record.setPayType(payType);// 1:支付宝; 2:微信
record.setTradeType(1);//1:保证金;2:货款;3:补偿款
record.setIncomeOutcome(1);// 1:用户收入; 2:用户支出
BigDecimal earnestMoney = BigDecimal.ZERO;
BigDecimal earnestMoney = backEarnestMoney;
BigDecimal amount = BigDecimal.ZERO;
try {
JSONObject metavalue = JSON.parseObject(meta.getMetaValue());
BigDecimal rate = metavalue.getJSONObject("serviceFeeRate").getBigDecimal("payChannelRate");
earnestMoney = metavalue.getJSONObject("earnestMoney").getBigDecimal("earnestMoney");
if (Objects.isNull(earnestMoney)) {
earnestMoney = metavalue.getJSONObject("earnestMoney").getBigDecimal("earnestMoney");
}
amount = earnestMoney.multiply(BigDecimal.ONE.subtract(rate)).multiply(new BigDecimal("-1")).setScale(2, BigDecimal.ROUND_HALF_UP);
} catch (Exception e) {
logger.error("PayRecordErr计费信息不完整, uid is {}, skup is {}, err is {}", uid, skup, e.getMessage());
// return;
}
record.setAmount(earnestMoney);
record.setSystemAmount(amount);// 有货收入
... ... @@ -75,6 +85,7 @@ public class TradeBillsService {
/**
* 退付货款流水记录
*
* @param uid
* @param sellerUid
* @param skup
... ... @@ -87,7 +98,7 @@ public class TradeBillsService {
Long orderCode, Integer payType, BigDecimal amount,
Integer tradeStatus) {
if(payType != null && Payment.WALLET.getCode() == payType){
if (payType != null && Payment.WALLET.getCode() == payType) {
return;
}
... ...
... ... @@ -44,7 +44,8 @@ public class TransferService {
}
try{
Integer sellerUid;
if(Objects.nonNull(sellerUid=req.getSellerUid()) && Objects.equals(transferCase, TransferCase.EARNEST_MONEY_TO_BUYER)) {
if(Objects.nonNull(sellerUid=req.getSellerUid())
&& (Objects.equals(transferCase, TransferCase.EARNEST_MONEY_TO_BUYER) || Objects.equals(transferCase, TransferCase.PART_EARNEST_MONEY_TO_BUYER))) {
logger.info("ready 2 processAfterWalletChange req {} sellerUid {}", req, sellerUid);
sellerService.processAfterWalletChange(sellerUid);
}
... ...
... ... @@ -33,9 +33,9 @@ public class SellerEarnestMoney2BuyerPenaltyCalculatorTest {
feeMeta.setMetaKey("fee");
feeMeta.setMetaValue(feeMetaValue.toJSONString());
PenaltyResult penaltyResult = SellerEarnestMoney2BuyerPenaltyCalculator.from(feeMeta).calculate().orElse(null);
assertBigDecimalEquals(BigDecimal.valueOf(0.99), penaltyResult.getPenaltyRule().getPenaltyRate());
assertBigDecimalEquals(BigDecimal.valueOf(1), penaltyResult.getPenaltyRule().getPenaltyRate());
// earnestMoney * (1 - earnestMoneyRate)
assertBigDecimalEquals(BigDecimal.valueOf(9.9), penaltyResult.getPenaltyAmount());
assertBigDecimalEquals(BigDecimal.valueOf(10), penaltyResult.getPenaltyAmount());
}
@Test
... ... @@ -65,6 +65,7 @@ public class SellerEarnestMoney2BuyerPenaltyCalculatorTest {
feeMeta.setMetaValue(feeMetaValue.toJSONString());
PenaltyResult penaltyResult = SellerEarnestMoney2BuyerPenaltyCalculator.from(feeMeta)
.diffTimeSupplier(() -> 3600)
.penaltyPartEarnestMoney(true)
.calculate()
.orElse(null);
assertBigDecimalEquals(BigDecimal.valueOf(0.04), penaltyResult.getPenaltyRule().getPenaltyRate());
... ... @@ -73,6 +74,7 @@ public class SellerEarnestMoney2BuyerPenaltyCalculatorTest {
// 86401 s后
PenaltyResult penaltyResult86401 = SellerEarnestMoney2BuyerPenaltyCalculator.from(feeMeta)
.diffTimeSupplier(() -> 86401)
.penaltyPartEarnestMoney(true)
.calculate()
.orElse(null);
assertBigDecimalEquals(BigDecimal.valueOf(0.08), penaltyResult86401.getPenaltyRule().getPenaltyRate());
... ...