Authored by wujiexiang

Merge branch 'dev-seller-order-stat-6.9.9' into test6.9.9

Showing 32 changed files with 997 additions and 12 deletions
... ... @@ -1123,11 +1123,33 @@ public class DateUtil {
return gc;
}
/**
* 返回整点时间,分、秒都为0
*
* @param date 指定日期。
* @return 指定日期的所处月份的第一天 00:00:00
*/
public static Date getCurrentHourDate(Date date) {
/**
* 详细设计: 1.设置为1号
*/
GregorianCalendar gc = (GregorianCalendar) Calendar.getInstance();
gc.setTime(date);
//将分钟至0
gc.set(Calendar.MINUTE, 0);
//将秒至0
gc.set(Calendar.SECOND,0);
//将毫秒至0
gc.set(Calendar.MILLISECOND, 0);
return gc.getTime();
}
/**
* 取得指定日期的所处月份的第一天
*
* @param date 指定日期。
* @return 指定日期的所处月份的第一天
* @return 指定日期的所处月份的第一天 00:00:00
*/
public static Date getFirstDayOfMonth(Date date) {
/**
... ... @@ -1136,6 +1158,16 @@ public class DateUtil {
GregorianCalendar gc = (GregorianCalendar) Calendar.getInstance();
gc.setTime(date);
gc.set(Calendar.DAY_OF_MONTH, 1);
//设置为1号,当前日期既为本月第一天
gc.set(Calendar.DAY_OF_MONTH, 1);
//将小时至0
gc.set(Calendar.HOUR_OF_DAY, 0);
//将分钟至0
gc.set(Calendar.MINUTE, 0);
//将秒至0
gc.set(Calendar.SECOND,0);
//将毫秒至0
gc.set(Calendar.MILLISECOND, 0);
return gc.getTime();
}
... ... @@ -2120,6 +2152,9 @@ public class DateUtil {
case day:
localDateTime = localDateTime.plusDays(timeLong);
break;
case month:
localDateTime = localDateTime.plusMonths(timeLong);
break;
}
break;
case minus:
... ... @@ -2133,6 +2168,9 @@ public class DateUtil {
case day:
localDateTime = localDateTime.minusDays(timeLong);
break;
case month:
localDateTime = localDateTime.minusMonths(timeLong);
break;
}
break;
}
... ... @@ -2155,7 +2193,7 @@ public class DateUtil {
}
public enum TimeUnit{
minute,hour,day
minute,hour,day,month
}
... ...
package com.yohoufo.dal.order;
import com.yohoufo.dal.order.model.SellerOrderStatsConfig;
import java.util.List;
/**
* Created by jiexiang.wu on 2019/7/22.
*/
public interface SellerOrderStatsConfigMapper {
/**
* 查询可用的统计配置
*
* @return
*/
List<SellerOrderStatsConfig> selectEnabledStatsConfig();
}
... ...
package com.yohoufo.dal.order;
import com.yohoufo.dal.order.model.SellerOrderStatsResult;
import org.apache.ibatis.annotations.Param;
/**
* Created by jiexiang.wu on 2019/7/22.
*/
public interface SellerOrderStatsResultMapper {
/**
* 新增
*
* @param result
* @return
*/
int insert(SellerOrderStatsResult result);
/**
* 查询统计结果
* @param uid
* @param statsCode
* @param currentTime
* @return
*/
SellerOrderStatsResult selectStatsResult(@Param("uid") int uid, @Param("statsCode") String statsCode, @Param("currentTime") int currentTime);
}
... ...
package com.yohoufo.dal.order.model;
import lombok.Data;
/**
* Created by jiexiang.wu on 2019/7/22.
*/
@Data
public class SellerOrderStatsConfig {
private long id;
private String statsCode;
//排除的uid
private String excludeUid;
//属性
private String orderAttribute;
//统计单位
private String statsUnit;
//统计周期
private int statsPeriod;
//统计处理器
private String statsProcessor;
//1 有效
private int statsEnabled;
//业务执行参数
private String actionParam;
//备注
private String remark;
}
... ...
package com.yohoufo.dal.order.model;
import lombok.Data;
import lombok.ToString;
/**
* Created by jiexiang.wu on 2019/7/22.
*/
@Data
@ToString
public class SellerOrderStatsResult {
private long id;
private String statsCode;
private int uid;
private int beginTime;
private int endTime;
//订单数量
private int quantity;
}
... ...
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.yohoufo.dal.order.SellerOrderStatsConfigMapper" >
<resultMap id="BaseResultMap" type="com.yohoufo.dal.order.model.SellerOrderStatsConfig" >
<id column="id" property="id" jdbcType="BIGINT" />
<result column="stats_code" property="statsCode" jdbcType="VARCHAR" />
<result column="exclude_uid" property="excludeUid" jdbcType="VARCHAR" />
<result column="order_attribute" property="orderAttribute" jdbcType="VARCHAR" />
<result column="stats_unit" property="statsUnit" jdbcType="VARCHAR" />
<result column="stats_period" property="statsPeriod" jdbcType="INTEGER" />
<result column="stats_processor" property="statsProcessor" jdbcType="VARCHAR" />
<result column="stats_enabled" property="statsEnabled" jdbcType="INTEGER" />
<result column="action_param" property="actionParam" jdbcType="VARCHAR" />
<result column="remark" property="remark" jdbcType="VARCHAR" />
</resultMap>
<sql id="Base_Column_List" >
id, stats_code, exclude_uid,order_attribute, stats_unit, stats_period, stats_processor, stats_enabled, action_param, remark
</sql>
<select id="selectEnabledStatsConfig" resultMap="BaseResultMap" >
select
<include refid="Base_Column_List" />
from seller_order_stats_config
where stats_enabled = 1
</select>
</mapper>
\ No newline at end of file
... ...
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.yohoufo.dal.order.SellerOrderStatsResultMapper">
<resultMap id="BaseResultMap" type="com.yohoufo.dal.order.model.SellerOrderStatsResult">
<id column="id" property="id" jdbcType="BIGINT"/>
<result column="stats_code" property="statsCode" jdbcType="VARCHAR"/>
<result column="uid" property="uid" jdbcType="INTEGER"/>
<result column="begin_time" property="beginTime" jdbcType="INTEGER"/>
<result column="end_time" property="endTime" jdbcType="INTEGER"/>
<result column="quantity" property="statsPeriod" jdbcType="INTEGER"/>
</resultMap>
<sql id="Base_Column_List">
id, stats_code, uid, begin_time, end_time, quantity
</sql>
<select id="selectStatsResult" resultMap="BaseResultMap">
select
<include refid="Base_Column_List"/>
from seller_order_stats_result
where uid = #{uid,jdbcType=INTEGER}
and stats_code = #{statsCode,jdbcType=VARCHAR}
and end_time <![CDATA[ >= ]]> #{currentTime,jdbcType=INTEGER}
and begin_time <![CDATA[ <= ]]> #{currentTime,jdbcType=INTEGER}
limit 1
</select>
<insert id="insert" parameterType="com.yohoufo.dal.order.model.SellerOrderStatsResult">
insert into seller_order_stats_result (id, uid, stats_code,begin_time, end_time, quantity)
values (#{id,jdbcType=BIGINT}, #{uid,jdbcType=INTEGER}, #{statsCode,jdbcType=VARCHAR},
#{beginTime,jdbcType=INTEGER}, #{endTime,jdbcType=INTEGER}, #{quantity,jdbcType=INTEGER})
ON DUPLICATE KEY UPDATE quantity = #{quantity,jdbcType=INTEGER} + quantity
</insert>
</mapper>
\ No newline at end of file
... ...
... ... @@ -2,6 +2,7 @@ package com.yohoufo.order.controller;
import com.yohobuy.ufo.model.order.common.EntrySellerType;
import com.yohobuy.ufo.model.order.resp.EntryThreshold;
import com.yohobuy.ufo.model.order.resp.SellerPlatformServiceFeeResp;
import com.yohobuy.ufo.model.order.resp.SellerResp;
import com.yohoufo.common.ApiResponse;
import com.yohoufo.common.exception.GatewayException;
... ... @@ -130,4 +131,17 @@ public class SellerController {
return new ApiResponse.ApiResponseBuilder().code(200).data(isSuper).message("刷新成功").build();
}
/**
* 卖家平台服务费
*
* @param uid
* @return
*/
@RequestMapping(params = "method=ufo.seller.platformServiceFee.detail")
@ResponseBody
public ApiResponse platformServiceFeeDetail(@RequestParam("uid") int uid) {
SellerPlatformServiceFeeResp resp = sellerService.platformServiceFeeDetail(uid);
return new ApiResponse.ApiResponseBuilder().code(200).data(resp).message("ok").build();
}
}
... ...
package com.yohoufo.order.model.bo;
import com.yohoufo.order.utils.BeanTool;
import lombok.Data;
import lombok.ToString;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import java.math.BigDecimal;
import java.util.Comparator;
import java.util.List;
/**
* Created by jiexiang.wu on 2019/7/23.
* 卖家平台服务费定义
*/
@Data
@ToString
public class PlatformServiceFeeDefinition {
//费用规则
private List<FeeRule> rules;
/**
* 根据阀值获取对应的折扣
*
* @param threshold
* @return
*/
public BigDecimal getFeeRate(int threshold) {
if (CollectionUtils.isEmpty(rules)) {
return null;
}
//nodes排序 按照threshold从大到小排序
rules.sort(Comparator.comparing(FeeRule::getThreshold).reversed());
for (FeeRule rule : rules) {
if (threshold >= rule.getThreshold()) {
return rule.getRate();
}
}
//没有匹配到
return null;
}
public static PlatformServiceFeeDefinition convert(String json) {
if (StringUtils.isEmpty(json)) {
return new PlatformServiceFeeDefinition();
} else {
return BeanTool.string2Value(json, PlatformServiceFeeDefinition.class);
}
}
@Data
@ToString
public static class FeeRule {
//阀值
private int threshold;
//比例
private BigDecimal rate;
}
}
... ...
package com.yohoufo.order.model.bo;
import lombok.Data;
import lombok.ToString;
import java.math.BigDecimal;
/**
* Created by jiexiang.wu on 2019/7/23.
* 卖家平台服务费
*/
@Data
@ToString
public class SellerPlatformServiceFee {
//订单数量
private int orderQuantity;
//费用定义
private PlatformServiceFeeDefinition definition;
public SellerPlatformServiceFee(int orderQuantity, PlatformServiceFeeDefinition definition) {
this.orderQuantity = orderQuantity;
this.definition = definition;
}
/**
* 费用比例
*
* @return
*/
public BigDecimal getFeeRate() {
return definition.getFeeRate(orderQuantity);
}
}
... ...
package com.yohoufo.order.service.cache;
import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import com.yoho.core.cache.LocalCache;
import com.yoho.core.cache.LocalCacheCallback;
import com.yohobuy.ufo.model.order.common.OrderAttributes;
import com.yohoufo.dal.order.SellerOrderStatsConfigMapper;
import com.yohoufo.dal.order.model.SellerOrderStatsConfig;
import com.yohoufo.order.service.stats.StatsUnit;
import com.yohoufo.order.service.stats.impl.SellerOrderStatsConfiguration;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
* Created by jiexiang.wu on 2019/7/22.
*/
@Component
public class SellerOrderStatsConfigCacheService {
private static final Logger logger = LoggerFactory.getLogger(SellerOrderStatsConfigCacheService.class);
//统计所有配置项
public final static String SELLER_ORDER_STATS_CONFIG_KEY = "SELLER_ORDER_STATS_CONFIG";
@Autowired
private SellerOrderStatsConfigMapper sellerOrderStatsConfigMapper;
private LocalCache localCache = new LocalCache();
@PostConstruct
private void init() {
localCache.init("Seller Order Stats Config Cache", 5, TimeUnit.MINUTES, new LocalCacheCallback() {
@Override
public Object load(String key, Object oldValue) throws Exception {
try {
List<SellerOrderStatsConfig> configs = sellerOrderStatsConfigMapper.selectEnabledStatsConfig();
if (CollectionUtils.isEmpty(configs)) {
logger.info("there is no seller order stats config");
return Lists.newArrayList();
}
List<SellerOrderStatsConfiguration> configurations = new ArrayList<>(configs.size());
configs.forEach(config -> {
SellerOrderStatsConfiguration configuration = SellerOrderStatsConfiguration.builder()
.statsCode(config.getStatsCode())
.excludeUids(Splitter.on(",").omitEmptyStrings().splitToList(config.getExcludeUid()).stream().map(uid -> Integer.parseInt(uid.trim())).collect(Collectors.toList()))
.orderAttributes(Splitter.on(",").omitEmptyStrings().splitToList(config.getOrderAttribute()).stream().map(code -> OrderAttributes.getOrderAttributes(Integer.parseInt(code.trim()))).collect(Collectors.toList()))
.statsUnit(StatsUnit.find(config.getStatsUnit()))
.statsPeriod(config.getStatsPeriod())
.statsProcessorName(config.getStatsProcessor())
.actionParam(config.getActionParam())
.build();
configurations.add(configuration);
});
return configurations;
} catch (Exception ex) {
logger.warn("key {}, old value is {}, error message is {}.", key, oldValue, ex.getMessage());
return oldValue;
}
}
});
}
public SellerOrderStatsConfiguration findBy(OrderAttributes orderAttributes) {
List<SellerOrderStatsConfiguration> configurations = (List) localCache.get(SELLER_ORDER_STATS_CONFIG_KEY);
if (CollectionUtils.isEmpty(configurations)) {
return null;
}
Optional<SellerOrderStatsConfiguration> optional = configurations.stream().filter(config -> config.getOrderAttributes().contains(orderAttributes)).findFirst();
return optional.isPresent() ? optional.get() : null;
}
}
... ...
... ... @@ -15,6 +15,7 @@ import java.util.stream.Collectors;
import javax.annotation.Resource;
import com.yohoufo.order.service.listener.BuyerOrderChangeEvent;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
... ... @@ -592,6 +593,9 @@ public class AppraiseService {
LOGGER.info("in judgeCenterPass record status change, orderCode {},uid {} ,sellerUid {}", orderCode, buyerUid, sellerUid);
orderStatusFlowService.addAsy(buyerOrder.getOrderCode(), targetStatus.getCode());
//瑕疵接受异步事件
orderChangeListenerContainer.fireAsyncEvent(new BuyerOrderChangeEvent(buyerOrder, BuyerOrderChangeEvent.BizCase.ACCEPT_FAULT, targetStatus));
BuyerOrderGoods bog = buyerOrderGoodsMapper.selectByOrderCode(buyerUid, orderCode);
int skup = bog.getSkup();
SellerOrder sellerOrder = sellerOrderMapper.selectBySkup(skup);
... ... @@ -1429,6 +1433,9 @@ public class AppraiseService {
.uid(buyerUid).orderCode(orderCode).orderAttr(buyerOrder.getAttributes()).build();
EventBusPublisher.publishEvent(buyerConfirmEvent);
//鉴定通过异步事件
orderChangeListenerContainer.fireAsyncEvent(new BuyerOrderChangeEvent(buyerOrder, BuyerOrderChangeEvent.BizCase.APPRAISE_SUCCESS, targetOrderStatus));
//更新平台物流状态为已发货
buyerOrderMapper.updatePlatformDeliveryStatusByOrderCode(orderCode, buyerOrder.getUid(),
EnumPlatformDeliveryStatus.delivery_to_buyer.getCode(), DateUtil.getCurrentTimeSecond());
... ...
... ... @@ -206,7 +206,7 @@ class BuyerOrderCancelHandler {
noticeBuyer(buyerOrder, buyerOrderGoods);
cleanCache(buyerOrder, sellerOrderGoods);
//取消事件
fireAsyncEvent(buyerOrder);
fireAsyncCancelEvent(buyerOrder);
} else {
log.info("cancel order {} fail, order status has changed", orderCode);
throwServiceException("当前状态不可取消订单");
... ... @@ -442,7 +442,7 @@ class BuyerOrderCancelHandler {
* 订单取消异步事件
* @param buyerOrder
*/
public void fireAsyncEvent(BuyerOrder buyerOrder) {
public void fireAsyncCancelEvent(BuyerOrder buyerOrder) {
orderChangeListenerContainer.fireAsyncEvent(new BuyerOrderChangeEvent(buyerOrder, BuyerOrderChangeEvent.BizCase.CANCEL_BYCS, targetStatus));
}
... ...
... ... @@ -29,6 +29,12 @@ public class BuyOrderChangeListener implements IOrderChangeListener<BuyerOrderCh
case PAY_SUCCESS:
businessPostProcessor.firePaySuccess(changeEvent.getBuyerOrder(), changeEvent.getBizCase(), changeEvent.getTargetStatus());
break;
case APPRAISE_SUCCESS:
businessPostProcessor.fireAppraiseSuccess(changeEvent.getBuyerOrder(), changeEvent.getBizCase(), changeEvent.getTargetStatus());
break;
case ACCEPT_FAULT:
businessPostProcessor.fireFaultAccept(changeEvent.getBuyerOrder(), changeEvent.getBizCase(), changeEvent.getTargetStatus());
break;
default:
throw new IllegalStateException("unknown bizCase" + bizCase);
}
... ...
... ... @@ -58,6 +58,11 @@ public class BuyerOrderChangeEvent extends OrderChangeEvent {
//cancel
CANCEL_BYBUYER, CANCEL_BYCS, CANCEL_BYSYSAUTO, CANCEL_BYSELLER,
//paySuccess
PAY_SUCCESS;
PAY_SUCCESS,
//鉴定通过
APPRAISE_SUCCESS,
//接受瑕疵
ACCEPT_FAULT;
}
}
... ...
... ... @@ -3,16 +3,20 @@ package com.yohoufo.order.service.listener.processor;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.yoho.core.rabbitmq.YhProducer;
import com.yohobuy.ufo.model.order.common.OrderAttributes;
import com.yohobuy.ufo.model.order.common.OrderStatus;
import com.yohoufo.common.alarm.EventBusPublisher;
import com.yohoufo.common.alarm.SmsAlarmEvent;
import com.yohoufo.dal.order.model.BuyerOrder;
import com.yohoufo.order.constants.ActivityTypeEnum;
import com.yohoufo.order.constants.MetaKey;
import com.yohoufo.order.service.listener.BuyerOrderChangeEvent;
import com.yohoufo.order.model.bo.ActivityBo;
import com.yohoufo.order.service.proxy.BaseServiceCaller;
import com.yohoufo.order.service.listener.BuyerOrderChangeEvent;
import com.yohoufo.order.service.proxy.BargainProxyService;
import com.yohoufo.order.service.proxy.BaseServiceCaller;
import com.yohoufo.order.service.stats.StatsConfigManager;
import com.yohoufo.order.service.stats.impl.SellerOrderStatsConfiguration;
import com.yohoufo.order.service.stats.impl.SellerOrderStatsEntry;
import com.yohoufo.order.service.support.BuyerOrderMetaMapperSupport;
import com.yohoufo.order.utils.LoggerUtils;
import org.slf4j.Logger;
... ... @@ -46,8 +50,12 @@ public class BuyerOrderChangeBusinessPostProcessor {
@Autowired
private BaseServiceCaller baseServiceCaller;
@Autowired
private StatsConfigManager<SellerOrderStatsEntry, SellerOrderStatsConfiguration> statsConfigurationManager;
//业务处理器
private List<BusinessProcessor> processors = Lists.newArrayList(
new SellerOrderQuantityStatsBusinessProcessor(),
new NotifyProcessor(),
new DefaultBusinessProcessor(),
//砍价
... ... @@ -124,6 +132,52 @@ public class BuyerOrderChangeBusinessPostProcessor {
}
}
/**
* 鉴定通过
*
* @param buyerOrder
* @param bizCase
* @param targetStatus
*/
public void fireAppraiseSuccess(BuyerOrder buyerOrder, BuyerOrderChangeEvent.BizCase bizCase, OrderStatus targetStatus) {
BusinessProcessorContext context = buildBusinessProcessorContext(buyerOrder, bizCase, targetStatus);
for (BusinessProcessor processor : processors) {
try {
processor.appraiseSuccess(context);
} catch (Exception ex) {
logger.warn("{} appraiseSuccess error,context:{}", processor.getClass().getName(), context, ex);
//告警
EventBusPublisher.publishEvent(
new SmsAlarmEvent("ufo.buyerOrderBusinessPostProcessor", "appraiseSuccess_exception",
processor.getClass().getName() + "(" + buyerOrder.getOrderCode() + ")", ex)
);
}
}
}
/**
* 瑕疵接受
*
* @param buyerOrder
* @param bizCase
* @param targetStatus
*/
public void fireFaultAccept(BuyerOrder buyerOrder, BuyerOrderChangeEvent.BizCase bizCase, OrderStatus targetStatus) {
BusinessProcessorContext context = buildBusinessProcessorContext(buyerOrder, bizCase, targetStatus);
for (BusinessProcessor processor : processors) {
try {
processor.acceptFault(context);
} catch (Exception ex) {
logger.warn("{} acceptFault error,context:{}", processor.getClass().getName(), context, ex);
//告警
EventBusPublisher.publishEvent(
new SmsAlarmEvent("ufo.buyerOrderBusinessPostProcessor", "acceptFault_exception",
processor.getClass().getName() + "(" + buyerOrder.getOrderCode() + ")", ex)
);
}
}
}
public BusinessProcessorContext buildBusinessProcessorContext(BuyerOrder buyerOrder, BuyerOrderChangeEvent.BizCase bizCase, OrderStatus targetStatus) {
BusinessProcessorContext context = new BusinessProcessorContext();
... ... @@ -170,6 +224,12 @@ public class BuyerOrderChangeBusinessPostProcessor {
//支付成功
void paySuccess(BusinessProcessorContext context);
//鉴定通过
void appraiseSuccess(BusinessProcessorContext context);
//接受瑕疵
void acceptFault(BusinessProcessorContext context);
}
/**
... ... @@ -190,6 +250,44 @@ public class BuyerOrderChangeBusinessPostProcessor {
public void paySuccess(BusinessProcessorContext context) {
}
@Override
public void appraiseSuccess(BusinessProcessorContext context) {
}
@Override
public void acceptFault(BusinessProcessorContext context) {
}
}
/**
* 卖家订单统计
*/
private class SellerOrderQuantityStatsBusinessProcessor extends BusinessProcessorAdapter {
@Override
public void appraiseSuccess(BusinessProcessorContext context) {
doProcess(context.buyerOrder);
}
@Override
public void acceptFault(BusinessProcessorContext context) {
doProcess(context.buyerOrder);
}
private void doProcess(BuyerOrder buyerOrder) {
SellerOrderStatsEntry statsEntry = SellerOrderStatsEntry.builder()
.buyerUid(buyerOrder.getUid())
.buyerOrderCode(buyerOrder.getOrderCode())
.sellerUid(buyerOrder.getSellerUid())
.orderAttribute(OrderAttributes.getOrderAttributes(buyerOrder.getAttributes()))
.build();
SellerOrderStatsConfiguration statsConfig = statsConfigurationManager.getStatsConfig(statsEntry);
statsConfigurationManager.getStatsProcessor(statsConfig.getStatsProcessorName()).accept(statsEntry, statsConfig);
}
}
/**
... ... @@ -241,7 +339,7 @@ public class BuyerOrderChangeBusinessPostProcessor {
}
//砍价业务
private class BargainBusinessProcessor implements BusinessProcessor {
private class BargainBusinessProcessor extends BusinessProcessorAdapter {
@Override
public void create(BusinessProcessorContext context) {
... ...
package com.yohoufo.order.service.seller.setting;
import com.google.common.collect.Lists;
import com.yohobuy.ufo.model.order.bo.SellerBo;
import com.yohobuy.ufo.model.order.bo.SellerLevelFuncBo;
import com.yohobuy.ufo.model.order.common.EntrySellerType;
import com.yohobuy.ufo.model.order.common.OrderAttributes;
import com.yohobuy.ufo.model.order.common.SuperEnterStageLevel;
import com.yohobuy.ufo.model.order.resp.EntryThreshold;
import com.yohobuy.ufo.model.order.resp.SellerPlatformServiceFeeResp;
import com.yohoufo.common.cache.CacheKeyEnum;
import com.yohoufo.dal.order.SellerEnterApplyMapper;
import com.yohoufo.dal.order.StoredSellerMapper;
import com.yohoufo.dal.order.SuperEntrySellerMapper;
import com.yohoufo.dal.order.model.SuperEntrySeller;
import com.yohoufo.order.common.SuperEntrySellerStatus;
import com.yohoufo.order.model.bo.PlatformServiceFeeDefinition;
import com.yohoufo.order.model.bo.SellerPlatformServiceFee;
import com.yohoufo.order.service.IStoredSellerService;
import com.yohoufo.order.service.MerchantOrderPaymentService;
import com.yohoufo.order.service.cache.StoredSellerCacheService;
import com.yohoufo.order.service.impl.MetaConfigService;
import com.yohoufo.order.service.stats.StatsConfigManager;
import com.yohoufo.order.service.stats.impl.SellerOrderStatsConfiguration;
import com.yohoufo.order.service.stats.impl.SellerOrderStatsEntry;
import com.yohoufo.order.utils.LoggerUtils;
import com.yohoufo.order.utils.MathUtils;
import com.yohoufo.order.utils.SellerHelper;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
... ... @@ -23,10 +32,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.*;
import java.util.stream.Collectors;
/**
... ... @@ -64,6 +70,9 @@ public class SellerService {
@Autowired
private SellerEnterApplyMapper sellerEnterApplyMapper;
@Autowired
private StatsConfigManager<SellerOrderStatsEntry, SellerOrderStatsConfiguration> statsConfigurationManager;
/**更低出价提醒
* 1)当有新卖家出价成功或调价成功时,给所有正在出售该sku(尺码)的其他卖家推送一条消息(push+消息盒子)
... ... @@ -150,6 +159,55 @@ public class SellerService {
return false;
}
/**
* 平台技术服务费
* 包括当前数量、规则明细
*
* @param uid
* @return
*/
public SellerPlatformServiceFeeResp platformServiceFeeDetail(int uid) {
logger.info("platformServiceFee uid {}", uid);
SellerOrderStatsEntry statsEntry = SellerOrderStatsEntry.builder().sellerUid(uid).orderAttribute(OrderAttributes.COMMON_IN_STOCK).build();
SellerOrderStatsConfiguration statsConfig = statsConfigurationManager.getStatsConfig(statsEntry);
SellerPlatformServiceFee serviceFee = (SellerPlatformServiceFee) statsConfigurationManager.getStatsProcessor(statsConfig.getStatsProcessorName()).apply(statsEntry, statsConfig);
if (Objects.isNull(serviceFee)) {
logger.info("platformServiceFee is null for uid {}", uid);
return SellerPlatformServiceFeeResp.builder()
.currentMonthRate(null)
.nodes(Lists.newArrayList())
.orderQuantity(0)
.build();
}
//扣点比例
List<PlatformServiceFeeDefinition.FeeRule> rules = serviceFee.getDefinition().getRules();
//从小到大排序
rules.sort(Comparator.comparing(PlatformServiceFeeDefinition.FeeRule::getThreshold));
List<SellerPlatformServiceFeeResp.Node> nodes = rules.stream().map(rule -> {
SellerPlatformServiceFeeResp.Node node = new SellerPlatformServiceFeeResp.Node();
node.setKey(rule.getThreshold());
node.setValue(MathUtils.convert2Percent(rule.getRate()));
return node;
}).collect(Collectors.toList());
SellerPlatformServiceFeeResp resp = SellerPlatformServiceFeeResp.builder()
.currentMonthRate(MathUtils.convert2Percent(serviceFee.getFeeRate()))
.nodes(nodes)
.orderQuantity(serviceFee.getOrderQuantity())
.build();
logger.info("platformServiceFee uid {},resp {}", uid, resp);
return resp;
}
... ...
package com.yohoufo.order.service.stats;
/**
* Created by jiexiang.wu on 2019/7/19.
*/
public interface StatsConfigManager<T extends StatsEntry, U extends StatsConfiguration> {
U getStatsConfig(T statsEntry);
StatsProcessor getStatsProcessor(String name);
}
... ...
package com.yohoufo.order.service.stats;
/**
* Created by jiexiang.wu on 2019/7/22.
* 统计配置
*/
public interface StatsConfiguration {
}
... ...
package com.yohoufo.order.service.stats;
/**
* Created by jiexiang.wu on 2019/7/19.
* 统计基础类 标识
*/
public interface StatsEntry {
}
... ...
package com.yohoufo.order.service.stats;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
/**
* Created by jiexiang.wu on 2019/7/19.
* 统计处理器
*/
public interface StatsProcessor<T extends StatsEntry, U extends StatsConfiguration, R> extends BiConsumer<T, U>, BiFunction<T, U, R> {
/**
* 名称
* 必须保证唯一,建议使用类名
*
* @return
*/
String getName();
/**
* 执行的动作
*
* @param t
* @param u
*/
@Override
void accept(T t, U u);
}
... ...
package com.yohoufo.order.service.stats;
import java.util.HashMap;
import java.util.Map;
/**
* Created by jiexiang.wu on 2019/7/19.
* 统计器注册容器
*/
public class StatsProcessorRegistry {
private final Map<String, StatsProcessor> statisticsMap = new HashMap<String, StatsProcessor>();
public StatsProcessor getStatsProcessor(String name) {
return statisticsMap.get(name);
}
public void registerStatsProcessor(StatsProcessor processor) {
statisticsMap.put(processor.getName(), processor);
}
}
\ No newline at end of file
... ...
package com.yohoufo.order.service.stats;
import com.yohoufo.common.utils.DateUtil;
import org.apache.commons.lang3.tuple.Pair;
import java.util.Date;
import java.util.stream.Stream;
/**
* Created by jiexiang.wu on 2019/7/22.
*/
public enum StatsUnit {
HOUR("H"), MONTH("M");
private String unit;
StatsUnit(String unit) {
this.unit = unit;
}
public String getUnit() {
return unit;
}
/**
* 根据delay,period,获取有效期元组
*
* @param delay 从当前时间延时多长时间生效,即开始时间
* @param period 周期,在开始时间的基础上 + period Unit
* @return pair<key,value> key:开始时间,value:结束时间
*/
public Pair<Integer, Integer> getValidityTimeTuple(int delay, int period) {
Date beginDate = null, endDate = null;
switch (this) {
case HOUR:
Date currentHour = DateUtil.getCurrentHourDate(new Date());
beginDate = DateUtil.calDateTime(currentHour, DateUtil.Operator.plus, delay, DateUtil.TimeUnit.hour);
endDate = DateUtil.calDateTime(beginDate, DateUtil.Operator.plus, period, DateUtil.TimeUnit.hour);
break;
case MONTH:
Date firstDayOfMonth = DateUtil.getFirstDayOfMonth(new Date());
beginDate = DateUtil.calDateTime(firstDayOfMonth, DateUtil.Operator.plus, delay, DateUtil.TimeUnit.month);
endDate = DateUtil.calDateTime(beginDate, DateUtil.Operator.plus, period, DateUtil.TimeUnit.month);
break;
}
//结束时间需要-1
return Pair.of(DateUtil.getDateTimeSecond(beginDate), DateUtil.getDateTimeSecond(endDate) - 1);
}
public static StatsUnit find(String unit) {
return Stream.of(StatsUnit.values())
.filter(e -> e.getUnit().equals(unit.toUpperCase()))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("unknown unit +(" + unit + ")"));
}
}
... ...
package com.yohoufo.order.service.stats.impl;
import com.yohoufo.order.service.stats.StatsProcessor;
import com.yohoufo.order.utils.LoggerUtils;
import org.slf4j.Logger;
import org.springframework.stereotype.Service;
/**
* Created by jiexiang.wu on 2019/7/22.
* nothing to do
*/
@Service
public class EmptyStatsProcessor implements StatsProcessor<SellerOrderStatsEntry, SellerOrderStatsConfiguration, Void> {
private Logger logger = LoggerUtils.getSellerOrderLogger();
@Override
public String getName() {
return "emptyStatsProcessor";
}
@Override
public void accept(SellerOrderStatsEntry entry, SellerOrderStatsConfiguration configuration) {
logger.info("accept entry:{},configuration:{},nothing to do", entry, configuration);
}
@Override
public Void apply(SellerOrderStatsEntry entry, SellerOrderStatsConfiguration configuration) {
logger.info("apply entry:{},configuration:{},nothing to do", entry, configuration);
return null;
}
}
... ...
package com.yohoufo.order.service.stats.impl;
import com.yohoufo.common.utils.DateUtil;
import com.yohoufo.dal.order.SellerOrderStatsResultMapper;
import com.yohoufo.dal.order.model.SellerOrderStatsResult;
import com.yohoufo.order.model.bo.PlatformServiceFeeDefinition;
import com.yohoufo.order.model.bo.SellerPlatformServiceFee;
import com.yohoufo.order.service.stats.StatsProcessor;
import com.yohoufo.order.utils.LoggerUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* Created by jiexiang.wu on 2019/7/19.
* 卖家订单数量汇总统计
*/
@Service
public class SellerOrderQuantityStatsProcessor implements StatsProcessor<SellerOrderStatsEntry, SellerOrderStatsConfiguration, SellerPlatformServiceFee> {
private Logger logger = LoggerUtils.getSellerOrderLogger();
@Autowired
private SellerOrderStatsResultMapper sellerOrderStatsResultMapper;
@Override
public String getName() {
return "sellerOrderQuantityStatsProcessor";
}
@Override
public void accept(SellerOrderStatsEntry entry, SellerOrderStatsConfiguration configuration) {
logger.info("accept entry:{},configuration:{}", entry, configuration);
Pair<Integer, Integer> timeTuple = configuration.getStatsUnit().getValidityTimeTuple(configuration.getStatsPeriod(), configuration.getStatsPeriod());
SellerOrderStatsResult quantityResult = new SellerOrderStatsResult();
quantityResult.setStatsCode(configuration.getStatsCode());
quantityResult.setUid(entry.getSellerUid());
quantityResult.setBeginTime(timeTuple.getKey());
quantityResult.setEndTime(timeTuple.getValue());
quantityResult.setQuantity(1);
int row = sellerOrderStatsResultMapper.insert(quantityResult);
if (row == 1) {
logger.info("stats process success");
} else {
logger.info("stats process fail");
}
}
@Override
public SellerPlatformServiceFee apply(SellerOrderStatsEntry entry, SellerOrderStatsConfiguration configuration) {
logger.info("apply entry:{},configuration:{}", entry, configuration);
SellerOrderStatsResult result = sellerOrderStatsResultMapper.selectStatsResult(entry.getSellerUid(), configuration.getStatsCode(), DateUtil.getCurrentTimeSecond());
int quantity = (result != null) ? result.getQuantity() : 0;
PlatformServiceFeeDefinition psfd = PlatformServiceFeeDefinition.convert(configuration.getActionParam());
SellerPlatformServiceFee serviceFee = new SellerPlatformServiceFee(quantity, psfd);
logger.info("seller platform service fee is:{},statsResult:{},entry:{}", serviceFee, result, entry);
return serviceFee;
}
}
\ No newline at end of file
... ...
package com.yohoufo.order.service.stats.impl;
import com.google.common.collect.Lists;
import com.yohobuy.ufo.model.order.common.OrderAttributes;
import com.yohoufo.order.service.stats.StatsConfiguration;
import com.yohoufo.order.service.stats.StatsUnit;
import lombok.*;
import java.util.List;
/**
* Created by jiexiang.wu on 2019/7/19.
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class SellerOrderStatsConfiguration implements StatsConfiguration {
public static SellerOrderStatsConfiguration emptyConfiguration = SellerOrderStatsConfiguration.builder().excludeUids(Lists.newArrayList()).statsProcessorName("emptyStatsProcessor").build();
private String statsCode;
//排除的uid
private List<Integer> excludeUids;
//属性
private List<OrderAttributes> orderAttributes;
private StatsUnit statsUnit;
private int statsPeriod;
private String statsProcessorName;
private String actionParam;
}
... ...
package com.yohoufo.order.service.stats.impl;
import com.yohoufo.order.service.cache.SellerOrderStatsConfigCacheService;
import com.yohoufo.order.service.stats.StatsConfigManager;
import com.yohoufo.order.service.stats.StatsProcessor;
import com.yohoufo.order.service.stats.StatsProcessorRegistry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.util.Objects;
/**
* Created by jiexiang.wu on 2019/7/19.
* 卖家订单统计配置管理
*/
@Service
public class SellerOrderStatsConfigurationManager implements StatsConfigManager<SellerOrderStatsEntry, SellerOrderStatsConfiguration> {
private StatsProcessorRegistry registry = new StatsProcessorRegistry();
@Autowired
private SellerOrderQuantityStatsProcessor sellerOrderQuantityStatsProcessor;
@Autowired
private EmptyStatsProcessor emptyStatsProcessor;
@Autowired
private SellerOrderStatsConfigCacheService sellerOrderStatsConfigCacheService;
@PostConstruct
public void init() {
registry.registerStatsProcessor(sellerOrderQuantityStatsProcessor);
registry.registerStatsProcessor(emptyStatsProcessor);
}
@Override
public SellerOrderStatsConfiguration getStatsConfig(SellerOrderStatsEntry statsEntry) {
SellerOrderStatsConfiguration configuration = sellerOrderStatsConfigCacheService.findBy(statsEntry.getOrderAttribute());
if (Objects.isNull(configuration) || configuration.getExcludeUids().stream().anyMatch(uid -> uid == statsEntry.getSellerUid())) {
// 没有找到配置项或卖家被排除
return SellerOrderStatsConfiguration.emptyConfiguration;
}
return configuration;
}
@Override
public StatsProcessor getStatsProcessor(String name) {
return registry.getStatsProcessor(name);
}
}
\ No newline at end of file
... ...
package com.yohoufo.order.service.stats.impl;
import com.yohobuy.ufo.model.order.common.OrderAttributes;
import com.yohoufo.order.service.stats.StatsEntry;
import lombok.*;
/**
* Created by jiexiang.wu on 2019/7/19.
*/
@Data
@Builder
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class SellerOrderStatsEntry implements StatsEntry {
private int sellerUid;
private int buyerUid;
private long buyerOrderCode;
private OrderAttributes orderAttribute;
}
... ...
package com.yohoufo.order.service.support;
import com.google.common.collect.Lists;
import com.yohobuy.ufo.model.order.common.OrderAttributes;
import com.yohobuy.ufo.model.order.resp.SellerPlatformServiceFeeResp;
import com.yohoufo.order.model.bo.SellerPlatformServiceFee;
import com.yohoufo.order.service.stats.StatsConfigManager;
import com.yohoufo.order.service.stats.impl.SellerOrderStatsConfiguration;
import com.yohoufo.order.service.stats.impl.SellerOrderStatsEntry;
import com.yohoufo.order.utils.LoggerUtils;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.Objects;
/**
* Created by jiexiang.wu on 2019/7/23.
*/
@Service
public class SellerPlatformServiceFeeSupport {
private static final Logger logger = LoggerUtils.getSellerOrderLogger();
@Autowired
private StatsConfigManager<SellerOrderStatsEntry, SellerOrderStatsConfiguration> statsConfigurationManager;
/**
* 获取平台技术服务费比例
*
* @param uid
* @param orderAttributes
* @return 可能为null
*/
public BigDecimal getPlatformServiceFeeRate(int uid, OrderAttributes orderAttributes) {
logger.info("platformServiceFeeRate,uid {}, attribute:{}", uid, orderAttributes);
SellerOrderStatsEntry statsEntry = SellerOrderStatsEntry.builder().sellerUid(uid).orderAttribute(orderAttributes).build();
SellerOrderStatsConfiguration statsConfig = statsConfigurationManager.getStatsConfig(statsEntry);
SellerPlatformServiceFee serviceFee = (SellerPlatformServiceFee) statsConfigurationManager.getStatsProcessor(statsConfig.getStatsProcessorName()).apply(statsEntry, statsConfig);
if (Objects.isNull(serviceFee)) {
logger.info("platformServiceFeeRate is null for uid {}", uid);
return null;
}
return serviceFee.getFeeRate();
}
}
... ...
package com.yohoufo.order.utils;
import com.alibaba.fastjson.JSON;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Created by jiexiang.wu on 2019/7/23.
*/
public class BeanTool {
private final static Logger logger = LoggerFactory.getLogger(BeanTool.class);
@SuppressWarnings("unchecked")
public static <T> T string2Value(String value, Class<T> clazz) {
if (StringUtils.isEmpty(value)) {
return null;
}
T t = null;
try {
if (clazz.equals(String.class)) {
t = (T) value;
} else if (clazz.equals(Integer.class)) {
t = (T) Integer.valueOf(value);
} else {
t = JSON.parseObject(value, clazz);
}
return t;
} catch (Exception ex) {
logger.error("string2Value({},{}) error", value, clazz, ex);
return null;
}
}
}
... ...
... ... @@ -109,6 +109,8 @@ datasources:
- com.yohoufo.dal.order.BlackUserMapper
- com.yohoufo.dal.order.StorageDepositMapper
- com.yohoufo.dal.order.DepositOrderMapper
- com.yohoufo.dal.order.SellerOrderStatsConfigMapper
- com.yohoufo.dal.order.SellerOrderStatsResultMapper
ufo_promotion:
servers:
... ...
... ... @@ -108,6 +108,8 @@ datasources:
- com.yohoufo.dal.order.BlackUserMapper
- com.yohoufo.dal.order.StorageDepositMapper
- com.yohoufo.dal.order.DepositOrderMapper
- com.yohoufo.dal.order.SellerOrderStatsConfigMapper
- com.yohoufo.dal.order.SellerOrderStatsResultMapper
ufo_promotion:
servers:
... ...