Authored by chenchao

Merge branch 'dev_order_6.8.6' into test6.8.6

... ... @@ -15,7 +15,7 @@ import com.yohoufo.dal.order.model.SellerOrder;
import com.yohoufo.order.model.request.OrderListRequest;
import com.yohoufo.order.model.request.OrderRequest;
import com.yohoufo.order.model.response.OrderSubmitResp;
import com.yohoufo.order.service.handler.SellerOrderComputeHandler;
import com.yohoufo.order.service.impl.OrderDynamicConfig;
import com.yohoufo.order.service.impl.SellerOrderService;
import com.yohoufo.order.service.impl.SellerService;
import com.yohoufo.order.service.impl.SkupListService;
... ... @@ -44,7 +44,7 @@ public class SellerOrderController {
private SellerOrderService sellerOrderService;
@Autowired
private SellerOrderComputeHandler sellerOrderComputeHandler;
protected OrderDynamicConfig orderDynamicConfig;
@Autowired
private SellerService sellerService;
... ... @@ -211,7 +211,7 @@ public class SellerOrderController {
@ResponseBody
public ApiResponse getEarnestMoneyRange(){
return new ApiResponse.ApiResponseBuilder()
.data(sellerOrderComputeHandler.getEarnestMoneyrange())
.data(orderDynamicConfig.getEMR())
.message("get EarnestMoneyrange success").build();
}
... ... @@ -231,7 +231,8 @@ public class SellerOrderController {
public ApiResponse batchChangePrice(@RequestParam(name = "uid", required = true)int uid,
@RequestParam(name = "price", required = true)String price,
@RequestParam(name = "batchNo", required = true)String batchNo,
@RequestParam(name = "skupList", required = true)String skupList
@RequestParam(name = "skupList", required = true)String skupList,
@RequestParam(name="skupType", defaultValue = DEFAULT_SKUP_TYPE, required = false) Integer skupType
) throws GatewayException {
... ... @@ -241,6 +242,7 @@ public class SellerOrderController {
req.setShowPriceError(true);
req.setBatchNo(batchNo);
req.setSkupList(skupList);
req.setSkupType(skupType);
logger.info("in ufo.sellerOrder.batchChangePrice, req {}", req);
BatchChangePriceResp result = sellerOrderService.batchChangePrice(req);
... ... @@ -269,7 +271,8 @@ public class SellerOrderController {
@RequestParam(name="price", required = true)String price,
@RequestParam(name = "batchNo", required = false)String batchNo,
@RequestParam(name = "skupList", required = false)String skupList,
@RequestParam(name="num", defaultValue = "1", required = false)int num) throws GatewayException {
@RequestParam(name="num", defaultValue = "1", required = false)int num,
@RequestParam(name="skupType", defaultValue = DEFAULT_SKUP_TYPE, required = false) Integer skupType) throws GatewayException {
BatchChangePriceReq req = new BatchChangePriceReq();
req.setStorageId(storage_id);
... ... @@ -278,6 +281,7 @@ public class SellerOrderController {
req.setBatchNo(batchNo);
req.setSkupList(skupList);
req.setShowPriceError(false);
req.setSkupType(skupType);
logger.info("in ufo.sellerOrder.computeChangePrice, req {}", req);
SoldPrdComputeBo computeBo = sellerOrderService.computeChangePrice(req);
return new ApiResponse.ApiResponseBuilder().code(200).data(computeBo).message("算费成功").build();
... ... @@ -303,7 +307,9 @@ public class SellerOrderController {
@RequestParam(name = "old_price") BigDecimal old_price,
@RequestParam(name = "new_price") String new_price,
@RequestParam(name = "product_id") int product_id,
@RequestParam(name = "num") int num) throws GatewayException {
@RequestParam(name = "num") int num,
@RequestParam(name="skupType", defaultValue = DEFAULT_SKUP_TYPE, required = false) Integer skupType
) throws GatewayException {
SellerBatchChangeReq req = new SellerBatchChangeReq();
req.setStorageId(storage_id);
req.setUid(uid);
... ... @@ -312,6 +318,7 @@ public class SellerOrderController {
req.setProductId(product_id);
req.setNum(num);
req.setShowPriceError(false);
req.setSkupType(skupType);
logger.info("in ufo.sellerOrder.computeAdjustPrice, req {}", req);
try {
SoldPrdComputeBo computeBo = sellerOrderService.computeAdjustPrice(req);
... ...
package com.yohoufo.order.service.handler;
import com.yohoufo.common.utils.BigDecimalHelper;
import com.yohoufo.order.model.dto.EarnestMoney;
import com.yohoufo.order.model.dto.PlatformFeeDto;
import com.yohoufo.order.model.dto.SellerOrderComputeResult;
import com.yohoufo.order.model.dto.ServiceFeeRate;
import com.yohoufo.order.utils.LoggerUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import com.yohoufo.order.service.seller.AbsSellerOrderComputeHandler;
import com.yohoufo.order.service.seller.OrderComputeHandler;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.math.BigDecimal;
/**
* Created by chenchao on 2018/9/14.
*/
@Component
public class SellerOrderComputeHandler {
private Logger logger = LoggerUtils.getSellerOrderLogger();
@Value("${order.seller.earnestmoney.min:28}")
private double earnestmoney_min;
@Value("${order.seller.earnestmoney.max:200}")
private double earnestmoney_max;
private BigDecimal[] EARNESTMONEYRANGE = new BigDecimal[2];
@Value("${order.seller.appraiseFee:5}")
private Double appraiseFee;
/**
* 有货包装费(暂定5元)
*/
@Value("${order.seller.packageFee:5}")
private Double packageFee ;
@Value("${order.seller.goodsPaymentRate}")
private Double goodsPaymentRate = 0.05D;
@Value("${order.seller.earnestMoneyRate}")
private Double earnestMoneyRate = 0.20D;
@Value("${order.seller.payChannelRate}")
private Double payChannelRate = 0.006D;
@PostConstruct
public void init(){
EARNESTMONEYRANGE[0] = new BigDecimal(earnestmoney_min);
EARNESTMONEYRANGE[1] = new BigDecimal(earnestmoney_max);
}
public BigDecimal[] getEarnestMoneyrange(){
return EARNESTMONEYRANGE;
}
public SellerOrderComputeResult compute(BigDecimal prdPrice){
//保证金(28-200(按照卖家发布商品的货款金额5%计算,最低28,封顶200))
EarnestMoney earnestMoney = calEarnestMoney(prdPrice);
//init fee rate
ServiceFeeRate serviceFeeRate = new ServiceFeeRate();
serviceFeeRate.setGoodsPaymentRate(new BigDecimal(goodsPaymentRate).setScale(2, BigDecimal.ROUND_HALF_UP));
serviceFeeRate.setEarnestMoneyRate(new BigDecimal(earnestMoneyRate).setScale(2, BigDecimal.ROUND_HALF_UP));
serviceFeeRate.setPayChannelRate(new BigDecimal(payChannelRate).setScale(4, BigDecimal.ROUND_HALF_UP));
//
PlatformFeeDto platformFeeDto = calPlatformFee(prdPrice, serviceFeeRate.getGoodsPaymentRate());
BigDecimal bankTransferFee = calBankTransferFee(prdPrice, serviceFeeRate.getPayChannelRate());
logger.info("in SellerOrder Compute, prdPrice {}, platformFee {}, bankTransferFee {}",
prdPrice, platformFeeDto, bankTransferFee);
BigDecimal income = calIncome(prdPrice, platformFeeDto.getTotal(), bankTransferFee);
//set
SellerOrderComputeResult result = new SellerOrderComputeResult();
result.setEarnestMoney(earnestMoney);
result.setPlatformFee(platformFeeDto);
result.setIncome(halfUp(income));
//TODO 根据配置文件
result.setServiceFeeRate(serviceFeeRate);
result.setBankTransferfee(bankTransferFee);
return result;
}
private BigDecimal calBankTransferFee(BigDecimal prdPrice, BigDecimal payServiceFeeRate){
//支付渠道转账费率(0.6%)
return halfUp(prdPrice.multiply(payServiceFeeRate));
}
/**
* (1-X-Z)*B-D-E *
B:货款(卖家发布商品自行输入);
D:有货鉴定费(暂定5元);
E:有货包装费(暂定5元);
X:货款抽成(暂定5%,后期可调整,上线初期为0,后期活动可根据活动进行减免,每个卖家可收费不一样);
Z:支付渠道费,调用银联支付接口时实时扣款(支付宝0.55%、微信均为0.6%,统一对用户收取0.6%,前期优惠策略可暂定0)
* @param prdPrice
* @param platformFee
* @return
*/
private BigDecimal calIncome(BigDecimal prdPrice,BigDecimal platformFee,BigDecimal bankTransferFee){
return prdPrice.subtract(platformFee).subtract(bankTransferFee);
}
public Double getAppraiseFee() {
return appraiseFee;
}
public Double getPackageFee() {
return packageFee;
}
/**
* 通过相加得出的数据
* 服务费参与计算后需要考虑精度问题(四舍五入)
* @return
*/
private PlatformFeeDto calPlatformFee(BigDecimal price, BigDecimal goodsServiceRate){
PlatformFeeDto platformFee = new PlatformFeeDto();
BigDecimal appraiseFee = new BigDecimal(getAppraiseFee());
BigDecimal packageFee = new BigDecimal(getPackageFee());
BigDecimal serviceFee = price.multiply(goodsServiceRate);
platformFee.setAppraiseFee(halfUp(appraiseFee));
platformFee.setPackageFee(halfUp(packageFee));
BigDecimal total = appraiseFee.add(packageFee).add(serviceFee);
platformFee.setTotal(halfUp(total));
platformFee.setServiceFee(halfUp(serviceFee));
return platformFee;
}
public class SellerOrderComputeHandler extends AbsSellerOrderComputeHandler implements OrderComputeHandler {
/**
* 相对独立 不涉及到计算其他费用
* @param prdPrice
* @return
*/
private EarnestMoney calEarnestMoney(BigDecimal prdPrice){
protected EarnestMoney calEarnestMoney(BigDecimal prdPrice){
BigDecimal[] EARNEST_MONEY_RANGE = orderDynamicConfig.getEMR();
EarnestMoney earnestMoney = new EarnestMoney();
//TODO earnestMoney.rate 需要调整为动态可配
BigDecimal real = halfUp(prdPrice.multiply(earnestMoney.getRate()));
final BigDecimal min = EARNESTMONEYRANGE[0] == null ? earnestMoney.getMin() : EARNESTMONEYRANGE[0];
final BigDecimal max = EARNESTMONEYRANGE[1] == null ? earnestMoney.getMax() : EARNESTMONEYRANGE[1];
if(real.subtract(min).doubleValue() < 0D){
real = min;
}
if (real.subtract(max).doubleValue() > 0D){
real = max;
}
final BigDecimal min = EARNEST_MONEY_RANGE[0] == null ? earnestMoney.getMin() : EARNEST_MONEY_RANGE[0];
final BigDecimal max = EARNEST_MONEY_RANGE[1] == null ? earnestMoney.getMax() : EARNEST_MONEY_RANGE[1];
real = calCrossWithThreshold(min, max, real);
earnestMoney.setMin(min);
earnestMoney.setMax(max);
earnestMoney.setEarnestMoney(real);
return earnestMoney;
}
private BigDecimal halfUp(BigDecimal fee){
return BigDecimalHelper.halfUp(fee);
@Override
protected ServiceFeeRate buildServiceFeeRate() {
ServiceFeeRate serviceFeeRate = orderDynamicConfig.getServiceFeeRate();
return serviceFeeRate;
}
}
... ...
package com.yohoufo.order.service.impl;
import com.yohoufo.common.utils.BigDecimalHelper;
import com.yohoufo.order.model.dto.ServiceFeeRate;
import lombok.Data;
import lombok.Getter;
import org.slf4j.Logger;
... ... @@ -14,12 +15,40 @@ import java.math.BigDecimal;
/**
* Created by chao.chen on 2018/11/15.
*/
@Component("orderDynamicConfig")
@Component
public class OrderDynamicConfig {
final private Logger logger = LoggerFactory.getLogger(getClass());
@Value("${order.seller.earnestmoney.min:28}")
protected double earnestmoney_min;
@Value("${order.seller.earnestmoney.max:200}")
protected double earnestmoney_max;
/**
* 货款抽成费率
*/
@Value("${order.seller.goodsPaymentRate}")
private Double goodsPaymentRate = 0.05D;
/**
* 保证金抽成费率
*/
@Value("${order.seller.earnestMoneyRate}")
private Double earnestMoneyRate = 0.20D;
/**
* (主要是第三方,支付宝 or 微信)支付渠道手续费率
*/
@Value("${order.seller.payChannelRate}")
private Double payChannelRate = 0.006D;
/**
* 保证金上下限阈值
*/
private BigDecimal[] EARNEST_MONEY_RANGE = new BigDecimal[2];
@Data
public static class BuyerCancelCompensateNode{
/**
... ... @@ -70,40 +99,30 @@ public class OrderDynamicConfig {
*/
private BuyerCancelCompensateNode beforeDepotReceiveBCCN;
@Getter
private ServiceFeeRate serviceFeeRate;
@PostConstruct
private void init() {
BigDecimal buyerCancelUnDeliveryMoney , beforeSellerDeliverRate;
BigDecimal buyerCancelDeliveryMoney, beforeDepotReceiveRate;
try {
buyerCancelDeliveryMoney = new BigDecimal(buyerCancelUnDelivery);
beforeSellerDeliverRate = new BigDecimal( sellerGetRateUnDelivery);
//包装结构时做格式化,之前请保留有效位
beforeSellerDeliverBCCN = new BuyerCancelCompensateNode(BigDecimalHelper.halfUp(buyerCancelDeliveryMoney),
BigDecimalHelper.halfUp(beforeSellerDeliverRate) );
buyerCancelUnDeliveryMoney = new BigDecimal(buyerCancelDelivery);
beforeDepotReceiveRate = new BigDecimal(sellerGetRateDelivery);
beforeDepotReceiveBCCN = new BuyerCancelCompensateNode(buyerCancelUnDeliveryMoney, beforeDepotReceiveRate);
} catch (Exception e) {
logger.error("买家取消罚款金额相关参数配置错误!", e);
throw new Error("买家取消罚款金额相关参数配置错误!");
}
if (buyerCancelDeliveryMoney.compareTo(BigDecimal.ZERO) < 0) {
throw new Error("buyerCancelDeliveryMoney买家取消(货已寄出)罚款金额不能为负数");
}
if (buyerCancelUnDeliveryMoney.compareTo(BigDecimal.ZERO) < 0) {
throw new Error("buyerCancelUnDeliveryMoney买家取消(货未寄出)罚款金额不能为负数");
}
if (beforeDepotReceiveRate.compareTo(BigDecimal.ZERO) < 0
|| beforeDepotReceiveRate.compareTo(BigDecimal.ONE) > 0) {
throw new Error("sellerGetRateDeliveryMoney买家取消(货已寄出)卖家获得赔偿比率必须在[0,1]");
}
if (beforeSellerDeliverRate.compareTo(BigDecimal.ZERO) < 0
|| beforeSellerDeliverRate.compareTo(BigDecimal.ONE) > 0) {
throw new Error("sellerGetRateUnDeliveryMoney买家取消(货未寄出)卖家获得赔偿比率必须在[0,1]");
}
EARNEST_MONEY_RANGE[0] = new BigDecimal(earnestmoney_min);
EARNEST_MONEY_RANGE[1] = new BigDecimal(earnestmoney_max);
//
//ServiceFeeRate buildServiceFeeRate() {
serviceFeeRate = new ServiceFeeRate();
serviceFeeRate.setGoodsPaymentRate(new BigDecimal(goodsPaymentRate).setScale(2, BigDecimal.ROUND_HALF_UP));
serviceFeeRate.setEarnestMoneyRate(new BigDecimal(earnestMoneyRate).setScale(2, BigDecimal.ROUND_HALF_UP));
serviceFeeRate.setPayChannelRate(new BigDecimal(payChannelRate).setScale(4, BigDecimal.ROUND_HALF_UP));
}
/**
*
* EMR : EarnestMoneyRange
* @return
*/
public BigDecimal[] getEMR(){
return EARNEST_MONEY_RANGE;
}
}
... ...
... ... @@ -6,6 +6,7 @@ import com.yoho.error.ServiceError;
import com.yoho.error.exception.ServiceException;
import com.yohobuy.ufo.model.order.bo.*;
import com.yohobuy.ufo.model.order.common.*;
import com.yohobuy.ufo.model.order.constants.SkupType;
import com.yohobuy.ufo.model.order.req.*;
import com.yohobuy.ufo.model.order.resp.*;
import com.yohoufo.common.alarm.EventBusPublisher;
... ... @@ -47,6 +48,8 @@ import com.yohoufo.order.service.impl.visitor.UserCancelCase;
import com.yohoufo.order.service.proxy.InBoxFacade;
import com.yohoufo.order.service.proxy.ProductProxyService;
import com.yohoufo.order.service.proxy.UserProxyService;
import com.yohoufo.order.service.seller.OrderComputeHandler;
import com.yohoufo.order.service.seller.OrderComputeProvider;
import com.yohoufo.order.service.support.codegenerator.OrderCodeGenerator;
import com.yohoufo.order.service.support.codegenerator.bean.CodeMeta;
import com.yohoufo.order.utils.LoggerUtils;
... ... @@ -77,7 +80,7 @@ public class SellerOrderService implements IOrderListService, IOrderDetailServi
private SellerOrderGoodsMapper sellerOrderGoodsMapper;
@Autowired
private SellerOrderComputeHandler computeHandler;
private OrderComputeProvider orderComputeProvider;
@Autowired
private OrderCodeGenerator orderCodeGenerator;
... ... @@ -167,7 +170,8 @@ public class SellerOrderService implements IOrderListService, IOrderDetailServi
tips = ex.getErrorMessage();
}
boolean isSuper = sellerService.isSuperEntrySeller(uid);
SoldPrdComputeBo spc = buildSoldPrdComputeBo(uid, num, salePrice, isSuper);
SkupType skupType = SkupType.getSkupType(req.getSkupType());
SoldPrdComputeBo spc = buildSoldPrdComputeBo(uid, num, salePrice, isSuper, skupType);
spc.setTips(tips);
return spc;
}
... ... @@ -508,7 +512,10 @@ public class SellerOrderService implements IOrderListService, IOrderDetailServi
}
}
private SoldPrdComputeBo buildSoldPrdComputeBo(int uid, int num, BigDecimal prdPrice, boolean isSuper){
private SoldPrdComputeBo buildSoldPrdComputeBo(int uid, int num,
BigDecimal prdPrice, boolean isSuper,
SkupType skupType){
OrderComputeHandler computeHandler = orderComputeProvider.findBySkupType(skupType);
SellerOrderComputeResult computeResult = computeHandler.compute(prdPrice);
/**
* 验证是否是入驻商家
... ...
package com.yohoufo.order.service.impl.processor;
import com.yohobuy.ufo.model.order.common.OrderStatus;
import com.yohobuy.ufo.model.order.constants.SkupType;
import com.yohobuy.ufo.model.order.req.SellerBaseChangeReq;
import com.yohoufo.common.exception.GatewayException;
import com.yohoufo.common.exception.UfoServiceException;
... ... @@ -14,9 +15,10 @@ import com.yohoufo.dal.order.model.SellerOrderGoods;
import com.yohoufo.order.model.dto.ChangePricePrepareDTO;
import com.yohoufo.order.model.dto.SellerOrderComputeResult;
import com.yohoufo.order.model.dto.SkupDto;
import com.yohoufo.order.service.handler.SellerOrderComputeHandler;
import com.yohoufo.order.service.impl.SellerService;
import com.yohoufo.order.service.proxy.ProductProxyService;
import com.yohoufo.order.service.seller.OrderComputeHandler;
import com.yohoufo.order.service.seller.OrderComputeProvider;
import com.yohoufo.order.utils.LoggerUtils;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
... ... @@ -48,7 +50,7 @@ public abstract class AbstractChangePricePrepareProcessor<T extends SellerBaseCh
private SellerOrderPrepareProcessor sellerOrderPrepareProcessor;
@Autowired
private SellerOrderComputeHandler computeHandler;
private OrderComputeProvider orderComputeProvider;
@Autowired
private PriceComputePrepareProcessor priceComputePrepareProcessor;
... ... @@ -68,20 +70,6 @@ public abstract class AbstractChangePricePrepareProcessor<T extends SellerBaseCh
throw new UfoServiceException(400, "您不是入驻商家");
}
// String skupList = req.getSkupList();
// if (StringUtils.isBlank(skupList)){
// logger.warn("ChangePrice checkAndAcquire uid illegal , req {}", req);
// throw new UfoServiceException(400, "参数[skupList]为空");
// }
//考虑到并发,需要进行过滤,将不是出售中状态的skup排除掉;
//不做过滤导致后面的数量 扣费检查都可能不对
// List<String> skupStrList = Splitter.on(',').trimResults().omitEmptyStrings().splitToList(skupList);
// List<Integer> needChangePriceSkupList = skupStrList.parallelStream().map(Integer::valueOf).collect(Collectors.toList());
//check batch no
// Long batchNo = checkNAcquireBatchNo(req.getBatchNo(), req);
//检查是否有买家下单,返回的是可售 待买家付款的skup
Map<Integer, SkupDto> skupOfSalingMap = checkExistWaitingBuyerPay(req);
... ... @@ -93,9 +81,6 @@ public abstract class AbstractChangePricePrepareProcessor<T extends SellerBaseCh
int sampleSkup = sampleSkupDto.getSkup();
SellerOrderGoods sampleSog = sampleSkupDto.getSellerOrderGoods();
BigDecimal preSalePrice = sampleSog.getGoodsPrice();
// if (preSalePrice.compareTo(salePrice) == 0){
// throw new UfoServiceException(401, "前后价格没有变化");
// }
SellerOrder sellerOrder = sellerOrderMapper.selectBySkup(sampleSkup);
BigDecimal sourceEM = sellerOrder.getEarnestMoney();
... ... @@ -110,6 +95,8 @@ public abstract class AbstractChangePricePrepareProcessor<T extends SellerBaseCh
tips = ex.getErrorMessage();
}
// compute every fee from price
SkupType skupType = SkupType.getSkupType(req.getSkupType());
OrderComputeHandler computeHandler = orderComputeProvider.findBySkupType(skupType);
SellerOrderComputeResult computeResult = computeHandler.compute(salePrice);
int num = skupMap.size();
//作为入驻商户 检查钱包
... ...
... ... @@ -2,11 +2,13 @@ package com.yohoufo.order.service.impl.processor;
import com.yoho.error.ServiceError;
import com.yoho.error.exception.ServiceException;
import com.yohobuy.ufo.model.GoodsSize;
import com.yohobuy.ufo.model.order.bo.GoodsInfo;
import com.yohobuy.ufo.model.order.common.SellerWalletType;
import com.yohobuy.ufo.model.order.constants.OrderConstant;
import com.yohobuy.ufo.model.order.constants.SkupType;
import com.yohobuy.ufo.model.order.req.SellerOrderSubmitReq;
import com.yohobuy.ufo.model.order.vo.AddressInfo;
import com.yohobuy.ufo.model.response.StorageDataResp;
import com.yohoufo.common.exception.GatewayException;
import com.yohoufo.common.exception.UfoServiceException;
... ... @@ -14,15 +16,14 @@ import com.yohoufo.common.utils.AddressUtil;
import com.yohoufo.common.utils.BigDecimalHelper;
import com.yohoufo.dal.order.SellerWalletMapper;
import com.yohoufo.dal.order.model.SellerWallet;
import com.yohobuy.ufo.model.order.vo.AddressInfo;
import com.yohoufo.order.model.SellerOrderContext;
import com.yohoufo.order.model.dto.SellerOrderComputeResult;
import com.yohoufo.order.service.handler.SellerOrderComputeHandler;
import com.yohoufo.order.service.proxy.ProductProxyService;
import com.yohoufo.order.service.proxy.UserProxyService;
import com.yohoufo.order.service.seller.OrderComputeHandler;
import com.yohoufo.order.service.seller.OrderComputeProvider;
import com.yohoufo.order.utils.AddressHelper;
import com.yohoufo.order.utils.LoggerUtils;
import com.yohobuy.ufo.model.GoodsSize;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
... ... @@ -45,7 +46,7 @@ public class SellerOrderPrepareProcessor {
private ProductProxyService productProxyService;
@Autowired
private SellerOrderComputeHandler computeHandler;
private OrderComputeProvider orderComputeProvider;
@Autowired
private SellerWalletMapper sellerWalletMapper;
... ... @@ -137,16 +138,17 @@ public class SellerOrderPrepareProcessor {
}catch (UfoServiceException ex){
context.setPriceOverFlowTips( ex.getErrorMessage());
}
//
SkupType skupType = SkupType.getSkupType(req.getSkupType());
context.setSkupType(skupType);
// compute every fee from price
OrderComputeHandler computeHandler = orderComputeProvider.findBySkupType(skupType);
SellerOrderComputeResult computeResult = computeHandler.compute(goodsInfo.getPrice());
checkIncome(storageId, computeResult.getIncome());
log.info("in buildSellerOrderContext , uid {}, storageId {}, price {}, computeResult {}", uid, storageId,
goodsInfo.getPrice(), computeResult);
context.setSellerOrderComputeResult(computeResult);
//
SkupType skupType = SkupType.getSkupType(req.getSkupType());
context.setSkupType(skupType);
return context;
}
... ... @@ -303,6 +305,8 @@ public class SellerOrderPrepareProcessor {
goodsInfo.setStorageNum(storageNum);
// compute every fee from price
SkupType skupType = SkupType.IN_STOCK;
OrderComputeHandler computeHandler = orderComputeProvider.findBySkupType(skupType);
SellerOrderComputeResult computeResult = computeHandler.compute(goodsInfo.getPrice());
log.info("in buildImportPrdCxt , uid {}, storageId {}, price {}, computeResult {}", uid, storageId,
goodsInfo.getPrice(), computeResult);
... ...
package com.yohoufo.order.service.seller;
import com.yohoufo.common.utils.BigDecimalHelper;
import com.yohoufo.order.model.dto.EarnestMoney;
import com.yohoufo.order.model.dto.PlatformFeeDto;
import com.yohoufo.order.model.dto.SellerOrderComputeResult;
import com.yohoufo.order.model.dto.ServiceFeeRate;
import com.yohoufo.order.service.impl.OrderDynamicConfig;
import com.yohoufo.order.utils.LoggerUtils;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import java.math.BigDecimal;
/**
* Created by chao.chen on 2019/2/1.
*/
public abstract class AbsSellerOrderComputeHandler implements OrderComputeHandler{
protected Logger logger = LoggerUtils.getSellerOrderLogger();
@Autowired
protected OrderDynamicConfig orderDynamicConfig;
/**
* 鉴定费
*/
@Value("${order.seller.appraiseFee:5}")
private Double appraiseFee;
/**
* 有货包装费(暂定5元)
*/
@Value("${order.seller.packageFee:5}")
private Double packageFee ;
@Override
public SellerOrderComputeResult compute(BigDecimal prdPrice){
//保证金(28-200(按照卖家发布商品的货款金额5%计算,最低28,封顶200))
EarnestMoney earnestMoney = calEarnestMoney(prdPrice);
//init fee rate
ServiceFeeRate serviceFeeRate = buildServiceFeeRate();
PlatformFeeDto platformFeeDto = calPlatformFee(prdPrice, serviceFeeRate);
BigDecimal bankTransferFee = calBankTransferFee(prdPrice, serviceFeeRate.getPayChannelRate());
logger.info("in SellerOrder Compute, prdPrice {}, platformFee {}, bankTransferFee {}",
prdPrice, platformFeeDto, bankTransferFee);
BigDecimal income = calIncome(prdPrice, platformFeeDto.getTotal(), bankTransferFee);
//set
SellerOrderComputeResult result = new SellerOrderComputeResult();
result.setEarnestMoney(earnestMoney);
result.setPlatformFee(platformFeeDto);
result.setIncome(halfUp(income));
//TODO 根据配置文件
result.setServiceFeeRate(serviceFeeRate);
result.setBankTransferfee(bankTransferFee);
return result;
}
protected BigDecimal calCrossWithThreshold(BigDecimal min, BigDecimal max, BigDecimal calByRate){
if(calByRate.compareTo(min) < 0){
calByRate = min;
}
if (calByRate.compareTo(max) > 0){
calByRate = max;
}
return calByRate;
}
protected BigDecimal halfUp(BigDecimal fee){
return BigDecimalHelper.halfUp(fee);
}
protected abstract EarnestMoney calEarnestMoney(BigDecimal prdPrice);
/**
* (1-X-Z)*B-D-E *
B:货款(卖家发布商品自行输入);
D:有货鉴定费(暂定5元);
E:有货包装费(暂定5元);
X:货款抽成(暂定5%,后期可调整,上线初期为0,后期活动可根据活动进行减免,每个卖家可收费不一样);
Z:支付渠道费,调用银联支付接口时实时扣款(支付宝0.55%、微信均为0.6%,统一对用户收取0.6%,前期优惠策略可暂定0)
* @param prdPrice
* @param platformFee
* @return
*/
protected BigDecimal calIncome(BigDecimal prdPrice, BigDecimal platformFee, BigDecimal bankTransferFee){
return prdPrice.subtract(platformFee).subtract(bankTransferFee);
}
protected BigDecimal calBankTransferFee(BigDecimal prdPrice, BigDecimal payServiceFeeRate){
//支付渠道转账费率(0.6%)
return halfUp(prdPrice.multiply(payServiceFeeRate));
}
/**
* 通过相加得出的数据
* 服务费参与计算后需要考虑精度问题(四舍五入)
* @return
*/
protected PlatformFeeDto calPlatformFee(BigDecimal price, ServiceFeeRate serviceFeeRate){
BigDecimal goodsServiceRate = serviceFeeRate.getGoodsPaymentRate();
PlatformFeeDto platformFee = new PlatformFeeDto();
BigDecimal appraiseFee = new BigDecimal(getAppraiseFee());
BigDecimal packageFee = new BigDecimal(getPackageFee());
BigDecimal serviceFee = price.multiply(goodsServiceRate);
platformFee.setAppraiseFee(halfUp(appraiseFee));
platformFee.setPackageFee(halfUp(packageFee));
BigDecimal total = appraiseFee.add(packageFee).add(serviceFee);
platformFee.setTotal(halfUp(total));
platformFee.setServiceFee(halfUp(serviceFee));
return platformFee;
}
public Double getAppraiseFee() {
return appraiseFee;
}
public Double getPackageFee() {
return packageFee;
}
protected abstract ServiceFeeRate buildServiceFeeRate();
}
... ...
package com.yohoufo.order.service.seller;
import com.yohoufo.order.model.dto.SellerOrderComputeResult;
import java.math.BigDecimal;
/**
* Created by chao.chen on 2019/2/1.
*/
public interface OrderComputeHandler {
SellerOrderComputeResult compute(BigDecimal prdPrice);
}
... ...
package com.yohoufo.order.service.seller;
import com.yohobuy.ufo.model.order.constants.SkupType;
import com.yohoufo.order.utils.LoggerUtils;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Created by chao.chen on 2019/2/1.
*/
@Service
public class OrderComputeProvider implements ApplicationContextAware {
private final Logger logger = LoggerUtils.getSellerOrderLogger();
private Map<String, OrderComputeHandler> cache;
public OrderComputeHandler findBySkupType(SkupType skupType){
OrderComputeHandler och = cache.get(skupType.orderComputeHandlerClzName());
logger.info("in findBySkupType skupType {} OrderComputeHandler {}", skupType, och);
return och;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
Map<String, OrderComputeHandler> allOCHMap = applicationContext.getBeansOfType(OrderComputeHandler.class);
cache = allOCHMap;
//check
SkupType[] sta = SkupType.values();
List<SkupType> errorST = new ArrayList<>(sta.length);
for(SkupType st : sta){
if(null == findBySkupType(st)){
errorST.add(st);
logger.warn("init check SkupType.orderComputeHandlerClzName set error SkupType {}", st);
}
}
if (CollectionUtils.isNotEmpty(errorST)){
throw new Error("SkupType.orderComputeHandlerClzName incorrect");
}
}
}
... ...
package com.yohoufo.order.service.seller;
import com.yohoufo.order.model.dto.EarnestMoney;
import com.yohoufo.order.model.dto.ServiceFeeRate;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
/**
* Created by chao.chen on 2019/2/1.
*/
@Component
public class SellerAdvanceOrderComputeHandler extends AbsSellerOrderComputeHandler implements OrderComputeHandler {
@Override
protected EarnestMoney calEarnestMoney(BigDecimal prdPrice) {
//TODO 根据配置(来自于数据库或缓存 zk ,某一种数据存储方式)
EarnestMoney earnestMoney = new EarnestMoney();
earnestMoney.setPrdSalePrice(prdPrice);
//TODO earnestMoney.rate 需要调整为动态可配
BigDecimal real = halfUp(prdPrice.multiply(new BigDecimal(0.08D)));
final BigDecimal min = new BigDecimal(56);
final BigDecimal max = new BigDecimal(438);
real = calCrossWithThreshold(min, max, real);
earnestMoney.setMin(min);
earnestMoney.setMax(max);
earnestMoney.setEarnestMoney(real);
return earnestMoney;
}
@Override
protected ServiceFeeRate buildServiceFeeRate() {
ServiceFeeRate serviceFeeRate = orderDynamicConfig.getServiceFeeRate();
return serviceFeeRate;
}
}
... ...