Authored by TANLING

优惠券限制可叠加

package com.yohoufo.common.helper;
import com.google.common.collect.Lists;
import com.yoho.service.model.promotion.ProductLimitValueBo;
import com.yohobuy.ufo.model.order.bo.ShoppingProductInfo;
import com.yohobuy.ufo.model.promotion.UserCouponsBo;
import com.yohobuy.ufo.model.promotion.constant.CouponProductLimitTypeEnum;
import com.yohobuy.ufo.model.promotion.response.ProductLimitInfo;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
... ... @@ -29,8 +28,45 @@ public class ProductLimitCollector {
LIMIT_VALUES_LIST.add(new ProductExcludeLimitValueHandler());
}
public static Optional<LimitValueHandler> getSpecifiedProductLimitHandler(CouponProductLimitTypeEnum productLimitTypeEnum) {
return LIMIT_VALUES_LIST.stream().filter(limitValueHandler -> limitValueHandler.getLimitValue() == productLimitTypeEnum).findFirst();
public static ProductLimitInfo getProductLimitInfo(List<ProductLimitValueBo> productLimitValueBo, Integer productLimitType, String productLimitValue ){
ProductLimitInfo productLimitInfo = new ProductLimitInfo();
// 处理 排除&指定的商品
if (CollectionUtils.isNotEmpty(productLimitValueBo)){
for (ProductLimitValueBo item : productLimitValueBo){
Optional<LimitValueHandler> handler = LIMIT_VALUES_LIST.stream().filter(x->Integer.valueOf(x.getLimitValue().getLimitType()) == item.getLimitType()).findFirst();
if (handler.isPresent()){
handler.get().setProductLimitValue(productLimitInfo, item.getProductIds(), productLimitValue);
}
}
}
Optional<LimitValueHandler> limitValueHandler = LIMIT_VALUES_LIST.stream().filter(x->Integer.valueOf(x.getLimitValue().getLimitType()) == productLimitType).findFirst();
limitValueHandler.ifPresent(x->x.setProductLimitValue(productLimitInfo, null, productLimitValue));
return productLimitInfo;
}
/**
*
* @param shoppingProductInfo
* @param productLimitInfo
* @return
*/
public static boolean match(ShoppingProductInfo shoppingProductInfo, ProductLimitInfo productLimitInfo){
for (LimitValueHandler limitValueHandler : LIMIT_VALUES_LIST){
if (!limitValueHandler.isMatch(shoppingProductInfo, productLimitInfo)){
return false;
}
}
return true;
}
... ... @@ -59,7 +95,7 @@ public class ProductLimitCollector {
* @param productIds
* @param productLimitValue
*/
ProductLimitInfo getProductLimitInfo(List<Integer> productIds, String productLimitValue);
void setProductLimitValue(ProductLimitInfo productLimitInfo, List<Integer> productIds, String productLimitValue);
/**
* 是否满足使用条件
... ... @@ -77,8 +113,8 @@ public class ProductLimitCollector {
}
@Override
public ProductLimitInfo getProductLimitInfo(List<Integer> productIds, String productLimitValue) {
return ProductLimitInfo.builder().build();
public void setProductLimitValue(ProductLimitInfo productLimitInfo, List<Integer> productIds, String productLimitValue) {
}
... ... @@ -99,15 +135,14 @@ public class ProductLimitCollector {
}
@Override
public ProductLimitInfo getProductLimitInfo(List<Integer> productIds, String productLimitValue) {
return ProductLimitInfo.builder().brandInclude(covertProductLimitValueList(productLimitValue)).build();
public void setProductLimitValue(ProductLimitInfo productLimitInfo, List<Integer> productIds, String productLimitValue) {
productLimitInfo.setBrandInclude(covertProductLimitValueList(productLimitValue));
}
@Override
public boolean isMatch(ShoppingProductInfo shoppingProductInfo, ProductLimitInfo productLimitInfo) {
return CollectionUtils.isNotEmpty(productLimitInfo.getBrandInclude())
&& productLimitInfo.getBrandInclude().contains(shoppingProductInfo.getBrandId());
return CollectionUtils.isEmpty(productLimitInfo.getBrandInclude()) || (CollectionUtils.isNotEmpty(productLimitInfo.getBrandInclude())
&& productLimitInfo.getBrandInclude().contains(shoppingProductInfo.getBrandId()));
}
}
... ... @@ -120,16 +155,17 @@ public class ProductLimitCollector {
}
@Override
public ProductLimitInfo getProductLimitInfo(List<Integer> productIds, String productLimitValue) {
return ProductLimitInfo.builder().categoryInclude(covertProductLimitValueList(productLimitValue)).build();
public void setProductLimitValue(ProductLimitInfo productLimitInfo, List<Integer> productIds, String productLimitValue) {
productLimitInfo.setCategoryInclude(covertProductLimitValueList(productLimitValue));
}
@Override
public boolean isMatch(ShoppingProductInfo shoppingProductInfo, ProductLimitInfo productLimitInfo) {
return CollectionUtils.isNotEmpty(productLimitInfo.getCategoryInclude())
&& productLimitInfo.getCategoryInclude().contains(shoppingProductInfo.getCategoryId());
return CollectionUtils.isEmpty(productLimitInfo.getCategoryInclude()) ||
(CollectionUtils.isNotEmpty(productLimitInfo.getCategoryInclude())
&& productLimitInfo.getCategoryInclude().contains(shoppingProductInfo.getCategoryId()));
}
... ... @@ -143,14 +179,15 @@ public class ProductLimitCollector {
}
@Override
public ProductLimitInfo getProductLimitInfo(List<Integer> productIds, String productLimitValue) {
return ProductLimitInfo.builder().seriesInclude(covertProductLimitValueList(productLimitValue)).build();
public void setProductLimitValue(ProductLimitInfo productLimitInfo, List<Integer> productIds, String productLimitValue) {
productLimitInfo.setSeriesInclude((covertProductLimitValueList(productLimitValue)));
}
@Override
public boolean isMatch(ShoppingProductInfo shoppingProductInfo, ProductLimitInfo productLimitInfo) {
return CollectionUtils.isNotEmpty(productLimitInfo.getSeriesInclude())
&& productLimitInfo.getSeriesInclude().contains(shoppingProductInfo.getSeriesId());
return CollectionUtils.isEmpty(productLimitInfo.getSeriesInclude())
|| (CollectionUtils.isNotEmpty(productLimitInfo.getSeriesInclude())
&& productLimitInfo.getSeriesInclude().contains(shoppingProductInfo.getSeriesId()));
}
}
... ... @@ -163,8 +200,8 @@ public class ProductLimitCollector {
}
@Override
public ProductLimitInfo getProductLimitInfo(List<Integer> productIds, String productLimitValue) {
return ProductLimitInfo.builder().productIdInclude(covertProductLimitValueList(productLimitValue)).build();
public void setProductLimitValue(ProductLimitInfo productLimitInfo, List<Integer> productIds, String productLimitValue) {
productLimitInfo.setProductIdInclude(productIds);
}
... ... @@ -172,8 +209,9 @@ public class ProductLimitCollector {
public boolean isMatch(ShoppingProductInfo shoppingProductInfo, ProductLimitInfo productLimitInfo) {
//包含商品
return CollectionUtils.isNotEmpty(productLimitInfo.getProductIdInclude())
&& productLimitInfo.getProductIdInclude().contains(shoppingProductInfo.getProductId());
return CollectionUtils.isEmpty(productLimitInfo.getProductIdInclude())
|| (CollectionUtils.isNotEmpty(productLimitInfo.getProductIdInclude())
&& productLimitInfo.getProductIdInclude().contains(shoppingProductInfo.getProductId()));
}
}
... ... @@ -186,15 +224,16 @@ public class ProductLimitCollector {
}
@Override
public ProductLimitInfo getProductLimitInfo(List<Integer> productIds, String productLimitValue) {
return ProductLimitInfo.builder().productIdExclude(covertProductLimitValueList(productLimitValue)).build();
public void setProductLimitValue(ProductLimitInfo productLimitInfo, List<Integer> productIds, String productLimitValue) {
productLimitInfo.setProductIdExclude(productIds);
}
@Override
public boolean isMatch(ShoppingProductInfo shoppingProductInfo, ProductLimitInfo productLimitInfo) {
//排除商品
return CollectionUtils.isNotEmpty(productLimitInfo.getProductIdExclude())
&& !productLimitInfo.getProductIdExclude().contains(shoppingProductInfo.getProductId());
return CollectionUtils.isEmpty(productLimitInfo.getProductIdExclude())
|| (CollectionUtils.isNotEmpty(productLimitInfo.getProductIdExclude())
&& !productLimitInfo.getProductIdExclude().contains(shoppingProductInfo.getProductId()));
}
}
... ...
... ... @@ -31,7 +31,7 @@ public class Coupon {
private Short useLimitValue;
private Byte productLimitType;
private Integer productLimitType;
private String productLimitValue;
... ... @@ -167,11 +167,11 @@ public class Coupon {
this.useLimitValue = useLimitValue;
}
public Byte getProductLimitType() {
public Integer getProductLimitType() {
return productLimitType;
}
public void setProductLimitType(Byte productLimitType) {
public void setProductLimitType(Integer productLimitType) {
this.productLimitType = productLimitType;
}
... ...
... ... @@ -5,7 +5,7 @@ public class CouponProductLimit {
private Integer couponId;
private Byte limitType;
private Integer limitType;
private Integer productId;
... ... @@ -25,11 +25,11 @@ public class CouponProductLimit {
this.couponId = couponId;
}
public Byte getLimitType() {
public Integer getLimitType() {
return limitType;
}
public void setLimitType(Byte limitType) {
public void setLimitType(Integer limitType) {
this.limitType = limitType;
}
... ...
... ... @@ -4,7 +4,7 @@
<resultMap id="BaseResultMap" type="com.yohoufo.dal.promotion.model.CouponProductLimit" >
<id column="id" property="id" jdbcType="INTEGER" />
<result column="coupon_id" property="couponId" jdbcType="INTEGER" />
<result column="limit_type" property="limitType" jdbcType="TINYINT" />
<result column="limit_type" property="limitType" jdbcType="INTEGER" />
<result column="product_id" property="productId" jdbcType="INTEGER" />
</resultMap>
<sql id="Base_Column_List" >
... ...
... ... @@ -109,17 +109,9 @@ public class CouponRuleMatcher {
@Override
public boolean match(ChargeGoods chargeGoods, UserCouponsBo couponsBo) {
final CouponProductLimitTypeEnum limitTypeEnum = CouponProductLimitTypeEnum.of(couponsBo.getProductLimitType()).orElse(null);
Optional<ProductLimitCollector.LimitValueHandler> valueHandlerOptional =
ProductLimitCollector.getSpecifiedProductLimitHandler(limitTypeEnum);
return ProductLimitCollector.match(chargeGoods.getShoppingProductInfo(), couponsBo.getProductLimitInfo());
if (valueHandlerOptional.isPresent()) {
return valueHandlerOptional.get().isMatch(chargeGoods.getShoppingProductInfo(), couponsBo.getProductLimitInfo());
} else {
//目前不存在
return false;
}
}
}
... ...
package com.yohoufo.promotion.convert;
import com.google.common.collect.Lists;
import com.yoho.service.model.promotion.ProductLimitValueBo;
import com.yohobuy.ufo.model.promotion.CouponSimpleBo;
import com.yohobuy.ufo.model.promotion.UserCouponsBo;
import com.yohobuy.ufo.model.promotion.constant.*;
... ... @@ -35,10 +36,10 @@ public class CouponConvert {
* @param userCoupon
* @param coupon
* @param couponType
* @param productIds
* @param productLimitValueBo
* @return
*/
public static UserCouponsBo covertCouponBo(UserCoupon userCoupon, Coupon coupon, CouponType couponType, List<Integer> productIds){
public static UserCouponsBo covertCouponBo(UserCoupon userCoupon, Coupon coupon, CouponType couponType, List<ProductLimitValueBo> productLimitValueBo){
UserCouponsBo couponBo = new UserCouponsBo();
... ... @@ -73,17 +74,9 @@ public class CouponConvert {
couponBo.setCouponTypeName(couponType.getCaption());
}
CouponProductLimitTypeEnum productLimitTypeEnum = CouponProductLimitTypeEnum.of(String.valueOf(coupon.getProductLimitType())).orElse(null);
if (productLimitTypeEnum == CouponProductLimitTypeEnum.SPECIFIC_PRODUCT) {
couponBo.setProductIdInclude(productIds);
} else if (productLimitTypeEnum == CouponProductLimitTypeEnum.EXCLUDE_PRODUCT) {
couponBo.setProductIdExclude(productIds);
}
// 根据商品限制类型,设置值
ProductLimitCollector.getSpecifiedProductLimitHandler(productLimitTypeEnum)
.ifPresent(limitValueSetter -> couponBo.setProductLimitInfo(limitValueSetter.getProductLimitInfo( productIds, coupon.getProductLimitValue())));
ProductLimitInfo productLimitInfo = ProductLimitCollector.getProductLimitInfo(productLimitValueBo, coupon.getProductLimitType(), coupon.getProductLimitValue());
couponBo.setProductLimitInfo(productLimitInfo);
couponBo.setBusinessClient(coupon.getBusinessClient());
... ...
package com.yohoufo.promotion.service.impl;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Range;
import com.yoho.core.redis.cluster.operations.serializer.RedisKeyBuilder;
import com.yoho.error.ServiceError;
import com.yoho.error.exception.ServiceException;
import com.yoho.service.model.promotion.ProductLimitValueBo;
import com.yohobuy.ufo.model.promotion.CouponSimpleBo;
import com.yohobuy.ufo.model.promotion.UserCouponsBo;
import com.yohobuy.ufo.model.promotion.UserCouponsListBo;
import com.yohobuy.ufo.model.promotion.constant.CouponProductLimitTypeEnum;
import com.yohobuy.ufo.model.promotion.constant.CouponUseStatusEnum;
import com.yohobuy.ufo.model.promotion.constant.CouponsStatusEnum;
import com.yohoufo.dal.promotion.CouponProductLimitMapper;
import com.yohoufo.promotion.model.CouponReceiveChannel;
import com.yohobuy.ufo.model.promotion.request.CouponSendType;
import com.yohobuy.ufo.model.promotion.request.UserCouponListReq;
... ... @@ -37,6 +40,7 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.lang.reflect.Array;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
... ... @@ -62,6 +66,9 @@ public class CouponServiceImpl implements ICouponService {
CouponMapper couponMapper;
@Autowired
CouponProductLimitMapper couponProductLimitMapper;
@Autowired
SingleCentCouponService singleCentSyncCoupNumService;
@Autowired
... ... @@ -83,24 +90,27 @@ public class CouponServiceImpl implements ICouponService {
if (CouponProductLimitTypeEnum.NON.getLimitType().equals(coupon.getProductLimitType().toString())) {
return new CouponInfo();
}
Map<Integer, List<Integer>> map = getAssociatedProductIdListMap(Arrays.asList(coupon));
if (map.isEmpty()) {
return null;
}
String productIds = StringUtils.join(map.values().iterator().next(), ",");
CouponInfo info = new CouponInfo();
if (CouponProductLimitTypeEnum.SPECIFIC_PRODUCT.getLimitType().equals(coupon.getProductLimitType().toString())) {
info.setContainsProductIds(productIds);
}
if (CouponProductLimitTypeEnum.EXCLUDE_PRODUCT.getLimitType().equals(coupon.getProductLimitType().toString())) {
info.setExcludeProductIds(productIds);
// Map<Integer, List<Integer>> map = getAssociatedProductIdListMap(Arrays.asList(coupon));
// if (map.isEmpty()) {
// return null;
// }
// String productIds = StringUtils.join(map.values().iterator().next(), ",");
// CouponInfo info = new CouponInfo();
// if (CouponProductLimitTypeEnum.SPECIFIC_PRODUCT.getLimitType().equals(coupon.getProductLimitType().toString())) {
// info.setContainsProductIds(productIds);
// }
// if (CouponProductLimitTypeEnum.EXCLUDE_PRODUCT.getLimitType().equals(coupon.getProductLimitType().toString())) {
// info.setExcludeProductIds(productIds);
// }
List<ProductLimitValueBo> productLimitValueBo = null;
Map<Integer, List<ProductLimitValueBo>> productLimitValueBoMap = getAssociatedProductIdMap(Arrays.asList(coupon));
if (productLimitValueBoMap != null){
productLimitValueBo = productLimitValueBoMap.get(coupon.getId());
}
CouponProductLimitTypeEnum limitTypeEnum = CouponProductLimitTypeEnum.of( String.valueOf(coupon.getProductLimitType())).orElse(null);
ProductLimitCollector.getSpecifiedProductLimitHandler(limitTypeEnum)
.ifPresent(limitValueHandler -> info.setProductLimitInfo(limitValueHandler.getProductLimitInfo(map.get(coupon.getId()) , coupon.getProductLimitValue() )));
CouponInfo info = new CouponInfo();
info.setProductLimitInfo(ProductLimitCollector.getProductLimitInfo(productLimitValueBo, coupon.getProductLimitType(), coupon.getProductLimitValue()));
return info;
}
... ... @@ -422,17 +432,47 @@ public class CouponServiceImpl implements ICouponService {
}).collect(Collectors.toMap(Coupon::getId, Function.identity()));
// 优惠券商品限制 key=couponId, value=ProductId集合
final Map<Integer, List<Integer>> couponProductIdMap = getAssociatedProductIdListMap(couponList);
// final Map<Integer, List<Integer>> couponProductIdMap = getAssociatedProductIdListMap(couponList);
Map<Integer, List<ProductLimitValueBo>> productLimitValueBoMap = getAssociatedProductIdMap(couponList);
//包装返回结果
List<UserCouponsBo> couponBoList = list.stream()
.filter(userCoupon -> couponMap.containsKey(userCoupon.getCouponId()))
.map(userCoupon -> wrapperUserCoupon(userCoupon, couponMap.get(userCoupon.getCouponId()), couponProductIdMap.get(userCoupon.getCouponId())))
.map(userCoupon -> wrapperUserCoupon(userCoupon, couponMap.get(userCoupon.getCouponId()), productLimitValueBoMap.get(userCoupon.getCouponId())))
.collect(Collectors.toList());
return UserCouponsListBo.builder().coupons(couponBoList).build();
}
private Map<Integer, List<ProductLimitValueBo>> getAssociatedProductIdMap(List<Coupon> couponList){
List<CouponProductLimit> couponProductLimitList = couponProductLimitMapper.selectByCouponIds(couponList.stream().map(Coupon::getId).collect(Collectors.toList()));
Map<Integer, List<CouponProductLimit>> map = couponProductLimitList.stream().collect(Collectors.groupingBy(CouponProductLimit::getCouponId));
// key=couponId, value=
Map<Integer, List<ProductLimitValueBo>> productLimitValueBoMap = Maps.newHashMap();
for (Integer couponId : map.keySet()){
List<ProductLimitValueBo> productLimitValueBos = Lists.newArrayList();
// key=limitType, value=
Map<Integer, List<CouponProductLimit>> typeToItem = map.get(couponId).stream().collect(Collectors.groupingBy(CouponProductLimit::getLimitType));
for (Integer type : typeToItem.keySet()){
productLimitValueBos.add(ProductLimitValueBo.builder()
.limitType(type)
.productIds(typeToItem.get(type).stream().map(CouponProductLimit::getProductId).collect(Collectors.toList())).build());
}
productLimitValueBoMap.put(couponId, productLimitValueBos);
}
return productLimitValueBoMap;
}
/**
* 关联的商品id
*
... ... @@ -478,7 +518,8 @@ public class CouponServiceImpl implements ICouponService {
}).collect(Collectors.toMap(Coupon::getId, Function.identity()));
// 优惠券商品限制 key=couponId, value=ProductId集合
Map<Integer, List<Integer>> couponProductIdMap = getAssociatedProductIdListMap(couponList);
// Map<Integer, List<Integer>> couponProductIdMap = getAssociatedProductIdListMap(couponList);
Map<Integer, List<ProductLimitValueBo>> productLimitValueBoMap = getAssociatedProductIdMap(couponList);
int time = DateUtil.getCurrentTimeSecond();
... ... @@ -514,19 +555,19 @@ public class CouponServiceImpl implements ICouponService {
}
//所有的校验都通过了,生成bo
return wrapperUserCoupon(userCoupon, coupon, couponProductIdMap.get(userCoupon.getCouponId()));
return wrapperUserCoupon(userCoupon, coupon, productLimitValueBoMap.get(userCoupon.getCouponId()));
}).collect(Collectors.toList());
return UserCouponsListBo.builder().coupons(couponBoList).build();
}
private UserCouponsBo wrapperUserCoupon(final UserCoupon userCoupon, final Coupon coupon, final List<Integer> productIds) {
private UserCouponsBo wrapperUserCoupon(final UserCoupon userCoupon, final Coupon coupon, final List<ProductLimitValueBo> productLimitValueBo) {
// 单个获取couponType
CouponType couponType = couponCacheService.getCouponTypeWithCache(userCoupon.getCouponType() != null ? userCoupon.getCouponType().intValue() : null);
UserCouponsBo couponBo = CouponConvert.covertCouponBo(userCoupon, coupon, couponType, productIds);
UserCouponsBo couponBo = CouponConvert.covertCouponBo(userCoupon, coupon, couponType, productLimitValueBo);
return couponBo;
}
... ...