Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop into fengtianyangyang_clerk

 Conflicts:
	DB/version4.2.3toMASTER.sql
	common-api/src/main/java/cn/lili/controller/common/SiteController.java
	common-api/src/main/java/cn/lili/controller/common/UploadController.java
	config/application.yml
	framework/src/main/java/cn/lili/modules/goods/entity/dos/Goods.java
	framework/src/main/java/cn/lili/modules/member/serviceimpl/MemberServiceImpl.java
	framework/src/main/java/cn/lili/modules/order/order/serviceimpl/OrderServiceImpl.java
	framework/src/main/java/cn/lili/modules/page/serviceimpl/PageDataServiceImpl.java
This commit is contained in:
fengtianyangyang
2022-08-09 18:54:19 +08:00
237 changed files with 4985 additions and 2159 deletions

View File

@@ -465,16 +465,19 @@ public enum CachePrefix {
*/
INIT_INDEX_FLAG,
/**
* 店铺
*/
STORE,
/**
* 店铺分类
*/
STORE_CATEGORY,
/**
* 用户菜单
*/
MENU_USER_ID,
/**
* 用户菜单
* <p>
* 这个缓存并非永久缓存而是300秒缓存也就是说修改用户关联的部门关联的角色
* 部门关联的角色角色关联的菜单等等最多需要5分钟才能生效
*/
STORE_MENU_USER_ID,
/**

View File

@@ -6,6 +6,7 @@ import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
/**
* 要实现对象的缓存定义自己的序列化和反序列化器。使用阿里的fastjson来实现的比较多
@@ -13,8 +14,8 @@ import java.nio.charset.Charset;
* @author Bulbasaur
*/
public class FastJsonRedisSerializer<T> implements RedisSerializer<T> {
private static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
private Class<T> clazz;
private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
private final Class<T> clazz;
public FastJsonRedisSerializer(Class<T> clazz) {
super();
@@ -26,7 +27,10 @@ public class FastJsonRedisSerializer<T> implements RedisSerializer<T> {
if (null == t) {
return new byte[0];
}
return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
return JSON.toJSONString(t,
SerializerFeature.WriteClassName,
SerializerFeature.DisableCircularReferenceDetect)
.getBytes(DEFAULT_CHARSET);
}
@Override

View File

@@ -11,7 +11,6 @@ import org.redisson.config.ClusterServersConfig;
import org.redisson.config.Config;
import org.redisson.config.SentinelServersConfig;
import org.redisson.config.SingleServerConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@@ -56,13 +55,11 @@ import java.util.Map;
public class RedisConfig extends CachingConfigurerSupport {
private static final String REDIS_PREFIX = "redis://";
@Value("${lili.cache.timeout:7200}")
private Integer timeout;
@Autowired
private RedisProperties redisProperties;
/**
* 当有多个管理器的时候,必须使用该注解在一个管理器上注释:表示该管理器为默认的管理器
*
@@ -101,7 +98,7 @@ public class RedisConfig extends CachingConfigurerSupport {
public RedisTemplate<Object, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
//使用fastjson序列化
FastJsonRedisSerializer fastJsonRedisSerializer = new FastJsonRedisSerializer(Object.class);
FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);
//value值的序列化采用fastJsonRedisSerializer
template.setValueSerializer(fastJsonRedisSerializer);
template.setHashValueSerializer(fastJsonRedisSerializer);
@@ -113,16 +110,15 @@ public class RedisConfig extends CachingConfigurerSupport {
}
@Bean(destroyMethod = "shutdown")
public RedissonClient redisson() {
public RedissonClient redisson(RedisProperties redisProperties) {
Config config = new Config();
if (redisProperties.getSentinel() != null && !redisProperties.getSentinel().getNodes().isEmpty()) {
// 哨兵模式
SentinelServersConfig sentinelServersConfig = config.useSentinelServers();
sentinelServersConfig.setMasterName(redisProperties.getSentinel().getMaster());
List<String> sentinelAddress = new ArrayList<>();
for (String node : redisProperties.getCluster().getNodes()) {
sentinelAddress.add("redis://" + node);
sentinelAddress.add(REDIS_PREFIX + node);
}
sentinelServersConfig.setSentinelAddresses(sentinelAddress);
if (CharSequenceUtil.isNotEmpty(redisProperties.getSentinel().getPassword())) {
@@ -133,7 +129,7 @@ public class RedisConfig extends CachingConfigurerSupport {
ClusterServersConfig clusterServersConfig = config.useClusterServers();
List<String> clusterNodes = new ArrayList<>();
for (String node : redisProperties.getCluster().getNodes()) {
clusterNodes.add("redis://" + node);
clusterNodes.add(REDIS_PREFIX + node);
}
clusterServersConfig.setNodeAddresses(clusterNodes);
if (CharSequenceUtil.isNotEmpty(redisProperties.getPassword())) {
@@ -141,10 +137,11 @@ public class RedisConfig extends CachingConfigurerSupport {
}
} else {
SingleServerConfig singleServerConfig = config.useSingleServer();
singleServerConfig.setAddress("redis://" + redisProperties.getHost() + ":" + redisProperties.getPort());
singleServerConfig.setAddress(REDIS_PREFIX + redisProperties.getHost() + ":" + redisProperties.getPort());
if (CharSequenceUtil.isNotEmpty(redisProperties.getPassword())) {
singleServerConfig.setPassword(redisProperties.getPassword());
}
singleServerConfig.setPingConnectionInterval(1000);
}
return Redisson.create(config);

View File

@@ -0,0 +1,25 @@
package cn.lili.common.aop.annotation;
import java.lang.annotation.*;
/**
* 异常重试注解
*
* @author paulG
* @since 2022/4/26
**/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface RetryOperation {
/**
* 重试次数
*/
int retryCount() default 3;
/**
* 重试间隔
*/
int waitSeconds() default 10;
}

View File

@@ -1,13 +1,5 @@
package cn.lili.common.aop.interceptor;
/**
* 防重复提交业务
*
* @author Chopper
* @version v1.0
* 2022-01-25 09:20
*/
import cn.lili.cache.Cache;
import cn.lili.common.aop.annotation.PreventDuplicateSubmissions;
import cn.lili.common.enums.ResultCode;
@@ -23,6 +15,13 @@ import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
/**
* 防重复提交业务
*
* @author Chopper
* @version v1.0
* 2022-01-25 09:20
*/
@Aspect
@Component
@Slf4j
@@ -37,8 +36,8 @@ public class PreventDuplicateSubmissionsInterceptor {
try {
Long count = cache.incr(getParams(), preventDuplicateSubmissions.expire());
//如果超过1或者设置的参数,则表示重复提交了
if (count.intValue() >= preventDuplicateSubmissions.expire()) {
//如果超过2或者设置的参数,则表示重复提交了
if (count.intValue() >= 2) {
throw new ServiceException(ResultCode.LIMIT_ERROR);
}
}

View File

@@ -0,0 +1,50 @@
package cn.lili.common.aop.interceptor;
import cn.lili.common.aop.annotation.RetryOperation;
import cn.lili.common.exception.RetryException;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
/**
* @author paulG
* @since 2022/4/26
**/
@Aspect
@Component
@Slf4j
public class RetryAspect {
@Around(value = "@annotation(retryOperation)")
public Object retryOperation(ProceedingJoinPoint joinPoint, RetryOperation retryOperation) throws Throwable {
Object response = null;
int retryCount = retryOperation.retryCount();
int waitSeconds = retryOperation.waitSeconds();
boolean successful = false;
do {
try {
response = joinPoint.proceed();
successful = true;
} catch (RetryException ex) {
log.info("Operation failed, retries remaining: {}", retryCount);
retryCount--;
if (retryCount < 0) {
successful = true;
log.error(ex.getMessage());
}
if (waitSeconds > 0 && !successful) {
log.info("Waiting for {} second(s) before next retry", waitSeconds);
Thread.sleep(waitSeconds * 1000L);
}
}
} while (!successful);
return response;
}
}

View File

@@ -40,6 +40,7 @@ public enum ResultCode {
FILE_TYPE_NOT_SUPPORT(1010, "不支持上传的文件类型!"),
PLATFORM_NOT_SUPPORTED_IM(1006, "平台未开启IM"),
STORE_NOT_SUPPORTED_IM(1007, "店铺未开启IM"),
UNINITIALIZED_PASSWORD(1008, "非初始化密码,无法进行初始化设置"),
/**
* 分类
*/
@@ -75,9 +76,13 @@ public enum ResultCode {
GOODS_SKU_QUANTITY_ERROR(11011, "商品库存数量不能为负数"),
GOODS_SKU_QUANTITY_NOT_ENOUGH(11011, "商品库存不足"),
MUST_HAVE_GOODS_SKU(11012, "规格必须要有一个!"),
MUST_HAVE_SALES_MODEL(11022, "销售模式为批发时必须要有批发规则!"),
HAVE_INVALID_SALES_MODEL(11023, "批发规则存在小于等于0的无效数据"),
GOODS_PARAMS_ERROR(11013, "商品参数错误,刷新后重试"),
PHYSICAL_GOODS_NEED_TEMP(11014, "实物商品需选择配送模板"),
VIRTUAL_GOODS_NOT_NEED_TEMP(11015, "实物商品需选择配送模板"),
VIRTUAL_GOODS_NOT_NEED_TEMP(11015, "虚拟商品需选择配送模板"),
GOODS_NOT_EXIST_STORE(11017, "当前用户无权操作此商品"),
GOODS_TYPE_ERROR(11016, "需选择商品类型"),
@@ -187,6 +192,7 @@ public enum ResultCode {
MEMBER_ADDRESS_NOT_EXIST(31009, "订单无收货地址,请先配置收货地址"),
ORDER_DELIVER_NUM_ERROR(31010, "没有待发货的订单"),
ORDER_NOT_SUPPORT_DISTRIBUTION(31011, "购物车中包含不支持配送的商品,请重新选择收货地址,或者重新选择商品"),
ORDER_NOT_EXIST_VALID(31041, "购物车中无有效商品,请检查购物车内商品,或者重新选择商品"),
ORDER_CAN_NOT_CANCEL(31012, "当前订单状态不可取消"),
ORDER_BATCH_DELIVER_ERROR(31013, "批量发货,文件读取失败"),
ORDER_ITEM_NOT_EXIST(31014, "当前订单项不存在!"),
@@ -258,6 +264,7 @@ public enum ResultCode {
*/
PROMOTION_GOODS_NOT_EXIT(40000, "当前促销商品不存在!"),
PROMOTION_GOODS_QUANTITY_NOT_EXIT(40020, "当前促销商品库存不足!"),
PROMOTION_GOODS_DO_NOT_JOIN_WHOLESALE(40050, "批发商品无法参加促销"),
PROMOTION_SAME_ACTIVE_EXIST(40001, "活动时间内已存在同类活动,请选择关闭、删除当前时段的活动"),
PROMOTION_START_TIME_ERROR(40002, "活动起始时间不能小于当前时间"),
PROMOTION_END_TIME_ERROR(40003, "活动结束时间不能小于当前时间"),
@@ -282,11 +289,6 @@ public enum ResultCode {
COUPON_RECEIVE_ERROR(41005, "当前优惠券已经被领取完了,下次要早点来哦"),
COUPON_NUM_INSUFFICIENT_ERROR(41006, "优惠券剩余领取数量不足"),
COUPON_NOT_EXIST(41007, "当前优惠券不存在"),
COUPON_DO_NOT_RECEIVER(41030, "当前优惠券不允许主动领取"),
COUPON_ACTIVITY_NOT_EXIST(410022, "当前优惠券活动不存在"),
COUPON_SAVE_ERROR(41020, "保存优惠券失败"),
COUPON_ACTIVITY_SAVE_ERROR(41023, "保存优惠券活动失败"),
COUPON_DELETE_ERROR(41021, "删除优惠券失败"),
COUPON_LIMIT_NUM_LESS_THAN_0(41008, "领取限制数量不能为负数"),
COUPON_LIMIT_GREATER_THAN_PUBLISH(41009, "领取限制数量超出发行数量"),
COUPON_DISCOUNT_ERROR(41010, "优惠券折扣必须小于10且大于0"),
@@ -297,6 +299,15 @@ public enum ResultCode {
COUPON_MEMBER_NOT_EXIST(41015, "没有当前会员优惠券"),
COUPON_MEMBER_STATUS_ERROR(41016, "当前会员优惠券已过期/作废无法变更状态!"),
SPECIAL_CANT_USE(41019, "特殊商品不能使用优惠券,不能使用"),
COUPON_SAVE_ERROR(41020, "保存优惠券失败"),
COUPON_DELETE_ERROR(41021, "删除优惠券失败"),
COUPON_ACTIVITY_NOT_EXIST(41022, "当前优惠券活动不存在"),
COUPON_ACTIVITY_SAVE_ERROR(41023, "保存优惠券活动失败"),
COUPON_ACTIVITY_MAX_NUM(41024, "优惠券活动赠券数量最多为3"),
COUPON_DO_NOT_RECEIVER(41030, "当前优惠券不允许主动领取"),
/**
* 拼团

View File

@@ -0,0 +1,32 @@
package cn.lili.common.event;
import lombok.Getter;
import org.springframework.context.ApplicationEvent;
/**
* 事务提交后发生mq事件
*
* @author paulG
* @since 2022/1/19
**/
public class TransactionCommitSendMQEvent extends ApplicationEvent {
private static final long serialVersionUID = 5885956821347953071L;
@Getter
private final String topic;
@Getter
private final String tag;
@Getter
private final Object message;
public TransactionCommitSendMQEvent(Object source, String topic, String tag, Object message) {
super(source);
this.topic = topic;
this.tag = tag;
this.message = message;
}
}

View File

@@ -0,0 +1,21 @@
package cn.lili.common.exception;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 如需异常重试,则抛出此异常
*
* @author paulG
* @since 2022/4/26
**/
@EqualsAndHashCode(callSuper = true)
@Data
public class RetryException extends RuntimeException {
private static final long serialVersionUID = 7886918292771470846L;
public RetryException(String message) {
super(message);
}
}

View File

@@ -0,0 +1,38 @@
package cn.lili.common.listener;
import cn.lili.common.event.TransactionCommitSendMQEvent;
import cn.lili.rocketmq.RocketmqSendCallbackBuilder;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.event.TransactionPhase;
import org.springframework.transaction.event.TransactionalEventListener;
/**
* 事务提交监听器
*
* @author paulG
* @since 2022/1/19
**/
@Component
@Slf4j
public class TransactionCommitSendMQListener {
/**
* rocketMq
*/
@Autowired
private RocketMQTemplate rocketMQTemplate;
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void send(TransactionCommitSendMQEvent event) {
log.info("事务提交发送mq信息!{}", event);
String destination = event.getTopic() + ":" + event.getTag();
//发送订单变更mq消息
rocketMQTemplate.asyncSend(destination, event.getMessage(), RocketmqSendCallbackBuilder.commonCallback());
}
}

View File

@@ -1,7 +1,7 @@
package cn.lili.common.utils;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
/**
* 通用工具
@@ -9,6 +9,8 @@ import java.util.UUID;
*/
public class CommonUtil {
public static final String BASE_NUMBER = "0123456789";
/**
* 以UUID重命名
* @param fileName 文件名称
@@ -24,12 +26,12 @@ public class CommonUtil {
* 随机6位数生成
*/
public static String getRandomNum() {
Random random = new Random();
int num = random.nextInt(999999);
//不足六位前面补0
String str = String.format("%06d", num);
return str;
StringBuilder sb = new StringBuilder(6);
for (int i = 0; i < 6; i++) {
int num = ThreadLocalRandom.current().nextInt(BASE_NUMBER.length());
sb.append(BASE_NUMBER.charAt(num));
}
return sb.toString();
}
}

View File

@@ -20,6 +20,23 @@ public class DateUtil {
public static final String FULL_DATE = "yyyyMMddHHmmss";
/**
* 当天的开始时间
*
* @return 今天开始时间
*/
public static Long getDayOfStart() {
return DateUtil.getDateline()/(60*24*60);
}
/**
* 指定日的开始时间
*
* @return 指定日时间
*/
public static Long getDayOfStart(Date date) {
return date.getTime()/(60*24*60);
}
/**
* 当天的开始时间
*

View File

@@ -147,6 +147,20 @@ public class StringUtils extends StrUtil {
return str.concat(appendStr);
}
/**
* 切割字符串
*
* @param str 字符串
* @param length 长度
* @return 处理后的字符串
*/
public static String sub(String str, Integer length) {
if (str.length() < length) {
return str;
}
return str.substring(0, length);
}
/**
* 过滤特殊字符串
*

View File

@@ -29,7 +29,6 @@ import org.springframework.beans.factory.annotation.Qualifier;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
/**
* @author paulG
@@ -124,7 +123,7 @@ public abstract class BaseElasticsearchService {
" \"type\": \"keyword\"\n" +
" },\n" +
" \"type\": {\n" +
" \"type\": \"long\"\n" +
" \"type\": \"integer\"\n" +
" },\n" +
" \"value\": {\n" +
" \"type\": \"keyword\"\n" +
@@ -165,14 +164,8 @@ public abstract class BaseElasticsearchService {
" \"type\": \"long\"\n" +
" },\n" +
" \"releaseTime\": {\n" +
" \"type\": \"text\",\n" +
" \"fielddata\": true, \n" +
" \"fields\": {\n" +
" \"keyword\": {\n" +
" \"type\": \"keyword\",\n" +
" \"ignore_above\": 256\n" +
" }\n" +
" }\n" +
" \"type\": \"date\",\n" +
" \"format\": \"yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis\"\n" +
" },\n" +
" \"categoryPath\": {\n" +
" \"type\": \"text\",\n" +
@@ -348,20 +341,20 @@ public abstract class BaseElasticsearchService {
PutMappingRequest request = new PutMappingRequest(index).source(source, XContentType.JSON);
CountDownLatch latch = new CountDownLatch(1);
AtomicReference<AcknowledgedResponse> response = new AtomicReference<>();
client.indices().putMappingAsync(
request,
RequestOptions.DEFAULT,
new ActionListener<AcknowledgedResponse>() {
@Override
public void onResponse(AcknowledgedResponse r) {
response.set(r);
latch.countDown();
log.info("创建索引mapping成功{}", r);
}
@Override
public void onFailure(Exception e) {
latch.countDown();
log.error("创建索引mapping失败", e);
}
});
latch.await(10, TimeUnit.SECONDS);

View File

@@ -16,7 +16,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.elasticsearch.config.AbstractElasticsearchConfiguration;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import javax.annotation.PreDestroy;
import java.io.IOException;
@@ -69,11 +68,6 @@ public class ElasticsearchConfig extends AbstractElasticsearchConfiguration {
return client;
}
@Bean("elasticsearchRestTemplate")
public ElasticsearchRestTemplate elasticsearchRestTemplate() {
return new ElasticsearchRestTemplate(this.client);
}
private HttpHost[] getHttpHosts() {
List<String> clusterNodes = elasticsearchProperties.getClusterNodes();
HttpHost[] httpHosts = new HttpHost[clusterNodes.size()];

View File

@@ -112,4 +112,11 @@ public interface ConnectService extends IService<Connect> {
* @return
*/
Connect queryConnect(ConnectQueryDTO connectQueryDTO);
/**
* 根据会员id删除记录
*
* @param userId 会员id
*/
void deleteByMemberId(String userId);
}

View File

@@ -8,7 +8,9 @@ import cn.lili.cache.CachePrefix;
import cn.lili.common.context.ThreadContextHolder;
import cn.lili.common.enums.ClientTypeEnum;
import cn.lili.common.enums.ResultCode;
import cn.lili.common.event.TransactionCommitSendMQEvent;
import cn.lili.common.exception.ServiceException;
import cn.lili.common.properties.RocketmqCustomProperties;
import cn.lili.common.security.AuthUser;
import cn.lili.common.security.context.UserContext;
import cn.lili.common.security.token.Token;
@@ -29,11 +31,13 @@ import cn.lili.modules.system.entity.dto.connect.WechatConnectSetting;
import cn.lili.modules.system.entity.dto.connect.dto.WechatConnectSettingItem;
import cn.lili.modules.system.entity.enums.SettingEnum;
import cn.lili.modules.system.service.SettingService;
import cn.lili.rocketmq.tags.MemberTagsEnum;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -66,6 +70,14 @@ public class ConnectServiceImpl extends ServiceImpl<ConnectMapper, Connect> impl
private MemberTokenGenerate memberTokenGenerate;
@Autowired
private Cache cache;
/**
* RocketMQ 配置
*/
@Autowired
private RocketmqCustomProperties rocketmqCustomProperties;
@Autowired
private ApplicationEventPublisher applicationEventPublisher;
@Override
@Transactional(rollbackFor = Exception.class)
@@ -89,6 +101,7 @@ public class ConnectServiceImpl extends ServiceImpl<ConnectMapper, Connect> impl
}
return memberTokenGenerate.createToken(member, longTerm);
} catch (NoPermissionException e) {
log.error("联合登陆失败:", e);
throw e;
}
}
@@ -121,7 +134,7 @@ public class ConnectServiceImpl extends ServiceImpl<ConnectMapper, Connect> impl
@Override
public void bind(String unionId, String type) {
AuthUser authUser = UserContext.getCurrentUser();
AuthUser authUser = Objects.requireNonNull(UserContext.getCurrentUser());
Connect connect = new Connect(authUser.getId(), unionId, type);
this.save(connect);
}
@@ -160,6 +173,7 @@ public class ConnectServiceImpl extends ServiceImpl<ConnectMapper, Connect> impl
@Override
@Transactional
public Token miniProgramAutoLogin(WechatMPLoginParams params) {
Object cacheData = cache.get(CachePrefix.WECHAT_SESSION_PARAMS.getPrefix() + params.getUuid());
@@ -186,8 +200,8 @@ public class ConnectServiceImpl extends ServiceImpl<ConnectMapper, Connect> impl
/**
* 通过微信返回等code 获取openid 等信息
*
* @param code
* @return
* @param code 微信code
* @return 微信返回的信息
*/
public JSONObject getConnect(String code) {
WechatConnectSettingItem setting = getWechatMPSetting();
@@ -208,11 +222,12 @@ public class ConnectServiceImpl extends ServiceImpl<ConnectMapper, Connect> impl
* @param params 微信小程序自动登录参数
* @param openId 微信openid
* @param unionId 微信unionid
* @return
* @return token
*/
@Transactional(rollbackFor = Exception.class)
public Token phoneMpBindAndLogin(String sessionKey, WechatMPLoginParams params, String openId, String unionId) {
String encryptedData = params.getEncryptedData(), iv = params.getIv();
String encryptedData = params.getEncryptedData();
String iv = params.getIv();
JSONObject userInfo = this.getUserInfo(encryptedData, sessionKey, iv);
log.info("联合登陆返回:{}", userInfo.toString());
String phone = (String) userInfo.get("purePhoneNumber");
@@ -232,6 +247,8 @@ public class ConnectServiceImpl extends ServiceImpl<ConnectMapper, Connect> impl
memberService.save(newMember);
newMember = memberService.findByUsername(newMember.getUsername());
bindMpMember(openId, unionId, newMember);
// 发送会员注册信息
applicationEventPublisher.publishEvent(new TransactionCommitSendMQEvent("new member register", rocketmqCustomProperties.getMemberTopic(), MemberTagsEnum.MEMBER_REGISTER.name(), newMember));
return memberTokenGenerate.createToken(newMember, true);
}
@@ -245,6 +262,13 @@ public class ConnectServiceImpl extends ServiceImpl<ConnectMapper, Connect> impl
return this.getOne(queryWrapper);
}
@Override
public void deleteByMemberId(String userId) {
LambdaQueryWrapper<Connect> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Connect::getUserId, userId);
this.remove(queryWrapper);
}
/**
* 会员绑定 绑定微信小程序
* <p>
@@ -252,9 +276,9 @@ public class ConnectServiceImpl extends ServiceImpl<ConnectMapper, Connect> impl
* 这样微信小程序注册之后其他app 公众号页面,都可以实现绑定自动登录功能
* </p>
*
* @param openId
* @param unionId
* @param member
* @param openId 微信openid
* @param unionId 微信unionid
* @param member 会员
*/
private void bindMpMember(String openId, String unionId, Member member) {
@@ -265,7 +289,7 @@ public class ConnectServiceImpl extends ServiceImpl<ConnectMapper, Connect> impl
lambdaQueryWrapper.eq(Connect::getUnionId, unionId);
lambdaQueryWrapper.eq(Connect::getUnionType, ConnectEnum.WECHAT.name());
List<Connect> connects = this.list(lambdaQueryWrapper);
if (connects.size() == 0) {
if (connects.isEmpty()) {
Connect connect = new Connect();
connect.setUnionId(unionId);
connect.setUserId(member.getId());
@@ -274,7 +298,7 @@ public class ConnectServiceImpl extends ServiceImpl<ConnectMapper, Connect> impl
}
}//如果openid 不为空 则为账号绑定openid
if (CharSequenceUtil.isNotEmpty(openId)) {
LambdaQueryWrapper<Connect> lambdaQueryWrapper = new LambdaQueryWrapper();
LambdaQueryWrapper<Connect> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(Connect::getUnionId, openId);
lambdaQueryWrapper.eq(Connect::getUnionType, ConnectEnum.WECHAT_MP_OPEN_ID.name());
List<Connect> connects = this.list(lambdaQueryWrapper);

View File

@@ -50,6 +50,9 @@ public class DistributionOrder extends BaseIdEntity {
private String distributionId;
@ApiModelProperty(value = "分销员名称")
private String distributionName;
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@ApiModelProperty(value = "解冻日期")
private Date settleCycle;
@ApiModelProperty(value = "提成金额")

View File

@@ -73,6 +73,7 @@ public class DistributionCashServiceImpl extends ServiceImpl<DistributionCashMap
}
//将提现金额存入冻结金额,扣减可提现金额
distribution.setCanRebate(CurrencyUtil.sub(distribution.getCanRebate(), applyMoney));
distribution.setCommissionFrozen(CurrencyUtil.add(distribution.getCommissionFrozen(), applyMoney));
distributionService.updateById(distribution);
//提现申请记录
DistributionCash distributionCash = new DistributionCash("D" + SnowFlake.getId(), distribution.getId(), applyMoney, distribution.getMemberName());

View File

@@ -94,6 +94,9 @@ public class DistributionOrderServiceImpl extends ServiceImpl<DistributionOrderM
//循环店铺流水记录判断是否包含分销商品
//包含分销商品则进行记录分销订单、计算分销总额
for (StoreFlow storeFlow : storeFlowList) {
if (storeFlow.getDistributionRebate() == null || storeFlow.getDistributionRebate() == 0) {
continue;
}
rebate = CurrencyUtil.add(rebate, storeFlow.getDistributionRebate());
DistributionOrder distributionOrder = new DistributionOrder(storeFlow);
distributionOrder.setDistributionId(order.getDistributionId());

View File

@@ -0,0 +1,17 @@
package cn.lili.modules.file.entity.enums;
import com.aliyun.oss.OSS;
/**
* OssEnum
*
* @author Chopper
* @version v1.0
* 2022-06-06 11:23
*/
public enum OssEnum {
/**
*
*/
ALI_OSS, MINIO;
}

View File

@@ -1,16 +1,23 @@
package cn.lili.modules.file.plugin;
import cn.lili.modules.file.entity.enums.OssEnum;
import java.io.InputStream;
import java.util.List;
/**
* 文件管理插件
* 文件插件接口
*
* @author Chopper
*/
public interface FileManagerPlugin {
public interface FilePlugin {
/**
* 插件名称
*/
OssEnum pluginName();
/**
* 文件路径上传
*

View File

@@ -0,0 +1,59 @@
package cn.lili.modules.file.plugin;
import cn.hutool.json.JSONUtil;
import cn.lili.common.exception.ServiceException;
import cn.lili.modules.file.entity.enums.OssEnum;
import cn.lili.modules.file.plugin.impl.AliFilePlugin;
import cn.lili.modules.file.plugin.impl.MinioFilePlugin;
import cn.lili.modules.system.entity.dos.Setting;
import cn.lili.modules.system.entity.dto.OssSetting;
import cn.lili.modules.system.entity.enums.SettingEnum;
import cn.lili.modules.system.service.SettingService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* 文件服务抽象工厂 直接返回操作类
*
* @author Chopper
* @version v1.0
* 2022-06-06 11:35
*/
@Component
public class FilePluginFactory {
@Autowired
private SettingService settingService;
/**
* 获取oss client
*
* @return
*/
public FilePlugin filePlugin() {
OssSetting ossSetting = null;
try {
Setting setting = settingService.get(SettingEnum.OSS_SETTING.name());
ossSetting = JSONUtil.toBean(setting.getSettingValue(), OssSetting.class);
switch (OssEnum.valueOf(ossSetting.getType())) {
case MINIO:
return new MinioFilePlugin(ossSetting);
case ALI_OSS:
return new AliFilePlugin(ossSetting);
default:
throw new ServiceException();
}
} catch (Exception e) {
throw new ServiceException();
}
}
}

View File

@@ -1,23 +1,17 @@
package cn.lili.modules.file.plugin.impl;
import cn.hutool.core.util.StrUtil;
import cn.lili.common.enums.ResultCode;
import cn.lili.common.exception.ServiceException;
import cn.lili.modules.file.plugin.FileManagerPlugin;
import cn.lili.modules.system.entity.dos.Setting;
import cn.lili.modules.file.entity.enums.OssEnum;
import cn.lili.modules.file.plugin.FilePlugin;
import cn.lili.modules.system.entity.dto.OssSetting;
import cn.lili.modules.system.entity.enums.SettingEnum;
import cn.lili.modules.system.service.SettingService;
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.DeleteObjectsRequest;
import com.aliyun.oss.model.ObjectMetadata;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.InputStream;
@@ -29,28 +23,19 @@ import java.util.List;
* @author Chopper
*/
@Component
@Slf4j
public class AliFileManagerPlugin implements FileManagerPlugin {
public class AliFilePlugin implements FilePlugin {
@Autowired
private SettingService settingService;
private OssSetting ossSetting;
/**
* 下一个初始化配置参数的时间
* 这里为了防止多次调用redis减少与redis的交互时间
*/
private static Long nextInitSetting;
public AliFilePlugin(OssSetting ossSetting) {
this.ossSetting = ossSetting;
}
/**
* 暂时设定3分账请求一次设置
*/
private static final Long INTERVAL = 60 * 3 * 1000L;
/**
* 静态设置最快三分钟更新一次
*/
private static OssSetting ossSetting;
@Override
public OssEnum pluginName() {
return OssEnum.ALI_OSS;
}
/**
* 获取oss client
@@ -58,32 +43,12 @@ public class AliFileManagerPlugin implements FileManagerPlugin {
* @return
*/
private OSS getOssClient() {
OssSetting ossSetting = getSetting();
return new OSSClientBuilder().build(
ossSetting.getEndPoint(),
ossSetting.getAccessKeyId(),
ossSetting.getAccessKeySecret());
}
/**
* 获取配置
*
* @return
*/
private OssSetting getSetting() {
//如果没有配置或者没有下次刷新时间或者下次刷新时间小于当前时间则从redis 更新一次
if (ossSetting == null || nextInitSetting == null || nextInitSetting < System.currentTimeMillis()) {
Setting setting = settingService.get(SettingEnum.OSS_SETTING.name());
if (setting == null || StrUtil.isBlank(setting.getSettingValue())) {
throw new ServiceException(ResultCode.OSS_NOT_EXIST);
}
nextInitSetting = System.currentTimeMillis() + INTERVAL;
ossSetting = new Gson().fromJson(setting.getSettingValue(), OssSetting.class);
return ossSetting;
}
return ossSetting;
}
/**
* 获取配置前缀
@@ -91,7 +56,6 @@ public class AliFileManagerPlugin implements FileManagerPlugin {
* @return
*/
private String getUrlPrefix() {
OssSetting ossSetting = getSetting();
return "https://" + ossSetting.getBucketName() + "." + ossSetting.getEndPoint() + "/";
}
@@ -130,7 +94,7 @@ public class AliFileManagerPlugin implements FileManagerPlugin {
try {
ObjectMetadata meta = new ObjectMetadata();
meta.setContentType("image/jpg");
ossClient.putObject(getSetting().getBucketName(), key, inputStream, meta);
ossClient.putObject(ossSetting.getBucketName(), key, inputStream, meta);
} catch (OSSException oe) {
log.error("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason.");
@@ -161,7 +125,7 @@ public class AliFileManagerPlugin implements FileManagerPlugin {
try {
ossClient.deleteObjects(
new DeleteObjectsRequest(getSetting().getBucketName()).withKeys(key));
new DeleteObjectsRequest(ossSetting.getBucketName()).withKeys(key));
} catch (OSSException oe) {
log.error("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason.");

View File

@@ -0,0 +1,165 @@
package cn.lili.modules.file.plugin.impl;
import cn.lili.common.enums.ResultCode;
import cn.lili.common.exception.ServiceException;
import cn.lili.modules.file.entity.enums.OssEnum;
import cn.lili.modules.file.plugin.FilePlugin;
import cn.lili.modules.system.entity.dto.OssSetting;
import io.minio.*;
import io.minio.errors.ErrorResponseException;
import io.minio.messages.DeleteObject;
import lombok.extern.slf4j.Slf4j;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;
/**
* MINIO文件插件
*
* @author liushuai(liushuai711 @ gmail.com)
* @version v4.0
* @Description:
* @since 2022/6/6 17:45
*/
@Slf4j
public class MinioFilePlugin implements FilePlugin {
private OssSetting ossSetting;
public MinioFilePlugin(OssSetting ossSetting) {
this.ossSetting = ossSetting;
}
/**
* 桶占位符
*/
private static final String BUCKET_PARAM = "${bucket}";
/**
* bucket权限-只读
*/
private static final String READ_ONLY = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:GetBucketLocation\",\"s3:ListBucket\"],\"Resource\":[\"arn:aws:s3:::" + BUCKET_PARAM + "\"]},{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:GetObject\"],\"Resource\":[\"arn:aws:s3:::" + BUCKET_PARAM + "/*\"]}]}";
/**
* bucket权限-只读
*/
private static final String WRITE_ONLY = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:GetBucketLocation\",\"s3:ListBucketMultipartUploads\"],\"Resource\":[\"arn:aws:s3:::" + BUCKET_PARAM + "\"]},{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:AbortMultipartUpload\",\"s3:DeleteObject\",\"s3:ListMultipartUploadParts\",\"s3:PutObject\"],\"Resource\":[\"arn:aws:s3:::" + BUCKET_PARAM + "/*\"]}]}";
/**
* bucket权限-读写
*/
private static final String READ_WRITE = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:GetBucketLocation\",\"s3:ListBucket\",\"s3:ListBucketMultipartUploads\"],\"Resource\":[\"arn:aws:s3:::" + BUCKET_PARAM + "\"]},{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:DeleteObject\",\"s3:GetObject\",\"s3:ListMultipartUploadParts\",\"s3:PutObject\",\"s3:AbortMultipartUpload\"],\"Resource\":[\"arn:aws:s3:::" + BUCKET_PARAM + "/*\"]}]}";
private MinioClient minioClient;
@Override
public OssEnum pluginName() {
return OssEnum.MINIO;
}
@Override
public String pathUpload(String filePath, String key) {
try {
return this.inputStreamUpload(new FileInputStream(filePath), key);
} catch (Exception e) {
throw new ServiceException(ResultCode.OSS_DELETE_ERROR, e.getMessage());
}
}
@Override
public String inputStreamUpload(InputStream inputStream, String key) {
String bucket = "";
try {
MinioClient client = getOssClient();
bucket = ossSetting.getM_bucketName();
PutObjectArgs putObjectArgs = PutObjectArgs.builder()
.bucket(bucket).stream(inputStream, inputStream.available(), 5 * 1024 * 1024)
.object(key)
.contentType("image/png" )
.build();
client.putObject(putObjectArgs);
} catch (Exception e) {
log.error("上传失败2", e);
throw new ServiceException(ResultCode.OSS_DELETE_ERROR, e.getMessage());
}
//拼接出可访问的url地址
return ossSetting.getM_frontUrl() + "/" + bucket + "/" + key;
}
@Override
public void deleteFile(List<String> key) {
if (key == null || key.isEmpty()) {
return;
}
MinioClient ossClient = getOssClient();
List<DeleteObject> objectList = key.stream().map(DeleteObject::new).collect(Collectors.toList());
ossClient.removeObjects(RemoveObjectsArgs.builder().objects(objectList).bucket(ossSetting.getM_bucketName()).build());
}
/**
* 获取oss client
*
* @return
*/
private MinioClient getOssClient() {
if (minioClient != null) {
return this.minioClient;
}
synchronized (this) {
if (minioClient == null) {
//创建客户端
this.minioClient = MinioClient.builder()
.endpoint(ossSetting.getM_endpoint())
.credentials(ossSetting.getM_accessKey(), ossSetting.getM_secretKey())
.build();
try {
//查看对应的bucket是否已经存在不存在则创建
if (!minioClient.bucketExists(BucketExistsArgs.builder().bucket(ossSetting.getM_bucketName()).build())) {
//创建bucket
MakeBucketArgs makeBucketArgs = MakeBucketArgs.builder().bucket(ossSetting.getM_bucketName()).build();
this.minioClient.makeBucket(makeBucketArgs);
setBucketPolicy(this.minioClient, ossSetting.getM_bucketName(), "read-write" );
log.info("创建minio桶成功{}", ossSetting.getM_bucketName());
}
} catch (Exception e) {
//晴空配置
minioClient = null;
log.error("创建[{}]bucket失败", ossSetting.getM_bucketName());
throw new ServiceException(ResultCode.OSS_DELETE_ERROR, e.getMessage());
}
}
}
return minioClient;
}
/**
* 更新桶权限策略
*
* @param bucket 桶
* @param policy 权限
*/
public static void setBucketPolicy(MinioClient client, String bucket, String policy) throws Exception {
switch (policy) {
case "read-only":
client.setBucketPolicy(SetBucketPolicyArgs.builder().bucket(bucket).config(READ_ONLY.replace(BUCKET_PARAM, bucket)).build());
break;
case "write-only":
client.setBucketPolicy(SetBucketPolicyArgs.builder().bucket(bucket).config(WRITE_ONLY.replace(BUCKET_PARAM, bucket)).build());
break;
case "read-write":
client.setBucketPolicy(SetBucketPolicyArgs.builder().bucket(bucket).region("public" ).config(READ_WRITE.replace(BUCKET_PARAM, bucket)).build());
break;
case "none":
default:
break;
}
}
}

View File

@@ -10,7 +10,8 @@ import cn.lili.common.vo.SearchVO;
import cn.lili.modules.file.entity.File;
import cn.lili.modules.file.entity.dto.FileOwnerDTO;
import cn.lili.modules.file.mapper.FileMapper;
import cn.lili.modules.file.plugin.FileManagerPlugin;
import cn.lili.modules.file.plugin.FilePlugin;
import cn.lili.modules.file.plugin.FilePluginFactory;
import cn.lili.modules.file.service.FileService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
@@ -31,7 +32,7 @@ import java.util.List;
public class FileServiceImpl extends ServiceImpl<FileMapper, File> implements FileService {
@Autowired
private FileManagerPlugin fileManagerPlugin;
private FilePluginFactory filePluginFactory;
@Override
public void batchDelete(List<String> ids) {
@@ -42,7 +43,7 @@ public class FileServiceImpl extends ServiceImpl<FileMapper, File> implements Fi
List<File> files = this.list(queryWrapper);
List<String> keys = new ArrayList<>();
files.forEach(item -> keys.add(item.getFileKey()));
fileManagerPlugin.deleteFile(keys);
filePluginFactory.filePlugin().deleteFile(keys);
this.remove(queryWrapper);
}
@@ -68,7 +69,7 @@ public class FileServiceImpl extends ServiceImpl<FileMapper, File> implements Fi
List<File> files = this.list(queryWrapper);
List<String> keys = new ArrayList<>();
files.forEach(item -> keys.add(item.getFileKey()));
fileManagerPlugin.deleteFile(keys);
filePluginFactory.filePlugin().deleteFile(keys);
this.remove(queryWrapper);
}

View File

@@ -12,7 +12,6 @@ import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.Max;
@@ -114,6 +113,9 @@ public class DraftGoods extends BaseEntity {
@ApiModelProperty(value = "是否为推荐商品")
private boolean recommend;
/**
* @see cn.lili.modules.goods.entity.enums.GoodsSalesModeEnum
*/
@ApiModelProperty(value = "销售模式")
private String salesModel;

View File

@@ -7,7 +7,8 @@ import cn.hutool.json.JSONUtil;
import cn.lili.common.enums.ResultCode;
import cn.lili.common.exception.ServiceException;
import cn.lili.modules.goods.entity.dto.GoodsOperationDTO;
import cn.lili.modules.goods.entity.dto.GoodsOperationFuLuDTO;
import cn.lili.modules.goods.entity.enums.GoodsAuthEnum;
import cn.lili.modules.goods.entity.enums.GoodsSalesModeEnum;
import cn.lili.modules.goods.entity.enums.GoodsStatusEnum;
import cn.lili.modules.goods.entity.enums.GoodsTypeEnum;
import cn.lili.mybatis.BaseEntity;
@@ -108,6 +109,9 @@ public class Goods extends BaseEntity {
@ApiModelProperty(value = "运费模板id")
private String templateId;
/**
* @see GoodsAuthEnum
*/
@ApiModelProperty(value = "审核状态")
private String authFlag;
@@ -130,6 +134,9 @@ public class Goods extends BaseEntity {
@ApiModelProperty(value = "是否为推荐商品", required = true)
private Boolean recommend;
/**
* @see cn.lili.modules.goods.entity.enums.GoodsSalesModeEnum
*/
@ApiModelProperty(value = "销售模式", required = true)
private String salesModel;
@@ -144,83 +151,15 @@ public class Goods extends BaseEntity {
@JsonIgnore
private String params;
//福禄所需参数
/**
* 商品编号
*/
@Length(max = 30, message = "商品规格编号太长不能超过30个字符")
@ApiModelProperty(value = "商品编号")
private String sn;
/**
* 重量
*/
@ApiModelProperty(value = "重量")
@Max(value = 99999999, message = "重量不能超过99999999")
private Double weight;
public Goods() {
}
/**
* 福禄
* @param goodsOperationDTO
*/
public Goods(GoodsOperationFuLuDTO goodsOperationDTO) {
this.goodsName = goodsOperationDTO.getGoodsName();
this.categoryPath = goodsOperationDTO.getCategoryPath();
this.storeCategoryPath = goodsOperationDTO.getStoreCategoryPath();
this.brandId = goodsOperationDTO.getBrandId();
this.sn = goodsOperationDTO.getSn();
this.price = goodsOperationDTO.getPrice();
this.weight = goodsOperationDTO.getWeight();
this.templateId = goodsOperationDTO.getTemplateId();
this.recommend = goodsOperationDTO.getRecommend();
this.sellingPoint = goodsOperationDTO.getSellingPoint();
this.salesModel = goodsOperationDTO.getSalesModel();
this.goodsUnit = goodsOperationDTO.getGoodsUnit();
this.intro = goodsOperationDTO.getIntro();
this.mobileIntro = goodsOperationDTO.getMobileIntro();
this.goodsVideo = goodsOperationDTO.getGoodsVideo();
this.price = goodsOperationDTO.getPrice();
if (goodsOperationDTO.getGoodsParamsDTOList() != null && goodsOperationDTO.getGoodsParamsDTOList().isEmpty()) {
this.params = JSONUtil.toJsonStr(goodsOperationDTO.getGoodsParamsDTOList());
}
//如果立即上架则
this.marketEnable = Boolean.TRUE.equals(goodsOperationDTO.getRelease()) ? GoodsStatusEnum.UPPER.name() : GoodsStatusEnum.DOWN.name();
this.goodsType = goodsOperationDTO.getGoodsType();
this.grade = 100D;
//循环sku判定sku是否有效
for (Map<String, Object> sku : goodsOperationDTO.getSkuList()) {
//判定参数不能为空
if (!sku.containsKey("sn") || sku.get("sn") == null) {
throw new ServiceException(ResultCode.GOODS_SKU_SN_ERROR);
}
if (!sku.containsKey("price") || StringUtil.isEmpty(sku.get("price").toString()) || Convert.toDouble(sku.get("price")) <= 0) {
throw new ServiceException(ResultCode.GOODS_SKU_PRICE_ERROR);
}
if (!sku.containsKey("cost") || StringUtil.isEmpty(sku.get("cost").toString()) || Convert.toDouble(sku.get("cost")) <= 0) {
throw new ServiceException(ResultCode.GOODS_SKU_COST_ERROR);
}
//虚拟商品没有重量字段
if (this.goodsType.equals(GoodsTypeEnum.PHYSICAL_GOODS.name()) && (!sku.containsKey("weight") || sku.containsKey("weight") && (StringUtil.isEmpty(sku.get("weight").toString()) || Convert.toDouble(sku.get("weight").toString()) < 0))) {
throw new ServiceException(ResultCode.GOODS_SKU_WEIGHT_ERROR);
}
if (!sku.containsKey("quantity") || StringUtil.isEmpty(sku.get("quantity").toString()) || Convert.toInt(sku.get("quantity").toString()) < 0) {
throw new ServiceException(ResultCode.GOODS_SKU_QUANTITY_ERROR);
}
}
}
public Goods(GoodsOperationDTO goodsOperationDTO) {
this.goodsName = goodsOperationDTO.getGoodsName();
this.categoryPath = goodsOperationDTO.getCategoryPath();
this.storeCategoryPath = goodsOperationDTO.getStoreCategoryPath();
this.brandId = goodsOperationDTO.getBrandId();
this.price = goodsOperationDTO.getPrice();
this.templateId = goodsOperationDTO.getTemplateId();
this.recommend = goodsOperationDTO.getRecommend();
this.sellingPoint = goodsOperationDTO.getSellingPoint();
@@ -244,10 +183,10 @@ public class Goods extends BaseEntity {
if (!sku.containsKey("sn") || sku.get("sn") == null) {
throw new ServiceException(ResultCode.GOODS_SKU_SN_ERROR);
}
if (!sku.containsKey("price") || StringUtil.isEmpty(sku.get("price").toString()) || Convert.toDouble(sku.get("price")) <= 0) {
if ((!sku.containsKey("price") || StringUtil.isEmpty(sku.get("price").toString()) || Convert.toDouble(sku.get("price")) <= 0) && !goodsOperationDTO.getSalesModel().equals(GoodsSalesModeEnum.WHOLESALE.name())) {
throw new ServiceException(ResultCode.GOODS_SKU_PRICE_ERROR);
}
if (!sku.containsKey("cost") || StringUtil.isEmpty(sku.get("cost").toString()) || Convert.toDouble(sku.get("cost")) <= 0) {
if ((!sku.containsKey("cost") || StringUtil.isEmpty(sku.get("cost").toString()) || Convert.toDouble(sku.get("cost")) <= 0) && !goodsOperationDTO.getSalesModel().equals(GoodsSalesModeEnum.WHOLESALE.name())) {
throw new ServiceException(ResultCode.GOODS_SKU_COST_ERROR);
}
//虚拟商品没有重量字段
@@ -275,4 +214,4 @@ public class Goods extends BaseEntity {
return mobileIntro;
}
}
}

View File

@@ -9,6 +9,7 @@ import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.Max;
@@ -24,6 +25,7 @@ import java.util.Date;
@Data
@TableName("li_goods_sku")
@ApiModel(value = "商品sku对象")
@NoArgsConstructor
public class GoodsSku extends BaseEntity {
private static final long serialVersionUID = 4865908658161118934L;
@@ -150,6 +152,9 @@ public class GoodsSku extends BaseEntity {
@ApiModelProperty(value = "是否为推荐商品", required = true)
private Boolean recommend;
/**
* @see cn.lili.modules.goods.entity.enums.GoodsSalesModeEnum
*/
@ApiModelProperty(value = "销售模式", required = true)
private String salesModel;
/**
@@ -166,11 +171,43 @@ public class GoodsSku extends BaseEntity {
}
@Override
public Date getUpdateTime() {
if (super.getUpdateTime() == null) {
public Date getCreateTime() {
if (super.getCreateTime() == null) {
return new Date(1593571928);
} else {
return super.getUpdateTime();
return super.getCreateTime();
}
}
/**
* 设置规格商品的基本商品信息
*
* @param goods 基本商品信息
*/
public GoodsSku(Goods goods) {
//商品基本信息
this.goodsId = goods.getId();
this.goodsName = goods.getGoodsName();
this.goodsType = goods.getGoodsType();
this.selfOperated = goods.getSelfOperated();
this.sellingPoint = goods.getSellingPoint();
this.categoryPath = goods.getCategoryPath();
this.brandId = goods.getBrandId();
this.marketEnable = goods.getMarketEnable();
this.intro = goods.getIntro();
this.mobileIntro = goods.getMobileIntro();
this.goodsUnit = goods.getGoodsUnit();
this.grade = 100D;
//商品状态
this.authFlag = goods.getAuthFlag();
this.salesModel = goods.getSalesModel();
//卖家信息
this.storeId = goods.getStoreId();
this.storeName = goods.getStoreName();
this.storeCategoryPath = goods.getStoreCategoryPath();
this.freightTemplateId = goods.getTemplateId();
this.recommend = goods.getRecommend();
}
}

View File

@@ -1,5 +1,6 @@
package cn.lili.modules.goods.entity.dos;
import cn.lili.modules.goods.entity.enums.GoodsWordsTypeEnum;
import cn.lili.mybatis.BaseEntity;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
@@ -41,7 +42,7 @@ public class GoodsWords extends BaseEntity {
private String abbreviate;
/**
* 类型
* @see GoodsWordsTypeEnum
*/
@ApiModelProperty(value = "类型")
private String type;

View File

@@ -1,5 +1,6 @@
package cn.lili.modules.goods.entity.dos;
import cn.lili.modules.goods.entity.enums.StudioStatusEnum;
import cn.lili.mybatis.BaseEntity;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
@@ -88,6 +89,9 @@ public class Studio extends BaseEntity {
@ApiModelProperty(value = "推荐直播间")
private boolean recommend;
/**
* @see StudioStatusEnum
*/
@ApiModelProperty(value = "直播间状态")
private String status;
}

View File

@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
@@ -15,11 +16,14 @@ import lombok.NoArgsConstructor;
* @since 2021/5/18 5:42 下午
*/
@Data
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "直播间商品")
@TableName("li_studio_commodity")
@NoArgsConstructor
public class StudioCommodity extends BaseIdEntity {
private static final long serialVersionUID = 8383627725577840261L;
@ApiModelProperty(value = "房间ID")
private Integer roomId;

View File

@@ -0,0 +1,30 @@
package cn.lili.modules.goods.entity.dos;
import cn.lili.mybatis.BaseIdEntity;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* @author paulG
* @since 2022/5/20
**/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("li_wholesale")
@ApiModel(value = "批发商品")
public class Wholesale extends BaseIdEntity {
private static final long serialVersionUID = -6389806138583086068L;
@ApiModelProperty(value = "商品ID")
private String goodsId;
@ApiModelProperty(value = "SkuID")
private String skuId;
@ApiModelProperty(value = "数量")
private Integer num;
@ApiModelProperty(value = "金额")
private Double price;
}

View File

@@ -13,7 +13,7 @@ import java.util.List;
import java.util.Map;
/**
* 商品编辑DTO
* 商品操作DTO
*
* @author pikachu
* @since 2020-02-24 19:27:20
@@ -77,13 +77,12 @@ public class GoodsOperationDTO implements Serializable {
@Min(value = 0, message = "运费模板值不正确")
private String templateId;
@ApiModelProperty(value = "sku列表")
@Valid
private List<Map<String, Object>> skuList;
@ApiModelProperty(value = "卖点")
private String sellingPoint;
/**
* @see cn.lili.modules.goods.entity.enums.GoodsSalesModeEnum
*/
@ApiModelProperty(value = "销售模式", required = true)
private String salesModel;
@@ -112,6 +111,17 @@ public class GoodsOperationDTO implements Serializable {
@ApiModelProperty(value = "商品视频")
private String goodsVideo;
@ApiModelProperty(value = "sku列表")
@Valid
private List<Map<String, Object>> skuList;
/**
* 批发商品规则
*/
@ApiModelProperty(value = "批发商品规则")
private List<WholesaleDTO> wholesaleList;
public String getGoodsName() {
//对商品对名称做一个极限处理。这里没有用xss过滤是因为xss过滤为全局过滤影响很大。
// 业务中,全局代码中只有商品名称不能拥有英文逗号,是由于商品名称存在一个数据库联合查询,结果要根据逗号分组

View File

@@ -77,6 +77,12 @@ public class GoodsSearchParams extends PageVO {
@ApiModelProperty(value = "商品类型")
private String goodsType;
/**
* @see cn.lili.modules.goods.entity.enums.GoodsSalesModeEnum
*/
@ApiModelProperty(value = "销售模式", required = true)
private String salesModel;
public <T> QueryWrapper<T> queryWrapper() {
QueryWrapper<T> queryWrapper = new QueryWrapper<>();
if (CharSequenceUtil.isNotEmpty(goodsId)) {
@@ -121,6 +127,9 @@ public class GoodsSearchParams extends PageVO {
if (CharSequenceUtil.isNotEmpty(goodsType)) {
queryWrapper.eq("goods_type", goodsType);
}
if (CharSequenceUtil.isNotEmpty(salesModel)) {
queryWrapper.eq("sales_model", salesModel);
}
queryWrapper.eq("delete_flag", false);
this.betweenWrapper(queryWrapper);

View File

@@ -0,0 +1,25 @@
package cn.lili.modules.goods.entity.dto;
import cn.lili.modules.goods.entity.dos.GoodsSku;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
/**
* @author paulG
* @since 2022/6/13
**/
@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@AllArgsConstructor
public class GoodsSkuDTO extends GoodsSku {
private static final long serialVersionUID = 6600436187015048097L;
@ApiModelProperty(value = "商品参数json")
private String params;
}

View File

@@ -0,0 +1,16 @@
package cn.lili.modules.goods.entity.dto;
import cn.lili.modules.goods.entity.dos.Wholesale;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* @author paulG
* @since 2022/5/25
**/
@Data
@EqualsAndHashCode(callSuper = true)
public class WholesaleDTO extends Wholesale {
private static final long serialVersionUID = 853297561151783335L;
}

View File

@@ -1,19 +1,14 @@
package cn.lili.modules.goods.entity.enums;
/**
* 商品审核
* 销售模式
*
* @author pikachu
* @since 2020-02-26 23:24:13
*/
public enum GoodsSalesModeEnum {
/**
* 需要审核 并且待审核
*/
RETAIL("零售"),
/**
* 审核通过
*/
WHOLESALE("批发");
private final String description;

View File

@@ -5,6 +5,7 @@ import cn.lili.modules.goods.entity.dos.GoodsSku;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import java.util.List;
@@ -16,6 +17,7 @@ import java.util.List;
* @since 2020-02-26 23:24:13
*/
@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@AllArgsConstructor
public class GoodsSkuVO extends GoodsSku {

View File

@@ -1,9 +1,11 @@
package cn.lili.modules.goods.entity.vos;
import cn.lili.modules.goods.entity.dos.Goods;
import cn.lili.modules.goods.entity.dos.Wholesale;
import cn.lili.modules.goods.entity.dto.GoodsParamsDTO;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
@@ -14,6 +16,7 @@ import java.util.List;
* @since 2020-02-26 23:24:13
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class GoodsVO extends Goods {
private static final long serialVersionUID = 6377623919990713567L;
@@ -29,4 +32,7 @@ public class GoodsVO extends Goods {
@ApiModelProperty(value = "sku列表")
private List<GoodsSkuVO> skuList;
@ApiModelProperty(value = "批发商品消费规则列表")
private List<Wholesale> wholesaleList;
}

View File

@@ -1,19 +0,0 @@
package cn.lili.modules.goods.event;
import lombok.Data;
import org.springframework.context.ApplicationEvent;
/**
* @author paulG
* @since 2022/1/19
**/
@Data
public class GeneratorEsGoodsIndexEvent extends ApplicationEvent {
private String goodsId;
public GeneratorEsGoodsIndexEvent(Object source, String goodsId) {
super(source);
this.goodsId = goodsId;
}
}

View File

@@ -1,38 +0,0 @@
package cn.lili.modules.goods.listener;
import cn.lili.common.properties.RocketmqCustomProperties;
import cn.lili.modules.goods.event.GeneratorEsGoodsIndexEvent;
import cn.lili.rocketmq.RocketmqSendCallbackBuilder;
import cn.lili.rocketmq.tags.GoodsTagsEnum;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.event.TransactionPhase;
import org.springframework.transaction.event.TransactionalEventListener;
/**
* @author paulG
* @since 2022/1/19
**/
@Component
public class GeneratorEsGoodsIndexListener {
/**
* rocketMq
*/
@Autowired
private RocketMQTemplate rocketMQTemplate;
/**
* rocketMq配置
*/
@Autowired
private RocketmqCustomProperties rocketmqCustomProperties;
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void generatorEsGoodsIndex(GeneratorEsGoodsIndexEvent esGoodsIndexEvent) {
String destination = rocketmqCustomProperties.getGoodsTopic() + ":" + GoodsTagsEnum.GENERATOR_GOODS_INDEX.name();
//发送mq消息
rocketMQTemplate.asyncSend(destination, esGoodsIndexEvent.getGoodsId(), RocketmqSendCallbackBuilder.commonCallback());
}
}

View File

@@ -1,7 +1,13 @@
package cn.lili.modules.goods.mapper;
import cn.lili.modules.goods.entity.dos.GoodsSku;
import cn.lili.modules.goods.entity.dto.GoodsSkuDTO;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
@@ -23,4 +29,89 @@ public interface GoodsSkuMapper extends BaseMapper<GoodsSku> {
@Select("SELECT id FROM li_goods_sku WHERE goods_id = #{goodsId}")
List<String> getGoodsSkuIdByGoodsId(String goodsId);
@Insert("replace into li_goods_sku (\n" +
"\tid,\n" +
"\tgoods_id,\n" +
"\tspecs,\n" +
"\tsimple_specs,\n" +
"\tfreight_template_id,\n" +
"\tgoods_name,\n" +
"\tsn,\n" +
"\tbrand_id,\n" +
"\tcategory_path,\n" +
"\tgoods_unit,\n" +
"\tselling_point,\n" +
"\tweight,\n" +
"\tmarket_enable,\n" +
"\tintro,\n" +
"\tprice,\n" +
"\tcost,\n" +
"\tquantity,\n" +
"\tgrade,\n" +
"\tthumbnail,\n" +
"\tsmall,\n" +
"\tstore_category_path,\n" +
"\tstore_id,\n" +
"\tstore_name,\n" +
"\tauth_flag,\n" +
"\tself_operated,\n" +
"\tmobile_intro,\n" +
"\trecommend,\n" +
"\tsales_model,\n" +
"\tgoods_type,\n" +
"\tcreate_by,\n" +
"\tcreate_time,\n" +
"\tupdate_time,\n" +
"\tdelete_flag \n" +
")\n" +
" VALUES\n" +
"(\n" +
"\t#{goodsSku.id},\n" +
"\t#{goodsSku.goodsId},\n" +
"\t#{goodsSku.specs},\n" +
"\t#{goodsSku.simpleSpecs},\n" +
"\t#{goodsSku.freightTemplateId},\n" +
"\t#{goodsSku.goodsName},\n" +
"\t#{goodsSku.sn},\n" +
"\t#{goodsSku.brandId},\n" +
"\t#{goodsSku.categoryPath},\n" +
"\t#{goodsSku.goodsUnit},\n" +
"\t#{goodsSku.sellingPoint},\n" +
"\t#{goodsSku.weight},\n" +
"\t#{goodsSku.marketEnable},\n" +
"\t#{goodsSku.intro},\n" +
"\t#{goodsSku.price},\n" +
"\t#{goodsSku.cost},\n" +
"\t#{goodsSku.quantity},\n" +
"\t#{goodsSku.grade},\n" +
"\t#{goodsSku.thumbnail},\n" +
"\t#{goodsSku.small},\n" +
"\t#{goodsSku.storeCategoryPath},\n" +
"\t#{goodsSku.storeId},\n" +
"\t#{goodsSku.storeName},\n" +
"\t#{goodsSku.authFlag},\n" +
"\t#{goodsSku.selfOperated},\n" +
"\t#{goodsSku.mobileIntro},\n" +
"\t#{goodsSku.recommend},\n" +
"\t#{goodsSku.salesModel},\n" +
"\t#{goodsSku.goodsType},\n" +
"\t#{goodsSku.createBy},\n" +
"\t#{goodsSku.createTime},\n" +
"\t#{goodsSku.updateTime},\n" +
"\t#{goodsSku.deleteFlag}\n" +
")")
int replaceGoodsSku(@Param("goodsSku") GoodsSku goodsSku);
/**
* 分页查询商品skuDTO
*
* @param page 分页
* @param queryWrapper 查询条件
* @return 售后VO分页
*/
@Select("SELECT *,g.params as params FROM li_goods_sku gs inner join li_goods g on gs.goods_id = g.id ${ew.customSqlSegment}")
IPage<GoodsSkuDTO> queryByParams(IPage<GoodsSkuDTO> page, @Param(Constants.WRAPPER) Wrapper<GoodsSkuDTO> queryWrapper);
}

View File

@@ -0,0 +1,11 @@
package cn.lili.modules.goods.mapper;
import cn.lili.modules.goods.entity.dos.Wholesale;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* @author paulG
* @since 2022/5/24
**/
public interface WholesaleMapper extends BaseMapper<Wholesale> {
}

View File

@@ -4,9 +4,6 @@ package cn.lili.modules.goods.service;
import cn.lili.modules.goods.entity.dos.Category;
import cn.lili.modules.goods.entity.vos.CategoryVO;
import com.baomidou.mybatisplus.extension.service.IService;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import java.util.List;
@@ -16,7 +13,6 @@ import java.util.List;
* @author pikachu
* @since 2020-03-02 16:44:56
*/
@CacheConfig(cacheNames = "{category}")
public interface CategoryService extends IService<Category> {
@@ -35,7 +31,6 @@ public interface CategoryService extends IService<Category> {
* @param id
* @return
*/
@Cacheable(key = "#id")
Category getCategoryById(String id);
/**
@@ -99,7 +94,6 @@ public interface CategoryService extends IService<Category> {
* @param category 商品分类信息
* @return 修改结果
*/
@CacheEvict(key = "#category.id")
void updateCategory(Category category);
/**

View File

@@ -36,4 +36,11 @@ public interface GoodsGalleryService extends IService<GoodsGallery> {
*/
List<GoodsGallery> goodsGalleryList(String goodsId);
/**
* 根据商品 id删除商品相册缩略图
*
* @param goodsId 商品ID
*/
void removeByGoodsId(String goodsId);
}

View File

@@ -129,6 +129,17 @@ public interface GoodsService extends IService<Goods> {
*/
Boolean updateGoodsMarketAble(List<String> goodsIds, GoodsStatusEnum goodsStatusEnum, String underReason);
/**
* 更新商品上架状态状态
*
* @param storeId 店铺ID
* @param goodsStatusEnum 更新的商品状态
* @param underReason 下架原因
* @return 更新结果
*/
Boolean updateGoodsMarketAbleByStoreId(String storeId, GoodsStatusEnum goodsStatusEnum, String underReason);
/**
* 更新商品上架状态状态
*

View File

@@ -3,10 +3,14 @@ package cn.lili.modules.goods.service;
import cn.lili.cache.CachePrefix;
import cn.lili.modules.goods.entity.dos.Goods;
import cn.lili.modules.goods.entity.dos.GoodsSku;
import cn.lili.modules.goods.entity.dto.GoodsOperationDTO;
import cn.lili.modules.goods.entity.dto.GoodsSearchParams;
import cn.lili.modules.goods.entity.dto.GoodsSkuDTO;
import cn.lili.modules.goods.entity.dto.GoodsSkuStockDTO;
import cn.lili.modules.goods.entity.vos.GoodsSkuVO;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
@@ -43,19 +47,18 @@ public interface GoodsSkuService extends IService<GoodsSku> {
/**
* 添加商品sku
*
* @param skuList sku列表
* @param goods 商品信息
* @param goods 商品信息
* @param goodsOperationDTO 商品操作信息
*/
void add(List<Map<String, Object>> skuList, Goods goods);
void add(Goods goods, GoodsOperationDTO goodsOperationDTO);
/**
* 更新商品sku
*
* @param skuList sku列表
* @param goods 商品信息
* @param regeneratorSkuFlag 是否是否重新生成sku
* @param goods 商品信息
* @param goodsOperationDTO 商品操作信息
*/
void update(List<Map<String, Object>> skuList, Goods goods, Boolean regeneratorSkuFlag);
void update(Goods goods, GoodsOperationDTO goodsOperationDTO);
/**
* 更新商品sku
@@ -79,6 +82,14 @@ public interface GoodsSkuService extends IService<GoodsSku> {
*/
GoodsSku getGoodsSkuByIdFromCache(String id);
/**
* 从缓存中获取可参与促销商品
*
* @param skuId skuid
* @return 商品详情
*/
GoodsSku getCanPromotionGoodsSkuByIdFromCache(String skuId);
/**
* 获取商品sku详情
*
@@ -136,6 +147,16 @@ public interface GoodsSkuService extends IService<GoodsSku> {
*/
IPage<GoodsSku> getGoodsSkuByPage(GoodsSearchParams searchParams);
/**
* 分页查询商品sku信息
*
* @param page 分页参数
* @param queryWrapper 查询参数
* @return 商品sku信息
*/
IPage<GoodsSkuDTO> getGoodsSkuDTOByPage(Page<GoodsSkuDTO> page, Wrapper<GoodsSkuDTO> queryWrapper);
/**
* 列表查询商品sku信息
*
@@ -151,6 +172,15 @@ public interface GoodsSkuService extends IService<GoodsSku> {
*/
void updateGoodsSkuStatus(Goods goods);
/**
* 更新商品sku状态根据店铺id
*
* @param storeId 店铺id
* @param marketEnable 市场启用状态
* @param authFlag 审核状态
*/
void updateGoodsSkuStatusByStoreId(String storeId, String marketEnable, String authFlag);
/**
* 发送生成ES商品索引
*
@@ -202,4 +232,20 @@ public interface GoodsSkuService extends IService<GoodsSku> {
* @return 全部skuId的集合
*/
List<String> getSkuIdsByGoodsId(String goodsId);
/**
* 删除并且新增sku即覆盖之前信息
*
* @param goodsSkus 商品sku集合
* @return
*/
boolean deleteAndInsertGoodsSkus(List<GoodsSku> goodsSkus);
/**
* 统计sku总数
*
* @param storeId 店铺id
* @return sku总数
*/
Long countSkuNum(String storeId);
}

View File

@@ -70,7 +70,7 @@ public interface StudioService extends IService<Studio> {
* @param status 直播间状态
* @return 直播间分页
*/
IPage<Studio> studioList(PageVO pageVO, Integer recommend, String status);
IPage<StudioVO> studioList(PageVO pageVO, Integer recommend, String status);
/**
* 修改直播间状态

View File

@@ -0,0 +1,28 @@
package cn.lili.modules.goods.service;
import cn.lili.modules.goods.entity.dos.Wholesale;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
/**
* @author paulG
* @since 2022/5/24
**/
public interface WholesaleService extends IService<Wholesale> {
List<Wholesale> findByGoodsId(String goodsId);
Boolean removeByGoodsId(String goodsId);
/**
* 匹配批发规则
*
* @param goodsId 商品规则
* @param num 数量
* @return 批发规则
*/
Wholesale match(String goodsId, Integer num);
}

View File

@@ -19,6 +19,9 @@ import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -36,6 +39,7 @@ import java.util.stream.Collectors;
* @since 2020-02-23 15:18:56
*/
@Service
@CacheConfig(cacheNames = "{CATEGORY}")
public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category> implements CategoryService {
private static final String DELETE_FLAG_COLUMN = "delete_flag";
@@ -60,6 +64,7 @@ public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category> i
}
@Override
@Cacheable(key = "#id")
public Category getCategoryById(String id) {
return this.getById(id);
}
@@ -216,6 +221,7 @@ public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category> i
}
@Override
@CacheEvict(key = "#category.id")
@Transactional(rollbackFor = Exception.class)
public void updateCategory(Category category) {
//判断分类佣金是否正确
@@ -242,6 +248,7 @@ public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category> i
@Override
@CacheEvict(key = "#id")
@Transactional(rollbackFor = Exception.class)
public void delete(String id) {
this.removeById(id);
@@ -253,6 +260,7 @@ public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category> i
}
@Override
@CacheEvict(key = "#categoryId")
@Transactional(rollbackFor = Exception.class)
public void updateCategoryStatus(String categoryId, Boolean enableOperations) {
//禁用子分类
@@ -335,7 +343,7 @@ public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category> i
return item.getChildren();
}
if (item.getChildren() != null && !item.getChildren().isEmpty()) {
return getChildren(parentId, categoryVOList);
return getChildren(parentId, item.getChildren());
}
}
return categoryVOList;
@@ -346,5 +354,6 @@ public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category> i
*/
private void removeCache() {
cache.remove(CachePrefix.CATEGORY.getPrefix());
cache.remove(CachePrefix.CATEGORY_ARRAY.getPrefix());
}
}

View File

@@ -75,4 +75,14 @@ public class GoodsGalleryServiceImpl extends ServiceImpl<GoodsGalleryMapper, Goo
//根据商品id查询商品相册
return this.baseMapper.selectList(new QueryWrapper<GoodsGallery>().eq("goods_id", goodsId));
}
/**
* 根据商品 id删除商品相册缩略图
*
* @param goodsId 商品ID
*/
@Override
public void removeByGoodsId(String goodsId) {
this.baseMapper.delete(new UpdateWrapper<GoodsGallery>().eq("goods_id", goodsId));
}
}

View File

@@ -1,5 +1,6 @@
package cn.lili.modules.goods.serviceimpl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.json.JSONUtil;
@@ -14,6 +15,7 @@ import cn.lili.common.security.enums.UserEnums;
import cn.lili.modules.goods.entity.dos.Category;
import cn.lili.modules.goods.entity.dos.Goods;
import cn.lili.modules.goods.entity.dos.GoodsGallery;
import cn.lili.modules.goods.entity.dos.Wholesale;
import cn.lili.modules.goods.entity.dto.GoodsOperationDTO;
import cn.lili.modules.goods.entity.dto.GoodsOperationFuLuDTO;
import cn.lili.modules.goods.entity.dto.GoodsParamsDTO;
@@ -23,10 +25,7 @@ import cn.lili.modules.goods.entity.enums.GoodsStatusEnum;
import cn.lili.modules.goods.entity.vos.GoodsSkuVO;
import cn.lili.modules.goods.entity.vos.GoodsVO;
import cn.lili.modules.goods.mapper.GoodsMapper;
import cn.lili.modules.goods.service.CategoryService;
import cn.lili.modules.goods.service.GoodsGalleryService;
import cn.lili.modules.goods.service.GoodsService;
import cn.lili.modules.goods.service.GoodsSkuService;
import cn.lili.modules.goods.service.*;
import cn.lili.modules.member.entity.dos.MemberEvaluation;
import cn.lili.modules.member.entity.enums.EvaluationGradeEnum;
import cn.lili.modules.member.service.MemberEvaluationService;
@@ -111,6 +110,9 @@ public class GoodsServiceImpl extends ServiceImpl<GoodsMapper, Goods> implements
@Autowired
private FreightTemplateService freightTemplateService;
@Autowired
private WholesaleService wholesaleService;
@Autowired
private Cache<GoodsVO> cache;
@@ -171,7 +173,7 @@ public class GoodsServiceImpl extends ServiceImpl<GoodsMapper, Goods> implements
//添加商品
this.save(goods);
//添加商品sku信息
this.goodsSkuService.add(goodsOperationDTO.getSkuList(), goods);
this.goodsSkuService.add(goods, goodsOperationDTO);
//添加相册
if (goodsOperationDTO.getGoodsGalleryList() != null && !goodsOperationDTO.getGoodsGalleryList().isEmpty()) {
this.goodsGalleryService.add(goodsOperationDTO.getGoodsGalleryList(), goods.getId());
@@ -220,7 +222,7 @@ public class GoodsServiceImpl extends ServiceImpl<GoodsMapper, Goods> implements
//修改商品
this.updateById(goods);
//修改商品sku信息
this.goodsSkuService.update(goodsOperationDTO.getSkuList(), goods, goodsOperationDTO.getRegeneratorSkuFlag());
this.goodsSkuService.update(goods, goodsOperationDTO);
//添加相册
if (goodsOperationDTO.getGoodsGalleryList() != null && !goodsOperationDTO.getGoodsGalleryList().isEmpty()) {
this.goodsGalleryService.add(goodsOperationDTO.getGoodsGalleryList(), goods.getId());
@@ -302,6 +304,12 @@ public class GoodsServiceImpl extends ServiceImpl<GoodsMapper, Goods> implements
if (CharSequenceUtil.isNotEmpty(goods.getParams())) {
goodsVO.setGoodsParamsDTOList(JSONUtil.toList(goods.getParams(), GoodsParamsDTO.class));
}
List<Wholesale> wholesaleList = wholesaleService.findByGoodsId(goodsId);
if (CollUtil.isNotEmpty(wholesaleList)) {
goodsVO.setWholesaleList(wholesaleList);
}
cache.put(CachePrefix.GOODS.getPrefix() + goodsId, goodsVO);
return goodsVO;
}
@@ -325,6 +333,7 @@ public class GoodsServiceImpl extends ServiceImpl<GoodsMapper, Goods> implements
@Override
@Transactional(rollbackFor = Exception.class)
public boolean auditGoods(List<String> goodsIds, GoodsAuthEnum goodsAuthEnum) {
List<String> goodsCacheKeys = new ArrayList<>();
boolean result = false;
for (String goodsId : goodsIds) {
Goods goods = this.checkExist(goodsId);
@@ -332,12 +341,13 @@ public class GoodsServiceImpl extends ServiceImpl<GoodsMapper, Goods> implements
result = this.updateById(goods);
goodsSkuService.updateGoodsSkuStatus(goods);
//删除之前的缓存
cache.remove(CachePrefix.GOODS.getPrefix() + goodsId);
goodsCacheKeys.add(CachePrefix.GOODS.getPrefix() + goodsId);
//商品审核消息
String destination = rocketmqCustomProperties.getGoodsTopic() + ":" + GoodsTagsEnum.GOODS_AUDIT.name();
//发送mq消息
rocketMQTemplate.asyncSend(destination, JSONUtil.toJsonStr(goods), RocketmqSendCallbackBuilder.commonCallback());
}
cache.multiDel(goodsCacheKeys);
return result;
}
@@ -361,13 +371,30 @@ public class GoodsServiceImpl extends ServiceImpl<GoodsMapper, Goods> implements
LambdaQueryWrapper<Goods> queryWrapper = this.getQueryWrapperByStoreAuthority();
queryWrapper.in(Goods::getId, goodsIds);
List<Goods> goodsList = this.list(queryWrapper);
for (Goods goods : goodsList) {
goodsSkuService.updateGoodsSkuStatus(goods);
}
this.updateGoodsStatus(goodsIds, goodsStatusEnum, goodsList);
return result;
}
if (GoodsStatusEnum.DOWN.equals(goodsStatusEnum)) {
this.deleteEsGoods(goodsIds);
}
/**
* 更新商品上架状态状态
*
* @param storeId 店铺ID
* @param goodsStatusEnum 更新的商品状态
* @param underReason 下架原因
* @return 更新结果
*/
@Override
public Boolean updateGoodsMarketAbleByStoreId(String storeId, GoodsStatusEnum goodsStatusEnum, String underReason) {
boolean result;
LambdaUpdateWrapper<Goods> updateWrapper = this.getUpdateWrapperByStoreAuthority();
updateWrapper.set(Goods::getMarketEnable, goodsStatusEnum.name());
updateWrapper.set(Goods::getUnderMessage, underReason);
updateWrapper.eq(Goods::getStoreId, storeId);
result = this.update(updateWrapper);
//修改规格商品
this.goodsSkuService.updateGoodsSkuStatusByStoreId(storeId, goodsStatusEnum.name(), null);
return result;
}
@@ -394,12 +421,7 @@ public class GoodsServiceImpl extends ServiceImpl<GoodsMapper, Goods> implements
LambdaQueryWrapper<Goods> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.in(Goods::getId, goodsIds);
List<Goods> goodsList = this.list(queryWrapper);
for (Goods goods : goodsList) {
goodsSkuService.updateGoodsSkuStatus(goods);
}
if (GoodsStatusEnum.DOWN.equals(goodsStatusEnum)) {
this.deleteEsGoods(goodsIds);
}
this.updateGoodsStatus(goodsIds, goodsStatusEnum, goodsList);
return result;
}
@@ -417,13 +439,15 @@ public class GoodsServiceImpl extends ServiceImpl<GoodsMapper, Goods> implements
LambdaQueryWrapper<Goods> queryWrapper = this.getQueryWrapperByStoreAuthority();
queryWrapper.in(Goods::getId, goodsIds);
List<Goods> goodsList = this.list(queryWrapper);
List<String> goodsCacheKeys = new ArrayList<>();
for (Goods goods : goodsList) {
//修改SKU状态
goodsSkuService.updateGoodsSkuStatus(goods);
goodsCacheKeys.add(CachePrefix.GOODS.getPrefix() + goods.getId());
}
//删除缓存
cache.multiDel(goodsCacheKeys);
this.deleteEsGoods(goodsIds);
return true;
}
@@ -503,11 +527,43 @@ public class GoodsServiceImpl extends ServiceImpl<GoodsMapper, Goods> implements
return this.count(
new LambdaQueryWrapper<Goods>()
.eq(Goods::getStoreId, storeId)
.eq(Goods::getDeleteFlag, Boolean.FALSE)
.eq(Goods::getAuthFlag, GoodsAuthEnum.PASS.name())
.eq(Goods::getMarketEnable, GoodsStatusEnum.UPPER.name()));
}
/**
* 更新店铺商品数量
*
* @param storeId 信息体
*/
void updateGoodsNum(String storeId) {
Long num = goodsSkuService.countSkuNum(storeId);
storeService.updateStoreGoodsNum(storeId, num);
}
/**
* 更新商品状态
*
* @param goodsIds 商品ID
* @param goodsStatusEnum 商品状态
* @param goodsList 商品列表
*/
private void updateGoodsStatus(List<String> goodsIds, GoodsStatusEnum goodsStatusEnum, List<Goods> goodsList) {
List<String> goodsCacheKeys = new ArrayList<>();
for (Goods goods : goodsList) {
goodsCacheKeys.add(CachePrefix.GOODS.getPrefix() + goods.getId());
goodsSkuService.updateGoodsSkuStatus(goods);
}
cache.multiDel(goodsCacheKeys);
if (GoodsStatusEnum.DOWN.equals(goodsStatusEnum)) {
this.deleteEsGoods(goodsIds);
}
}
/**
* 发送删除es索引的信息
*

View File

@@ -1,6 +1,5 @@
package cn.lili.modules.goods.serviceimpl;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.NumberUtil;
@@ -10,25 +9,29 @@ import cn.lili.cache.Cache;
import cn.lili.cache.CachePrefix;
import cn.lili.common.enums.PromotionTypeEnum;
import cn.lili.common.enums.ResultCode;
import cn.lili.common.event.TransactionCommitSendMQEvent;
import cn.lili.common.exception.ServiceException;
import cn.lili.common.properties.RocketmqCustomProperties;
import cn.lili.common.security.context.UserContext;
import cn.lili.common.utils.SnowFlake;
import cn.lili.modules.goods.entity.dos.Goods;
import cn.lili.modules.goods.entity.dos.GoodsGallery;
import cn.lili.modules.goods.entity.dos.GoodsSku;
import cn.lili.modules.goods.entity.dto.GoodsOperationDTO;
import cn.lili.modules.goods.entity.dto.GoodsSearchParams;
import cn.lili.modules.goods.entity.dto.GoodsSkuDTO;
import cn.lili.modules.goods.entity.dto.GoodsSkuStockDTO;
import cn.lili.modules.goods.entity.enums.GoodsAuthEnum;
import cn.lili.modules.goods.entity.enums.GoodsSalesModeEnum;
import cn.lili.modules.goods.entity.enums.GoodsStatusEnum;
import cn.lili.modules.goods.entity.vos.GoodsSkuSpecVO;
import cn.lili.modules.goods.entity.vos.GoodsSkuVO;
import cn.lili.modules.goods.entity.vos.GoodsVO;
import cn.lili.modules.goods.entity.vos.SpecValueVO;
import cn.lili.modules.goods.event.GeneratorEsGoodsIndexEvent;
import cn.lili.modules.goods.mapper.GoodsSkuMapper;
import cn.lili.modules.goods.service.CategoryService;
import cn.lili.modules.goods.service.GoodsGalleryService;
import cn.lili.modules.goods.service.GoodsService;
import cn.lili.modules.goods.service.GoodsSkuService;
import cn.lili.modules.goods.service.*;
import cn.lili.modules.goods.sku.GoodsSkuBuilder;
import cn.lili.modules.goods.sku.render.SalesModelRender;
import cn.lili.modules.member.entity.dos.FootPrint;
import cn.lili.modules.member.entity.dto.EvaluationQueryParams;
import cn.lili.modules.member.entity.enums.EvaluationGradeEnum;
@@ -37,16 +40,17 @@ import cn.lili.modules.promotion.entity.dos.PromotionGoods;
import cn.lili.modules.promotion.entity.dto.search.PromotionGoodsSearchParams;
import cn.lili.modules.promotion.entity.enums.CouponGetEnum;
import cn.lili.modules.promotion.service.PromotionGoodsService;
import cn.lili.modules.search.entity.dos.EsGoodsAttribute;
import cn.lili.modules.search.entity.dos.EsGoodsIndex;
import cn.lili.modules.search.service.EsGoodsIndexService;
import cn.lili.modules.search.utils.EsIndexUtil;
import cn.lili.mybatis.util.PageUtil;
import cn.lili.rocketmq.RocketmqSendCallbackBuilder;
import cn.lili.rocketmq.tags.GoodsTagsEnum;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
@@ -113,35 +117,42 @@ public class GoodsSkuServiceImpl extends ServiceImpl<GoodsSkuMapper, GoodsSku> i
@Autowired
private ApplicationEventPublisher applicationEventPublisher;
@Autowired
private WholesaleService wholesaleService;
@Autowired
private List<SalesModelRender> salesModelRenders;
@Override
@Transactional(rollbackFor = Exception.class)
public void add(List<Map<String, Object>> skuList, Goods goods) {
// 检查是否需要生成索引
List<GoodsSku> newSkuList;
//如果有规格
if (skuList != null && !skuList.isEmpty()) {
// 添加商品sku
newSkuList = this.addGoodsSku(skuList, goods);
} else {
public void add(Goods goods, GoodsOperationDTO goodsOperationDTO) {
// 是否存在规格
if (goodsOperationDTO.getSkuList() == null || goodsOperationDTO.getSkuList().isEmpty()) {
throw new ServiceException(ResultCode.MUST_HAVE_GOODS_SKU);
}
// 检查是否需要生成索引
List<GoodsSku> goodsSkus = GoodsSkuBuilder.buildBatch(goods, goodsOperationDTO);
renderGoodsSkuList(goodsSkus, goodsOperationDTO);
this.updateStock(newSkuList);
if (!newSkuList.isEmpty()) {
generateEs(goods);
if (!goodsSkus.isEmpty()) {
this.saveOrUpdateBatch(goodsSkus);
this.updateStock(goodsSkus);
this.generateEs(goods);
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void update(List<Map<String, Object>> skuList, Goods goods, Boolean regeneratorSkuFlag) {
public void update(Goods goods, GoodsOperationDTO goodsOperationDTO) {
// 是否存在规格
if (skuList == null || skuList.isEmpty()) {
if (goodsOperationDTO.getSkuList() == null || goodsOperationDTO.getSkuList().isEmpty()) {
throw new ServiceException(ResultCode.MUST_HAVE_GOODS_SKU);
}
List<GoodsSku> newSkuList;
List<GoodsSku> skuList;
//删除旧的sku信息
if (Boolean.TRUE.equals(regeneratorSkuFlag)) {
if (Boolean.TRUE.equals(goodsOperationDTO.getRegeneratorSkuFlag())) {
skuList = GoodsSkuBuilder.buildBatch(goods, goodsOperationDTO);
renderGoodsSkuList(skuList, goodsOperationDTO);
List<GoodsSkuVO> goodsListByGoodsId = getGoodsListByGoodsId(goods.getId());
List<String> oldSkuIds = new ArrayList<>();
//删除旧索引
@@ -149,36 +160,32 @@ public class GoodsSkuServiceImpl extends ServiceImpl<GoodsSkuMapper, GoodsSku> i
oldSkuIds.add(goodsSkuVO.getId());
cache.remove(GoodsSkuService.getCacheKeys(goodsSkuVO.getId()));
}
goodsIndexService.deleteIndexByIds(oldSkuIds);
this.removeByIds(oldSkuIds);
this.remove(new LambdaQueryWrapper<GoodsSku>().eq(GoodsSku::getGoodsId, goods.getId()));
//删除sku相册
goodsGalleryService.removeByIds(oldSkuIds);
// 添加商品sku
newSkuList = this.addGoodsSku(skuList, goods);
goodsGalleryService.removeByGoodsId(goods.getId());
//发送mq消息
String destination = rocketmqCustomProperties.getGoodsTopic() + ":" + GoodsTagsEnum.SKU_DELETE.name();
rocketMQTemplate.asyncSend(destination, JSONUtil.toJsonStr(oldSkuIds), RocketmqSendCallbackBuilder.commonCallback());
} else {
newSkuList = new ArrayList<>();
for (Map<String, Object> map : skuList) {
GoodsSku sku = new GoodsSku();
//设置商品信息
goodsInfo(sku, goods);
//设置商品规格信息
skuInfo(sku, goods, map, null);
newSkuList.add(sku);
skuList = new ArrayList<>();
for (Map<String, Object> map : goodsOperationDTO.getSkuList()) {
GoodsSku sku = GoodsSkuBuilder.build(goods, map, goodsOperationDTO);
renderGoodsSku(sku, goodsOperationDTO);
skuList.add(sku);
//如果商品状态值不对则es索引移除
if (goods.getAuthFlag().equals(GoodsAuthEnum.PASS.name()) && goods.getMarketEnable().equals(GoodsStatusEnum.UPPER.name())) {
goodsIndexService.deleteIndexById(sku.getId());
this.clearCache(sku.getId());
}
}
this.updateBatchById(newSkuList);
}
this.updateStock(newSkuList);
if (GoodsAuthEnum.PASS.name().equals(goods.getAuthFlag()) && !newSkuList.isEmpty()) {
generateEs(goods);
if (!skuList.isEmpty()) {
this.remove(new LambdaQueryWrapper<GoodsSku>().eq(GoodsSku::getGoodsId, goods.getId()));
this.saveOrUpdateBatch(skuList);
this.updateStock(skuList);
this.generateEs(goods);
}
}
@@ -231,6 +238,15 @@ public class GoodsSkuServiceImpl extends ServiceImpl<GoodsSkuMapper, GoodsSku> i
return goodsSku;
}
@Override
public GoodsSku getCanPromotionGoodsSkuByIdFromCache(String skuId) {
GoodsSku goodsSku = this.getGoodsSkuByIdFromCache(skuId);
if (goodsSku != null && GoodsSalesModeEnum.WHOLESALE.name().equals(goodsSku.getSalesModel())) {
throw new ServiceException(ResultCode.PROMOTION_GOODS_DO_NOT_JOIN_WHOLESALE, goodsSku.getGoodsName());
}
return goodsSku;
}
@Override
public Map<String, Object> getGoodsSkuDetail(String goodsId, String skuId) {
Map<String, Object> map = new HashMap<>(16);
@@ -244,13 +260,16 @@ public class GoodsSkuServiceImpl extends ServiceImpl<GoodsSkuMapper, GoodsSku> i
GoodsSku goodsSku = this.getGoodsSkuByIdFromCache(skuId);
//如果使用商品ID无法查询SKU则返回错误
if (goodsVO == null || goodsSku == null) {
//发送mq消息
String destination = rocketmqCustomProperties.getGoodsTopic() + ":" + GoodsTagsEnum.GOODS_DELETE.name();
rocketMQTemplate.asyncSend(destination, JSONUtil.toJsonStr(Collections.singletonList(goodsId)), RocketmqSendCallbackBuilder.commonCallback());
throw new ServiceException(ResultCode.GOODS_NOT_EXIST);
}
//商品下架||商品未审核通过||商品删除,则提示:商品已下架
if (GoodsStatusEnum.DOWN.name().equals(goodsVO.getMarketEnable())
|| !GoodsAuthEnum.PASS.name().equals(goodsVO.getAuthFlag())
|| Boolean.TRUE.equals(goodsVO.getDeleteFlag())) {
if (GoodsStatusEnum.DOWN.name().equals(goodsVO.getMarketEnable()) || !GoodsAuthEnum.PASS.name().equals(goodsVO.getAuthFlag()) || Boolean.TRUE.equals(goodsVO.getDeleteFlag())) {
String destination = rocketmqCustomProperties.getGoodsTopic() + ":" + GoodsTagsEnum.GOODS_DELETE.name();
rocketMQTemplate.asyncSend(destination, JSONUtil.toJsonStr(Collections.singletonList(goodsId)), RocketmqSendCallbackBuilder.commonCallback());
throw new ServiceException(ResultCode.GOODS_NOT_EXIST);
}
@@ -269,13 +288,10 @@ public class GoodsSkuServiceImpl extends ServiceImpl<GoodsSkuMapper, GoodsSku> i
promotionMap = promotionMap.entrySet().stream().parallel().filter(i -> {
JSONObject jsonObject = JSONUtil.parseObj(i.getValue());
// 过滤活动赠送优惠券和无效时间的活动
return (jsonObject.get("getType") == null || jsonObject.get("getType", String.class).equals(CouponGetEnum.FREE.name())) &&
(jsonObject.get("startTime") != null && jsonObject.get("startTime", Date.class).getTime() <= System.currentTimeMillis()) &&
(jsonObject.get("endTime") == null || jsonObject.get("endTime", Date.class).getTime() >= System.currentTimeMillis());
return (jsonObject.get("getType") == null || jsonObject.get("getType", String.class).equals(CouponGetEnum.FREE.name())) && (jsonObject.get("startTime") != null && jsonObject.get("startTime", Date.class).getTime() <= System.currentTimeMillis()) && (jsonObject.get("endTime") == null || jsonObject.get("endTime", Date.class).getTime() >= System.currentTimeMillis());
}).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
Optional<Map.Entry<String, Object>> containsPromotion = promotionMap.entrySet().stream().filter(i ->
i.getKey().contains(PromotionTypeEnum.SECKILL.name()) || i.getKey().contains(PromotionTypeEnum.PINTUAN.name())).findFirst();
Optional<Map.Entry<String, Object>> containsPromotion = promotionMap.entrySet().stream().filter(i -> i.getKey().contains(PromotionTypeEnum.SECKILL.name()) || i.getKey().contains(PromotionTypeEnum.PINTUAN.name())).findFirst();
if (containsPromotion.isPresent()) {
JSONObject jsonObject = JSONUtil.parseObj(containsPromotion.get().getValue());
PromotionGoodsSearchParams searchParams = new PromotionGoodsSearchParams();
@@ -296,6 +312,7 @@ public class GoodsSkuServiceImpl extends ServiceImpl<GoodsSkuMapper, GoodsSku> i
//获取分类
String[] split = goodsSkuDetail.getCategoryPath().split(",");
map.put("wholesaleList", wholesaleService.findByGoodsId(goodsSkuDetail.getGoodsId()));
map.put("categoryName", categoryService.getCategoryNameByIds(Arrays.asList(split)));
//获取规格信息
@@ -325,7 +342,8 @@ public class GoodsSkuServiceImpl extends ServiceImpl<GoodsSkuMapper, GoodsSku> i
@Transactional(rollbackFor = Exception.class)
public void updateGoodsSkuStatus(Goods goods) {
LambdaUpdateWrapper<GoodsSku> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(GoodsSku::getGoodsId, goods.getId());
updateWrapper.eq(CharSequenceUtil.isNotEmpty(goods.getId()), GoodsSku::getGoodsId, goods.getId());
updateWrapper.eq(CharSequenceUtil.isNotEmpty(goods.getStoreId()), GoodsSku::getStoreId, goods.getStoreId());
updateWrapper.set(GoodsSku::getMarketEnable, goods.getMarketEnable());
updateWrapper.set(GoodsSku::getAuthFlag, goods.getAuthFlag());
updateWrapper.set(GoodsSku::getDeleteFlag, goods.getDeleteFlag());
@@ -337,7 +355,32 @@ public class GoodsSkuServiceImpl extends ServiceImpl<GoodsSkuMapper, GoodsSku> i
cache.put(GoodsSkuService.getCacheKeys(sku.getId()), sku);
}
if (!goodsSkus.isEmpty()) {
generateEs(goods);
this.generateEs(goods);
}
}
}
/**
* 更新商品sku状态根据店铺id
*
* @param storeId 店铺id
* @param marketEnable 市场启用状态
* @param authFlag 审核状态
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void updateGoodsSkuStatusByStoreId(String storeId, String marketEnable, String authFlag) {
LambdaUpdateWrapper<GoodsSku> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(GoodsSku::getStoreId, storeId);
updateWrapper.set(CharSequenceUtil.isNotEmpty(marketEnable), GoodsSku::getMarketEnable, marketEnable);
updateWrapper.set(CharSequenceUtil.isNotEmpty(authFlag), GoodsSku::getAuthFlag, authFlag);
boolean update = this.update(updateWrapper);
if (Boolean.TRUE.equals(update)) {
if (GoodsStatusEnum.UPPER.name().equals(marketEnable)) {
applicationEventPublisher.publishEvent(new TransactionCommitSendMQEvent("生成店铺商品", rocketmqCustomProperties.getGoodsTopic(), GoodsTagsEnum.GENERATOR_STORE_GOODS_INDEX.name(), storeId));
} else if (GoodsStatusEnum.DOWN.name().equals(marketEnable)) {
cache.vagueDel(CachePrefix.GOODS_SKU.getPrefix());
applicationEventPublisher.publishEvent(new TransactionCommitSendMQEvent("删除店铺商品", rocketmqCustomProperties.getGoodsTopic(), GoodsTagsEnum.STORE_GOODS_DELETE.name(), storeId));
}
}
}
@@ -362,7 +405,7 @@ public class GoodsSkuServiceImpl extends ServiceImpl<GoodsSkuMapper, GoodsSku> i
@Override
public List<GoodsSkuVO> getGoodsListByGoodsId(String goodsId) {
List<GoodsSku> list = this.list(new LambdaQueryWrapper<GoodsSku>().eq(GoodsSku::getGoodsId, goodsId));
List<GoodsSku> list = this.list(new LambdaQueryWrapper<GoodsSku>().eq(GoodsSku::getGoodsId, goodsId).orderByAsc(GoodsSku::getGoodsName));
return this.getGoodsSkuVOList(list);
}
@@ -423,6 +466,11 @@ public class GoodsSkuServiceImpl extends ServiceImpl<GoodsSkuMapper, GoodsSku> i
return this.page(PageUtil.initPage(searchParams), searchParams.queryWrapper());
}
@Override
public IPage<GoodsSkuDTO> getGoodsSkuDTOByPage(Page<GoodsSkuDTO> page, Wrapper<GoodsSkuDTO> queryWrapper) {
return this.baseMapper.queryByParams(page, queryWrapper);
}
/**
* 列表查询商品sku信息
*
@@ -481,18 +529,14 @@ public class GoodsSkuServiceImpl extends ServiceImpl<GoodsSkuMapper, GoodsSku> i
@Override
@Transactional(rollbackFor = Exception.class)
public void updateGoodsStuck(List<GoodsSku> goodsSkus) {
//商品id集合 hashset 去重复
Set<String> goodsIds = new HashSet<>();
for (GoodsSku sku : goodsSkus) {
goodsIds.add(sku.getGoodsId());
}
Map<String, List<GoodsSku>> groupByGoodsIds = goodsSkus.stream().collect(Collectors.groupingBy(GoodsSku::getGoodsId));
//获取相关的sku集合
LambdaQueryWrapper<GoodsSku> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.in(GoodsSku::getGoodsId, goodsIds);
lambdaQueryWrapper.in(GoodsSku::getGoodsId, groupByGoodsIds.keySet());
List<GoodsSku> goodsSkuList = this.list(lambdaQueryWrapper);
//统计每个商品的库存
for (String goodsId : goodsIds) {
for (String goodsId : groupByGoodsIds.keySet()) {
//库存
Integer quantity = 0;
for (GoodsSku goodsSku : goodsSkuList) {
@@ -530,10 +574,7 @@ public class GoodsSkuServiceImpl extends ServiceImpl<GoodsSkuMapper, GoodsSku> i
//修改规格索引,发送mq消息
Map<String, Object> updateIndexFieldsMap = EsIndexUtil.getUpdateIndexFieldsMap(
MapUtil.builder(new HashMap<String, Object>()).put("id", goodsSku.getId()).build(),
MapUtil.builder(new HashMap<String, Object>()).put("commentNum", goodsSku.getCommentNum()).put("highPraiseNum", highPraiseNum)
.put("grade", grade).build());
Map<String, Object> updateIndexFieldsMap = EsIndexUtil.getUpdateIndexFieldsMap(MapUtil.builder(new HashMap<String, Object>()).put("id", goodsSku.getId()).build(), MapUtil.builder(new HashMap<String, Object>()).put("commentNum", goodsSku.getCommentNum()).put("highPraiseNum", highPraiseNum).put("grade", grade).build());
String destination = rocketmqCustomProperties.getGoodsTopic() + ":" + GoodsTagsEnum.UPDATE_GOODS_INDEX_FIELD.name();
rocketMQTemplate.asyncSend(destination, JSONUtil.toJsonStr(updateIndexFieldsMap), RocketmqSendCallbackBuilder.commonCallback());
@@ -558,12 +599,38 @@ public class GoodsSkuServiceImpl extends ServiceImpl<GoodsSkuMapper, GoodsSku> i
* @param goods 商品信息
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void generateEs(Goods goods) {
// 不生成没有审核通过且没有上架的商品
if (!GoodsStatusEnum.UPPER.name().equals(goods.getMarketEnable()) || !GoodsAuthEnum.PASS.name().equals(goods.getAuthFlag())) {
return;
}
applicationEventPublisher.publishEvent(new GeneratorEsGoodsIndexEvent("生成商品索引事件", goods.getId()));
applicationEventPublisher.publishEvent(new TransactionCommitSendMQEvent("生成商品", rocketmqCustomProperties.getGoodsTopic(), GoodsTagsEnum.GENERATOR_GOODS_INDEX.name(), goods.getId()));
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean deleteAndInsertGoodsSkus(List<GoodsSku> goodsSkus) {
int count = 0;
for (GoodsSku skus : goodsSkus) {
if (CharSequenceUtil.isEmpty(skus.getId())) {
skus.setId(SnowFlake.getIdStr());
}
count = this.baseMapper.replaceGoodsSku(skus);
}
return count > 0;
}
@Override
public Long countSkuNum(String storeId) {
LambdaQueryWrapper<GoodsSku> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper
.eq(GoodsSku::getStoreId, storeId)
.eq(GoodsSku::getDeleteFlag, Boolean.FALSE)
.eq(GoodsSku::getAuthFlag, GoodsAuthEnum.PASS.name())
.eq(GoodsSku::getMarketEnable, GoodsStatusEnum.UPPER.name());
return this.count(queryWrapper);
}
/**
@@ -584,152 +651,64 @@ public class GoodsSkuServiceImpl extends ServiceImpl<GoodsSkuMapper, GoodsSku> i
/**
* 增加sku集合
* 批量渲染商品sku
*
* @param skuList sku列表
* @param goods 商品信息
* @param goodsSkuList sku集合
* @param goodsOperationDTO 商品操作DTO
*/
List<GoodsSku> addGoodsSku(List<Map<String, Object>> skuList, Goods goods) {
List<GoodsSku> skus = new ArrayList<>();
for (Map<String, Object> skuVO : skuList) {
Map<String, Object> resultMap = this.add(skuVO, goods);
GoodsSku goodsSku = (GoodsSku) resultMap.get("goodsSku");
if (goods.getSelfOperated() != null) {
goodsSku.setSelfOperated(goods.getSelfOperated());
}
goodsSku.setGoodsType(goods.getGoodsType());
skus.add(goodsSku);
cache.put(GoodsSkuService.getStockCacheKey(goodsSku.getId()), goodsSku.getQuantity());
void renderGoodsSkuList(List<GoodsSku> goodsSkuList, GoodsOperationDTO goodsOperationDTO) {
// 商品销售模式渲染器
salesModelRenders.stream().filter(i -> i.getSalesMode().equals(goodsOperationDTO.getSalesModel())).findFirst().ifPresent(i -> i.renderBatch(goodsSkuList, goodsOperationDTO));
for (GoodsSku goodsSku : goodsSkuList) {
extendOldSkuValue(goodsSku);
this.renderImages(goodsSku);
}
this.saveBatch(skus);
return skus;
}
/**
* 添加商品规格
* 渲染商品sku
*
* @param map 规格属性
* @param goods 商品
* @return 规格商品
* @param goodsSku sku
* @param goodsOperationDTO 商品操作DTO
*/
private Map<String, Object> add(Map<String, Object> map, Goods goods) {
Map<String, Object> resultMap = new HashMap<>(2);
GoodsSku sku = new GoodsSku();
//商品索引
EsGoodsIndex esGoodsIndex = new EsGoodsIndex();
//设置商品信息
goodsInfo(sku, goods);
//设置商品规格信息
skuInfo(sku, goods, map, esGoodsIndex);
esGoodsIndex.setGoodsSku(sku);
resultMap.put("goodsSku", sku);
resultMap.put("goodsIndex", esGoodsIndex);
return resultMap;
void renderGoodsSku(GoodsSku goodsSku, GoodsOperationDTO goodsOperationDTO) {
extendOldSkuValue(goodsSku);
// 商品销售模式渲染器
salesModelRenders.stream().filter(i -> i.getSalesMode().equals(goodsOperationDTO.getSalesModel())).findFirst().ifPresent(i -> i.renderSingle(goodsSku, goodsOperationDTO));
this.renderImages(goodsSku);
}
/**
* 设置规格商品的商品信息
* 将原sku的一些不会直接传递的值放到新的sku中
*
* @param sku 规格
* @param goods 商品
* @param goodsSku 商品sku
*/
private void goodsInfo(GoodsSku sku, Goods goods) {
//商品基本信息
sku.setGoodsId(goods.getId());
sku.setSellingPoint(goods.getSellingPoint());
sku.setCategoryPath(goods.getCategoryPath());
sku.setBrandId(goods.getBrandId());
sku.setMarketEnable(goods.getMarketEnable());
sku.setIntro(goods.getIntro());
sku.setMobileIntro(goods.getMobileIntro());
sku.setGoodsUnit(goods.getGoodsUnit());
sku.setGrade(100D);
//商品状态
sku.setAuthFlag(goods.getAuthFlag());
sku.setSalesModel(goods.getSalesModel());
//卖家信息
sku.setStoreId(goods.getStoreId());
sku.setStoreName(goods.getStoreName());
sku.setStoreCategoryPath(goods.getStoreCategoryPath());
sku.setFreightTemplateId(goods.getTemplateId());
sku.setRecommend(goods.getRecommend());
}
/**
* 设置商品规格信息
*
* @param sku 规格商品
* @param goods 商品
* @param map 规格信息
* @param esGoodsIndex 商品索引
*/
private void skuInfo(GoodsSku sku, Goods goods, Map<String, Object> map, EsGoodsIndex esGoodsIndex) {
//规格简短信息
StringBuilder simpleSpecs = new StringBuilder();
//商品名称
StringBuilder goodsName = new StringBuilder(goods.getGoodsName());
//规格商品缩略图
String thumbnail = "";
String small = "";
//规格值
Map<String, Object> specMap = new HashMap<>(16);
//商品属性
List<EsGoodsAttribute> attributes = new ArrayList<>();
//获取规格信息
for (Map.Entry<String, Object> spec : map.entrySet()) {
//保存规格信息
if (("id").equals(spec.getKey()) || ("sn").equals(spec.getKey()) || ("cost").equals(spec.getKey())
|| ("price").equals(spec.getKey()) || ("quantity").equals(spec.getKey())
|| ("weight").equals(spec.getKey())) {
continue;
} else {
specMap.put(spec.getKey(), spec.getValue());
if (("images").equals(spec.getKey())) {
//设置规格商品缩略图
List<Map<String, String>> images = (List<Map<String, String>>) spec.getValue();
if (images == null || images.isEmpty()) {
continue;
}
//设置规格商品缩略图
//如果规格没有图片,则用商品图片复盖。有则增加规格图片,放在商品图片集合之前
if (CharSequenceUtil.isNotEmpty(spec.getValue().toString())) {
thumbnail = goodsGalleryService.getGoodsGallery(images.get(0).get("url")).getThumbnail();
small = goodsGalleryService.getGoodsGallery(images.get(0).get("url")).getSmall();
}
} else {
if (spec.getValue() != null) {
//设置商品名称
goodsName.append(" ").append(spec.getValue());
//规格简短信息
simpleSpecs.append(" ").append(spec.getValue());
}
}
private void extendOldSkuValue(GoodsSku goodsSku) {
if (CharSequenceUtil.isNotEmpty(goodsSku.getGoodsId())) {
GoodsSku oldSku = this.getGoodsSkuByIdFromCache(goodsSku.getId());
if (oldSku != null) {
goodsSku.setCommentNum(oldSku.getCommentNum());
goodsSku.setViewCount(oldSku.getViewCount());
goodsSku.setBuyCount(oldSku.getBuyCount());
goodsSku.setGrade(oldSku.getGrade());
}
}
//设置规格信息
sku.setGoodsName(goodsName.toString());
sku.setThumbnail(thumbnail);
sku.setSmall(small);
}
//规格信息
sku.setId(Convert.toStr(map.get("id"), ""));
sku.setSn(Convert.toStr(map.get("sn")));
sku.setWeight(Convert.toDouble(map.get("weight"), 0D));
sku.setPrice(Convert.toDouble(map.get("price"), 0D));
sku.setCost(Convert.toDouble(map.get("cost"), 0D));
sku.setQuantity(Convert.toInt(map.get("quantity"), 0));
sku.setSpecs(JSONUtil.toJsonStr(specMap));
sku.setSimpleSpecs(simpleSpecs.toString());
if (esGoodsIndex != null) {
//商品索引
esGoodsIndex.setAttrList(attributes);
/**
* 渲染sku图片
*
* @param goodsSku sku
*/
void renderImages(GoodsSku goodsSku) {
JSONObject jsonObject = JSONUtil.parseObj(goodsSku.getSpecs());
List<Map<String, String>> images = jsonObject.get("images", List.class);
if (images != null && !images.isEmpty()) {
GoodsGallery goodsGallery = goodsGalleryService.getGoodsGallery(images.get(0).get("url"));
goodsSku.setBig(goodsGallery.getOriginal());
goodsSku.setOriginal(goodsGallery.getOriginal());
goodsSku.setThumbnail(goodsGallery.getThumbnail());
goodsSku.setSmall(goodsGallery.getSmall());
}
}

View File

@@ -56,7 +56,7 @@ public class StoreGoodsLabelServiceImpl extends ServiceImpl<StoreGoodsLabelMappe
StoreGoodsLabelVO storeGoodsLabelVO = new StoreGoodsLabelVO(storeGoodsLabel.getId(), storeGoodsLabel.getLabelName(), storeGoodsLabel.getLevel(), storeGoodsLabel.getSortOrder());
List<StoreGoodsLabelVO> storeGoodsLabelVOChildList = new ArrayList<>();
list.stream()
.filter(label -> label.getParentId().equals(storeGoodsLabel.getId()))
.filter(label -> label.getParentId() != null && label.getParentId().equals(storeGoodsLabel.getId()))
.forEach(storeGoodsLabelChild -> storeGoodsLabelVOChildList.add(new StoreGoodsLabelVO(storeGoodsLabelChild.getId(), storeGoodsLabelChild.getLabelName(), storeGoodsLabelChild.getLevel(), storeGoodsLabelChild.getSortOrder())));
storeGoodsLabelVO.setChildren(storeGoodsLabelVOChildList);
storeGoodsLabelVOList.add(storeGoodsLabelVO);
@@ -66,7 +66,7 @@ public class StoreGoodsLabelServiceImpl extends ServiceImpl<StoreGoodsLabelMappe
storeGoodsLabelVOList.sort(Comparator.comparing(StoreGoodsLabelVO::getSortOrder));
if (!storeGoodsLabelVOList.isEmpty()) {
cache.put(CachePrefix.CATEGORY.getPrefix() + storeId + "tree", storeGoodsLabelVOList);
cache.put(CachePrefix.CATEGORY.getPrefix() + storeId, storeGoodsLabelVOList);
}
return storeGoodsLabelVOList;
}

View File

@@ -1,6 +1,7 @@
package cn.lili.modules.goods.serviceimpl;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.json.JSONUtil;
import cn.lili.common.enums.ResultCode;
import cn.lili.common.exception.ServiceException;
@@ -32,12 +33,15 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -117,7 +121,7 @@ public class StudioServiceImpl extends ServiceImpl<StudioMapper, Studio> impleme
rocketmqCustomProperties.getPromotionTopic());
//直播间结束
broadcastMessage = new BroadcastMessage(studio.getId(), StudioStatusEnum.START.name());
broadcastMessage = new BroadcastMessage(studio.getId(), StudioStatusEnum.END.name());
this.timeTrigger.edit(
TimeExecuteConstant.BROADCAST_EXECUTOR,
broadcastMessage,
@@ -209,15 +213,27 @@ public class StudioServiceImpl extends ServiceImpl<StudioMapper, Studio> impleme
}
@Override
public IPage<Studio> studioList(PageVO pageVO, Integer recommend, String status) {
public IPage<StudioVO> studioList(PageVO pageVO, Integer recommend, String status) {
QueryWrapper queryWrapper = new QueryWrapper<Studio>()
.eq(recommend != null, "recommend", true)
.eq(status != null, "status", status)
.eq(CharSequenceUtil.isNotEmpty(status), "status", status)
.orderByDesc("create_time");
if (UserContext.getCurrentUser() != null && UserContext.getCurrentUser().getRole().equals(UserEnums.STORE)) {
queryWrapper.eq("store_id", UserContext.getCurrentUser().getStoreId());
}
return this.page(PageUtil.initPage(pageVO), queryWrapper);
Page page = this.page(PageUtil.initPage(pageVO), queryWrapper);
List<Studio> records = page.getRecords();
List<StudioVO> studioVOS = new ArrayList<>();
for (Studio record : records) {
StudioVO studioVO = new StudioVO();
//获取直播间信息
BeanUtil.copyProperties(record, studioVO);
//获取直播间商品信息
studioVO.setCommodityList(commodityMapper.getCommodityByRoomId(studioVO.getRoomId()));
studioVOS.add(studioVO);
}
page.setRecords(studioVOS);
return page;
}

View File

@@ -0,0 +1,65 @@
package cn.lili.modules.goods.serviceimpl;
import cn.hutool.core.collection.CollUtil;
import cn.lili.cache.Cache;
import cn.lili.modules.goods.entity.dos.Wholesale;
import cn.lili.modules.goods.mapper.WholesaleMapper;
import cn.lili.modules.goods.service.WholesaleService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author paulG
* @since 2022/5/24
**/
@Service
@CacheConfig(cacheNames = "{wholesale}_")
public class WholesaleServiceImpl extends ServiceImpl<WholesaleMapper, Wholesale> implements WholesaleService {
@Autowired
private Cache<List<Wholesale>> cache;
@Override
@Cacheable(key = "#goodsId")
public List<Wholesale> findByGoodsId(String goodsId) {
LambdaQueryWrapper<Wholesale> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Wholesale::getGoodsId, goodsId);
return this.list(queryWrapper).stream().sorted(Comparator.comparing(Wholesale::getNum)).collect(Collectors.toList());
}
@Override
@CacheEvict(key = "#goodsId")
public Boolean removeByGoodsId(String goodsId) {
LambdaQueryWrapper<Wholesale> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Wholesale::getGoodsId, goodsId);
cache.remove("{wholesale}_" + goodsId);
return this.remove(queryWrapper);
}
@Override
public Wholesale match(String goodsId, Integer num) {
List<Wholesale> wholesaleList = cache.get("{wholesale}_" + goodsId);
if (wholesaleList == null) {
wholesaleList = this.findByGoodsId(goodsId);
cache.put("{wholesale}_" + goodsId, wholesaleList);
}
List<Wholesale> matchList = wholesaleList.stream()
.filter(wholesale -> wholesale.getNum() <= num)
.collect(Collectors.toList());
if (CollUtil.isNotEmpty(matchList)) {
return matchList.get(matchList.size() - 1);
} else if (CollUtil.isNotEmpty(wholesaleList) && CollUtil.isEmpty(matchList)) {
return wholesaleList.get(0);
}
return null;
}
}

View File

@@ -0,0 +1,116 @@
package cn.lili.modules.goods.sku;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Assert;
import cn.hutool.json.JSONUtil;
import cn.lili.modules.goods.entity.dos.Goods;
import cn.lili.modules.goods.entity.dos.GoodsSku;
import cn.lili.modules.goods.entity.dto.GoodsOperationDTO;
import org.springframework.stereotype.Component;
import java.util.*;
/**
* @author paulG
* @since 2022/5/20
**/
@Component
public class GoodsSkuBuilder {
private static final String IMAGES_KEY = "images";
/**
* 构建商品sku
*
* @param goods 商品
* @param skuInfo sku信息列表
* @param goodsOperationDTO 商品操作信息(如需处理额外信息传递,不需可传空)
* @return 商品sku
*/
public static GoodsSku build(Goods goods, Map<String, Object> skuInfo, GoodsOperationDTO goodsOperationDTO) {
GoodsSku goodsSku = new GoodsSku(goods);
builderSingle(goodsSku, skuInfo, goodsOperationDTO);
return goodsSku;
}
/**
* 批量构建商品sku
*
* @param goods 商品
* @param goodsOperationDTO 商品操作信息
* @return 商品sku
*/
public static List<GoodsSku> buildBatch(Goods goods, GoodsOperationDTO goodsOperationDTO) {
return builderBatch(goods, goodsOperationDTO);
}
/**
* 从已有的商品sku中构建商品sku
*
* @param goodsSku 原商品sku
* @param skuInfo sku信息列表
* @param goodsOperationDTO 商品操作信息(如需处理额外信息传递,不需可传空)
* @return 商品sku
*/
public static GoodsSku build(GoodsSku goodsSku, Map<String, Object> skuInfo, GoodsOperationDTO goodsOperationDTO) {
builderSingle(goodsSku, skuInfo, goodsOperationDTO);
return goodsSku;
}
private static void builderSingle(GoodsSku goodsSku, Map<String, Object> skuInfo, GoodsOperationDTO goodsOperationDTO) {
Assert.notNull(goodsSku, "goodsSku不能为空");
Assert.notEmpty(skuInfo, "skuInfo不能为空");
//规格简短信息
StringBuilder simpleSpecs = new StringBuilder();
//商品名称
StringBuilder goodsName = new StringBuilder(goodsOperationDTO.getGoodsName());
//规格值
Map<String, Object> specMap = new HashMap<>(16);
// 原始规格项
String[] ignoreOriginKeys = {"id", "sn", "cost", "price", "quantity", "weight"};
//获取规格信息
for (Map.Entry<String, Object> spec : skuInfo.entrySet()) {
//保存新增规格信息
if (!CollUtil.contains(Arrays.asList(ignoreOriginKeys), spec.getKey()) && spec.getValue() != null) {
specMap.put(spec.getKey(), spec.getValue());
if (!spec.getKey().equals(IMAGES_KEY)) {
//设置商品名称
goodsName.append(" ").append(spec.getValue());
//规格简短信息
simpleSpecs.append(" ").append(spec.getValue());
}
}
}
//设置规格信息
goodsSku.setGoodsName(goodsName.toString());
//规格信息
goodsSku.setId(Convert.toStr(skuInfo.get("id"), ""));
goodsSku.setSn(Convert.toStr(skuInfo.get("sn")));
goodsSku.setWeight(Convert.toDouble(skuInfo.get("weight"), 0D));
goodsSku.setPrice(Convert.toDouble(skuInfo.get("price"), 0D));
goodsSku.setCost(Convert.toDouble(skuInfo.get("cost"), 0D));
goodsSku.setQuantity(Convert.toInt(skuInfo.get("quantity"), 0));
goodsSku.setSpecs(JSONUtil.toJsonStr(specMap));
goodsSku.setSimpleSpecs(simpleSpecs.toString());
}
private static List<GoodsSku> builderBatch(Goods goods, GoodsOperationDTO goodsOperationDTO) {
Assert.notEmpty(goodsOperationDTO.getSkuList(), "goodsOperationDTO.getSkuList()不能为空");
Assert.notNull(goods, "goods不能为空");
List<GoodsSku> goodsSkus = new ArrayList<>();
for (Map<String, Object> skuInfo : goodsOperationDTO.getSkuList()) {
GoodsSku goodsSku = new GoodsSku(goods);
builderSingle(goodsSku, skuInfo, goodsOperationDTO);
goodsSkus.add(goodsSku);
}
return goodsSkus;
}
}

View File

@@ -0,0 +1,23 @@
package cn.lili.modules.goods.sku.render;
import cn.lili.modules.goods.entity.dos.GoodsSku;
import cn.lili.modules.goods.entity.dto.GoodsOperationDTO;
import java.util.List;
/**
* 根据商品销售模型渲染商品sku
*
* @author paulG
* @since 2022/5/20
**/
public interface SalesModelRender {
String getSalesMode();
void renderSingle(GoodsSku goodsSku, GoodsOperationDTO goodsOperationDTO);
void renderBatch(List<GoodsSku> goodsSkus, GoodsOperationDTO goodsOperationDTO);
}

View File

@@ -0,0 +1,81 @@
package cn.lili.modules.goods.sku.render.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.text.CharSequenceUtil;
import cn.lili.common.enums.ResultCode;
import cn.lili.common.exception.ServiceException;
import cn.lili.modules.goods.entity.dos.GoodsSku;
import cn.lili.modules.goods.entity.dos.Wholesale;
import cn.lili.modules.goods.entity.dto.GoodsOperationDTO;
import cn.lili.modules.goods.entity.dto.WholesaleDTO;
import cn.lili.modules.goods.entity.enums.GoodsSalesModeEnum;
import cn.lili.modules.goods.service.WholesaleService;
import cn.lili.modules.goods.sku.render.SalesModelRender;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author paulG
* @since 2022/5/24
**/
@Component
public class WholesaleSaleModelRenderImpl implements SalesModelRender {
/**
* 批发商品
*/
@Autowired
private WholesaleService wholesaleService;
@Override
@Transactional(rollbackFor = Exception.class)
public void renderSingle(GoodsSku goodsSku, GoodsOperationDTO goodsOperationDTO) {
Assert.notEmpty(goodsOperationDTO.getWholesaleList(), "批发规则不能为空");
this.checkWholesaleList(goodsOperationDTO.getWholesaleList(), goodsSku);
List<Wholesale> collect = goodsOperationDTO.getWholesaleList().stream().sorted(Comparator.comparing(Wholesale::getPrice)).collect(Collectors.toList());
wholesaleService.removeByGoodsId(goodsSku.getGoodsId());
wholesaleService.saveOrUpdateBatch(collect);
goodsSku.setPrice(collect.get(0).getPrice());
goodsSku.setCost(collect.get(0).getPrice());
}
@Override
@Transactional(rollbackFor = Exception.class)
public void renderBatch(List<GoodsSku> goodsSkus, GoodsOperationDTO goodsOperationDTO) {
Assert.notEmpty(goodsOperationDTO.getWholesaleList(), "批发规则不能为空");
this.checkWholesaleList(goodsOperationDTO.getWholesaleList(), goodsSkus.get(0));
List<Wholesale> collect = goodsOperationDTO.getWholesaleList().stream().sorted(Comparator.comparing(Wholesale::getPrice)).collect(Collectors.toList());
for (GoodsSku skus : goodsSkus) {
skus.setPrice(collect.get(0).getPrice());
skus.setCost(collect.get(0).getPrice());
}
wholesaleService.removeByGoodsId(goodsSkus.get(0).getGoodsId());
wholesaleService.saveOrUpdateBatch(collect);
}
private void checkWholesaleList(List<WholesaleDTO> wholesaleList, GoodsSku goodsSku) {
if (CollUtil.isEmpty(wholesaleList)) {
throw new ServiceException(ResultCode.MUST_HAVE_SALES_MODEL);
}
for (WholesaleDTO wholesaleDTO : wholesaleList) {
if (wholesaleDTO.getPrice() == null || wholesaleDTO.getPrice() <= 0 || wholesaleDTO.getNum() == null || wholesaleDTO.getNum() <= 0) {
throw new ServiceException(ResultCode.HAVE_INVALID_SALES_MODEL);
}
if (CharSequenceUtil.isEmpty(wholesaleDTO.getGoodsId())) {
wholesaleDTO.setGoodsId(goodsSku.getGoodsId());
}
}
}
@Override
public String getSalesMode() {
return GoodsSalesModeEnum.WHOLESALE.name();
}
}

View File

@@ -42,4 +42,8 @@ public class MemberSign extends BaseIdEntity {
@ApiModelProperty(value = "连续签到天数")
private Integer signDay;
@ApiModelProperty(value = "签到日 为数字 从现在减去19700101 的日期")
private Integer day;
}

View File

@@ -21,9 +21,8 @@ import java.util.Date;
@Data
public class ManagerMemberEditDTO {
@ApiModelProperty(value = "会员用户名,用户名不能进行修改", required = true)
@NotNull(message = "会员用户名不能为空")
private String username;
@NotNull(message = "用户ID不能为空")
private String id;
@ApiModelProperty(value = "会员密码")
private String password;
@@ -45,7 +44,7 @@ public class ManagerMemberEditDTO {
private Integer sex;
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
@DateTimeFormat(pattern = "yyyy-MM-dd")
@DateTimeFormat(pattern = "yyyy-MM-dd")
@ApiModelProperty(value = "会员生日")
private Date birthday;

View File

@@ -12,7 +12,7 @@ import lombok.Data;
@Data
public class EvaluationNumberVO {
@ApiModelProperty(value = "全部商品")
@ApiModelProperty(value = "全部评价")
private Integer all;
@ApiModelProperty(value = "好评数量")

View File

@@ -18,17 +18,6 @@ import java.util.List;
* @since 2020-02-25 14:10:16
*/
public interface FootprintMapper extends BaseMapper<FootPrint> {
/**
* 获取用户足迹的SkuId分页
*
* @param page 分页
* @param queryWrapper 查询条件
* @return 用户足迹的SkuId分页
*/
@Select("select sku_id from li_foot_print ${ew.customSqlSegment} ")
List<String> footprintSkuIdList(IPage<String> page, @Param(Constants.WRAPPER) Wrapper<FootPrint> queryWrapper);
/**
* 删除超过100条后的记录
*

View File

@@ -38,7 +38,7 @@ public interface MemberEvaluationMapper extends BaseMapper<MemberEvaluation> {
* @param goodsId 商品ID
* @return 会员评价
*/
@Select("select grade,count(1) as num from li_member_evaluation Where goods_id=#{goodsId} and status='OPEN' GROUP BY grade")
@Select("select grade,count(1) as num from li_member_evaluation Where goods_id=#{goodsId} and status='OPEN' and delete_flag = false GROUP BY grade")
List<Map<String, Object>> getEvaluationNumber(String goodsId);
/**

View File

@@ -3,6 +3,7 @@ package cn.lili.modules.member.service;
import cn.lili.common.vo.PageVO;
import cn.lili.modules.member.entity.dos.FootPrint;
import cn.lili.modules.search.entity.dos.EsGoodsIndex;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
@@ -44,7 +45,7 @@ public interface FootprintService extends IService<FootPrint> {
* @param pageVO 分页
* @return 会员浏览历史列表
*/
List<EsGoodsIndex> footPrintPage(PageVO pageVO);
IPage<EsGoodsIndex> footPrintPage(PageVO pageVO);
/**
* 获取当前会员的浏览记录数量

View File

@@ -25,6 +25,11 @@ import java.util.Map;
*/
public interface MemberService extends IService<Member> {
/**
* 默认密码
*/
static String DEFAULT_PASSWORD = "111111";
/**
* 获取当前登录的用户信息
*
@@ -92,6 +97,29 @@ public interface MemberService extends IService<Member> {
*/
Member modifyPass(String memberId, String oldPassword, String newPassword);
/**
* 是否可以初始化密码
*
* @return
*/
boolean canInitPass();
/**
* 初始化密码
*
* @param password 密码
* @return 操作结果
*/
void initPass(String password);
/**
* 注销账号
*
* @param password 密码
* @return 操作结果
*/
void cancellation(String password);
/**
* 注册会员
*
@@ -257,6 +285,7 @@ public interface MemberService extends IService<Member> {
/**
* 获取用户VO
*
* @param id 会员id
* @return 用户VO
*/

View File

@@ -9,16 +9,18 @@ import cn.lili.modules.search.entity.dos.EsGoodsIndex;
import cn.lili.modules.search.service.EsGoodsSearchService;
import cn.lili.mybatis.util.PageUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* 会员浏览历史业务层实现
@@ -29,9 +31,7 @@ import java.util.Objects;
@Service
public class FootprintServiceImpl extends ServiceImpl<FootprintMapper, FootPrint> implements FootprintService {
/**
* es商品业务层
*/
@Autowired
private EsGoodsSearchService esGoodsSearchService;
@@ -74,20 +74,33 @@ public class FootprintServiceImpl extends ServiceImpl<FootprintMapper, FootPrint
}
@Override
public List<EsGoodsIndex> footPrintPage(PageVO pageVO) {
public IPage<EsGoodsIndex> footPrintPage(PageVO pageVO) {
LambdaQueryWrapper<FootPrint> lambdaQueryWrapper = Wrappers.lambdaQuery();
lambdaQueryWrapper.eq(FootPrint::getMemberId, UserContext.getCurrentUser().getId());
lambdaQueryWrapper.eq(FootPrint::getDeleteFlag, false);
lambdaQueryWrapper.orderByDesc(FootPrint::getUpdateTime);
List<String> skuIdList = this.baseMapper.footprintSkuIdList(PageUtil.initPage(pageVO), lambdaQueryWrapper);
if (!skuIdList.isEmpty()) {
List<EsGoodsIndex> list = esGoodsSearchService.getEsGoodsBySkuIds(skuIdList);
lambdaQueryWrapper.orderByDesc(FootPrint::getCreateTime);
IPage<FootPrint> footPrintPages = this.page(PageUtil.initPage(pageVO), lambdaQueryWrapper);
//定义结果
IPage<EsGoodsIndex> esGoodsIndexIPage = new Page<>();
if (footPrintPages.getRecords() == null || footPrintPages.getRecords().isEmpty()) {
return esGoodsIndexIPage;
} else {
List<EsGoodsIndex> list = esGoodsSearchService.getEsGoodsBySkuIds(
footPrintPages.getRecords().stream().map(FootPrint::getSkuId).collect(Collectors.toList()));
//去除为空的商品数据
list.removeIf(Objects::isNull);
return list;
esGoodsIndexIPage.setPages(footPrintPages.getPages());
esGoodsIndexIPage.setRecords(list);
esGoodsIndexIPage.setTotal(footPrintPages.getTotal());
esGoodsIndexIPage.setSize(footPrintPages.getSize());
esGoodsIndexIPage.setCurrent(footPrintPages.getCurrent());
return esGoodsIndexIPage;
}
return Collections.emptyList();
}
@Override

View File

@@ -113,13 +113,15 @@ public class MemberEvaluationServiceImpl extends ServiceImpl<MemberEvaluationMap
Order order = orderService.getBySn(orderItem.getOrderSn());
//检测是否可以添加会员评价
Member member;
checkMemberEvaluation(orderItem, order);
if (Boolean.TRUE.equals(isSelf)) {
checkMemberEvaluation(orderItem, order);
//获取用户信息 非自己评价时,读取数据库
member = memberService.getById(order.getMemberId());
} else {
//自我评价商品时,获取当前登录用户信息
member = memberService.getUserInfo();
} else {
//获取用户信息 非自己评价时,读取数据库
member = memberService.getById(order.getMemberId());
}
//获取商品信息
GoodsSku goodsSku = goodsSkuService.getGoodsSkuByIdFromCache(memberEvaluationDTO.getSkuId());

View File

@@ -5,9 +5,11 @@ import cn.hutool.core.convert.Convert;
import cn.hutool.core.text.CharSequenceUtil;
import cn.lili.cache.Cache;
import cn.lili.cache.CachePrefix;
import cn.lili.common.aop.annotation.DemoSite;
import cn.lili.common.context.ThreadContextHolder;
import cn.lili.common.enums.ResultCode;
import cn.lili.common.enums.SwitchEnum;
import cn.lili.common.event.TransactionCommitSendMQEvent;
import cn.lili.common.exception.ServiceException;
import cn.lili.common.properties.RocketmqCustomProperties;
import cn.lili.common.security.AuthUser;
@@ -15,11 +17,7 @@ import cn.lili.common.security.context.UserContext;
import cn.lili.common.security.enums.UserEnums;
import cn.lili.common.security.token.Token;
import cn.lili.common.sensitive.SensitiveWordsFilter;
import cn.lili.common.utils.BeanUtil;
import cn.lili.common.utils.CookieUtil;
import cn.lili.common.utils.StringUtils;
import cn.lili.common.utils.SnowFlake;
import cn.lili.common.utils.UuidUtils;
import cn.lili.common.utils.*;
import cn.lili.common.vo.PageVO;
import cn.lili.modules.connect.config.ConnectAuthEnum;
import cn.lili.modules.connect.entity.Connect;
@@ -39,7 +37,6 @@ import cn.lili.modules.store.entity.dos.Store;
import cn.lili.modules.store.entity.enums.StoreStatusEnum;
import cn.lili.modules.store.service.StoreService;
import cn.lili.mybatis.util.PageUtil;
import cn.lili.rocketmq.RocketmqSendCallbackBuilder;
import cn.lili.rocketmq.tags.MemberTagsEnum;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
@@ -47,8 +44,8 @@ import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -92,11 +89,9 @@ public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member> impleme
*/
@Autowired
private RocketmqCustomProperties rocketmqCustomProperties;
/**
* RocketMQ
*/
@Autowired
private RocketMQTemplate rocketMQTemplate;
private ApplicationEventPublisher applicationEventPublisher;
/**
* 缓存
*/
@@ -121,12 +116,17 @@ public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member> impleme
}
@Override
public Member findByMobile(String mobile) {
public boolean findByMobile(String uuid, String mobile) {
QueryWrapper<Member> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("mobile", mobile);
return this.baseMapper.selectOne(queryWrapper);
}
Member member = this.baseMapper.selectOne(queryWrapper);
if (member == null) {
throw new ServiceException(ResultCode.USER_NOT_PHONE);
}
cache.put(CachePrefix.FIND_MOBILE + uuid, mobile, 300L);
return true;
}
@Override
public Token usernameLogin(String username, String password) {
@@ -181,6 +181,7 @@ public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member> impleme
}
@Override
@Transactional
public Token autoRegister(ConnectAuthUser authUser) {
if (CharSequenceUtil.isEmpty(authUser.getNickname())) {
@@ -194,11 +195,12 @@ public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member> impleme
Member member = new Member(username, UuidUtils.getUUID(), authUser.getAvatar(), authUser.getNickname(),
authUser.getGender() != null ? Convert.toInt(authUser.getGender().getCode()) : 0);
registerHandler(member);
member.setPassword(DEFAULT_PASSWORD);
//绑定登录方式
loginBindUser(member, authUser.getUuid(), authUser.getSource());
return memberTokenGenerate.createToken(member, false);
} catch (ServiceException e) {
log.error("自动注册服务出异常:", e);
log.error("自动注册服务出异常:", e);
throw e;
} catch (Exception e) {
log.error("自动注册异常:", e);
@@ -223,6 +225,7 @@ public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member> impleme
}
@Override
@Transactional
public Token mobilePhoneLogin(String mobilePhone) {
QueryWrapper<Member> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("mobile", mobilePhone);
@@ -241,12 +244,13 @@ public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member> impleme
*
* @param member
*/
private void registerHandler(Member member) {
@Transactional
public void registerHandler(Member member) {
member.setId(SnowFlake.getIdStr());
//保存会员
this.save(member);
String destination = rocketmqCustomProperties.getMemberTopic() + ":" + MemberTagsEnum.MEMBER_REGISTER.name();
rocketMQTemplate.asyncSend(destination, member, RocketmqSendCallbackBuilder.commonCallback());
// 发送会员注册信息
applicationEventPublisher.publishEvent(new TransactionCommitSendMQEvent("new member register", rocketmqCustomProperties.getMemberTopic(), MemberTagsEnum.MEMBER_REGISTER.name(), member));
}
@Override
@@ -261,8 +265,13 @@ public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member> impleme
}
@Override
public Member modifyPass(String memberId, String oldPassword, String newPassword) {
Member member = this.getById(memberId);
@DemoSite
public Member modifyPass(String oldPassword, String newPassword) {
AuthUser tokenUser = UserContext.getCurrentUser();
if (tokenUser == null) {
throw new ServiceException(ResultCode.USER_NOT_LOGIN);
}
Member member = this.getById(tokenUser.getId());
//判断旧密码输入是否正确
if (!new BCryptPasswordEncoder().matches(oldPassword, member.getPassword())) {
throw new ServiceException(ResultCode.USER_OLD_PASSWORD_ERROR);
@@ -276,6 +285,65 @@ public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member> impleme
}
@Override
public boolean canInitPass() {
AuthUser tokenUser = UserContext.getCurrentUser();
if (tokenUser == null) {
throw new ServiceException(ResultCode.USER_NOT_LOGIN);
}
Member member = this.getById(tokenUser.getId());
return member.getPassword().equals(DEFAULT_PASSWORD);
}
@Override
public void initPass(String password) {
AuthUser tokenUser = UserContext.getCurrentUser();
if (tokenUser == null) {
throw new ServiceException(ResultCode.USER_NOT_LOGIN);
}
Member member = this.getById(tokenUser.getId());
if (member.getPassword().equals(DEFAULT_PASSWORD)) {
//修改会员密码
LambdaUpdateWrapper<Member> lambdaUpdateWrapper = Wrappers.lambdaUpdate();
lambdaUpdateWrapper.eq(Member::getId, member.getId());
lambdaUpdateWrapper.set(Member::getPassword, new BCryptPasswordEncoder().encode(password));
this.update(lambdaUpdateWrapper);
}
throw new ServiceException(ResultCode.UNINITIALIZED_PASSWORD);
}
@Override
public void cancellation(String password) {
AuthUser tokenUser = UserContext.getCurrentUser();
if (tokenUser == null) {
throw new ServiceException(ResultCode.USER_NOT_LOGIN);
}
Member member = this.getById(tokenUser.getId());
if (member.getPassword().equals(new BCryptPasswordEncoder().encode(password))) {
//删除联合登录
connectService.deleteByMemberId(member.getId());
//混淆用户信息
this.confusionMember(member);
}
}
/**
* 混淆之前的会员信息
*
* @param member
*/
private void confusionMember(Member member) {
member.setUsername(UuidUtils.getUUID());
member.setMobile(UuidUtils.getUUID() + member.getMobile());
member.setNickName("用户已注销");
member.setDisabled(false);
this.updateById(member);
}
@Override
@Transactional
public Token register(String userName, String password, String mobilePhone) {
//检测会员信息
checkMember(userName, mobilePhone);
@@ -283,8 +351,7 @@ public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member> impleme
Member member = new Member(userName, new BCryptPasswordEncoder().encode(password), mobilePhone);
//注册成功后用户自动登录
registerHandler(member);
Token token = memberTokenGenerate.createToken(member, false);
return token;
return memberTokenGenerate.createToken(member, false);
}
@Override
@@ -321,6 +388,7 @@ public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member> impleme
}
@Override
@Transactional
public Member addMember(MemberAddDTO memberAddDTO) {
//检测会员信息
@@ -334,21 +402,16 @@ public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member> impleme
@Override
public Member updateMember(ManagerMemberEditDTO managerMemberEditDTO) {
//判断是否用户登录并且会员ID为当前登录会员ID
AuthUser tokenUser = UserContext.getCurrentUser();
if (tokenUser == null) {
throw new ServiceException(ResultCode.USER_NOT_LOGIN);
}
//过滤会员昵称敏感词
if (com.baomidou.mybatisplus.core.toolkit.StringUtils.isNotBlank(managerMemberEditDTO.getNickName())) {
if (StringUtils.isNotBlank(managerMemberEditDTO.getNickName())) {
managerMemberEditDTO.setNickName(SensitiveWordsFilter.filter(managerMemberEditDTO.getNickName()));
}
//如果密码不为空则加密密码
if (com.baomidou.mybatisplus.core.toolkit.StringUtils.isNotBlank(managerMemberEditDTO.getPassword())) {
if (StringUtils.isNotBlank(managerMemberEditDTO.getPassword())) {
managerMemberEditDTO.setPassword(new BCryptPasswordEncoder().encode(managerMemberEditDTO.getPassword()));
}
//查询会员信息
Member member = this.findByUsername(managerMemberEditDTO.getUsername());
Member member = this.getById(managerMemberEditDTO.getId());
//传递修改会员信息
BeanUtil.copyProperties(managerMemberEditDTO, member);
this.updateById(member);
@@ -401,8 +464,7 @@ public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member> impleme
memberPointMessage.setPoint(point);
memberPointMessage.setType(type);
memberPointMessage.setMemberId(memberId);
String destination = rocketmqCustomProperties.getMemberTopic() + ":" + MemberTagsEnum.MEMBER_POINT_CHANGE.name();
rocketMQTemplate.asyncSend(destination, memberPointMessage, RocketmqSendCallbackBuilder.commonCallback());
applicationEventPublisher.publishEvent(new TransactionCommitSendMQEvent("update member point", rocketmqCustomProperties.getMemberTopic(), MemberTagsEnum.MEMBER_POINT_CHANGE.name(), memberPointMessage));
return true;
}
return false;
@@ -426,10 +488,10 @@ public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member> impleme
* @param mobilePhone 手机号
* @return 会员
*/
private Long findMember(String userName,String mobilePhone) {
private Long findMember(String mobilePhone, String userName) {
QueryWrapper<Member> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("mobile", mobilePhone)
.eq("username", userName);
.or().eq("username", userName);
return this.baseMapper.selectCount(queryWrapper);
}
@@ -579,31 +641,6 @@ public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member> impleme
}
}
@Override
public void updateHaveShop(Boolean haveStore, String storeId, List<String> memberIds) {
List<Member> members = this.baseMapper.selectBatchIds(memberIds);
if (members.size() > 0) {
members.forEach(member -> {
member.setHaveStore(haveStore);
if (haveStore) {
member.setStoreId(storeId);
} else {
member.setStoreId(null);
}
});
this.updateBatchById(members);
}
}
@Override
public void resetPassword(List<String> ids) {
String password = new BCryptPasswordEncoder().encode(StringUtils.md5("123456"));
LambdaUpdateWrapper<Member> lambdaUpdateWrapper = Wrappers.lambdaUpdate();
lambdaUpdateWrapper.in(Member::getId, ids);
lambdaUpdateWrapper.set(Member::getPassword, password);
this.update(lambdaUpdateWrapper);
}
/**
* 获取所有会员的手机号
*
@@ -641,9 +678,8 @@ public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member> impleme
*/
private void checkMember(String userName, String mobilePhone) {
//判断手机号是否存在
if (findMember(userName, mobilePhone) > 0) {
if (findMember(mobilePhone, userName) > 0) {
throw new ServiceException(ResultCode.USER_EXIST);
}
}
}

View File

@@ -77,8 +77,8 @@ public class MemberSignServiceImpl extends ServiceImpl<MemberSignMapper, MemberS
} else {
memberSign.setSignDay(1);
}
//手动写入创建时间,以保证唯一索引生效
memberSign.setCreateTime(DateUtil.getCurrentDayEndTime());
memberSign.setDay(DateUtil.getDayOfStart().intValue());
try {
this.baseMapper.insert(memberSign);
//签到成功后发送消息赠送积分

View File

@@ -36,7 +36,7 @@ public class StoreCollectionServiceImpl extends ServiceImpl<StoreCollectionMappe
@Override
public IPage<StoreCollectionVO> storeCollection(PageVO pageVo) {
QueryWrapper<StoreCollectionVO> queryWrapper = new QueryWrapper();
QueryWrapper<StoreCollectionVO> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("sc.member_id", UserContext.getCurrentUser().getId());
queryWrapper.orderByDesc("sc.create_time");
return this.baseMapper.storeCollectionVOList(PageUtil.initPage(pageVo), queryWrapper);
@@ -44,10 +44,10 @@ public class StoreCollectionServiceImpl extends ServiceImpl<StoreCollectionMappe
@Override
public boolean isCollection(String storeId) {
QueryWrapper<StoreCollection> queryWrapper = new QueryWrapper();
QueryWrapper<StoreCollection> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("member_id", UserContext.getCurrentUser().getId());
queryWrapper.eq("store_id", storeId);
return Optional.ofNullable(this.getOne(queryWrapper)).isPresent();
return Optional.ofNullable(this.getOne(queryWrapper, false)).isPresent();
}
@Override
@@ -67,7 +67,7 @@ public class StoreCollectionServiceImpl extends ServiceImpl<StoreCollectionMappe
@Override
@Transactional(rollbackFor = Exception.class)
public boolean deleteStoreCollection(String storeId) {
QueryWrapper<StoreCollection> queryWrapper = new QueryWrapper();
QueryWrapper<StoreCollection> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("member_id", UserContext.getCurrentUser().getId());
queryWrapper.eq("store_id", storeId);
storeService.updateStoreCollectionNum(new CollectionDTO(storeId, -1));

View File

@@ -37,7 +37,7 @@ public enum NoticeMessageParameterEnum {
*/
CANCEL_REASON("cancel_reason", "取消原因"),
/**
* 取消原因
* 金额
*/
PRICE("price", "金额");

View File

@@ -126,8 +126,9 @@ public class AfterSaleServiceImpl extends ServiceImpl<AfterSaleMapper, AfterSale
//获取订单货物判断是否可申请售后
OrderItem orderItem = orderItemService.getBySn(sn);
//未申请售后订单货物才能进行申请
if (!orderItem.getAfterSaleStatus().equals(OrderItemAfterSaleStatusEnum.NOT_APPLIED.name())) {
//未申请售后订单货物或部分售后才能进行申请
if (!orderItem.getAfterSaleStatus().equals(OrderItemAfterSaleStatusEnum.NOT_APPLIED.name())
&& !orderItem.getAfterSaleStatus().equals(OrderItemAfterSaleStatusEnum.PART_AFTER_SALE.name())) {
throw new ServiceException(ResultCode.AFTER_SALES_BAN);
}
@@ -268,8 +269,8 @@ public class AfterSaleServiceImpl extends ServiceImpl<AfterSaleMapper, AfterSale
//根据售后单号获取售后单
AfterSale afterSale = OperationalJudgment.judgment(this.getBySn(afterSaleSn));
return logisticsService.getLogistic(afterSale.getMLogisticsCode(), afterSale.getMLogisticsNo());
String str=storeDetailService.getStoreDetail(afterSale.getStoreId()).getSalesConsigneeMobile();
return logisticsService.getLogistic(afterSale.getMLogisticsCode(), afterSale.getMLogisticsNo(), str.substring(str.length()-4));
}
@Override

View File

@@ -160,4 +160,9 @@ public class TradeDTO implements Serializable {
}
return skuList;
}
public void removeCoupon() {
this.canUseCoupons = new ArrayList<>();
this.cantUseCoupons = new ArrayList<>();
}
}

View File

@@ -6,6 +6,7 @@ import cn.lili.modules.order.cart.entity.enums.CartTypeEnum;
import cn.lili.modules.promotion.tools.PromotionTools;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@@ -19,6 +20,7 @@ import java.util.Map;
*/
@Data
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
public class CartSkuVO extends CartBase implements Serializable {
@@ -117,4 +119,8 @@ public class CartSkuVO extends CartBase implements Serializable {
public Map<String, Object> getPromotionMap() {
return PromotionTools.filterInvalidPromotionsMap(this.promotionMap);
}
public Map<String, Object> getNotFilterPromotionMap() {
return this.promotionMap;
}
}

View File

@@ -1,5 +1,6 @@
package cn.lili.modules.order.cart.render.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
@@ -7,10 +8,14 @@ import cn.lili.common.enums.PromotionTypeEnum;
import cn.lili.common.enums.ResultCode;
import cn.lili.common.exception.ServiceException;
import cn.lili.common.security.context.UserContext;
import cn.lili.common.utils.CurrencyUtil;
import cn.lili.modules.goods.entity.dos.GoodsSku;
import cn.lili.modules.goods.entity.dos.Wholesale;
import cn.lili.modules.goods.entity.enums.GoodsAuthEnum;
import cn.lili.modules.goods.entity.enums.GoodsSalesModeEnum;
import cn.lili.modules.goods.entity.enums.GoodsStatusEnum;
import cn.lili.modules.goods.service.GoodsSkuService;
import cn.lili.modules.goods.service.WholesaleService;
import cn.lili.modules.member.entity.dos.Member;
import cn.lili.modules.member.service.MemberService;
import cn.lili.modules.order.cart.entity.dto.TradeDTO;
@@ -26,6 +31,7 @@ import cn.lili.modules.promotion.entity.dos.Coupon;
import cn.lili.modules.promotion.entity.dos.Pintuan;
import cn.lili.modules.promotion.entity.dos.PointsGoods;
import cn.lili.modules.promotion.entity.vos.CouponVO;
import cn.lili.modules.promotion.service.PromotionGoodsService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -55,6 +61,14 @@ public class CheckDataRender implements CartRenderStep {
@Autowired
private MemberService memberService;
@Autowired
private WholesaleService wholesaleService;
/**
* 商品索引
*/
@Autowired
private PromotionGoodsService promotionGoodsService;
@Override
public RenderStepEnums step() {
@@ -69,6 +83,7 @@ public class CheckDataRender implements CartRenderStep {
//校验商品有效性
checkData(tradeDTO);
preSaleModel(tradeDTO);
//店铺分组数据初始化
groupStore(tradeDTO);
@@ -92,7 +107,7 @@ public class CheckDataRender implements CartRenderStep {
//缓存中的商品信息
GoodsSku dataSku = goodsSkuService.getGoodsSkuByIdFromCache(cartSkuVO.getGoodsSku().getId());
//商品有效性判定
if (dataSku == null || dataSku.getUpdateTime().before(cartSkuVO.getGoodsSku().getUpdateTime())) {
if (dataSku == null || dataSku.getCreateTime().after(cartSkuVO.getGoodsSku().getCreateTime())) {
//设置购物车未选中
cartSkuVO.setChecked(false);
//设置购物车此sku商品已失效
@@ -118,6 +133,17 @@ public class CheckDataRender implements CartRenderStep {
//设置失效消息
cartSkuVO.setErrorMessage("商品库存不足,现有库存数量[" + dataSku.getQuantity() + "]");
}
//如果存在商品促销活动,则判定商品促销状态
if (!cartSkuVO.getCartType().equals(CartTypeEnum.POINTS) && (CollUtil.isNotEmpty(cartSkuVO.getNotFilterPromotionMap()) || Boolean.TRUE.equals(cartSkuVO.getGoodsSku().getPromotionFlag()))) {
//获取当前最新的促销信息
cartSkuVO.setPromotionMap(this.promotionGoodsService.getCurrentGoodsPromotion(cartSkuVO.getGoodsSku(), tradeDTO.getCartTypeEnum().name()));
//设定商品价格
Double goodsPrice = cartSkuVO.getGoodsSku().getPromotionFlag() != null && cartSkuVO.getGoodsSku().getPromotionFlag() ? cartSkuVO.getGoodsSku().getPromotionPrice() : cartSkuVO.getGoodsSku().getPrice();
cartSkuVO.setPurchasePrice(goodsPrice);
cartSkuVO.setUtilPrice(goodsPrice);
cartSkuVO.setSubTotal(CurrencyUtil.mul(cartSkuVO.getPurchasePrice(), cartSkuVO.getNum()));
}
}
}
@@ -142,10 +168,12 @@ public class CheckDataRender implements CartRenderStep {
try {
//筛选属于当前店铺的优惠券
storeCart.getValue().forEach(i -> i.getPromotionMap().forEach((key, value) -> {
JSONObject promotionsObj = JSONUtil.parseObj(value);
Coupon coupon = JSONUtil.toBean(promotionsObj, Coupon.class);
if (key.contains(PromotionTypeEnum.COUPON.name()) && coupon.getStoreId().equals(storeCart.getKey())) {
cartVO.getCanReceiveCoupon().add(new CouponVO(coupon));
if (key.contains(PromotionTypeEnum.COUPON.name())) {
JSONObject promotionsObj = JSONUtil.parseObj(value);
Coupon coupon = JSONUtil.toBean(promotionsObj, Coupon.class);
if (key.contains(PromotionTypeEnum.COUPON.name()) && coupon.getStoreId().equals(storeCart.getKey())) {
cartVO.getCanReceiveCoupon().add(new CouponVO(coupon));
}
}
}));
} catch (Exception e) {
@@ -212,4 +240,41 @@ public class CheckDataRender implements CartRenderStep {
}
/**
* 商品销售模式特殊处理
*
* @param tradeDTO 交易信息
*/
private void preSaleModel(TradeDTO tradeDTO) {
// 寻找同goods下销售模式为批发的商品
Map<String, List<CartSkuVO>> goodsGroup = tradeDTO.getSkuList().stream().filter(i -> i.getGoodsSku().getSalesModel().equals(GoodsSalesModeEnum.WHOLESALE.name())).collect(Collectors.groupingBy(i -> i.getGoodsSku().getGoodsId()));
if (CollUtil.isNotEmpty(goodsGroup)) {
goodsGroup.forEach((k, v) -> {
// 获取购买总数
int sum = v.stream().filter(i -> Boolean.TRUE.equals(i.getChecked())).mapToInt(CartSkuVO::getNum).sum();
int fSum = v.stream().filter(i -> Boolean.FALSE.equals(i.getChecked())).mapToInt(CartSkuVO::getNum).sum();
// 匹配符合的批发规则
Wholesale match = wholesaleService.match(k, sum);
if (match != null) {
v.forEach(i -> {
// 将符合规则的商品设置批发价格
if (Boolean.TRUE.equals(i.getChecked())) {
i.setPurchasePrice(match.getPrice());
i.getGoodsSku().setPrice(match.getPrice());
i.getGoodsSku().setCost(match.getPrice());
i.setUtilPrice(match.getPrice());
i.setSubTotal(CurrencyUtil.mul(i.getPurchasePrice(), i.getNum()));
} else {
i.setPurchasePrice(wholesaleService.match(k, fSum).getPrice());
i.getGoodsSku().setPrice(i.getPurchasePrice());
i.getGoodsSku().setCost(i.getPurchasePrice());
i.setUtilPrice(i.getPurchasePrice());
i.setSubTotal(CurrencyUtil.mul(i.getPurchasePrice(), i.getNum()));
}
});
}
});
}
}
}

View File

@@ -4,6 +4,7 @@ import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.lili.common.enums.PromotionTypeEnum;
import cn.lili.common.utils.CurrencyUtil;
import cn.lili.modules.goods.service.CategoryService;
import cn.lili.modules.order.cart.entity.dto.TradeDTO;
import cn.lili.modules.order.cart.entity.enums.CartTypeEnum;
@@ -85,7 +86,7 @@ public class CommissionRender implements CartRenderStep {
if (kanjiaPromotions.isPresent()) {
JSONObject promotionsObj = JSONUtil.parseObj(kanjiaPromotions.get().getValue());
KanjiaActivityGoods kanjiaActivityGoods = JSONUtil.toBean(promotionsObj, KanjiaActivityGoods.class);
priceDetailDTO.setSettlementPrice(kanjiaActivityGoods.getSettlementPrice());
priceDetailDTO.setSettlementPrice(CurrencyUtil.add(kanjiaActivityGoods.getSettlementPrice(),priceDetailDTO.getBillPrice()));
}
}
}

View File

@@ -19,10 +19,7 @@ import cn.lili.modules.promotion.service.MemberCouponService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.stream.Collectors;
/**
@@ -60,8 +57,16 @@ public class CouponRender implements CartRenderStep {
* @param tradeDTO 交易dto
*/
private void renderCouponRule(TradeDTO tradeDTO) {
// 清除之前的优惠券
tradeDTO.removeCoupon();
List<MemberCoupon> memberCouponList = memberCouponService.getMemberCoupons(tradeDTO.getMemberId());
//获取最新优惠券
memberCouponList = memberCouponList.stream()
.filter(item -> item.getStartTime().before(new Date()) && item.getEndTime().after(new Date()))
.collect(Collectors.toList());
if (!memberCouponList.isEmpty()) {
this.checkMemberExistCoupon(tradeDTO, memberCouponList);
} else {

View File

@@ -15,7 +15,10 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* sku 运费计算
@@ -43,31 +46,35 @@ public class SkuFreightRender implements CartRenderStep {
if (memberAddress == null) {
return;
}
//循环渲染购物车商品运费价格
forSku:
for (CartSkuVO cartSkuVO : cartSkuVOS) {
//获取sku运费模版
String freightTemplateId = cartSkuVO.getGoodsSku().getFreightTemplateId();
//免运费则跳出运费计算
if (Boolean.TRUE.equals(cartSkuVO.getIsFreeFreight()) || freightTemplateId == null) {
continue;
}
//运费分组信息
Map<String, List<String>> freightGroups = freightTemplateGrouping(cartSkuVOS);
//循环运费模版
for (Map.Entry<String, List<String>> freightTemplateGroup : freightGroups.entrySet()) {
//商品id列表
List<String> skuIds = freightTemplateGroup.getValue();
//当前购物车商品列表
List<CartSkuVO> currentCartSkus = cartSkuVOS.stream().filter(item -> skuIds.contains(item.getGoodsSku().getId())).collect(Collectors.toList());
//寻找对应对商品运费计算模版
FreightTemplateVO freightTemplate = freightTemplateService.getFreightTemplate(freightTemplateId);
FreightTemplateVO freightTemplate = freightTemplateService.getFreightTemplate(freightTemplateGroup.getKey());
if (freightTemplate != null
&& freightTemplate.getFreightTemplateChildList() != null
&& !freightTemplate.getFreightTemplateChildList().isEmpty()) {
//店铺支付运费则跳过
//店铺模版免运费则跳过
if (freightTemplate.getPricingMethod().equals(FreightTemplateEnum.FREE.name())) {
break;
}
//运费模版
FreightTemplateChild freightTemplateChild = null;
//获取市级别id
//获取市级别id匹配运费模版
String addressId = memberAddress.getConsigneeAddressIdPath().split(",")[1];
//获取匹配的收货地址
for (FreightTemplateChild templateChild : freightTemplate.getFreightTemplateChildList()) {
//如果当前模版包含,则返回
//模版匹配判定
if (templateChild.getAreaId().contains(addressId)) {
freightTemplateChild = templateChild;
break;
@@ -78,28 +85,97 @@ public class SkuFreightRender implements CartRenderStep {
if (tradeDTO.getNotSupportFreight() == null) {
tradeDTO.setNotSupportFreight(new ArrayList<>());
}
tradeDTO.getNotSupportFreight().add(cartSkuVO);
continue forSku;
tradeDTO.getNotSupportFreight().addAll(currentCartSkus);
continue;
}
//物流规则模型创立
FreightTemplateChildDTO freightTemplateChildDTO = new FreightTemplateChildDTO(freightTemplateChild);
//模型写入运费模版设置的计费方式
freightTemplateChildDTO.setPricingMethod(freightTemplate.getPricingMethod());
//计算的基数 数量/重量
Double count = (freightTemplateChildDTO.getPricingMethod().equals(FreightTemplateEnum.NUM.name())) ?
cartSkuVO.getNum() :
cartSkuVO.getGoodsSku().getWeight() * cartSkuVO.getNum();
//计算运费总数
Double count = currentCartSkus.stream().mapToDouble(item ->
// 根据计费规则 累加计费基数
freightTemplateChildDTO.getPricingMethod().equals(FreightTemplateEnum.NUM.name()) ?
item.getNum().doubleValue() :
CurrencyUtil.mul(item.getNum(), item.getGoodsSku().getWeight())
).sum();
//计算运费
Double countFreight = countFreight(count, freightTemplateChildDTO);
//写入SKU运费
cartSkuVO.getPriceDetailDTO().setFreightPrice(countFreight);
resetFreightPrice(FreightTemplateEnum.valueOf(freightTemplateChildDTO.getPricingMethod()), count, countFreight, currentCartSkus);
}
}
}
/**
* sku运费写入
*
* @param freightTemplateEnum 运费计算模式
* @param count 计费基数总数
* @param countFreight 总运费
* @param cartSkuVOS 与运费相关的购物车商品
*/
private void resetFreightPrice(FreightTemplateEnum freightTemplateEnum, Double count, Double countFreight, List<CartSkuVO> cartSkuVOS) {
//剩余运费 默认等于总运费
Double surplusFreightPrice = countFreight;
//当前下标
int index = 1;
for (CartSkuVO cartSkuVO : cartSkuVOS) {
//如果是最后一个 则将剩余运费直接赋值
//PS: 循环中避免百分比累加不等于100%,所以最后一个运费不以比例计算,直接将剩余运费赋值
if (index == cartSkuVOS.size()) {
cartSkuVO.getPriceDetailDTO().setFreightPrice(surplusFreightPrice);
break;
}
Double freightPrice = freightTemplateEnum == FreightTemplateEnum.NUM ?
CurrencyUtil.mul(countFreight, CurrencyUtil.div(cartSkuVO.getNum(), count)) :
CurrencyUtil.mul(countFreight,
CurrencyUtil.div(CurrencyUtil.mul(cartSkuVO.getNum(), cartSkuVO.getGoodsSku().getWeight()), count));
//剩余运费=总运费-当前循环的商品运费
surplusFreightPrice = CurrencyUtil.sub(surplusFreightPrice, freightPrice);
cartSkuVO.getPriceDetailDTO().setFreightPrice(freightPrice);
index++;
}
}
/**
* 运费模版分组
*
* @param cartSkuVOS 购物车商品
* @return map<运费模版id List < skuid>>
*/
private Map<String, List<String>> freightTemplateGrouping(List<CartSkuVO> cartSkuVOS) {
Map<String, List<String>> map = new HashMap<>();
//循环渲染购物车商品运费价格
for (CartSkuVO cartSkuVO : cartSkuVOS) {
////免运费判定
String freightTemplateId = cartSkuVO.getGoodsSku().getFreightTemplateId();
if (Boolean.TRUE.equals(cartSkuVO.getIsFreeFreight()) || freightTemplateId == null) {
continue;
}
//包含 则value值中写入sku标识否则直接写入新的对象key为模版idvalue为new arraylist
if (map.containsKey(freightTemplateId)) {
map.get(freightTemplateId).add(cartSkuVO.getGoodsSku().getId());
} else {
List<String> skuIdsList = new ArrayList<>();
skuIdsList.add(cartSkuVO.getGoodsSku().getId());
map.put(freightTemplateId, skuIdsList);
}
}
return map;
}
/**
* 计算运费
*

View File

@@ -74,7 +74,7 @@ public class SkuPromotionRender implements CartRenderStep {
renderBasePrice(tradeDTO);
//渲染单品促销
renderSkuPromotion(tradeDTO);
//检查促销库存
checkPromotionQuantity(tradeDTO);
@@ -186,7 +186,6 @@ public class SkuPromotionRender implements CartRenderStep {
*/
private void checkPromotionQuantity(TradeDTO tradeDTO) {
for (CartSkuVO cartSkuVO : tradeDTO.getCheckedSkuList()) {
cartSkuVO.getPromotionMap();
List<PromotionSkuVO> joinPromotion = cartSkuVO.getPriceDetailDTO().getJoinPromotion();
if (!joinPromotion.isEmpty()) {
for (PromotionSkuVO promotionSkuVO : joinPromotion) {

View File

@@ -95,13 +95,6 @@ public interface CartService {
*/
void clean();
/**
* 清空购物车无效数据
*
* @param way 购物车类型
*/
void cleanChecked(CartTypeEnum way);
/**
* 重新写入
*

View File

@@ -1,5 +1,6 @@
package cn.lili.modules.order.cart.service;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
@@ -11,11 +12,12 @@ import cn.lili.common.security.AuthUser;
import cn.lili.common.security.context.UserContext;
import cn.lili.common.utils.CurrencyUtil;
import cn.lili.modules.goods.entity.dos.GoodsSku;
import cn.lili.modules.goods.entity.dos.Wholesale;
import cn.lili.modules.goods.entity.enums.GoodsAuthEnum;
import cn.lili.modules.goods.entity.enums.GoodsSalesModeEnum;
import cn.lili.modules.goods.entity.enums.GoodsStatusEnum;
import cn.lili.modules.goods.entity.vos.GoodsVO;
import cn.lili.modules.goods.service.GoodsService;
import cn.lili.modules.goods.service.GoodsSkuService;
import cn.lili.modules.goods.service.WholesaleService;
import cn.lili.modules.member.entity.dos.Member;
import cn.lili.modules.member.entity.dos.MemberAddress;
import cn.lili.modules.member.service.MemberAddressService;
@@ -32,10 +34,8 @@ import cn.lili.modules.order.order.entity.dos.Trade;
import cn.lili.modules.order.order.entity.vo.ReceiptVO;
import cn.lili.modules.promotion.entity.dos.KanjiaActivity;
import cn.lili.modules.promotion.entity.dos.MemberCoupon;
import cn.lili.modules.promotion.entity.dos.PromotionGoods;
import cn.lili.modules.promotion.entity.dto.search.KanjiaActivitySearchParams;
import cn.lili.modules.promotion.entity.dto.search.MemberCouponSearchParams;
import cn.lili.modules.promotion.entity.dto.search.PromotionGoodsSearchParams;
import cn.lili.modules.promotion.entity.enums.KanJiaStatusEnum;
import cn.lili.modules.promotion.entity.enums.MemberCouponStatusEnum;
import cn.lili.modules.promotion.entity.enums.PromotionsScopeTypeEnum;
@@ -45,7 +45,6 @@ import cn.lili.modules.promotion.service.MemberCouponService;
import cn.lili.modules.promotion.service.PointsGoodsService;
import cn.lili.modules.promotion.service.PromotionGoodsService;
import cn.lili.modules.search.entity.dos.EsGoodsIndex;
import cn.lili.modules.search.service.EsGoodsIndexService;
import cn.lili.modules.search.service.EsGoodsSearchService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
@@ -97,16 +96,6 @@ public class CartServiceImpl implements CartService {
*/
@Autowired
private EsGoodsSearchService esGoodsSearchService;
/**
* 商品索引
*/
@Autowired
private EsGoodsIndexService goodsIndexService;
/**
* ES商品
*/
@Autowired
private GoodsService goodsService;
/**
* 砍价
*/
@@ -124,6 +113,9 @@ public class CartServiceImpl implements CartService {
@Autowired
private PromotionGoodsService promotionGoodsService;
@Autowired
private WholesaleService wholesaleService;
@Override
public void add(String skuId, Integer num, String cartType, Boolean cover) {
AuthUser currentUser = Objects.requireNonNull(UserContext.getCurrentUser());
@@ -132,7 +124,7 @@ public class CartServiceImpl implements CartService {
}
CartTypeEnum cartTypeEnum = getCartType(cartType);
GoodsSku dataSku = checkGoods(skuId);
Map<String, Object> promotionMap = this.getCurrentGoodsPromotion(dataSku, cartType);
Map<String, Object> promotionMap = promotionGoodsService.getCurrentGoodsPromotion(dataSku, cartTypeEnum.name());
try {
//购物车方式购买需要保存之前的选择,其他方式购买,则直接抹除掉之前的记录
@@ -146,7 +138,7 @@ public class CartServiceImpl implements CartService {
//购物车中已经存在,更新数量
if (cartSkuVO != null && dataSku.getUpdateTime().equals(cartSkuVO.getGoodsSku().getUpdateTime())) {
if (cartSkuVO != null && dataSku.getCreateTime().equals(cartSkuVO.getGoodsSku().getCreateTime())) {
//如果覆盖购物车中商品数量
if (Boolean.TRUE.equals(cover)) {
@@ -157,7 +149,7 @@ public class CartServiceImpl implements CartService {
int newNum = oldNum + num;
this.checkSetGoodsQuantity(cartSkuVO, skuId, newNum);
}
cartSkuVO.setPromotionMap(promotionMap);
//计算购物车小计
cartSkuVO.setSubTotal(CurrencyUtil.mul(cartSkuVO.getPurchasePrice(), cartSkuVO.getNum()));
} else {
@@ -185,7 +177,6 @@ public class CartServiceImpl implements CartService {
//购物车中不存在此商品,则新建立一个
CartSkuVO cartSkuVO = new CartSkuVO(dataSku, promotionMap);
this.checkSetGoodsQuantity(cartSkuVO, skuId, num);
cartSkuVO.setCartType(cartTypeEnum);
//检测购物车数据
checkCart(cartTypeEnum, cartSkuVO, skuId, num);
@@ -194,10 +185,11 @@ public class CartServiceImpl implements CartService {
cartSkuVOS.add(cartSkuVO);
}
this.checkGoodsSaleModel(dataSku, tradeDTO.getSkuList());
tradeDTO.setCartTypeEnum(cartTypeEnum);
//如购物车发生更改,则重置优惠券
tradeDTO.setStoreCoupons(null);
tradeDTO.setPlatformCoupon(null);
remoteCoupon(tradeDTO);
this.resetTradeDTO(tradeDTO);
} catch (ServiceException serviceException) {
throw serviceException;
@@ -241,39 +233,59 @@ public class CartServiceImpl implements CartService {
@Override
public void checked(String skuId, boolean checked) {
TradeDTO tradeDTO = this.readDTO(CartTypeEnum.CART);
remoteCoupon(tradeDTO);
List<CartSkuVO> cartSkuVOS = tradeDTO.getSkuList();
for (CartSkuVO cartSkuVO : cartSkuVOS) {
if (cartSkuVO.getGoodsSku().getId().equals(skuId)) {
cartSkuVO.setChecked(checked);
}
}
cache.put(this.getOriginKey(CartTypeEnum.CART), tradeDTO);
this.resetTradeDTO(tradeDTO);
}
@Override
public void checkedStore(String storeId, boolean checked) {
TradeDTO tradeDTO = this.readDTO(CartTypeEnum.CART);
remoteCoupon(tradeDTO);
List<CartSkuVO> cartSkuVOS = tradeDTO.getSkuList();
for (CartSkuVO cartSkuVO : cartSkuVOS) {
if (cartSkuVO.getStoreId().equals(storeId)) {
cartSkuVO.setChecked(checked);
}
}
cache.put(this.getOriginKey(CartTypeEnum.CART), tradeDTO);
resetTradeDTO(tradeDTO);
}
@Override
public void checkedAll(boolean checked) {
TradeDTO tradeDTO = this.readDTO(CartTypeEnum.CART);
remoteCoupon(tradeDTO);
List<CartSkuVO> cartSkuVOS = tradeDTO.getSkuList();
for (CartSkuVO cartSkuVO : cartSkuVOS) {
cartSkuVO.setChecked(checked);
}
cache.put(this.getOriginKey(CartTypeEnum.CART), tradeDTO);
resetTradeDTO(tradeDTO);
}
/**
* 当购物车商品发生变更时,取消已选择当优惠券
*
* @param tradeDTO
*/
private void remoteCoupon(TradeDTO tradeDTO) {
tradeDTO.setPlatformCoupon(null);
tradeDTO.setStoreCoupons(new HashMap<>());
}
@Override
@Transactional(rollbackFor = Exception.class)
public void delete(String[] skuIds) {
TradeDTO tradeDTO = this.readDTO(CartTypeEnum.CART);
List<CartSkuVO> cartSkuVOS = tradeDTO.getSkuList();
@@ -286,7 +298,7 @@ public class CartServiceImpl implements CartService {
}
}
cartSkuVOS.removeAll(deleteVos);
cache.put(this.getOriginKey(CartTypeEnum.CART), tradeDTO);
resetTradeDTO(tradeDTO);
}
@Override
@@ -308,17 +320,8 @@ public class CartServiceImpl implements CartService {
tradeDTO.setStoreCoupons(null);
//清除添加过的备注
tradeDTO.setStoreRemark(null);
cache.put(this.getOriginKey(tradeDTO.getCartTypeEnum()), tradeDTO);
}
@Override
public void cleanChecked(CartTypeEnum way) {
if (way.equals(CartTypeEnum.CART)) {
TradeDTO tradeDTO = this.readDTO(CartTypeEnum.CART);
this.cleanChecked(tradeDTO);
} else {
cache.remove(this.getOriginKey(way));
}
resetTradeDTO(tradeDTO);
}
@Override
@@ -415,7 +418,7 @@ public class CartServiceImpl implements CartService {
cartSkuVO.setNum(num);
}
if (cartSkuVO.getNum() > 99) {
if (cartSkuVO.getGoodsSku() != null && !GoodsSalesModeEnum.WHOLESALE.name().equals(cartSkuVO.getGoodsSku().getSalesModel()) && cartSkuVO.getNum() > 99) {
cartSkuVO.setNum(99);
}
}
@@ -504,6 +507,12 @@ public class CartServiceImpl implements CartService {
AuthUser currentUser = Objects.requireNonNull(UserContext.getCurrentUser());
//获取购物车,然后重新写入优惠券
CartTypeEnum cartTypeEnum = getCartType(way);
//积分商品不允许使用优惠券
if (cartTypeEnum.equals(CartTypeEnum.POINTS)) {
throw new ServiceException(ResultCode.SPECIAL_CANT_USE);
}
TradeDTO tradeDTO = this.readDTO(cartTypeEnum);
MemberCouponSearchParams searchParams = new MemberCouponSearchParams();
@@ -543,46 +552,10 @@ public class CartServiceImpl implements CartService {
}
//构建交易
Trade trade = tradeBuilder.createTrade(tradeDTO);
this.cleanChecked(tradeDTO);
this.cleanChecked(this.readDTO(cartTypeEnum));
return trade;
}
private Map<String, Object> getCurrentGoodsPromotion(GoodsSku dataSku, String cartType) {
Map<String, Object> promotionMap;
EsGoodsIndex goodsIndex = goodsIndexService.findById(dataSku.getId());
if (goodsIndex == null) {
GoodsVO goodsVO = this.goodsService.getGoodsVO(dataSku.getGoodsId());
goodsIndex = goodsIndexService.getResetEsGoodsIndex(dataSku, goodsVO.getGoodsParamsDTOList());
}
if (goodsIndex.getPromotionMap() != null && !goodsIndex.getPromotionMap().isEmpty()) {
if (goodsIndex.getPromotionMap().keySet().stream().anyMatch(i -> i.contains(PromotionTypeEnum.SECKILL.name())) ||
(goodsIndex.getPromotionMap().keySet().stream().anyMatch(i -> i.contains(PromotionTypeEnum.PINTUAN.name()))
&& CartTypeEnum.PINTUAN.name().equals(cartType))) {
Optional<Map.Entry<String, Object>> containsPromotion = goodsIndex.getPromotionMap().entrySet().stream().filter(i ->
i.getKey().contains(PromotionTypeEnum.SECKILL.name()) || i.getKey().contains(PromotionTypeEnum.PINTUAN.name())).findFirst();
if (containsPromotion.isPresent()) {
JSONObject promotionsObj = JSONUtil.parseObj(containsPromotion.get().getValue());
PromotionGoodsSearchParams searchParams = new PromotionGoodsSearchParams();
searchParams.setSkuId(dataSku.getId());
searchParams.setPromotionId(promotionsObj.get("id").toString());
PromotionGoods promotionsGoods = promotionGoodsService.getPromotionsGoods(searchParams);
if (promotionsGoods != null && promotionsGoods.getPrice() != null) {
dataSku.setPromotionFlag(true);
dataSku.setPromotionPrice(promotionsGoods.getPrice());
} else {
dataSku.setPromotionFlag(false);
dataSku.setPromotionPrice(null);
}
}
}
promotionMap = goodsIndex.getPromotionMap();
} else {
promotionMap = null;
}
return promotionMap;
}
/**
* 获取购物车类型
@@ -636,6 +609,9 @@ public class CartServiceImpl implements CartService {
cartPrice = CurrencyUtil.add(cartPrice, CurrencyUtil.mul(cartSkuVO.getGoodsSku().getPrice(), cartSkuVO.getNum()));
skuPrice.put(cartSkuVO.getGoodsSku().getId(), CurrencyUtil.mul(cartSkuVO.getGoodsSku().getPrice(), cartSkuVO.getNum()));
}
} else {
cartPrice = CurrencyUtil.add(cartPrice, CurrencyUtil.mul(cartSkuVO.getGoodsSku().getPrice(), cartSkuVO.getNum()));
skuPrice.put(cartSkuVO.getGoodsSku().getId(), CurrencyUtil.mul(cartSkuVO.getGoodsSku().getPrice(), cartSkuVO.getNum()));
}
}
@@ -710,6 +686,24 @@ public class CartServiceImpl implements CartService {
}
}
private void checkGoodsSaleModel(GoodsSku dataSku, List<CartSkuVO> cartSkuVOS) {
if (dataSku.getSalesModel().equals(GoodsSalesModeEnum.WHOLESALE.name())) {
int numSum = 0;
List<CartSkuVO> sameGoodsIdSkuList = cartSkuVOS.stream().filter(i -> i.getGoodsSku().getGoodsId().equals(dataSku.getGoodsId())).collect(Collectors.toList());
if (CollUtil.isNotEmpty(sameGoodsIdSkuList)) {
numSum += sameGoodsIdSkuList.stream().mapToInt(CartSkuVO::getNum).sum();
}
Wholesale match = wholesaleService.match(dataSku.getGoodsId(), numSum);
if (match != null) {
sameGoodsIdSkuList.forEach(i -> {
i.setPurchasePrice(match.getPrice());
i.setSubTotal(CurrencyUtil.mul(i.getPurchasePrice(), i.getNum()));
});
}
}
}
/**
* 校验拼团信息
*

View File

@@ -12,6 +12,7 @@ import cn.lili.modules.order.cart.entity.enums.DeliveryMethodEnum;
import cn.lili.modules.order.cart.entity.vo.CartVO;
import cn.lili.modules.order.order.entity.dto.PriceDetailDTO;
import cn.lili.modules.order.order.entity.enums.*;
import cn.lili.modules.payment.entity.enums.PaymentMethodEnum;
import cn.lili.mybatis.BaseEntity;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
@@ -78,6 +79,9 @@ public class Order extends BaseEntity {
@ApiModelProperty(value = "第三方付款流水号")
private String receivableNo;
/**
* @see PaymentMethodEnum
*/
@ApiModelProperty(value = "支付方式")
private String paymentMethod;
@@ -181,7 +185,7 @@ public class Order extends BaseEntity {
@ApiModelProperty(value = "订单促销类型")
private String orderPromotionType;
@ApiModelProperty(value = "价格详情")
@ApiModelProperty(value = "价格价格详情")
private String priceDetail;
@ApiModelProperty(value = "订单是否支持原路退回")

View File

@@ -1,6 +1,14 @@
package cn.lili.modules.order.order.entity.dos;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.json.JSONUtil;
import cn.lili.common.utils.BeanUtil;
import cn.lili.common.utils.CurrencyUtil;
import cn.lili.common.utils.SnowFlake;
import cn.lili.modules.order.order.entity.dto.PriceDetailDTO;
import cn.lili.modules.order.order.entity.enums.FlowTypeEnum;
import cn.lili.modules.order.order.entity.enums.OrderPromotionTypeEnum;
import cn.lili.modules.payment.entity.enums.PaymentMethodEnum;
import cn.lili.mybatis.BaseIdEntity;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
@@ -9,6 +17,8 @@ import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.format.annotation.DateTimeFormat;
@@ -23,6 +33,8 @@ import java.util.Date;
@Data
@TableName("li_store_flow")
@ApiModel(value = "商家订单流水")
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
public class StoreFlow extends BaseIdEntity {
private static final long serialVersionUID = -5998757398902747939L;
@@ -92,10 +104,10 @@ public class StoreFlow extends BaseIdEntity {
@ApiModelProperty(value = "平台优惠券 使用金额")
private Double siteCouponPrice;
@ApiModelProperty(value = "站点优惠券佣金比例")
@ApiModelProperty(value = "站点优惠券补贴比例")
private Double siteCouponPoint;
@ApiModelProperty(value = "站点优惠券佣金")
@ApiModelProperty(value = "站点优惠券补贴金额")
private Double siteCouponCommission;
@ApiModelProperty(value = "单品分销返现支出")
@@ -113,6 +125,9 @@ public class StoreFlow extends BaseIdEntity {
@ApiModelProperty(value = "第三方交易流水号")
private String transactionId;
/**
* @see PaymentMethodEnum
*/
@ApiModelProperty(value = "支付方式名称")
private String paymentName;
@@ -125,4 +140,62 @@ public class StoreFlow extends BaseIdEntity {
@TableField(fill = FieldFill.INSERT)
@ApiModelProperty(value = "创建时间", hidden = true)
private Date createTime;
public StoreFlow(Order order, OrderItem item, FlowTypeEnum flowTypeEnum) {
//获取订单促销类型,如果为促销订单则获取促销商品并获取结算价
String promotionType = order.getOrderPromotionType();
BeanUtil.copyProperties(item, this);
//去掉orderitem的时间。
this.setCreateTime(null);
//入账
this.setId(SnowFlake.getIdStr());
this.setFlowType(flowTypeEnum.name());
this.setSn(SnowFlake.createStr("SF"));
this.setOrderSn(item.getOrderSn());
this.setOrderItemSn(item.getSn());
this.setStoreId(order.getStoreId());
this.setStoreName(order.getStoreName());
this.setMemberId(order.getMemberId());
this.setMemberName(order.getMemberName());
this.setGoodsName(item.getGoodsName());
this.setOrderPromotionType(item.getPromotionType());
//格式化订单价格详情
PriceDetailDTO priceDetailDTO = JSONUtil.toBean(item.getPriceDetail(), PriceDetailDTO.class);
//站点优惠券比例=最大比例(100)-店铺承担比例
this.setSiteCouponPoint(CurrencyUtil.sub(100, priceDetailDTO.getSiteCouponPoint()));
//平台优惠券 使用金额
this.setSiteCouponPrice(priceDetailDTO.getSiteCouponPrice());
//站点优惠券佣金(站点优惠券承担金额=优惠券金额 * (站点承担比例/100)
this.setSiteCouponCommission(CurrencyUtil.mul(this.getSiteCouponPrice(), CurrencyUtil.div(this.getSiteCouponPoint(), 100)));
/**
* @TODO 计算平台佣金
*/
//店铺流水金额=goodsPrice(商品总金额(商品原价))+ freightPrice(配送费) - discountPrice(优惠金额) - couponPrice(优惠券金额) + updatePrice(订单修改金额)
this.setFinalPrice(item.getPriceDetailDTO().getFlowPrice());
//平台收取交易佣金=(flowPrice(流水金额) * platFormCommissionPoint(平台佣金比例))/100
this.setCommissionPrice(item.getPriceDetailDTO().getPlatFormCommission());
//单品分销返现支出
this.setDistributionRebate(item.getPriceDetailDTO().getDistributionCommission());
//最终结算金额=flowPrice(流水金额) - platFormCommission(平台收取交易佣金) - distributionCommission(单品分销返现支出)
this.setBillPrice(item.getPriceDetailDTO().getBillPrice());
//兼容为空,以及普通订单操作
if (CharSequenceUtil.isNotEmpty(promotionType)) {
//如果为砍价活动,填写砍价结算价
if (promotionType.equals(OrderPromotionTypeEnum.KANJIA.name())) {
this.setKanjiaSettlementPrice(item.getPriceDetailDTO().getSettlementPrice());
}
//如果为砍价活动,填写砍价结算价
else if (promotionType.equals(OrderPromotionTypeEnum.POINTS.name())) {
this.setPointSettlementPrice(item.getPriceDetailDTO().getSettlementPrice());
}
}
//添加支付方式
this.setPaymentName(order.getPaymentMethod());
//添加第三方支付流水号
this.setTransactionId(order.getReceivableNo());
}
}

View File

@@ -35,6 +35,9 @@ public class Trade extends BaseEntity {
@ApiModelProperty(value = "买家用户名")
private String memberName;
/**
* @see PayStatusEnum
*/
@ApiModelProperty(value = "支付方式")
private String paymentMethod;

View File

@@ -121,7 +121,7 @@ public class OrderSearchParams extends PageVO {
//关键字查询
if (CharSequenceUtil.isNotEmpty(keywords)) {
wrapper.like("o.sn", keywords).or().like("oi.goods_name", keywords);
wrapper.and(keyWrapper -> keyWrapper.like("o.sn", keywords).or().like("oi.goods_name", keywords));
}
if (currentUser != null) {
//按卖家查询

View File

@@ -57,7 +57,8 @@ public class PriceDetailDTO implements Serializable {
@ApiModelProperty(value = "平台收取交易佣金比例")
private Double platFormCommissionPoint;
@ApiModelProperty(value = "平台收取交易佣金")
@ApiModelProperty(value = "平台收取交易佣金=(flowPrice(流水金额) * platFormCommissionPoint(平台佣金比例))/100")
private Double platFormCommission;
//=========end distribution==========
@@ -82,13 +83,15 @@ public class PriceDetailDTO implements Serializable {
//=========end update price==========
@ApiModelProperty(value = "流水金额(入账 出帐金额) = goodsPrice + freight - discountPrice - couponPrice + updatePrice")
@ApiModelProperty(value = "流水金额(入账 出帐金额) = " +
"goodsPrice(商品总金额(商品原价)) + freightPrice(配送费) - " +
"discountPrice(优惠金额) - couponPrice(优惠券金额) + updatePrice(订单修改金额)")
private Double flowPrice;
@ApiModelProperty(value = "结算价格 与 商家/供应商 结算价格(例如积分商品/砍价商品)")
private Double settlementPrice;
@ApiModelProperty(value = "最终结算金额 = flowPrice - platFormCommission - distributionCommission")
@ApiModelProperty(value = "最终结算金额 = flowPrice(流水金额) - platFormCommission(平台收取交易佣金) - distributionCommission(单品分销返现支出)")
private Double billPrice;
/**

View File

@@ -5,6 +5,7 @@ import cn.lili.modules.order.order.entity.enums.OrderComplaintStatusEnum;
import cn.lili.modules.order.order.entity.enums.OrderItemAfterSaleStatusEnum;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 子订单VO
@@ -13,6 +14,7 @@ import lombok.Data;
* @since 2020-08-17 20:28
*/
@Data
@NoArgsConstructor
public class OrderItemVO {
@ApiModelProperty(value = "编号")
@@ -55,17 +57,39 @@ public class OrderItemVO {
private String commentStatus;
public OrderItemVO(String sn, String goodsId, String skuId, String num, String image, String name, String afterSaleStatus, String complainStatus, String commentStatus, Double goodsPrice) {
public void setSn(String sn) {
this.sn = sn;
this.goodsId = goodsId;
}
public void setSkuId(String skuId) {
this.skuId = skuId;
}
public void setNum(String num) {
this.num = num;
}
public void setImage(String image) {
this.image = image;
}
public void setName(String name) {
this.name = name;
this.afterSaleStatus = afterSaleStatus;
this.complainStatus = complainStatus;
this.commentStatus = commentStatus;
}
public void setGoodsPrice(Double goodsPrice) {
this.goodsPrice = goodsPrice;
}
public void setAfterSaleStatus(String afterSaleStatus) {
this.afterSaleStatus = afterSaleStatus;
}
public void setComplainStatus(String complainStatus) {
this.complainStatus = complainStatus;
}
public void setCommentStatus(String commentStatus) {
this.commentStatus = commentStatus;
}
}

View File

@@ -1,8 +1,7 @@
package cn.lili.modules.order.order.entity.vo;
import cn.hutool.core.text.CharSequenceUtil;
import cn.lili.common.enums.ClientTypeEnum;
import cn.lili.common.utils.StringUtils;
import cn.lili.modules.order.order.entity.enums.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@@ -135,28 +134,54 @@ public class OrderSimpleVO {
private String deliverStatus;
public List<OrderItemVO> getOrderItems() {
if (StringUtils.isEmpty(groupGoodsId)) {
if (CharSequenceUtil.isEmpty(groupGoodsId)) {
return new ArrayList<>();
}
List<OrderItemVO> orderItemVOS = new ArrayList<>();
String[] orderItemsSn = groupOrderItemsSn.split(",");
String[] goodsId = groupGoodsId.split(",");
String[] skuId = groupSkuId.split(",");
String[] num = groupNum.split(",");
String[] image = groupImages.split(",");
String[] name = groupName.split(",");
String[] afterSaleStatus = groupAfterSaleStatus.split(",");
String[] complainStatus = groupComplainStatus.split(",");
String[] commentStatus = groupCommentStatus.split(",");
String[] goodsPrice = groupGoodsPrice.split(",");
for (int i = 0; i < goodsId.length; i++) {
orderItemVOS.add(new OrderItemVO(orderItemsSn[i], goodsId[i], skuId[i], num[i], image[i], name[i], afterSaleStatus[i], complainStatus[i], commentStatus[i], Double.parseDouble(goodsPrice[i])));
orderItemVOS.add(this.getOrderItemVO(i));
}
return orderItemVOS;
}
private OrderItemVO getOrderItemVO(int i) {
OrderItemVO orderItemVO = new OrderItemVO();
orderItemVO.setGoodsId(groupGoodsId.split(",")[i]);
if (CharSequenceUtil.isNotEmpty(groupOrderItemsSn)) {
orderItemVO.setSn(groupOrderItemsSn.split(",")[i]);
}
if (CharSequenceUtil.isNotEmpty(groupSkuId)) {
orderItemVO.setSkuId(groupSkuId.split(",")[i]);
}
if (CharSequenceUtil.isNotEmpty(groupName)) {
orderItemVO.setName(groupName.split(",")[i]);
}
if (CharSequenceUtil.isNotEmpty(groupNum) && groupNum.split(",").length == groupGoodsId.split(",").length) {
orderItemVO.setNum(groupNum.split(",")[i]);
}
if (CharSequenceUtil.isNotEmpty(groupImages) && groupImages.split(",").length == groupGoodsId.split(",").length) {
orderItemVO.setImage(groupImages.split(",")[i]);
}
if (CharSequenceUtil.isNotEmpty(groupAfterSaleStatus) && groupAfterSaleStatus.split(",").length == groupGoodsId.split(",").length) {
orderItemVO.setAfterSaleStatus(groupAfterSaleStatus.split(",")[i]);
}
if (CharSequenceUtil.isNotEmpty(groupComplainStatus) && groupComplainStatus.split(",").length == groupGoodsId.split(",").length) {
orderItemVO.setComplainStatus(groupComplainStatus.split(",")[i]);
}
if (CharSequenceUtil.isNotEmpty(groupCommentStatus) && groupCommentStatus.split(",").length == groupGoodsId.split(",").length) {
orderItemVO.setCommentStatus(groupCommentStatus.split(",")[i]);
}
if (CharSequenceUtil.isNotEmpty(groupGoodsPrice) && groupGoodsPrice.split(",").length == groupGoodsId.split(",").length) {
orderItemVO.setGoodsPrice(Double.parseDouble(groupGoodsPrice.split(",")[i]));
}
return orderItemVO;
}
/**
* 初始化自身状态
*/

View File

@@ -10,16 +10,14 @@ import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import cn.lili.common.enums.PromotionTypeEnum;
import cn.lili.common.enums.ResultCode;
import cn.lili.common.event.TransactionCommitSendMQEvent;
import cn.lili.common.exception.ServiceException;
import cn.lili.common.fulu.core.utils.Test;
import cn.lili.common.properties.RocketmqCustomProperties;
import cn.lili.common.security.OperationalJudgment;
import cn.lili.common.security.context.UserContext;
import cn.lili.common.security.enums.UserEnums;
import cn.lili.common.utils.SnowFlake;
import cn.lili.modules.goods.entity.dos.Goods;
import cn.lili.modules.goods.entity.dto.GoodsCompleteMessage;
import cn.lili.modules.goods.service.GoodsService;
import cn.lili.modules.member.entity.dto.MemberAddressDTO;
import cn.lili.modules.order.cart.entity.dto.TradeDTO;
import cn.lili.modules.order.order.aop.OrderLogPoint;
@@ -41,9 +39,6 @@ import cn.lili.modules.order.trade.service.OrderLogService;
import cn.lili.modules.payment.entity.enums.PaymentMethodEnum;
import cn.lili.modules.promotion.entity.dos.Pintuan;
import cn.lili.modules.promotion.service.PintuanService;
import cn.lili.modules.store.entity.dos.StoreDetail;
import cn.lili.modules.store.entity.dto.FuLuConfigureDTO;
import cn.lili.modules.store.service.StoreDetailService;
import cn.lili.modules.system.aspect.annotation.SystemLogPoint;
import cn.lili.modules.system.entity.dos.Logistics;
import cn.lili.modules.system.entity.vo.Traces;
@@ -58,7 +53,6 @@ import cn.lili.trigger.message.PintuanOrderMessage;
import cn.lili.trigger.model.TimeExecuteConstant;
import cn.lili.trigger.model.TimeTriggerMsg;
import cn.lili.trigger.util.DelayQueueTools;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
@@ -66,9 +60,11 @@ import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
@@ -88,6 +84,7 @@ import java.util.stream.Collectors;
* @since 2020/11/17 7:38 下午
*/
@Service
@Slf4j
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {
private static final String ORDER_SN_COLUMN = "order_sn";
@@ -146,17 +143,9 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
@Autowired
private TradeService tradeService;
/**
* 商品
*/
@Autowired
private GoodsService goodsService;
/**
* 商品
*/
@Autowired
private StoreDetailService storeDetailService;
private ApplicationEventPublisher applicationEventPublisher;
@Override
@Transactional(rollbackFor = Exception.class)
@@ -313,6 +302,8 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
order.setCancelReason(reason);
//修改订单
this.updateById(order);
//生成店铺退款流水
this.generatorStoreRefundFlow(order);
orderStatusMessage(order);
return order;
} else {
@@ -329,6 +320,8 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
order.setOrderStatus(OrderStatusEnum.CANCELLED.name());
order.setCancelReason(reason);
this.updateById(order);
//生成店铺退款流水
this.generatorStoreRefundFlow(order);
orderStatusMessage(order);
}
@@ -350,6 +343,7 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
Order order = this.getBySn(orderSn);
//如果订单已支付,就不能再次进行支付
if (order.getPayStatus().equals(PayStatusEnum.PAID.name())) {
log.error("订单[ {} ]检测到重复付款,请处理", orderSn);
throw new ServiceException(ResultCode.PAY_DOUBLE_ERROR);
}
@@ -362,7 +356,7 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
order.setCanReturn(!PaymentMethodEnum.BANK_TRANSFER.name().equals(order.getPaymentMethod()));
this.updateById(order);
//记录订单流水
//记录店铺订单支付流水
storeFlowService.payOrder(orderSn);
//发送订单已付款消息
@@ -458,11 +452,13 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
//获取订单信息
Order order = this.getBySn(orderSn);
//获取踪迹信息
return logisticsService.getLogistic(order.getLogisticsCode(), order.getLogisticsNo());
String str = order.getConsigneeMobile();
return logisticsService.getLogistic(order.getLogisticsCode(), order.getLogisticsNo(), str.substring(str.length() - 4));
}
@Override
@OrderLogPoint(description = "'订单['+#orderSn+']核销,核销码['+#verificationCode+']'", orderSn = "#orderSn")
@Transactional(rollbackFor = Exception.class)
public Order take(String orderSn, String verificationCode) {
//获取订单信息
@@ -507,7 +503,8 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
* @param order 订单
* @param orderSn 订单编号
*/
private void complete(Order order, String orderSn) {//修改订单状态为完成
@Transactional(rollbackFor = Exception.class)
public void complete(Order order, String orderSn) {//修改订单状态为完成
this.updateStatus(orderSn, OrderStatusEnum.COMPLETED);
//修改订单货物可以进行评价
@@ -546,10 +543,9 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
}
@Override
@Transactional(rollbackFor = Exception.class)
public void sendUpdateStatusMessage(OrderMessage orderMessage) {
String destination = rocketmqCustomProperties.getOrderTopic() + ":" + OrderTagsEnum.STATUS_CHANGE.name();
//发送订单变更mq消息
rocketMQTemplate.asyncSend(destination, JSONUtil.toJsonStr(orderMessage), RocketmqSendCallbackBuilder.commonCallback());
applicationEventPublisher.publishEvent(new TransactionCommitSendMQEvent("发送订单变更mq消息", rocketmqCustomProperties.getOrderTopic(), OrderTagsEnum.STATUS_CHANGE.name(), JSONUtil.toJsonStr(orderMessage)));
}
@Override
@@ -633,6 +629,7 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
}
@Override
@Transactional(rollbackFor = Exception.class)
public void batchDeliver(MultipartFile files) {
InputStream inputStream;
@@ -721,6 +718,7 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
* @return 是否成功
*/
@Override
@Transactional(rollbackFor = Exception.class)
public boolean checkFictitiousOrder(String pintuanId, Integer requiredNum, Boolean fictitious) {
Map<String, List<Order>> collect = this.queryListByPromotion(pintuanId)
.stream().collect(Collectors.groupingBy(Order::getParentOrderSn));
@@ -788,15 +786,35 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
/**
* 订单状态变更消息
*
* @param order
* @param order 订单信息
*/
private void orderStatusMessage(Order order) {
@Transactional(rollbackFor = Exception.class)
public void orderStatusMessage(Order order) {
OrderMessage orderMessage = new OrderMessage();
orderMessage.setOrderSn(order.getSn());
orderMessage.setNewStatus(OrderStatusEnum.valueOf(order.getOrderStatus()));
this.sendUpdateStatusMessage(orderMessage);
}
/**
* 生成店铺退款流水
*
* @param order 订单信息
*/
private void generatorStoreRefundFlow(Order order) {
// 判断订单是否是付款
if (!PayStatusEnum.PAID.name().equals((order.getPayStatus()))) {
return;
}
List<OrderItem> items = orderItemService.getByOrderSn(order.getSn());
List<StoreFlow> storeFlows = new ArrayList<>();
for (OrderItem item : items) {
StoreFlow storeFlow = new StoreFlow(order, item, FlowTypeEnum.REFUND);
storeFlows.add(storeFlow);
}
storeFlowService.saveBatch(storeFlows);
}
/**
* 此方法只提供内部调用,调用前应该做好权限处理
* 修改订单状态
@@ -822,11 +840,10 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
List<Order> list = this.getPintuanOrder(pintuanId, parentOrderSn);
int count = list.size();
if (count == 1) {
//如果为开团订单,则发布一个小时的延时任务,时间到达后,如果未成团则自动结束(未开启虚拟成团的情况下)
//如果为开团订单,则发布一个24小时的延时任务,时间到达后,如果未成团则自动结束(未开启虚拟成团的情况下)
PintuanOrderMessage pintuanOrderMessage = new PintuanOrderMessage();
//开团结束时间
// long startTime = DateUtil.offsetHour(new Date(), 1).getTime();
long startTime = DateUtil.offsetMinute(new Date(), 2).getTime();
long startTime = DateUtil.offsetHour(new Date(), 24).getTime();
pintuanOrderMessage.setOrderSn(parentOrderSn);
pintuanOrderMessage.setPintuanId(pintuanId);
TimeTriggerMsg timeTriggerMsg = new TimeTriggerMsg(TimeExecuteConstant.PROMOTION_EXECUTOR,
@@ -918,7 +935,8 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
*
* @param orderSn 订单编号
*/
private void normalOrderConfirm(String orderSn) {
@Transactional(rollbackFor = Exception.class)
public void normalOrderConfirm(String orderSn) {
//修改订单
this.update(new LambdaUpdateWrapper<Order>()
.eq(Order::getSn, orderSn)
@@ -937,7 +955,8 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
*
* @param orderSn 订单编号
*/
private void virtualOrderConfirm(String orderSn) {
@Transactional(rollbackFor = Exception.class)
public void virtualOrderConfirm(String orderSn) {
//修改订单
this.update(new LambdaUpdateWrapper<Order>()
.eq(Order::getSn, orderSn)
@@ -960,71 +979,16 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
throw new ServiceException(ResultCode.ORDER_NOT_EXIST);
}
//判断是否为虚拟订单
else if (!order.getOrderType().equals(OrderTypeEnum.VIRTUAL.name())) {
if (!order.getOrderType().equals(OrderTypeEnum.VIRTUAL.name())) {
throw new ServiceException(ResultCode.ORDER_TAKE_ERROR);
}
//判断虚拟订单状态
else if (!order.getOrderStatus().equals(OrderStatusEnum.TAKE.name())) {
if (!order.getOrderStatus().equals(OrderStatusEnum.TAKE.name())) {
throw new ServiceException(ResultCode.ORDER_TAKE_ERROR);
}
//判断验证码是否正确
else if (!verificationCode.equals(order.getVerificationCode())) {
if (!verificationCode.equals(order.getVerificationCode())) {
throw new ServiceException(ResultCode.ORDER_TAKE_ERROR);
}
}
/**
* 获取订单
*
* @param receivableNo 微信支付单号
* @return 订单详情
*/
@Override
public Order getOrderByReceivableNo(String receivableNo) {
return this.getOne(new LambdaQueryWrapper<Order>().eq(Order::getReceivableNo, receivableNo));
}
/**
* 验证福禄订单进行处理
*
* @param tradeNo 第三方流水
*/
@Override
public void fuluOrder(String tradeNo) {
Order order = this.getOrderByReceivableNo(tradeNo);
if (order != null) {
List<StoreFlow> storeFlows = storeFlowService.list(new LambdaQueryWrapper<StoreFlow>().eq(StoreFlow::getOrderSn, order.getSn()));
if (storeFlows.size() > 0) {
Goods goods = goodsService.getById(storeFlows.get(0).getGoodsId());
if (goods != null) {
FuLuConfigureDTO fuLuConfigureDTO = new FuLuConfigureDTO();
StoreDetail storeDetail = storeDetailService.getOne(
new LambdaQueryWrapper<StoreDetail>()
.eq(StoreDetail::getStoreId, storeFlows.get(0).getStoreId())
);
fuLuConfigureDTO.setAppSecretKey(storeDetail.getAppSecretKey());
fuLuConfigureDTO.setMerchantNumber(storeDetail.getMerchantNumber());
fuLuConfigureDTO.setAppMerchantKey(storeDetail.getAppMerchantKey());
try {
if (goods.getBrandId().equals("1496301301183672321")) {
Map map1 = (Map) JSON.parse(Test.productInfoGetTest(fuLuConfigureDTO, goods.getSn()).get("result").toString());
if (map1.get("product_type").toString().equals("直充")) {
Test.directOrderAddTest(fuLuConfigureDTO, Integer.valueOf(goods.getSn()), order.getGoodsNum(), order.getQrCode(), order.getSn());
} else if (map1.get("product_type").toString().equals("卡密")) {
Test.cardOrderAddTest(fuLuConfigureDTO, Integer.valueOf(goods.getSn()), order.getGoodsNum(), order.getSn());
} else {
//不是直充也不是卡密需要修改代码
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
}

View File

@@ -1,7 +1,6 @@
package cn.lili.modules.order.order.serviceimpl;
import cn.hutool.core.text.CharSequenceUtil;
import cn.lili.common.utils.BeanUtil;
import cn.lili.common.utils.CurrencyUtil;
import cn.lili.common.utils.SnowFlake;
import cn.lili.common.vo.PageVO;
@@ -11,8 +10,6 @@ import cn.lili.modules.order.order.entity.dos.OrderItem;
import cn.lili.modules.order.order.entity.dos.StoreFlow;
import cn.lili.modules.order.order.entity.dto.StoreFlowQueryDTO;
import cn.lili.modules.order.order.entity.enums.FlowTypeEnum;
import cn.lili.modules.order.order.entity.enums.OrderPromotionTypeEnum;
import cn.lili.modules.order.order.entity.enums.PayStatusEnum;
import cn.lili.modules.order.order.mapper.StoreFlowMapper;
import cn.lili.modules.order.order.service.OrderItemService;
import cn.lili.modules.order.order.service.OrderService;
@@ -64,6 +61,11 @@ public class StoreFlowServiceImpl extends ServiceImpl<StoreFlowMapper, StoreFlow
@Autowired
private BillService billService;
/**
* 店铺订单支付流水
*
* @param orderSn 订单编号
*/
@Override
public void payOrder(String orderSn) {
//根据订单编号获取子订单列表
@@ -71,61 +73,20 @@ public class StoreFlowServiceImpl extends ServiceImpl<StoreFlowMapper, StoreFlow
//根据订单编号获取订单数据
Order order = orderService.getBySn(orderSn);
//如果查询到多条支付记录,打印日志
if (order.getPayStatus().equals(PayStatusEnum.PAID.name())) {
log.error("订单[{}]检测到重复付款,请处理", orderSn);
}
//获取订单促销类型,如果为促销订单则获取促销商品并获取结算价
String orderPromotionType = order.getOrderPromotionType();
//循环子订单记录流水
for (OrderItem item : orderItems) {
StoreFlow storeFlow = new StoreFlow();
BeanUtil.copyProperties(item, storeFlow);
//入账
storeFlow.setId(SnowFlake.getIdStr());
storeFlow.setFlowType(FlowTypeEnum.PAY.name());
storeFlow.setSn(SnowFlake.createStr("SF"));
storeFlow.setOrderSn(item.getOrderSn());
storeFlow.setOrderItemSn(item.getSn());
storeFlow.setStoreId(order.getStoreId());
storeFlow.setStoreName(order.getStoreName());
storeFlow.setMemberId(order.getMemberId());
storeFlow.setMemberName(order.getMemberName());
storeFlow.setGoodsName(item.getGoodsName());
storeFlow.setOrderPromotionType(item.getPromotionType());
//计算平台佣金
storeFlow.setFinalPrice(item.getPriceDetailDTO().getFlowPrice());
storeFlow.setCommissionPrice(item.getPriceDetailDTO().getPlatFormCommission());
storeFlow.setDistributionRebate(item.getPriceDetailDTO().getDistributionCommission());
storeFlow.setBillPrice(item.getPriceDetailDTO().getBillPrice());
//兼容为空,以及普通订单操作
if (CharSequenceUtil.isNotEmpty(orderPromotionType)) {
if (orderPromotionType.equals(OrderPromotionTypeEnum.NORMAL.name())) {
//普通订单操作
}
//如果为砍价活动,填写砍价结算价
else if (orderPromotionType.equals(OrderPromotionTypeEnum.KANJIA.name())) {
storeFlow.setKanjiaSettlementPrice(item.getPriceDetailDTO().getSettlementPrice());
}
//如果为砍价活动,填写砍价结算价
else if (orderPromotionType.equals(OrderPromotionTypeEnum.POINTS.name())) {
storeFlow.setPointSettlementPrice(item.getPriceDetailDTO().getSettlementPrice());
}
}
//添加支付方式
storeFlow.setPaymentName(order.getPaymentMethod());
//添加第三方支付流水号
storeFlow.setTransactionId(order.getReceivableNo());
StoreFlow storeFlow = new StoreFlow(order, item, FlowTypeEnum.PAY);
//添加付款交易流水
this.save(storeFlow);
}
}
/**
* 店铺订单退款流水
*
* @param afterSale 售后单
*/
@Override
public void refundOrder(AfterSale afterSale) {
StoreFlow storeFlow = new StoreFlow();
@@ -149,19 +110,29 @@ public class StoreFlowServiceImpl extends ServiceImpl<StoreFlowMapper, StoreFlow
//获取付款信息
StoreFlow payStoreFlow = this.getOne(new LambdaUpdateWrapper<StoreFlow>().eq(StoreFlow::getOrderItemSn, afterSale.getOrderItemSn())
.eq(StoreFlow::getFlowType, FlowTypeEnum.PAY));
//申请商品退款数量
storeFlow.setNum(afterSale.getNum());
//分类ID
storeFlow.setCategoryId(payStoreFlow.getCategoryId());
//佣金
//佣金 = (佣金/订单商品数量)* 售后商品数量
storeFlow.setCommissionPrice(CurrencyUtil.mul(CurrencyUtil.div(payStoreFlow.getCommissionPrice(), payStoreFlow.getNum()), afterSale.getNum()));
//分销佣金
//分销佣金 =(分销佣金/订单商品数量)* 售后商品数量
storeFlow.setDistributionRebate(CurrencyUtil.mul(CurrencyUtil.div(payStoreFlow.getDistributionRebate(), payStoreFlow.getNum()), afterSale.getNum()));
//流水金额
storeFlow.setFinalPrice(afterSale.getActualRefundPrice());
//最终结算金额
storeFlow.setBillPrice(CurrencyUtil.add(storeFlow.getFinalPrice(), storeFlow.getDistributionRebate(), storeFlow.getCommissionPrice()));
//获取第三方支付流水号
//流水金额 = 支付最终结算金额
storeFlow.setFinalPrice(payStoreFlow.getBillPrice());
//最终结算金额 =实际退款金额
storeFlow.setBillPrice(afterSale.getActualRefundPrice());
//站点优惠券补贴返还金额=(站点优惠券补贴金额/购买商品数量)*退款商品数量
storeFlow.setSiteCouponCommission(CurrencyUtil.mul(CurrencyUtil.div(payStoreFlow.getSiteCouponCommission(), payStoreFlow.getNum()), afterSale.getNum()));
//平台优惠券 使用金额
storeFlow.setSiteCouponPrice(payStoreFlow.getSiteCouponPrice());
//站点优惠券佣金比例
storeFlow.setSiteCouponPoint(payStoreFlow.getSiteCouponPoint());
//退款日志
RefundLog refundLog = refundLogService.queryByAfterSaleSn(afterSale.getSn());
//第三方流水单号
storeFlow.setTransactionId(refundLog.getReceivableNo());
//支付方式
storeFlow.setPaymentName(refundLog.getPaymentName());
this.save(storeFlow);
}

File diff suppressed because one or more lines are too long

View File

@@ -53,7 +53,7 @@ public interface ArticleService extends IService<Article> {
Article updateArticle(Article article);
/**
* 删除文章
* 删除文章--id
*
* @param id
*/
@@ -87,4 +87,12 @@ public interface ArticleService extends IService<Article> {
*/
@CacheEvict(key = "#id")
Boolean updateArticleStatus(String id, boolean status);
/**
* 修改文章--文章类型修改
* @param article
* @return
*/
@CacheEvict(key = "#article.type")
Article updateArticleType(Article article);
}

View File

@@ -91,4 +91,12 @@ public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article> impl
article.setOpenStatus(status);
return this.updateById(article);
}
@Override
public Article updateArticleType(Article article) {
Article oldArticle = this.getById(article.getId());
BeanUtil.copyProperties(article, oldArticle);
this.updateById(oldArticle);
return oldArticle;
}
}

View File

@@ -1,5 +1,6 @@
package cn.lili.modules.page.serviceimpl;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.StrUtil;
import cn.lili.common.enums.ClientTypeEnum;
@@ -82,12 +83,11 @@ public class PageDataServiceImpl extends ServiceImpl<PageDataMapper, PageData> i
@Override
@Transactional(rollbackFor = Exception.class)
public PageData updatePageData(PageData pageData) {
//如果页面为发布,则关闭其他页面,开启此页面
if (pageData.getPageShow() != null && pageData.getPageShow().equals(SwitchEnum.OPEN.name())) {
LambdaUpdateWrapper<PageData> lambdaUpdateWrapper = Wrappers.lambdaUpdate();
lambdaUpdateWrapper.eq(PageData::getPageType, pageData.getPageType());
lambdaUpdateWrapper.eq(PageData::getPageClientType, pageData.getPageClientType());
lambdaUpdateWrapper.eq(CharSequenceUtil.isNotEmpty(pageData.getPageType()), PageData::getPageType, pageData.getPageType());
lambdaUpdateWrapper.eq(CharSequenceUtil.isNotEmpty(pageData.getPageClientType()), PageData::getPageClientType, pageData.getPageClientType());
lambdaUpdateWrapper.set(PageData::getPageShow, SwitchEnum.CLOSE.name());
lambdaUpdateWrapper.set(StrUtil.isNotEmpty(pageData.getNum()), PageData::getNum, SwitchEnum.CLOSE.name());
this.update(lambdaUpdateWrapper);

View File

@@ -1,5 +1,6 @@
package cn.lili.modules.payment.entity;
import cn.lili.modules.payment.entity.enums.PaymentMethodEnum;
import cn.lili.mybatis.BaseIdEntity;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
@@ -48,6 +49,9 @@ public class RefundLog extends BaseIdEntity {
@ApiModelProperty(value = "是否已退款")
private Boolean isRefund;
/**
* @see PaymentMethodEnum
*/
@ApiModelProperty(value = "退款方式")
private String paymentName;

View File

@@ -83,17 +83,6 @@ public interface Payment {
throw new ServiceException(ResultCode.PAY_ERROR);
}
/**
* 取消支付订单
*
* @param refundLog 支付参数
*/
default void cancel(RefundLog refundLog) {
throw new ServiceException(ResultCode.PAY_ERROR);
}
/**
* 回调
*
@@ -131,6 +120,7 @@ public interface Payment {
default String callbackUrl(String api, PaymentMethodEnum paymentMethodEnum) {
return api + "/buyer/payment/cashier/callback/" + paymentMethodEnum.name();
}
/**
* 支付异步通知地址
*

View File

@@ -75,7 +75,6 @@ public class RefundSupport {
*
* @return void
* @Author ftyy
* @Description //TODO
* @Date 17:33 2021/11/18
* @Param [afterSale]
**/
@@ -89,31 +88,6 @@ public class RefundSupport {
orderItemService.updateById(orderItem);
}
/**
* 订单取消
*
* @param afterSale
*/
public void cancel(AfterSale afterSale) {
Order order = orderService.getBySn(afterSale.getOrderSn());
RefundLog refundLog = RefundLog.builder()
.isRefund(false)
.totalAmount(afterSale.getActualRefundPrice())
.payPrice(afterSale.getActualRefundPrice())
.memberId(afterSale.getMemberId())
.paymentName(order.getPaymentMethod())
.afterSaleNo(afterSale.getSn())
.paymentReceivableNo(order.getReceivableNo())
.outOrderNo("AF" + SnowFlake.getIdStr())
.orderSn(afterSale.getOrderSn())
.refundReason(afterSale.getReason())
.build();
PaymentMethodEnum paymentMethodEnum = PaymentMethodEnum.paymentNameOf(order.getPaymentMethod());
Payment payment = (Payment) SpringContextUtil.getBean(paymentMethodEnum.getPlugin());
payment.refund(refundLog);
}
/**
* 退款通知

View File

@@ -1,10 +1,11 @@
package cn.lili.modules.payment.kit.core.http;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.net.SSLContextBuilder;
import cn.hutool.core.net.SSLProtocols;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.http.ssl.SSLSocketFactoryBuilder;
import cn.lili.modules.payment.kit.core.PaymentHttpResponse;
import javax.net.ssl.KeyManager;
@@ -235,12 +236,12 @@ public abstract class AbstractHttpDelegate {
try {
File file = FileUtil.newFile(filePath);
return HttpRequest.post(url)
.setSSLSocketFactory(SSLSocketFactoryBuilder
.setSSLSocketFactory(SSLContextBuilder
.create()
.setProtocol(protocol)
.setKeyManagers(getKeyManager(certPass, certPath, null))
.setSecureRandom(new SecureRandom())
.build()
.build().getSocketFactory()
)
.header("Content-Type", "multipart/form-data;boundary=\"boundary\"")
.form("file", file)
@@ -263,7 +264,7 @@ public abstract class AbstractHttpDelegate {
* @return {@link String} 请求返回的结果
*/
public String upload(String url, String data, String certPath, String certPass, String filePath) {
return upload(url, data, certPath, certPass, filePath, SSLSocketFactoryBuilder.TLSv1);
return upload(url, data, certPath, certPass, filePath, SSLProtocols.TLSv1);
}
/**
@@ -279,12 +280,12 @@ public abstract class AbstractHttpDelegate {
public String post(String url, String data, String certPath, String certPass, String protocol) {
try {
return HttpRequest.post(url)
.setSSLSocketFactory(SSLSocketFactoryBuilder
.setSSLSocketFactory(SSLContextBuilder
.create()
.setProtocol(protocol)
.setKeyManagers(getKeyManager(certPass, certPath, null))
.setSecureRandom(new SecureRandom())
.build()
.build().getSocketFactory()
)
.body(data)
.execute()
@@ -304,7 +305,7 @@ public abstract class AbstractHttpDelegate {
* @return {@link String} 请求返回的结果
*/
public String post(String url, String data, String certPath, String certPass) {
return post(url, data, certPath, certPass, SSLSocketFactoryBuilder.TLSv1);
return post(url, data, certPath, certPass, SSLProtocols.TLSv1);
}
/**
@@ -320,12 +321,12 @@ public abstract class AbstractHttpDelegate {
public String post(String url, String data, InputStream certFile, String certPass, String protocol) {
try {
return HttpRequest.post(url)
.setSSLSocketFactory(SSLSocketFactoryBuilder
.setSSLSocketFactory(SSLContextBuilder
.create()
.setProtocol(protocol)
.setKeyManagers(getKeyManager(certPass, null, certFile))
.setSecureRandom(new SecureRandom())
.build()
.build().getSocketFactory()
)
.body(data)
.execute()
@@ -345,7 +346,7 @@ public abstract class AbstractHttpDelegate {
* @return {@link String} 请求返回的结果
*/
public String post(String url, String data, InputStream certFile, String certPass) {
return post(url, data, certFile, certPass, SSLSocketFactoryBuilder.TLSv1);
return post(url, data, certFile, certPass, SSLProtocols.TLSv1);
}
/**

Some files were not shown because too many files have changed in this diff Show More