【同步】BOOT 和 CLOUD 的功能
This commit is contained in:
@@ -12,6 +12,9 @@ import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
|
||||
|
||||
@FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory =
|
||||
@Tag(name = "RPC 服务 - 商品 SPU")
|
||||
@@ -24,6 +27,16 @@ public interface ProductSpuApi {
|
||||
@Parameter(name = "ids", description = "SPU 编号列表", required = true, example = "1,3,5")
|
||||
CommonResult<List<ProductSpuRespDTO>> getSpuList(@RequestParam("ids") Collection<Long> ids);
|
||||
|
||||
/**
|
||||
* 批量查询 SPU MAP
|
||||
*
|
||||
* @param ids SPU 编号列表
|
||||
* @return SPU MAP
|
||||
*/
|
||||
default Map<Long, ProductSpuRespDTO> getSpusMap(Collection<Long> ids) {
|
||||
return convertMap(getSpuList(ids).getCheckedData(), ProductSpuRespDTO::getId);
|
||||
}
|
||||
|
||||
@GetMapping(PREFIX + "/valid")
|
||||
@Schema(description = "批量查询 SPU 数组,并且校验是否 SPU 是否有效")
|
||||
@Parameter(name = "ids", description = "SPU 编号列表", required = true, example = "1,3,5")
|
||||
|
||||
@@ -10,6 +10,7 @@ import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@@ -33,6 +34,7 @@ public class AppCategoryController {
|
||||
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "获得商品分类列表")
|
||||
@PermitAll
|
||||
public CommonResult<List<AppCategoryRespVO>> getProductCategoryList() {
|
||||
List<ProductCategoryDO> list = categoryService.getEnableCategoryList();
|
||||
list.sort(Comparator.comparing(ProductCategoryDO::getSort));
|
||||
@@ -42,6 +44,7 @@ public class AppCategoryController {
|
||||
@GetMapping("/list-by-ids")
|
||||
@Operation(summary = "获得商品分类列表,指定编号")
|
||||
@Parameter(name = "ids", description = "商品分类编号数组", required = true)
|
||||
@PermitAll
|
||||
public CommonResult<List<AppCategoryRespVO>> getProductCategoryList(@RequestParam("ids") List<Long> ids) {
|
||||
if (CollUtil.isEmpty(ids)) {
|
||||
return success(Collections.emptyList());
|
||||
|
||||
@@ -11,6 +11,7 @@ import cn.iocoder.yudao.module.product.service.comment.ProductCommentService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
@@ -30,6 +31,7 @@ public class AppProductCommentController {
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得商品评价分页")
|
||||
@PermitAll
|
||||
public CommonResult<PageResult<AppProductCommentRespVO>> getCommentPage(@Valid AppCommentPageReqVO pageVO) {
|
||||
// 查询评论分页
|
||||
PageResult<ProductCommentDO> pageResult = productCommentService.getCommentPage(pageVO, Boolean.TRUE);
|
||||
|
||||
@@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.product.controller.app.favorite;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
|
||||
import cn.iocoder.yudao.module.product.controller.app.favorite.vo.AppFavoritePageReqVO;
|
||||
import cn.iocoder.yudao.module.product.controller.app.favorite.vo.AppFavoriteReqVO;
|
||||
import cn.iocoder.yudao.module.product.controller.app.favorite.vo.AppFavoriteRespVO;
|
||||
@@ -36,14 +35,12 @@ public class AppFavoriteController {
|
||||
|
||||
@PostMapping(value = "/create")
|
||||
@Operation(summary = "添加商品收藏")
|
||||
@PreAuthenticated
|
||||
public CommonResult<Long> createFavorite(@RequestBody @Valid AppFavoriteReqVO reqVO) {
|
||||
return success(productFavoriteService.createFavorite(getLoginUserId(), reqVO.getSpuId()));
|
||||
}
|
||||
|
||||
@DeleteMapping(value = "/delete")
|
||||
@Operation(summary = "取消单个商品收藏")
|
||||
@PreAuthenticated
|
||||
public CommonResult<Boolean> deleteFavorite(@RequestBody @Valid AppFavoriteReqVO reqVO) {
|
||||
productFavoriteService.deleteFavorite(getLoginUserId(), reqVO.getSpuId());
|
||||
return success(Boolean.TRUE);
|
||||
@@ -51,7 +48,6 @@ public class AppFavoriteController {
|
||||
|
||||
@GetMapping(value = "/page")
|
||||
@Operation(summary = "获得商品收藏分页")
|
||||
@PreAuthenticated
|
||||
public CommonResult<PageResult<AppFavoriteRespVO>> getFavoritePage(AppFavoritePageReqVO reqVO) {
|
||||
PageResult<ProductFavoriteDO> favoritePage = productFavoriteService.getFavoritePage(getLoginUserId(), reqVO);
|
||||
if (CollUtil.isEmpty(favoritePage.getList())) {
|
||||
@@ -71,7 +67,6 @@ public class AppFavoriteController {
|
||||
|
||||
@GetMapping(value = "/exits")
|
||||
@Operation(summary = "检查是否收藏过商品")
|
||||
@PreAuthenticated
|
||||
public CommonResult<Boolean> isFavoriteExists(AppFavoriteReqVO reqVO) {
|
||||
ProductFavoriteDO favorite = productFavoriteService.getFavorite(getLoginUserId(), reqVO.getSpuId());
|
||||
return success(favorite != null);
|
||||
@@ -79,7 +74,6 @@ public class AppFavoriteController {
|
||||
|
||||
@GetMapping(value = "/get-count")
|
||||
@Operation(summary = "获得商品收藏数量")
|
||||
@PreAuthenticated
|
||||
public CommonResult<Long> getFavoriteCount() {
|
||||
return success(productFavoriteService.getFavoriteCount(getLoginUserId()));
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import cn.hutool.core.collection.CollUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
|
||||
import cn.iocoder.yudao.module.product.controller.admin.history.vo.ProductBrowseHistoryPageReqVO;
|
||||
import cn.iocoder.yudao.module.product.controller.app.history.vo.AppProductBrowseHistoryDeleteReqVO;
|
||||
import cn.iocoder.yudao.module.product.controller.app.history.vo.AppProductBrowseHistoryPageReqVO;
|
||||
@@ -40,7 +39,6 @@ public class AppProductBrowseHistoryController {
|
||||
|
||||
@DeleteMapping(value = "/delete")
|
||||
@Operation(summary = "删除商品浏览记录")
|
||||
@PreAuthenticated
|
||||
public CommonResult<Boolean> deleteBrowseHistory(@RequestBody @Valid AppProductBrowseHistoryDeleteReqVO reqVO) {
|
||||
productBrowseHistoryService.hideUserBrowseHistory(getLoginUserId(), reqVO.getSpuIds());
|
||||
return success(Boolean.TRUE);
|
||||
@@ -48,7 +46,6 @@ public class AppProductBrowseHistoryController {
|
||||
|
||||
@DeleteMapping(value = "/clean")
|
||||
@Operation(summary = "清空商品浏览记录")
|
||||
@PreAuthenticated
|
||||
public CommonResult<Boolean> deleteBrowseHistory() {
|
||||
productBrowseHistoryService.hideUserBrowseHistory(getLoginUserId(), null);
|
||||
return success(Boolean.TRUE);
|
||||
@@ -56,7 +53,6 @@ public class AppProductBrowseHistoryController {
|
||||
|
||||
@GetMapping(value = "/page")
|
||||
@Operation(summary = "获得商品浏览记录分页")
|
||||
@PreAuthenticated
|
||||
public CommonResult<PageResult<AppProductBrowseHistoryRespVO>> getBrowseHistoryPage(AppProductBrowseHistoryPageReqVO reqVO) {
|
||||
ProductBrowseHistoryPageReqVO pageReqVO = BeanUtils.toBean(reqVO, ProductBrowseHistoryPageReqVO.class)
|
||||
.setUserId(getLoginUserId())
|
||||
|
||||
@@ -4,10 +4,6 @@ import cn.hutool.core.collection.CollUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.member.api.level.MemberLevelApi;
|
||||
import cn.iocoder.yudao.module.member.api.level.dto.MemberLevelRespDTO;
|
||||
import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
|
||||
import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
|
||||
import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuDetailRespVO;
|
||||
import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageReqVO;
|
||||
import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuRespVO;
|
||||
@@ -21,6 +17,7 @@ import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
@@ -51,14 +48,10 @@ public class AppProductSpuController {
|
||||
@Resource
|
||||
private ProductBrowseHistoryService productBrowseHistoryService;
|
||||
|
||||
@Resource
|
||||
private MemberLevelApi memberLevelApi;
|
||||
@Resource
|
||||
private MemberUserApi memberUserApi;
|
||||
|
||||
@GetMapping("/list-by-ids")
|
||||
@Operation(summary = "获得商品 SPU 列表")
|
||||
@Parameter(name = "ids", description = "编号列表", required = true)
|
||||
@PermitAll
|
||||
public CommonResult<List<AppProductSpuRespVO>> getSpuList(@RequestParam("ids") Set<Long> ids) {
|
||||
List<ProductSpuDO> list = productSpuService.getSpuList(ids);
|
||||
if (CollUtil.isEmpty(list)) {
|
||||
@@ -68,14 +61,12 @@ public class AppProductSpuController {
|
||||
// 拼接返回
|
||||
list.forEach(spu -> spu.setSalesCount(spu.getSalesCount() + spu.getVirtualSalesCount()));
|
||||
List<AppProductSpuRespVO> voList = BeanUtils.toBean(list, AppProductSpuRespVO.class);
|
||||
// 处理 vip 价格
|
||||
MemberLevelRespDTO memberLevel = getMemberLevel();
|
||||
voList.forEach(vo -> vo.setVipPrice(calculateVipPrice(vo.getPrice(), memberLevel)));
|
||||
return success(voList);
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得商品 SPU 分页")
|
||||
@PermitAll
|
||||
public CommonResult<PageResult<AppProductSpuRespVO>> getSpuPage(@Valid AppProductSpuPageReqVO pageVO) {
|
||||
PageResult<ProductSpuDO> pageResult = productSpuService.getSpuPage(pageVO);
|
||||
if (CollUtil.isEmpty(pageResult.getList())) {
|
||||
@@ -85,15 +76,13 @@ public class AppProductSpuController {
|
||||
// 拼接返回
|
||||
pageResult.getList().forEach(spu -> spu.setSalesCount(spu.getSalesCount() + spu.getVirtualSalesCount()));
|
||||
PageResult<AppProductSpuRespVO> voPageResult = BeanUtils.toBean(pageResult, AppProductSpuRespVO.class);
|
||||
// 处理 vip 价格
|
||||
MemberLevelRespDTO memberLevel = getMemberLevel();
|
||||
voPageResult.getList().forEach(vo -> vo.setVipPrice(calculateVipPrice(vo.getPrice(), memberLevel)));
|
||||
return success(voPageResult);
|
||||
}
|
||||
|
||||
@GetMapping("/get-detail")
|
||||
@Operation(summary = "获得商品 SPU 明细")
|
||||
@Parameter(name = "id", description = "编号", required = true)
|
||||
@PermitAll
|
||||
public CommonResult<AppProductSpuDetailRespVO> getSpuDetail(@RequestParam("id") Long id) {
|
||||
// 获得商品 SPU
|
||||
ProductSpuDO spu = productSpuService.getSpu(id);
|
||||
@@ -115,37 +104,7 @@ public class AppProductSpuController {
|
||||
spu.setSalesCount(spu.getSalesCount() + spu.getVirtualSalesCount());
|
||||
AppProductSpuDetailRespVO spuVO = BeanUtils.toBean(spu, AppProductSpuDetailRespVO.class)
|
||||
.setSkus(BeanUtils.toBean(skus, AppProductSpuDetailRespVO.Sku.class));
|
||||
// 处理 vip 价格
|
||||
MemberLevelRespDTO memberLevel = getMemberLevel();
|
||||
spuVO.setVipPrice(calculateVipPrice(spuVO.getPrice(), memberLevel));
|
||||
return success(spuVO);
|
||||
}
|
||||
|
||||
private MemberLevelRespDTO getMemberLevel() {
|
||||
Long userId = getLoginUserId();
|
||||
if (userId == null) {
|
||||
return null;
|
||||
}
|
||||
MemberUserRespDTO user = memberUserApi.getUser(userId).getCheckedData();
|
||||
if (user.getLevelId() == null || user.getLevelId() <= 0) {
|
||||
return null;
|
||||
}
|
||||
return memberLevelApi.getMemberLevel(user.getLevelId()).getCheckedData();
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算会员 VIP 优惠价格
|
||||
*
|
||||
* @param price 原价
|
||||
* @param memberLevel 会员等级
|
||||
* @return 优惠价格
|
||||
*/
|
||||
public Integer calculateVipPrice(Integer price, MemberLevelRespDTO memberLevel) {
|
||||
if (memberLevel == null || memberLevel.getDiscountPercent() == null) {
|
||||
return 0;
|
||||
}
|
||||
Integer newPrice = price * memberLevel.getDiscountPercent() / 100;
|
||||
return price - newPrice;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -46,9 +46,6 @@ public class AppProductSpuDetailRespVO {
|
||||
@Schema(description = "市场价,单位使用:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Integer marketPrice;
|
||||
|
||||
@Schema(description = "VIP 价格,单位使用:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "968") // 通过会员等级,计算出折扣后价格
|
||||
private Integer vipPrice;
|
||||
|
||||
@Schema(description = "库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "666")
|
||||
private Integer stock;
|
||||
|
||||
|
||||
@@ -38,9 +38,6 @@ public class AppProductSpuRespVO {
|
||||
@Schema(description = "市场价,单位使用:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Integer marketPrice;
|
||||
|
||||
@Schema(description = "VIP 价格,单位使用:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "968") // 通过会员等级,计算出折扣后价格
|
||||
private Integer vipPrice;
|
||||
|
||||
@Schema(description = "库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "666")
|
||||
private Integer stock;
|
||||
|
||||
|
||||
@@ -87,6 +87,7 @@ public interface ProductCategoryService {
|
||||
* 校验商品分类是否有效。如下情况,视为无效:
|
||||
* 1. 商品分类编号不存在
|
||||
* 2. 商品分类被禁用
|
||||
* 3. 商品分类层级校验,必须使用第二级的商品分类及以下
|
||||
*
|
||||
* @param ids 商品分类编号数组
|
||||
*/
|
||||
|
||||
@@ -20,6 +20,7 @@ import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.module.product.dal.dataobject.category.ProductCategoryDO.CATEGORY_LEVEL;
|
||||
import static cn.iocoder.yudao.module.product.dal.dataobject.category.ProductCategoryDO.PARENT_ID_NULL;
|
||||
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.*;
|
||||
|
||||
@@ -112,13 +113,19 @@ public class ProductCategoryServiceImpl implements ProductCategoryService {
|
||||
Map<Long, ProductCategoryDO> categoryMap = CollectionUtils.convertMap(list, ProductCategoryDO::getId);
|
||||
// 校验
|
||||
ids.forEach(id -> {
|
||||
// 校验分类是否存在
|
||||
ProductCategoryDO category = categoryMap.get(id);
|
||||
if (category == null) {
|
||||
throw exception(CATEGORY_NOT_EXISTS);
|
||||
}
|
||||
// 校验分类是否启用
|
||||
if (!CommonStatusEnum.ENABLE.getStatus().equals(category.getStatus())) {
|
||||
throw exception(CATEGORY_DISABLED, category.getName());
|
||||
}
|
||||
// 商品分类层级校验,必须使用第二级的商品分类
|
||||
if (getCategoryLevel(id) < CATEGORY_LEVEL) {
|
||||
throw exception(SPU_SAVE_FAIL_CATEGORY_LEVEL_ERROR);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,6 @@ public interface DiscountActivityApi {
|
||||
@GetMapping(PREFIX + "/list-by-sku-id")
|
||||
@Operation(summary = "获得商品匹配的的限时折扣信息")
|
||||
@Parameter(name = "skuIds", description = "商品 SKU 编号数组", required = true, example = "[1, 2]")
|
||||
CommonResult<List<DiscountProductRespDTO>> getMatchDiscountProductList(@RequestParam("skuIds") Collection<Long> skuIds);
|
||||
CommonResult<List<DiscountProductRespDTO>> getMatchDiscountProductListBySkuIds(@RequestParam("skuIds") Collection<Long> skuIds);
|
||||
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ package cn.iocoder.yudao.module.promotion.api.discount.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 限时折扣活动商品 Response DTO
|
||||
*
|
||||
@@ -44,5 +46,13 @@ public class DiscountProductRespDTO {
|
||||
* 活动标题
|
||||
*/
|
||||
private String activityName;
|
||||
/**
|
||||
* 活动开始时间点
|
||||
*/
|
||||
private LocalDateTime activityStartTime;
|
||||
/**
|
||||
* 活动结束时间点
|
||||
*/
|
||||
private LocalDateTime activityEndTime;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,6 @@ public interface RewardActivityApi {
|
||||
@GetMapping(PREFIX + "/list-by-spu-id")
|
||||
@Operation(summary = "获得商品匹配的的满减送活动信息")
|
||||
@Parameter(name = "spuIds", description = "商品 SPU 编号数组", required = true, example = "[1, 2]")
|
||||
CommonResult<List<RewardActivityMatchRespDTO>> getMatchRewardActivityList(@RequestParam("spuIds") Collection<Long> spuIds);
|
||||
CommonResult<List<RewardActivityMatchRespDTO>> getMatchRewardActivityListBySpuIds(@RequestParam("spuIds") Collection<Long> spuIds);
|
||||
|
||||
}
|
||||
|
||||
@@ -18,6 +18,11 @@ import java.util.Map;
|
||||
@Data
|
||||
public class RewardActivityMatchRespDTO {
|
||||
|
||||
/**
|
||||
* 匹配的 SPU 数组
|
||||
*/
|
||||
private List<Long> spuIds;
|
||||
|
||||
/**
|
||||
* 活动编号,主键自增
|
||||
*/
|
||||
@@ -100,6 +105,13 @@ public class RewardActivityMatchRespDTO {
|
||||
*/
|
||||
private Map<Long, Integer> giveCouponTemplateCounts;
|
||||
|
||||
/**
|
||||
* 规则描述
|
||||
*
|
||||
* 通过 {@link #limit}、{@link #discountPrice} 等字段进行拼接
|
||||
*/
|
||||
private String description;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ public interface ErrorCodeConstants {
|
||||
|
||||
// ========== 促销活动相关 1-013-001-000 ============
|
||||
ErrorCode DISCOUNT_ACTIVITY_NOT_EXISTS = new ErrorCode(1_013_001_000, "限时折扣活动不存在");
|
||||
ErrorCode DISCOUNT_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1_013_001_001, "存在商品参加了其它限时折扣活动");
|
||||
ErrorCode DISCOUNT_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1_013_001_001, "存在商品参加了其它限时折扣活动【{}】");
|
||||
ErrorCode DISCOUNT_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_001_002, "限时折扣活动已关闭,不能修改");
|
||||
ErrorCode DISCOUNT_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED = new ErrorCode(1_013_001_003, "限时折扣活动未关闭,不能删除");
|
||||
ErrorCode DISCOUNT_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_001_004, "限时折扣活动已关闭,不能重复关闭");
|
||||
@@ -38,14 +38,18 @@ public interface ErrorCodeConstants {
|
||||
|
||||
// ========== 满减送活动 1-013-006-000 ==========
|
||||
ErrorCode REWARD_ACTIVITY_NOT_EXISTS = new ErrorCode(1_013_006_000, "满减送活动不存在");
|
||||
ErrorCode REWARD_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1_013_006_001, "存在商品参加了其它满减送活动");
|
||||
ErrorCode REWARD_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1_013_006_001, "该时间段存在商品参加了其它满减送活动");
|
||||
ErrorCode REWARD_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_006_002, "满减送活动已关闭,不能修改");
|
||||
ErrorCode REWARD_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED = new ErrorCode(1_013_006_003, "满减送活动未关闭,不能删除");
|
||||
ErrorCode REWARD_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_006_004, "满减送活动已关闭,不能重复关闭");
|
||||
ErrorCode REWARD_ACTIVITY_SCOPE_ALL_EXISTS = new ErrorCode(1_013_006_005, "已存在商品范围为全场的满减送活动");
|
||||
ErrorCode REWARD_ACTIVITY_SCOPE_CATEGORY_EXISTS = new ErrorCode(1_013_006_006, "存在商品类型参加了其它满减送活动");
|
||||
ErrorCode REWARD_ACTIVITY_SCOPE_EXISTS = new ErrorCode(1_013_006_005, "与该时间段满减送活动【{}】商品范围冲突,原因:{}");
|
||||
|
||||
// ========== TODO 空着 1-013-007-000 ============
|
||||
// ========== 积分商城活动 1-013-007-000 ==========
|
||||
ErrorCode POINT_ACTIVITY_NOT_EXISTS = new ErrorCode(1_013_007_000, "积分商城活动不存在");
|
||||
ErrorCode POINT_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1_013_007_001, "存在商品参加了其它积分商城活动");
|
||||
ErrorCode POINT_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_007_002, "积分商城活动已关闭,不能修改");
|
||||
ErrorCode POINT_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1_013_007_003, "积分商城活动未关闭或未结束,不能删除");
|
||||
ErrorCode POINT_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_007_004, "积分商城活动已关闭,不能重复关闭");
|
||||
|
||||
// ========== 秒杀活动 1-013-008-000 ==========
|
||||
ErrorCode SECKILL_ACTIVITY_NOT_EXISTS = new ErrorCode(1_013_008_000, "秒杀活动不存在");
|
||||
|
||||
@@ -5,6 +5,7 @@ import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 优惠劵领取方式
|
||||
@@ -20,12 +21,12 @@ public enum CouponTakeTypeEnum implements IntArrayValuable {
|
||||
REGISTER(3, "新人券"), // 注册时自动领取
|
||||
;
|
||||
|
||||
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CouponTakeTypeEnum::getValue).toArray();
|
||||
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CouponTakeTypeEnum::getType).toArray();
|
||||
|
||||
/**
|
||||
* 值
|
||||
*/
|
||||
private final Integer value;
|
||||
private final Integer type;
|
||||
/**
|
||||
* 名字
|
||||
*/
|
||||
@@ -35,4 +36,9 @@ public enum CouponTakeTypeEnum implements IntArrayValuable {
|
||||
public int[] array() {
|
||||
return ARRAYS;
|
||||
}
|
||||
|
||||
public static boolean isUser(Integer type) {
|
||||
return Objects.equals(USER.getType(), type);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
package cn.iocoder.yudao.module.promotion.api.discount;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.promotion.api.discount.dto.DiscountProductRespDTO;
|
||||
import cn.iocoder.yudao.module.promotion.convert.discount.DiscountActivityConvert;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO;
|
||||
import cn.iocoder.yudao.module.promotion.service.discount.DiscountActivityService;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
@@ -26,8 +27,9 @@ public class DiscountActivityApiImpl implements DiscountActivityApi {
|
||||
private DiscountActivityService discountActivityService;
|
||||
|
||||
@Override
|
||||
public CommonResult<List<DiscountProductRespDTO>> getMatchDiscountProductList(Collection<Long> skuIds) {
|
||||
return success(DiscountActivityConvert.INSTANCE.convertList02(discountActivityService.getMatchDiscountProductList(skuIds)));
|
||||
public CommonResult<List<DiscountProductRespDTO>> getMatchDiscountProductListBySkuIds(Collection<Long> skuIds) {
|
||||
List<DiscountProductDO> list = discountActivityService.getMatchDiscountProductListBySkuIds(skuIds);
|
||||
return success(BeanUtils.toBean(list, DiscountProductRespDTO.class));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,8 +25,8 @@ public class RewardActivityApiImpl implements RewardActivityApi {
|
||||
private RewardActivityService rewardActivityService;
|
||||
|
||||
@Override
|
||||
public CommonResult<List<RewardActivityMatchRespDTO>> getMatchRewardActivityList(Collection<Long> spuIds) {
|
||||
return success(rewardActivityService.getMatchRewardActivityList(spuIds));
|
||||
public CommonResult<List<RewardActivityMatchRespDTO>> getMatchRewardActivityListBySpuIds(Collection<Long> spuIds) {
|
||||
return success(rewardActivityService.getMatchRewardActivityListBySpuIds(spuIds));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,9 +3,10 @@ package cn.iocoder.yudao.module.promotion.controller.admin.discount;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
|
||||
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.*;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityCreateReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityPageReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityRespVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityUpdateReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.convert.discount.DiscountActivityConvert;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivityDO;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO;
|
||||
@@ -33,9 +34,6 @@ public class DiscountActivityController {
|
||||
@Resource
|
||||
private DiscountActivityService discountActivityService;
|
||||
|
||||
@Resource
|
||||
private ProductSpuApi productSpuApi;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建限时折扣活动")
|
||||
@PreAuthorize("@ss.hasPermission('promotion:discount-activity:create')")
|
||||
@@ -73,7 +71,7 @@ public class DiscountActivityController {
|
||||
@Operation(summary = "获得限时折扣活动")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('promotion:discount-activity:query')")
|
||||
public CommonResult<DiscountActivityDetailRespVO> getDiscountActivity(@RequestParam("id") Long id) {
|
||||
public CommonResult<DiscountActivityRespVO> getDiscountActivity(@RequestParam("id") Long id) {
|
||||
DiscountActivityDO discountActivity = discountActivityService.getDiscountActivity(id);
|
||||
if (discountActivity == null) {
|
||||
return success(null);
|
||||
@@ -88,18 +86,14 @@ public class DiscountActivityController {
|
||||
@PreAuthorize("@ss.hasPermission('promotion:discount-activity:query')")
|
||||
public CommonResult<PageResult<DiscountActivityRespVO>> getDiscountActivityPage(@Valid DiscountActivityPageReqVO pageVO) {
|
||||
PageResult<DiscountActivityDO> pageResult = discountActivityService.getDiscountActivityPage(pageVO);
|
||||
|
||||
if (CollUtil.isEmpty(pageResult.getList())) { // TODO @zhangshuai:方法里的空行,目的是让代码分块,可以更清晰;所以上面这个空格可以不要,而下面判断之后的,空格,其实加下比较好;类似的还有 spuList、以及后面的 convert
|
||||
if (CollUtil.isEmpty(pageResult.getList())) {
|
||||
return success(PageResult.empty(pageResult.getTotal()));
|
||||
}
|
||||
|
||||
// 拼接数据
|
||||
List<DiscountProductDO> products = discountActivityService.getDiscountProductsByActivityId(
|
||||
convertSet(pageResult.getList(), DiscountActivityDO::getId));
|
||||
|
||||
List<ProductSpuRespDTO> spuList = productSpuApi.getSpuList(
|
||||
convertSet(products, DiscountProductDO::getSpuId)).getCheckedData();
|
||||
|
||||
return success(DiscountActivityConvert.INSTANCE.convertPage(pageResult, products, spuList));
|
||||
return success(DiscountActivityConvert.INSTANCE.convertPage(pageResult, products));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
package cn.iocoder.yudao.module.promotion.controller.admin.discount.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - 限时折扣活动的详细 Response VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class DiscountActivityDetailRespVO extends DiscountActivityRespVO {
|
||||
|
||||
/**
|
||||
* 商品列表
|
||||
*/
|
||||
private List<Product> products;
|
||||
|
||||
}
|
||||
@@ -25,25 +25,7 @@ public class DiscountActivityRespVO extends DiscountActivityBaseVO {
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
|
||||
@Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") // TODO @zhangshuai:属性和属性之间,最多空一行噢;
|
||||
private Long spuId;
|
||||
|
||||
@Schema(description = "限时折扣商品", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private List<DiscountActivityBaseVO.Product> products;
|
||||
|
||||
// ========== 商品字段 ==========
|
||||
|
||||
// TODO @zhangshuai:一个优惠活动,会关联多个商品,所以它不用返回 spuName 哈;
|
||||
// TODO 最终界面展示字段就:编号、活动名称、参与商品数、活动状态、开始时间、结束时间、操作
|
||||
@Schema(description = "商品名称", requiredMode = Schema.RequiredMode.REQUIRED, // 从 SPU 的 name 读取
|
||||
example = "618大促")
|
||||
private String spuName;
|
||||
@Schema(description = "商品主图", requiredMode = Schema.RequiredMode.REQUIRED, // 从 SPU 的 picUrl 读取
|
||||
example = "https://www.iocoder.cn/xx.png")
|
||||
private String picUrl;
|
||||
@Schema(description = "商品市场价,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, // 从 SPU 的 marketPrice 读取
|
||||
example = "50")
|
||||
private Integer marketPrice;
|
||||
private List<Product> products;
|
||||
|
||||
}
|
||||
|
||||
@@ -25,6 +25,6 @@ public class DiscountActivityUpdateReqVO extends DiscountActivityBaseVO {
|
||||
*/
|
||||
@NotEmpty(message = "商品列表不能为空")
|
||||
@Valid
|
||||
private List<DiscountActivityCreateReqVO.Product> products;
|
||||
private List<Product> products;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
package cn.iocoder.yudao.module.promotion.controller.admin.point;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
|
||||
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.point.vo.activity.PointActivityPageReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.point.vo.activity.PointActivityRespVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.point.vo.activity.PointActivitySaveReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.point.vo.product.PointProductRespVO;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.point.PointActivityDO;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.point.PointProductDO;
|
||||
import cn.iocoder.yudao.module.promotion.service.point.PointActivityService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen;
|
||||
|
||||
@Tag(name = "管理后台 - 积分商城活动")
|
||||
@RestController
|
||||
@RequestMapping("/promotion/point-activity")
|
||||
@Validated
|
||||
public class PointActivityController {
|
||||
|
||||
@Resource
|
||||
private PointActivityService pointActivityService;
|
||||
@Resource
|
||||
private ProductSpuApi productSpuApi;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建积分商城活动")
|
||||
@PreAuthorize("@ss.hasPermission('promotion:point-activity:create')")
|
||||
public CommonResult<Long> createPointActivity(@Valid @RequestBody PointActivitySaveReqVO createReqVO) {
|
||||
return success(pointActivityService.createPointActivity(createReqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新积分商城活动")
|
||||
@PreAuthorize("@ss.hasPermission('promotion:point-activity:update')")
|
||||
public CommonResult<Boolean> updatePointActivity(@Valid @RequestBody PointActivitySaveReqVO updateReqVO) {
|
||||
pointActivityService.updatePointActivity(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PutMapping("/close")
|
||||
@Operation(summary = "关闭积分商城活动")
|
||||
@Parameter(name = "id", description = "编号", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('promotion:point-activity:close')")
|
||||
public CommonResult<Boolean> closeSeckillActivity(@RequestParam("id") Long id) {
|
||||
pointActivityService.closePointActivity(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除积分商城活动")
|
||||
@Parameter(name = "id", description = "编号", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('promotion:point-activity:delete')")
|
||||
public CommonResult<Boolean> deletePointActivity(@RequestParam("id") Long id) {
|
||||
pointActivityService.deletePointActivity(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得积分商城活动")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('promotion:point-activity:query')")
|
||||
public CommonResult<PointActivityRespVO> getPointActivity(@RequestParam("id") Long id) {
|
||||
PointActivityDO pointActivity = pointActivityService.getPointActivity(id);
|
||||
if (pointActivity == null) {
|
||||
return success(null);
|
||||
}
|
||||
|
||||
List<PointProductDO> products = pointActivityService.getPointProductListByActivityIds(Collections.singletonList(id));
|
||||
PointActivityRespVO respVO = BeanUtils.toBean(pointActivity, PointActivityRespVO.class);
|
||||
respVO.setProducts(BeanUtils.toBean(products, PointProductRespVO.class));
|
||||
return success(respVO);
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得积分商城活动分页")
|
||||
@PreAuthorize("@ss.hasPermission('promotion:point-activity:query')")
|
||||
public CommonResult<PageResult<PointActivityRespVO>> getPointActivityPage(@Valid PointActivityPageReqVO pageReqVO) {
|
||||
PageResult<PointActivityDO> pageResult = pointActivityService.getPointActivityPage(pageReqVO);
|
||||
if (CollUtil.isEmpty(pageResult.getList())) {
|
||||
return success(PageResult.empty(pageResult.getTotal()));
|
||||
}
|
||||
|
||||
// 拼接数据
|
||||
List<PointActivityRespVO> resultList = buildPointActivityRespVOList(pageResult.getList());
|
||||
return success(new PageResult<>(resultList, pageResult.getTotal()));
|
||||
}
|
||||
|
||||
@GetMapping("/list-by-ids")
|
||||
@Operation(summary = "获得积分商城活动列表,基于活动编号数组")
|
||||
@Parameter(name = "ids", description = "活动编号数组", required = true, example = "[1024, 1025]")
|
||||
public CommonResult<List<PointActivityRespVO>> getPointActivityListByIds(@RequestParam("ids") List<Long> ids) {
|
||||
// 1. 获得开启的活动列表
|
||||
List<PointActivityDO> activityList = pointActivityService.getPointActivityListByIds(ids);
|
||||
activityList.removeIf(activity -> CommonStatusEnum.isDisable(activity.getStatus()));
|
||||
if (CollUtil.isEmpty(activityList)) {
|
||||
return success(Collections.emptyList());
|
||||
}
|
||||
// 2. 拼接返回
|
||||
List<PointActivityRespVO> result = buildPointActivityRespVOList(activityList);
|
||||
return success(result);
|
||||
}
|
||||
|
||||
private List<PointActivityRespVO> buildPointActivityRespVOList(List<PointActivityDO> activityList) {
|
||||
List<PointProductDO> products = pointActivityService.getPointProductListByActivityIds(
|
||||
convertSet(activityList, PointActivityDO::getId));
|
||||
Map<Long, List<PointProductDO>> productsMap = convertMultiMap(products, PointProductDO::getActivityId);
|
||||
Map<Long, ProductSpuRespDTO> spuMap = productSpuApi.getSpusMap(
|
||||
convertSet(activityList, PointActivityDO::getSpuId));
|
||||
List<PointActivityRespVO> result = BeanUtils.toBean(activityList, PointActivityRespVO.class);
|
||||
result.forEach(activity -> {
|
||||
// 设置 product 信息
|
||||
PointProductDO minProduct = getMinObject(productsMap.get(activity.getId()), PointProductDO::getPoint);
|
||||
assert minProduct != null;
|
||||
activity.setPoint(minProduct.getPoint()).setPrice(minProduct.getPrice());
|
||||
findAndThen(spuMap, activity.getSpuId(),
|
||||
spu -> activity.setSpuName(spu.getName()).setPicUrl(spu.getPicUrl()).setMarketPrice(spu.getMarketPrice()));
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package cn.iocoder.yudao.module.promotion.controller.admin.point.vo.activity;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
@Schema(description = "管理后台 - 积分商城活动分页 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class PointActivityPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "积分商城活动商品", example = "19509")
|
||||
private Long spuId;
|
||||
|
||||
@Schema(description = "活动状态", example = "2")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "备注", example = "你说的对")
|
||||
private String remark;
|
||||
|
||||
@Schema(description = "排序")
|
||||
private Integer sort;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package cn.iocoder.yudao.module.promotion.controller.admin.point.vo.activity;
|
||||
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.point.vo.product.PointProductRespVO;
|
||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - 积分商城活动 Response VO")
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
public class PointActivityRespVO {
|
||||
|
||||
@Schema(description = "积分商城活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11373")
|
||||
@ExcelProperty("积分商城活动编号")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "积分商城活动商品", requiredMode = Schema.RequiredMode.REQUIRED, example = "19509")
|
||||
@ExcelProperty("积分商城活动商品")
|
||||
private Long spuId;
|
||||
|
||||
@Schema(description = "活动状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
|
||||
@ExcelProperty("活动状态")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "积分商城活动库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
|
||||
@ExcelProperty("积分商城活动库存")
|
||||
private Integer stock; // 剩余库存积分兑换时扣减
|
||||
|
||||
@Schema(description = "积分商城活动总库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
|
||||
@ExcelProperty("积分商城活动总库存")
|
||||
private Integer totalStock;
|
||||
|
||||
@Schema(description = "备注", example = "你说的对")
|
||||
@ExcelProperty("备注")
|
||||
private String remark;
|
||||
|
||||
@Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@ExcelProperty("排序")
|
||||
private Integer sort;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@ExcelProperty("创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@Schema(description = "积分商城商品", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private List<PointProductRespVO> products;
|
||||
|
||||
// ========== 商品字段 ==========
|
||||
|
||||
@Schema(description = "商品名称", requiredMode = Schema.RequiredMode.REQUIRED, // 从 SPU 的 name 读取
|
||||
example = "618大促")
|
||||
private String spuName;
|
||||
@Schema(description = "商品主图", requiredMode = Schema.RequiredMode.REQUIRED, // 从 SPU 的 picUrl 读取
|
||||
example = "https://www.iocoder.cn/xx.png")
|
||||
private String picUrl;
|
||||
@Schema(description = "商品市场价,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, // 从 SPU 的 marketPrice 读取
|
||||
example = "50")
|
||||
private Integer marketPrice;
|
||||
|
||||
//======================= 显示所需兑换积分最少的 sku 信息 =======================
|
||||
|
||||
@Schema(description = "兑换积分", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private Integer point;
|
||||
|
||||
@Schema(description = "兑换金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "15860")
|
||||
private Integer price;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package cn.iocoder.yudao.module.promotion.controller.admin.point.vo.activity;
|
||||
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.point.vo.product.PointProductSaveReqVO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - 积分商城活动新增/修改 Request VO")
|
||||
@Data
|
||||
public class PointActivitySaveReqVO {
|
||||
|
||||
@Schema(description = "积分商城活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11373")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "积分商城活动商品", requiredMode = Schema.RequiredMode.REQUIRED, example = "19509")
|
||||
@NotNull(message = "积分商城活动商品不能为空")
|
||||
private Long spuId;
|
||||
|
||||
@Schema(description = "备注", example = "你说的对")
|
||||
private String remark;
|
||||
|
||||
@Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "排序不能为空")
|
||||
private Integer sort;
|
||||
|
||||
@Schema(description = "积分商城商品", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private List<PointProductSaveReqVO> products;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package cn.iocoder.yudao.module.promotion.controller.admin.point.vo.product;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - 积分商城商品 Response VO")
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
public class PointProductRespVO {
|
||||
|
||||
@Schema(description = "积分商城商品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "31718")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "积分商城活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "29388")
|
||||
private Long activityId;
|
||||
|
||||
@Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "8112")
|
||||
private Long spuId;
|
||||
|
||||
@Schema(description = "商品 SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2736")
|
||||
private Long skuId;
|
||||
|
||||
@Schema(description = "可兑换数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "3926")
|
||||
private Integer count;
|
||||
|
||||
@Schema(description = "兑换积分", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private Integer point;
|
||||
|
||||
@Schema(description = "兑换金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "15860")
|
||||
private Integer price;
|
||||
|
||||
@Schema(description = "积分商城商品库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
|
||||
private Integer stock;
|
||||
|
||||
@Schema(description = "积分商城商品状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
|
||||
private Integer activityStatus;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package cn.iocoder.yudao.module.promotion.controller.admin.point.vo.product;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - 积分商城商品新增/修改 Request VO")
|
||||
@Data
|
||||
public class PointProductSaveReqVO {
|
||||
|
||||
@Schema(description = "积分商城商品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "31718")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "积分商城活动 id", requiredMode = Schema.RequiredMode.REQUIRED, example = "29388")
|
||||
@NotNull(message = "积分商城活动 id不能为空")
|
||||
private Long activityId;
|
||||
|
||||
@Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "8112")
|
||||
@NotNull(message = "商品 SPU 编号不能为空")
|
||||
private Long spuId;
|
||||
|
||||
@Schema(description = "商品 SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2736")
|
||||
@NotNull(message = "商品 SKU 编号不能为空")
|
||||
private Long skuId;
|
||||
|
||||
@Schema(description = "可兑换数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "3926")
|
||||
@NotNull(message = "可兑换数量不能为空")
|
||||
private Integer count;
|
||||
|
||||
@Schema(description = "兑换积分", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "兑换积分不能为空")
|
||||
private Integer point;
|
||||
|
||||
@Schema(description = "兑换金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "15860")
|
||||
@NotNull(message = "兑换金额,单位:分不能为空")
|
||||
private Integer price;
|
||||
|
||||
@Schema(description = "积分商城商品库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
|
||||
@NotNull(message = "积分商城商品不能为空")
|
||||
private Integer stock;
|
||||
|
||||
@Schema(description = "积分商城商品状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
|
||||
@NotNull(message = "积分商城商品状态不能为空")
|
||||
private Integer activityStatus;
|
||||
|
||||
}
|
||||
@@ -102,7 +102,7 @@ public class SeckillActivityController {
|
||||
@GetMapping("/list-by-ids")
|
||||
@Operation(summary = "获得秒杀活动列表,基于活动编号数组")
|
||||
@Parameter(name = "ids", description = "活动编号数组", required = true, example = "[1024, 1025]")
|
||||
public CommonResult<List<SeckillActivityRespVO>> getCombinationActivityListByIds(@RequestParam("ids") List<Long> ids) {
|
||||
public CommonResult<List<SeckillActivityRespVO>> getSeckillActivityListByIds(@RequestParam("ids") List<Long> ids) {
|
||||
// 1. 获得开启的活动列表
|
||||
List<SeckillActivityDO> activityList = seckillActivityService.getSeckillActivityListByIds(ids);
|
||||
activityList.removeIf(activity -> CommonStatusEnum.isDisable(activity.getStatus()));
|
||||
|
||||
@@ -54,7 +54,7 @@ public class SeckillActivityRespVO extends SeckillActivityBaseVO {
|
||||
example = "50")
|
||||
private Integer marketPrice;
|
||||
|
||||
@Schema(description = "拼团金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
|
||||
@Schema(description = "秒杀金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
|
||||
private Integer seckillPrice; // 从 products 获取最小 price 读取
|
||||
|
||||
}
|
||||
|
||||
@@ -1,41 +1,29 @@
|
||||
package cn.iocoder.yudao.module.promotion.controller.app.activity;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
|
||||
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.app.activity.vo.AppActivityRespVO;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivityDO;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillActivityDO;
|
||||
import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum;
|
||||
import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum;
|
||||
import cn.iocoder.yudao.module.promotion.service.bargain.BargainActivityService;
|
||||
import cn.iocoder.yudao.module.promotion.service.combination.CombinationActivityService;
|
||||
import cn.iocoder.yudao.module.promotion.service.discount.DiscountActivityService;
|
||||
import cn.iocoder.yudao.module.promotion.service.reward.RewardActivityService;
|
||||
import cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
|
||||
|
||||
@Tag(name = "用户 APP - 营销活动") // 用于提供跨多个活动的 HTTP 接口
|
||||
@RestController
|
||||
@@ -49,152 +37,32 @@ public class AppActivityController {
|
||||
private SeckillActivityService seckillActivityService;
|
||||
@Resource
|
||||
private BargainActivityService bargainActivityService;
|
||||
@Resource
|
||||
private DiscountActivityService discountActivityService;
|
||||
@Resource
|
||||
private RewardActivityService rewardActivityService;
|
||||
|
||||
@Resource
|
||||
private ProductSpuApi productSpuApi;
|
||||
|
||||
@GetMapping("/list-by-spu-id")
|
||||
@Operation(summary = "获得单个商品,近期参与的每个活动")
|
||||
@Operation(summary = "获得单个商品,进行中的拼团、秒杀、砍价活动信息", description = "每种活动,只返回一个")
|
||||
@Parameter(name = "spuId", description = "商品编号", required = true)
|
||||
@PermitAll
|
||||
public CommonResult<List<AppActivityRespVO>> getActivityListBySpuId(@RequestParam("spuId") Long spuId) {
|
||||
// 每种活动,只返回一个
|
||||
return success(getAppActivityList(Collections.singletonList(spuId)));
|
||||
}
|
||||
|
||||
@GetMapping("/list-by-spu-ids")
|
||||
@Operation(summary = "获得多个商品,近期参与的每个活动")
|
||||
@Parameter(name = "spuIds", description = "商品编号数组", required = true)
|
||||
public CommonResult<Map<Long, List<AppActivityRespVO>>> getActivityListBySpuIds(@RequestParam("spuIds") List<Long> spuIds) {
|
||||
if (CollUtil.isEmpty(spuIds)) {
|
||||
return success(MapUtil.empty());
|
||||
}
|
||||
// 每种活动,只返回一个;key 为 SPU 编号
|
||||
return success(convertMultiMap(getAppActivityList(spuIds), AppActivityRespVO::getSpuId));
|
||||
}
|
||||
|
||||
private List<AppActivityRespVO> getAppActivityList(Collection<Long> spuIds) {
|
||||
if (CollUtil.isEmpty(spuIds)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
// 获取开启的且开始的且没有结束的活动
|
||||
List<AppActivityRespVO> activityList = new ArrayList<>();
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
List<AppActivityRespVO> activityVOList = new ArrayList<>();
|
||||
// 1. 拼团活动
|
||||
getCombinationActivities(spuIds, now, activityList);
|
||||
CombinationActivityDO combinationActivity = combinationActivityService.getMatchCombinationActivityBySpuId(spuId);
|
||||
if (combinationActivity != null) {
|
||||
activityVOList.add(new AppActivityRespVO(combinationActivity.getId(), PromotionTypeEnum.COMBINATION_ACTIVITY.getType(),
|
||||
combinationActivity.getName(), combinationActivity.getSpuId(), combinationActivity.getStartTime(), combinationActivity.getEndTime()));
|
||||
}
|
||||
// 2. 秒杀活动
|
||||
getSeckillActivities(spuIds, now, activityList);
|
||||
SeckillActivityDO seckillActivity = seckillActivityService.getMatchSeckillActivityBySpuId(spuId);
|
||||
if (seckillActivity != null) {
|
||||
activityVOList.add(new AppActivityRespVO(seckillActivity.getId(), PromotionTypeEnum.SECKILL_ACTIVITY.getType(),
|
||||
seckillActivity.getName(), seckillActivity.getSpuId(), seckillActivity.getStartTime(), seckillActivity.getEndTime()));
|
||||
}
|
||||
// 3. 砍价活动
|
||||
getBargainActivities(spuIds, now, activityList);
|
||||
// 4. 限时折扣活动
|
||||
getDiscountActivities(spuIds, now, activityList);
|
||||
// 5. 满减送活动
|
||||
getRewardActivityList(spuIds, now, activityList);
|
||||
return activityList;
|
||||
}
|
||||
|
||||
private void getCombinationActivities(Collection<Long> spuIds, LocalDateTime now, List<AppActivityRespVO> activityList) {
|
||||
List<CombinationActivityDO> combinationActivities = combinationActivityService.getCombinationActivityBySpuIdsAndStatusAndDateTimeLt(
|
||||
spuIds, CommonStatusEnum.ENABLE.getStatus(), now);
|
||||
if (CollUtil.isEmpty(combinationActivities)) {
|
||||
return;
|
||||
}
|
||||
|
||||
combinationActivities.forEach(item -> {
|
||||
activityList.add(new AppActivityRespVO(item.getId(), PromotionTypeEnum.COMBINATION_ACTIVITY.getType(),
|
||||
item.getName(), item.getSpuId(), item.getStartTime(), item.getEndTime()));
|
||||
});
|
||||
}
|
||||
|
||||
private void getSeckillActivities(Collection<Long> spuIds, LocalDateTime now, List<AppActivityRespVO> activityList) {
|
||||
List<SeckillActivityDO> seckillActivities = seckillActivityService.getSeckillActivityBySpuIdsAndStatusAndDateTimeLt(
|
||||
spuIds, CommonStatusEnum.ENABLE.getStatus(), now);
|
||||
if (CollUtil.isEmpty(seckillActivities)) {
|
||||
return;
|
||||
}
|
||||
|
||||
seckillActivities.forEach(item -> {
|
||||
activityList.add(new AppActivityRespVO(item.getId(), PromotionTypeEnum.SECKILL_ACTIVITY.getType(),
|
||||
item.getName(), item.getSpuId(), item.getStartTime(), item.getEndTime()));
|
||||
});
|
||||
}
|
||||
|
||||
private void getBargainActivities(Collection<Long> spuIds, LocalDateTime now, List<AppActivityRespVO> activityList) {
|
||||
List<BargainActivityDO> bargainActivities = bargainActivityService.getBargainActivityBySpuIdsAndStatusAndDateTimeLt(
|
||||
spuIds, CommonStatusEnum.ENABLE.getStatus(), now);
|
||||
if (CollUtil.isNotEmpty(bargainActivities)) {
|
||||
return;
|
||||
}
|
||||
|
||||
bargainActivities.forEach(item -> {
|
||||
activityList.add(new AppActivityRespVO(item.getId(), PromotionTypeEnum.BARGAIN_ACTIVITY.getType(),
|
||||
item.getName(), item.getSpuId(), item.getStartTime(), item.getEndTime()));
|
||||
});
|
||||
}
|
||||
|
||||
private void getDiscountActivities(Collection<Long> spuIds, LocalDateTime now, List<AppActivityRespVO> activityList) {
|
||||
List<DiscountActivityDO> discountActivities = discountActivityService.getDiscountActivityBySpuIdsAndStatusAndDateTimeLt(
|
||||
spuIds, CommonStatusEnum.ENABLE.getStatus(), now);
|
||||
if (CollUtil.isEmpty(discountActivities)) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<DiscountProductDO> products = discountActivityService.getDiscountProductsByActivityId(
|
||||
convertSet(discountActivities, DiscountActivityDO::getId));
|
||||
Map<Long, Long> productMap = convertMap(products, DiscountProductDO::getActivityId, DiscountProductDO::getSpuId);
|
||||
discountActivities.forEach(item -> activityList.add(new AppActivityRespVO(item.getId(), PromotionTypeEnum.DISCOUNT_ACTIVITY.getType(),
|
||||
item.getName(), productMap.get(item.getId()), item.getStartTime(), item.getEndTime())));
|
||||
}
|
||||
|
||||
private void getRewardActivityList(Collection<Long> spuIds, LocalDateTime now, List<AppActivityRespVO> activityList) {
|
||||
// 1.1 获得所有的活动
|
||||
List<RewardActivityDO> rewardActivityList = rewardActivityService.getRewardActivityListByStatusAndDateTimeLt(
|
||||
CommonStatusEnum.ENABLE.getStatus(), now);
|
||||
if (CollUtil.isEmpty(rewardActivityList)) {
|
||||
return;
|
||||
}
|
||||
// 1.2 获得所有的商品信息
|
||||
List<ProductSpuRespDTO> spuList = productSpuApi.getSpuList(spuIds).getCheckedData();
|
||||
if (CollUtil.isEmpty(spuList)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. 构建活动
|
||||
for (RewardActivityDO rewardActivity : rewardActivityList) {
|
||||
// 情况一:所有商品都能参加
|
||||
if (PromotionProductScopeEnum.isAll(rewardActivity.getProductScope())) {
|
||||
buildAppActivityRespVO(rewardActivity, spuIds, activityList);
|
||||
}
|
||||
// 情况二:指定商品参加
|
||||
if (PromotionProductScopeEnum.isSpu(rewardActivity.getProductScope())) {
|
||||
List<Long> fSpuIds = spuList.stream().map(ProductSpuRespDTO::getId).filter(id ->
|
||||
rewardActivity.getProductScopeValues().contains(id)).toList();
|
||||
buildAppActivityRespVO(rewardActivity, fSpuIds, activityList);
|
||||
}
|
||||
// 情况三:指定商品类型参加
|
||||
if (PromotionProductScopeEnum.isCategory(rewardActivity.getProductScope())) {
|
||||
List<Long> fSpuIds = spuList.stream().filter(spuItem -> rewardActivity.getProductScopeValues()
|
||||
.contains(spuItem.getCategoryId())).map(ProductSpuRespDTO::getId).toList();
|
||||
buildAppActivityRespVO(rewardActivity, fSpuIds, activityList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void buildAppActivityRespVO(RewardActivityDO rewardActivity, Collection<Long> spuIds,
|
||||
List<AppActivityRespVO> activityList) {
|
||||
for (Long spuId : spuIds) {
|
||||
// 校验商品是否已经加入过活动
|
||||
if (anyMatch(activityList, appActivity -> ObjUtil.equal(appActivity.getId(), rewardActivity.getId()) &&
|
||||
ObjUtil.equal(appActivity.getSpuId(), spuId))) {
|
||||
continue;
|
||||
}
|
||||
activityList.add(new AppActivityRespVO(rewardActivity.getId(),
|
||||
PromotionTypeEnum.REWARD_ACTIVITY.getType(), rewardActivity.getName(), spuId,
|
||||
rewardActivity.getStartTime(), rewardActivity.getEndTime()));
|
||||
BargainActivityDO bargainActivity = bargainActivityService.getMatchBargainActivityBySpuId(spuId);
|
||||
if (bargainActivity != null) {
|
||||
activityVOList.add(new AppActivityRespVO(bargainActivity.getId(), PromotionTypeEnum.BARGAIN_ACTIVITY.getType(),
|
||||
bargainActivity.getName(), bargainActivity.getSpuId(), bargainActivity.getStartTime(), bargainActivity.getEndTime()));
|
||||
}
|
||||
return success(activityVOList);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,13 +12,14 @@ import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.Parameters;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
@@ -38,6 +39,7 @@ public class AppArticleController {
|
||||
@Parameter(name = "recommendHot", description = "是否热门", example = "false"), // 场景一:查看指定的文章
|
||||
@Parameter(name = "recommendBanner", description = "是否轮播图", example = "false") // 场景二:查看指定的文章
|
||||
})
|
||||
@PermitAll
|
||||
public CommonResult<List<AppArticleRespVO>> getArticleList(
|
||||
@RequestParam(value = "recommendHot", required = false) Boolean recommendHot,
|
||||
@RequestParam(value = "recommendBanner", required = false) Boolean recommendBanner) {
|
||||
@@ -47,6 +49,7 @@ public class AppArticleController {
|
||||
|
||||
@RequestMapping("/page")
|
||||
@Operation(summary = "获得文章详情分页")
|
||||
@PermitAll
|
||||
public CommonResult<PageResult<AppArticleRespVO>> getArticlePage(AppArticlePageReqVO pageReqVO) {
|
||||
return success(ArticleConvert.INSTANCE.convertPage02(articleService.getArticlePage(pageReqVO)));
|
||||
}
|
||||
@@ -57,6 +60,7 @@ public class AppArticleController {
|
||||
@Parameter(name = "id", description = "文章编号", example = "1024"),
|
||||
@Parameter(name = "title", description = "文章标题", example = "1024"),
|
||||
})
|
||||
@PermitAll
|
||||
public CommonResult<AppArticleRespVO> getArticle(@RequestParam(value = "id", required = false) Long id,
|
||||
@RequestParam(value = "title", required = false) String title) {
|
||||
ArticleDO article = id != null ? articleService.getArticle(id)
|
||||
@@ -67,6 +71,7 @@ public class AppArticleController {
|
||||
@PutMapping("/add-browse-count")
|
||||
@Operation(summary = "增加文章浏览量")
|
||||
@Parameter(name = "id", description = "文章编号", example = "1024")
|
||||
@PermitAll
|
||||
public CommonResult<Boolean> addBrowseCount(@RequestParam("id") Long id) {
|
||||
articleService.addArticleBrowseCount(id);
|
||||
return success(true);
|
||||
|
||||
@@ -8,10 +8,11 @@ import cn.iocoder.yudao.module.promotion.service.banner.BannerService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
@@ -28,6 +29,7 @@ public class AppBannerController {
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "获得 banner 列表")
|
||||
@Parameter(name = "position", description = "Banner position", example = "1")
|
||||
@PermitAll
|
||||
public CommonResult<List<AppBannerRespVO>> getBannerList(@RequestParam("position") Integer position) {
|
||||
List<BannerDO> bannerList = bannerService.getBannerListByPosition(position);
|
||||
return success(BannerConvert.INSTANCE.convertList01(bannerList));
|
||||
@@ -36,6 +38,7 @@ public class AppBannerController {
|
||||
@PutMapping("/add-browse-count")
|
||||
@Operation(summary = "增加 Banner 点击量")
|
||||
@Parameter(name = "id", description = "Banner 编号", example = "1024")
|
||||
@PermitAll
|
||||
public CommonResult<Boolean> addBrowseCount(@RequestParam("id") Long id) {
|
||||
bannerService.addBannerBrowseCount(id);
|
||||
return success(true);
|
||||
|
||||
@@ -19,6 +19,7 @@ import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@@ -31,7 +32,6 @@ import java.util.List;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.common.util.cache.CacheUtils.buildAsyncReloadingCache;
|
||||
import static cn.iocoder.yudao.framework.common.util.cache.CacheUtils.buildCache;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
|
||||
|
||||
@Tag(name = "用户 App - 砍价活动")
|
||||
@@ -43,7 +43,7 @@ public class AppBargainActivityController {
|
||||
/**
|
||||
* {@link AppBargainActivityRespVO} 缓存,通过它异步刷新 {@link #getBargainActivityList0(Integer)} 所要的首页数据
|
||||
*/
|
||||
private final LoadingCache<Integer, List<AppBargainActivityRespVO>> bargainActivityListCache = buildCache(Duration.ofSeconds(10L),
|
||||
private final LoadingCache<Integer, List<AppBargainActivityRespVO>> bargainActivityListCache = buildAsyncReloadingCache(Duration.ofSeconds(10L),
|
||||
new CacheLoader<Integer, List<AppBargainActivityRespVO>>() {
|
||||
|
||||
@Override
|
||||
@@ -64,6 +64,7 @@ public class AppBargainActivityController {
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "获得砍价活动列表", description = "用于小程序首页")
|
||||
@Parameter(name = "count", description = "需要展示的数量", example = "6")
|
||||
@PermitAll
|
||||
public CommonResult<List<AppBargainActivityRespVO>> getBargainActivityList(
|
||||
@RequestParam(name = "count", defaultValue = "6") Integer count) {
|
||||
return success(bargainActivityListCache.getUnchecked(count));
|
||||
@@ -81,6 +82,7 @@ public class AppBargainActivityController {
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得砍价活动分页")
|
||||
@PermitAll
|
||||
public CommonResult<PageResult<AppBargainActivityRespVO>> getBargainActivityPage(PageParam pageReqVO) {
|
||||
PageResult<BargainActivityDO> result = bargainActivityService.getBargainActivityPage(pageReqVO);
|
||||
if (CollUtil.isEmpty(result.getList())) {
|
||||
@@ -94,6 +96,7 @@ public class AppBargainActivityController {
|
||||
@GetMapping("/get-detail")
|
||||
@Operation(summary = "获得砍价活动详情")
|
||||
@Parameter(name = "id", description = "活动编号", example = "1")
|
||||
@PermitAll
|
||||
public CommonResult<AppBargainActivityDetailRespVO> getBargainActivityDetail(@RequestParam("id") Long id) {
|
||||
BargainActivityDO activity = bargainActivityService.getBargainActivity(id);
|
||||
if (activity == null) {
|
||||
|
||||
@@ -5,7 +5,6 @@ import cn.hutool.core.lang.Assert;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
|
||||
import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
|
||||
import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
|
||||
import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
|
||||
@@ -28,6 +27,7 @@ import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.Parameters;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@@ -61,6 +61,7 @@ public class AppBargainRecordController {
|
||||
|
||||
@GetMapping("/get-summary")
|
||||
@Operation(summary = "获得砍价记录的概要信息", description = "用于小程序首页")
|
||||
@PermitAll
|
||||
public CommonResult<AppBargainRecordSummaryRespVO> getBargainRecordSummary() {
|
||||
// 砍价成功的用户数量
|
||||
Integer successUserCount = bargainRecordService.getBargainRecordUserCount(
|
||||
@@ -86,6 +87,7 @@ public class AppBargainRecordController {
|
||||
@Parameter(name = "id", description = "砍价记录编号", example = "111"), // 场景一:查看指定的砍价记录
|
||||
@Parameter(name = "activityId", description = "砍价活动编号", example = "222") // 场景二:查看指定的砍价活动
|
||||
})
|
||||
@PermitAll
|
||||
public CommonResult<AppBargainRecordDetailRespVO> getBargainRecordDetail(
|
||||
@RequestParam(value = "id", required = false) Long id,
|
||||
@RequestParam(value = "activityId", required = false) Long activityId) {
|
||||
@@ -153,7 +155,6 @@ public class AppBargainRecordController {
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建砍价记录", description = "参与砍价活动")
|
||||
@PreAuthenticated
|
||||
public CommonResult<Long> createBargainRecord(@RequestBody AppBargainRecordCreateReqVO reqVO) {
|
||||
Long recordId = bargainRecordService.createBargainRecord(getLoginUserId(), reqVO);
|
||||
return success(recordId);
|
||||
|
||||
@@ -18,6 +18,7 @@ import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@@ -44,6 +45,7 @@ public class AppCombinationActivityController {
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得拼团活动分页")
|
||||
@PermitAll
|
||||
public CommonResult<PageResult<AppCombinationActivityRespVO>> getCombinationActivityPage(PageParam pageParam) {
|
||||
PageResult<CombinationActivityDO> pageResult = activityService.getCombinationActivityPage(pageParam);
|
||||
if (CollUtil.isEmpty(pageResult.getList())) {
|
||||
@@ -59,6 +61,7 @@ public class AppCombinationActivityController {
|
||||
@GetMapping("/list-by-ids")
|
||||
@Operation(summary = "获得拼团活动列表,基于活动编号数组")
|
||||
@Parameter(name = "ids", description = "活动编号数组", required = true, example = "[1024, 1025]")
|
||||
@PermitAll
|
||||
public CommonResult<List<AppCombinationActivityRespVO>> getCombinationActivityListByIds(@RequestParam("ids") List<Long> ids) {
|
||||
// 1. 获得开启的活动列表
|
||||
List<CombinationActivityDO> activityList = activityService.getCombinationActivityListByIds(ids);
|
||||
@@ -76,6 +79,7 @@ public class AppCombinationActivityController {
|
||||
@GetMapping("/get-detail")
|
||||
@Operation(summary = "获得拼团活动明细")
|
||||
@Parameter(name = "id", description = "活动编号", required = true, example = "1024")
|
||||
@PermitAll
|
||||
public CommonResult<AppCombinationActivityDetailRespVO> getCombinationActivityDetail(@RequestParam("id") Long id) {
|
||||
// 1. 获取活动
|
||||
CombinationActivityDO activity = activityService.getCombinationActivity(id);
|
||||
|
||||
@@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.promotion.controller.app.combination;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
|
||||
import cn.iocoder.yudao.module.promotion.controller.app.combination.vo.record.AppCombinationRecordDetailRespVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.app.combination.vo.record.AppCombinationRecordPageReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.app.combination.vo.record.AppCombinationRecordRespVO;
|
||||
@@ -16,6 +15,7 @@ import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.Parameters;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.Max;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
@@ -43,6 +43,7 @@ public class AppCombinationRecordController {
|
||||
|
||||
@GetMapping("/get-summary")
|
||||
@Operation(summary = "获得拼团记录的概要信息", description = "用于小程序首页")
|
||||
@PermitAll
|
||||
public CommonResult<AppCombinationRecordSummaryRespVO> getCombinationRecordSummary() {
|
||||
AppCombinationRecordSummaryRespVO summary = new AppCombinationRecordSummaryRespVO();
|
||||
// 1. 获得拼团参与用户数量
|
||||
@@ -68,6 +69,7 @@ public class AppCombinationRecordController {
|
||||
@Parameter(name = "status", description = "拼团状态"), // 对应 CombinationRecordStatusEnum 枚举
|
||||
@Parameter(name = "count", description = "数量")
|
||||
})
|
||||
@PermitAll
|
||||
public CommonResult<List<AppCombinationRecordRespVO>> getHeadCombinationRecordList(
|
||||
@RequestParam(value = "activityId", required = false) Long activityId,
|
||||
@RequestParam("status") Integer status,
|
||||
@@ -78,7 +80,6 @@ public class AppCombinationRecordController {
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得我的拼团记录分页")
|
||||
@PreAuthenticated
|
||||
public CommonResult<PageResult<AppCombinationRecordRespVO>> getCombinationRecordPage(
|
||||
@Valid AppCombinationRecordPageReqVO pageReqVO) {
|
||||
PageResult<CombinationRecordDO> pageResult = combinationRecordService.getCombinationRecordPage(
|
||||
@@ -89,6 +90,7 @@ public class AppCombinationRecordController {
|
||||
@GetMapping("/get-detail")
|
||||
@Operation(summary = "获得拼团记录明细")
|
||||
@Parameter(name = "id", description = "拼团记录编号", required = true, example = "1024")
|
||||
@PermitAll
|
||||
public CommonResult<AppCombinationRecordDetailRespVO> getCombinationRecordDetail(@RequestParam("id") Long id) {
|
||||
// 1. 查找这条拼团记录
|
||||
CombinationRecordDO record = combinationRecordService.getCombinationRecordById(id);
|
||||
|
||||
@@ -4,7 +4,6 @@ import cn.hutool.core.collection.CollUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
|
||||
import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.coupon.AppCouponPageReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.coupon.AppCouponRespVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.coupon.AppCouponTakeReqVO;
|
||||
@@ -41,7 +40,6 @@ public class AppCouponController {
|
||||
@PostMapping("/take")
|
||||
@Operation(summary = "领取优惠劵")
|
||||
@Parameter(name = "templateId", description = "优惠券模板编号", required = true, example = "1024")
|
||||
@PreAuthenticated
|
||||
public CommonResult<Boolean> takeCoupon(@Valid @RequestBody AppCouponTakeReqVO reqVO) {
|
||||
// 1. 领取优惠劵
|
||||
Long userId = getLoginUserId();
|
||||
@@ -59,7 +57,6 @@ public class AppCouponController {
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "我的优惠劵列表")
|
||||
@PreAuthenticated
|
||||
public CommonResult<PageResult<AppCouponRespVO>> getCouponPage(AppCouponPageReqVO pageReqVO) {
|
||||
PageResult<CouponDO> pageResult = couponService.getCouponPage(
|
||||
CouponConvert.INSTANCE.convert(pageReqVO, Collections.singleton(getLoginUserId())));
|
||||
@@ -69,7 +66,6 @@ public class AppCouponController {
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得优惠劵")
|
||||
@Parameter(name = "id", description = "优惠劵编号", required = true, example = "1024")
|
||||
@PreAuthenticated
|
||||
public CommonResult<AppCouponRespVO> getCoupon(@RequestParam("id") Long id) {
|
||||
CouponDO coupon = couponService.getCoupon(getLoginUserId(), id);
|
||||
return success(BeanUtils.toBean(coupon, AppCouponRespVO.class));
|
||||
@@ -77,7 +73,6 @@ public class AppCouponController {
|
||||
|
||||
@GetMapping(value = "/get-unused-count")
|
||||
@Operation(summary = "获得未使用的优惠劵数量")
|
||||
@PreAuthenticated
|
||||
public CommonResult<Long> getUnusedCouponCount() {
|
||||
return success(couponService.getUnusedCouponCount(getLoginUserId()));
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.Parameters;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@@ -51,6 +52,7 @@ public class AppCouponTemplateController {
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得优惠劵模版")
|
||||
@Parameter(name = "id", description = "优惠券模板编号", required = true, example = "1024")
|
||||
@PermitAll
|
||||
public CommonResult<AppCouponTemplateRespVO> getCouponTemplate(Long id) {
|
||||
CouponTemplateDO template = couponTemplateService.getCouponTemplate(id);
|
||||
if (template == null) {
|
||||
@@ -69,6 +71,7 @@ public class AppCouponTemplateController {
|
||||
@Parameter(name = "productScope", description = "使用类型"),
|
||||
@Parameter(name = "count", description = "数量", required = true)
|
||||
})
|
||||
@PermitAll
|
||||
public CommonResult<List<AppCouponTemplateRespVO>> getCouponTemplateList(
|
||||
@RequestParam(value = "spuId", required = false) Long spuId,
|
||||
@RequestParam(value = "productScope", required = false) Integer productScope,
|
||||
@@ -76,7 +79,7 @@ public class AppCouponTemplateController {
|
||||
// 1.1 处理查询条件:商品范围编号
|
||||
Long productScopeValue = getProductScopeValue(productScope, spuId);
|
||||
// 1.2 处理查询条件:领取方式 = 直接领取
|
||||
List<Integer> canTakeTypes = singletonList(CouponTakeTypeEnum.USER.getValue());
|
||||
List<Integer> canTakeTypes = singletonList(CouponTakeTypeEnum.USER.getType());
|
||||
|
||||
// 2. 查询
|
||||
List<CouponTemplateDO> list = couponTemplateService.getCouponTemplateList(canTakeTypes, productScope,
|
||||
@@ -91,6 +94,7 @@ public class AppCouponTemplateController {
|
||||
@GetMapping("/list-by-ids")
|
||||
@Operation(summary = "获得优惠劵模版列表")
|
||||
@Parameter(name = "ids", description = "优惠券模板编号列表")
|
||||
@PermitAll
|
||||
public CommonResult<List<AppCouponTemplateRespVO>> getCouponTemplateList(
|
||||
@RequestParam(value = "ids", required = false) Set<Long> ids) {
|
||||
// 1. 查询
|
||||
@@ -104,11 +108,12 @@ public class AppCouponTemplateController {
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得优惠劵模版分页")
|
||||
@PermitAll
|
||||
public CommonResult<PageResult<AppCouponTemplateRespVO>> getCouponTemplatePage(AppCouponTemplatePageReqVO pageReqVO) {
|
||||
// 1.1 处理查询条件:商品范围编号
|
||||
Long productScopeValue = getProductScopeValue(pageReqVO.getProductScope(), pageReqVO.getSpuId());
|
||||
// 1.2 处理查询条件:领取方式 = 直接领取
|
||||
List<Integer> canTakeTypes = singletonList(CouponTakeTypeEnum.USER.getValue());
|
||||
List<Integer> canTakeTypes = singletonList(CouponTakeTypeEnum.USER.getType());
|
||||
|
||||
// 2. 分页查询
|
||||
PageResult<CouponTemplateDO> pageResult = couponTemplateService.getCouponTemplatePage(
|
||||
|
||||
@@ -9,6 +9,7 @@ import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@@ -29,6 +30,7 @@ public class AppDiyPageController {
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得装修页面")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PermitAll
|
||||
public CommonResult<AppDiyPagePropertyRespVO> getDiyPage(@RequestParam("id") Long id) {
|
||||
DiyPageDO diyPage = diyPageService.getDiyPage(id);
|
||||
return success(BeanUtils.toBean(diyPage, AppDiyPagePropertyRespVO.class));
|
||||
|
||||
@@ -12,6 +12,7 @@ import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@@ -37,6 +38,7 @@ public class AppDiyTemplateController {
|
||||
// TODO @疯狂:要不要把 used 和 get 接口合并哈;不传递 id,直接拿默认;
|
||||
@GetMapping("/used")
|
||||
@Operation(summary = "使用中的装修模板")
|
||||
@PermitAll
|
||||
public CommonResult<AppDiyTemplatePropertyRespVO> getUsedDiyTemplate() {
|
||||
DiyTemplateDO diyTemplate = diyTemplateService.getUsedDiyTemplate();
|
||||
return success(buildVo(diyTemplate));
|
||||
@@ -45,6 +47,7 @@ public class AppDiyTemplateController {
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得装修模板")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PermitAll
|
||||
public CommonResult<AppDiyTemplatePropertyRespVO> getDiyTemplate(@RequestParam("id") Long id) {
|
||||
DiyTemplateDO diyTemplate = diyTemplateService.getDiyTemplate(id);
|
||||
return success(buildVo(diyTemplate));
|
||||
|
||||
@@ -4,7 +4,6 @@ import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.kefu.vo.message.KeFuMessageRespVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.app.kefu.vo.message.AppKeFuMessagePageReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.app.kefu.vo.message.AppKeFuMessageSendReqVO;
|
||||
@@ -32,7 +31,6 @@ public class AppKeFuMessageController {
|
||||
|
||||
@PostMapping("/send")
|
||||
@Operation(summary = "发送客服消息")
|
||||
@PreAuthenticated
|
||||
public CommonResult<Long> sendKefuMessage(@Valid @RequestBody AppKeFuMessageSendReqVO sendReqVO) {
|
||||
sendReqVO.setSenderId(getLoginUserId()).setSenderType(UserTypeEnum.MEMBER.getValue()); // 设置用户编号和类型
|
||||
return success(kefuMessageService.sendKefuMessage(sendReqVO));
|
||||
@@ -41,7 +39,6 @@ public class AppKeFuMessageController {
|
||||
@PutMapping("/update-read-status")
|
||||
@Operation(summary = "更新客服消息已读状态")
|
||||
@Parameter(name = "conversationId", description = "会话编号", required = true)
|
||||
@PreAuthenticated
|
||||
public CommonResult<Boolean> updateKefuMessageReadStatus(@RequestParam("conversationId") Long conversationId) {
|
||||
kefuMessageService.updateKeFuMessageReadStatus(conversationId, getLoginUserId(), UserTypeEnum.MEMBER.getValue());
|
||||
return success(true);
|
||||
@@ -49,7 +46,6 @@ public class AppKeFuMessageController {
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得客服消息分页")
|
||||
@PreAuthenticated
|
||||
public CommonResult<PageResult<KeFuMessageRespVO>> getKefuMessagePage(@Valid AppKeFuMessagePageReqVO pageReqVO) {
|
||||
PageResult<KeFuMessageDO> pageResult = kefuMessageService.getKeFuMessagePage(pageReqVO, getLoginUserId());
|
||||
return success(BeanUtils.toBean(pageResult, KeFuMessageRespVO.class));
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
package cn.iocoder.yudao.module.promotion.controller.app.point;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
|
||||
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.point.vo.activity.PointActivityPageReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.app.point.vo.AppPointActivityDetailRespVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.app.point.vo.AppPointActivityPageReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.app.point.vo.AppPointActivityRespVO;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.point.PointActivityDO;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.point.PointProductDO;
|
||||
import cn.iocoder.yudao.module.promotion.service.point.PointActivityService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen;
|
||||
|
||||
@Tag(name = "用户 App - 积分商城活动")
|
||||
@RestController
|
||||
@RequestMapping("/promotion/point-activity")
|
||||
@Validated
|
||||
public class AppPointActivityController {
|
||||
|
||||
@Resource
|
||||
private PointActivityService pointActivityService;
|
||||
|
||||
@Resource
|
||||
private ProductSpuApi productSpuApi;
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得积分商城活动分页")
|
||||
@PermitAll
|
||||
public CommonResult<PageResult<AppPointActivityRespVO>> getPointActivityPage(AppPointActivityPageReqVO pageReqVO) {
|
||||
// 1. 查询满足当前阶段的活动
|
||||
PageResult<PointActivityDO> pageResult = pointActivityService.getPointActivityPage(
|
||||
BeanUtils.toBean(pageReqVO, PointActivityPageReqVO.class));
|
||||
if (CollUtil.isEmpty(pageResult.getList())) {
|
||||
return success(PageResult.empty(pageResult.getTotal()));
|
||||
}
|
||||
|
||||
// 2. 拼接数据
|
||||
List<AppPointActivityRespVO> resultList = buildAppPointActivityRespVOList(pageResult.getList());
|
||||
return success(new PageResult<>(resultList, pageResult.getTotal()));
|
||||
}
|
||||
|
||||
@GetMapping("/get-detail")
|
||||
@Operation(summary = "获得积分商城活动明细")
|
||||
@Parameter(name = "id", description = "活动编号", required = true, example = "1024")
|
||||
@PermitAll
|
||||
public CommonResult<AppPointActivityDetailRespVO> getPointActivity(@RequestParam("id") Long id) {
|
||||
// 1. 获取活动
|
||||
PointActivityDO activity = pointActivityService.getPointActivity(id);
|
||||
if (activity == null
|
||||
|| ObjUtil.equal(activity.getStatus(), CommonStatusEnum.DISABLE.getStatus())) {
|
||||
return success(null);
|
||||
}
|
||||
|
||||
// 2. 拼接数据
|
||||
List<PointProductDO> products = pointActivityService.getPointProductListByActivityIds(Collections.singletonList(id));
|
||||
AppPointActivityDetailRespVO respVO = BeanUtils.toBean(activity, AppPointActivityDetailRespVO.class);
|
||||
respVO.setProducts(BeanUtils.toBean(products, AppPointActivityDetailRespVO.Product.class));
|
||||
return success(respVO);
|
||||
}
|
||||
|
||||
@GetMapping("/list-by-ids")
|
||||
@Operation(summary = "获得积分商城活动列表,基于活动编号数组")
|
||||
@Parameter(name = "ids", description = "活动编号数组", required = true, example = "[1024, 1025]")
|
||||
@PermitAll
|
||||
public CommonResult<List<AppPointActivityRespVO>> getCombinationActivityListByIds(@RequestParam("ids") List<Long> ids) {
|
||||
// 1. 获得开启的活动列表
|
||||
List<PointActivityDO> activityList = pointActivityService.getPointActivityListByIds(ids);
|
||||
activityList.removeIf(activity -> CommonStatusEnum.isDisable(activity.getStatus()));
|
||||
if (CollUtil.isEmpty(activityList)) {
|
||||
return success(Collections.emptyList());
|
||||
}
|
||||
// 2. 拼接返回
|
||||
List<AppPointActivityRespVO> result = buildAppPointActivityRespVOList(activityList);
|
||||
return success(result);
|
||||
}
|
||||
|
||||
private List<AppPointActivityRespVO> buildAppPointActivityRespVOList(List<PointActivityDO> activityList) {
|
||||
List<PointProductDO> products = pointActivityService.getPointProductListByActivityIds(
|
||||
convertSet(activityList, PointActivityDO::getId));
|
||||
Map<Long, List<PointProductDO>> productsMap = convertMultiMap(products, PointProductDO::getActivityId);
|
||||
Map<Long, ProductSpuRespDTO> spuMap = productSpuApi.getSpusMap(
|
||||
convertSet(activityList, PointActivityDO::getSpuId));
|
||||
List<AppPointActivityRespVO> result = BeanUtils.toBean(activityList, AppPointActivityRespVO.class);
|
||||
result.forEach(activity -> {
|
||||
// 设置 product 信息
|
||||
PointProductDO minProduct = getMinObject(productsMap.get(activity.getId()), PointProductDO::getPoint);
|
||||
assert minProduct != null;
|
||||
activity.setPoint(minProduct.getPoint()).setPrice(minProduct.getPrice());
|
||||
findAndThen(spuMap, activity.getSpuId(),
|
||||
spu -> activity.setSpuName(spu.getName()).setPicUrl(spu.getPicUrl()).setMarketPrice(spu.getMarketPrice()));
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package cn.iocoder.yudao.module.promotion.controller.app.point.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "用户 App - 积分商城活动的详细 Response VO")
|
||||
@Data
|
||||
public class AppPointActivityDetailRespVO {
|
||||
|
||||
@Schema(description = "积分商城活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11373")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "积分商城活动商品", requiredMode = Schema.RequiredMode.REQUIRED, example = "19509")
|
||||
private Long spuId;
|
||||
|
||||
@Schema(description = "活动状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "积分商城活动库存(剩余库存积分兑换时扣减)", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
|
||||
private Integer stock;
|
||||
|
||||
@Schema(description = "积分商城活动总库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
|
||||
private Integer totalStock;
|
||||
|
||||
@Schema(description = "备注", example = "你说的对")
|
||||
private String remark;
|
||||
|
||||
@Schema(description = "商品信息数组", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private List<Product> products;
|
||||
|
||||
@Schema(description = "商品信息")
|
||||
@Data
|
||||
public static class Product {
|
||||
|
||||
@Schema(description = "积分商城商品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "31718")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "商品 SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2736")
|
||||
private Long skuId;
|
||||
|
||||
@Schema(description = "可兑换数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "3926")
|
||||
private Integer count;
|
||||
|
||||
@Schema(description = "兑换积分", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private Integer point;
|
||||
|
||||
@Schema(description = "兑换金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "15860")
|
||||
private Integer price;
|
||||
|
||||
@Schema(description = "积分商城商品库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
|
||||
private Integer stock;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package cn.iocoder.yudao.module.promotion.controller.app.point.vo;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
@Schema(description = "用户 App - 积分商城活动分页 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class AppPointActivityPageReqVO extends PageParam {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package cn.iocoder.yudao.module.promotion.controller.app.point.vo;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "用户 App - 积分商城活动 Response VO")
|
||||
@Data
|
||||
public class AppPointActivityRespVO {
|
||||
|
||||
@Schema(description = "积分商城活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11373")
|
||||
@ExcelProperty("积分商城活动编号")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "积分商城活动商品", requiredMode = Schema.RequiredMode.REQUIRED, example = "19509")
|
||||
@ExcelProperty("积分商城活动商品")
|
||||
private Long spuId;
|
||||
|
||||
@Schema(description = "活动状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
|
||||
@ExcelProperty("活动状态")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "积分商城活动库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
|
||||
@ExcelProperty("积分商城活动库存")
|
||||
private Integer stock; // 剩余库存积分兑换时扣减
|
||||
|
||||
@Schema(description = "积分商城活动总库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
|
||||
@ExcelProperty("积分商城活动总库存")
|
||||
private Integer totalStock;
|
||||
|
||||
// TODO @puhui999:只返回必要的字段,例如说 remark、sort、createTime 应该是不需要的呢。也可以看看别的也不需要哈。
|
||||
|
||||
@Schema(description = "备注", example = "你说的对")
|
||||
@ExcelProperty("备注")
|
||||
private String remark;
|
||||
|
||||
@Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@ExcelProperty("排序")
|
||||
private Integer sort;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@ExcelProperty("创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
// ========== 商品字段 ==========
|
||||
|
||||
@Schema(description = "商品名称", requiredMode = Schema.RequiredMode.REQUIRED, // 从 SPU 的 name 读取
|
||||
example = "618大促")
|
||||
private String spuName;
|
||||
@Schema(description = "商品主图", requiredMode = Schema.RequiredMode.REQUIRED, // 从 SPU 的 picUrl 读取
|
||||
example = "https://www.iocoder.cn/xx.png")
|
||||
private String picUrl;
|
||||
@Schema(description = "商品市场价,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, // 从 SPU 的 marketPrice 读取
|
||||
example = "50")
|
||||
private Integer marketPrice;
|
||||
|
||||
//======================= 显示所需兑换积分最少的 sku 信息 =======================
|
||||
|
||||
@Schema(description = "兑换积分", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private Integer point;
|
||||
|
||||
@Schema(description = "兑换金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "15860")
|
||||
private Integer price;
|
||||
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@@ -29,9 +30,20 @@ public class AppRewardActivityController {
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得满减送活动")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PermitAll
|
||||
public CommonResult<AppRewardActivityRespVO> getRewardActivity(@RequestParam("id") Long id) {
|
||||
RewardActivityDO rewardActivity = rewardActivityService.getRewardActivity(id);
|
||||
return success(BeanUtils.toBean(rewardActivity, AppRewardActivityRespVO.class));
|
||||
RewardActivityDO activity = rewardActivityService.getRewardActivity(id);
|
||||
if (activity == null) {
|
||||
return success(null);
|
||||
}
|
||||
// 拼接 Rule 描述
|
||||
AppRewardActivityRespVO activityVO = BeanUtils.toBean(activity, AppRewardActivityRespVO.class);
|
||||
for (int i = 0; i < activityVO.getRules().size(); i++) {
|
||||
AppRewardActivityRespVO.Rule ruleVO = activityVO.getRules().get(i);
|
||||
RewardActivityDO.Rule rule = activity.getRules().get(i);
|
||||
ruleVO.setDescription(rewardActivityService.getRewardActivityRuleDescription(activity.getConditionType(), rule));
|
||||
}
|
||||
return success(activityVO);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivi
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "用户 App - 满减送活动 Response VO")
|
||||
@@ -19,6 +20,12 @@ public class AppRewardActivityRespVO {
|
||||
@Schema(description = "活动标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "满啦满啦")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "开始时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime startTime;
|
||||
|
||||
@Schema(description = "结束时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime endTime;
|
||||
|
||||
@Schema(description = "条件类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Integer conditionType;
|
||||
|
||||
@@ -26,9 +33,18 @@ public class AppRewardActivityRespVO {
|
||||
private Integer productScope;
|
||||
|
||||
@Schema(description = "商品 SPU 编号的数组", example = "1,2,3")
|
||||
private List<Long> productSpuIds;
|
||||
private List<Long> productScopeValues;
|
||||
|
||||
@Schema(description = "优惠规则的数组")
|
||||
private List<RewardActivityBaseVO.Rule> rules;
|
||||
private List<Rule> rules;
|
||||
|
||||
@Schema(description = "优惠规则")
|
||||
@Data
|
||||
public static class Rule extends RewardActivityBaseVO.Rule {
|
||||
|
||||
@Schema(description = "规则描述")
|
||||
private String description; // 通过 {@link #limit}、{@link #discountPrice} 等字段进行拼接
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
@@ -74,6 +75,7 @@ public class AppSeckillActivityController {
|
||||
|
||||
@GetMapping("/get-now")
|
||||
@Operation(summary = "获得当前秒杀活动", description = "获取当前正在进行的活动,提供给首页使用")
|
||||
@PermitAll
|
||||
public CommonResult<AppSeckillActivityNowRespVO> getNowSeckillActivity() {
|
||||
return success(nowSeckillActivityCache.getUnchecked("")); // 缓存
|
||||
}
|
||||
@@ -96,6 +98,7 @@ public class AppSeckillActivityController {
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得秒杀活动分页")
|
||||
@PermitAll
|
||||
public CommonResult<PageResult<AppSeckillActivityRespVO>> getSeckillActivityPage(AppSeckillActivityPageReqVO pageReqVO) {
|
||||
// 1. 查询满足当前阶段的活动
|
||||
PageResult<SeckillActivityDO> pageResult = activityService.getSeckillActivityAppPageByConfigId(pageReqVO);
|
||||
@@ -113,6 +116,7 @@ public class AppSeckillActivityController {
|
||||
@GetMapping("/get-detail")
|
||||
@Operation(summary = "获得秒杀活动明细")
|
||||
@Parameter(name = "id", description = "活动编号", required = true, example = "1024")
|
||||
@PermitAll
|
||||
public CommonResult<AppSeckillActivityDetailRespVO> getSeckillActivity(@RequestParam("id") Long id) {
|
||||
// 1. 获取活动
|
||||
SeckillActivityDO activity = activityService.getSeckillActivity(id);
|
||||
@@ -151,8 +155,9 @@ public class AppSeckillActivityController {
|
||||
}
|
||||
|
||||
@GetMapping("/list-by-ids")
|
||||
@Operation(summary = "获得拼团活动列表,基于活动编号数组")
|
||||
@Operation(summary = "获得秒杀活动列表,基于活动编号数组")
|
||||
@Parameter(name = "ids", description = "活动编号数组", required = true, example = "[1024, 1025]")
|
||||
@PermitAll
|
||||
public CommonResult<List<AppSeckillActivityRespVO>> getCombinationActivityListByIds(@RequestParam("ids") List<Long> ids) {
|
||||
// 1. 获得开启的活动列表
|
||||
List<SeckillActivityDO> activityList = activityService.getSeckillActivityListByIds(ids);
|
||||
|
||||
@@ -9,6 +9,7 @@ import cn.iocoder.yudao.module.promotion.service.seckill.SeckillConfigService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@@ -28,6 +29,7 @@ public class AppSeckillConfigController {
|
||||
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "获得秒杀时间段列表")
|
||||
@PermitAll
|
||||
public CommonResult<List<AppSeckillConfigRespVO>> getSeckillConfigList() {
|
||||
List<SeckillConfigDO> list = configService.getSeckillConfigListByStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
return success(SeckillConfigConvert.INSTANCE.convertList2(list));
|
||||
|
||||
@@ -1,20 +1,17 @@
|
||||
package cn.iocoder.yudao.module.promotion.convert.discount;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
|
||||
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
|
||||
import cn.iocoder.yudao.module.promotion.api.discount.dto.DiscountProductRespDTO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.*;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityBaseVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityCreateReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityRespVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityUpdateReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivityDO;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO;
|
||||
import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 限时折扣活动 Convert
|
||||
@@ -33,105 +30,22 @@ public interface DiscountActivityConvert {
|
||||
DiscountActivityRespVO convert(DiscountActivityDO bean);
|
||||
|
||||
List<DiscountActivityRespVO> convertList(List<DiscountActivityDO> list);
|
||||
List<DiscountActivityBaseVO.Product> convertList2(List<DiscountProductDO> list);
|
||||
|
||||
List<DiscountProductRespDTO> convertList02(List<DiscountProductDO> list);
|
||||
List<DiscountActivityBaseVO.Product> convertList2(List<DiscountProductDO> list);
|
||||
|
||||
PageResult<DiscountActivityRespVO> convertPage(PageResult<DiscountActivityDO> page);
|
||||
|
||||
default PageResult<DiscountActivityRespVO> convertPage(PageResult<DiscountActivityDO> page,
|
||||
List<DiscountProductDO> discountProductDOList,
|
||||
List<ProductSpuRespDTO> spuList) {
|
||||
List<DiscountProductDO> discountProductDOList) {
|
||||
PageResult<DiscountActivityRespVO> pageResult = convertPage(page);
|
||||
|
||||
// 拼接商品 TODO @zhangshuai:类似空行的问题,也可以看看
|
||||
Map<Long, DiscountProductDO> discountActivityMap = CollectionUtils.convertMap(discountProductDOList, DiscountProductDO::getActivityId);
|
||||
Map<Long, ProductSpuRespDTO> spuMap = CollectionUtils.convertMap(spuList, ProductSpuRespDTO::getId);
|
||||
pageResult.getList().forEach(item -> {
|
||||
item.setProducts(convertList2(discountProductDOList));
|
||||
item.setSpuId(discountActivityMap.get(item.getId())==null?null: discountActivityMap.get(item.getId()).getSpuId());
|
||||
if (item.getSpuId() != null) {
|
||||
MapUtils.findAndThen(spuMap, item.getSpuId(),
|
||||
spu -> item.setSpuName(spu.getName()).setPicUrl(spu.getPicUrl()).setMarketPrice(spu.getMarketPrice()));
|
||||
}
|
||||
|
||||
});
|
||||
pageResult.getList().forEach(item -> item.setProducts(convertList2(discountProductDOList)));
|
||||
return pageResult;
|
||||
}
|
||||
|
||||
DiscountProductDO convert(DiscountActivityBaseVO.Product bean);
|
||||
|
||||
default DiscountActivityDetailRespVO convert(DiscountActivityDO activity, List<DiscountProductDO> products){
|
||||
if ( activity == null && products == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
DiscountActivityDetailRespVO discountActivityDetailRespVO = new DiscountActivityDetailRespVO();
|
||||
|
||||
if ( activity != null ) {
|
||||
discountActivityDetailRespVO.setName( activity.getName() );
|
||||
discountActivityDetailRespVO.setStartTime( activity.getStartTime() );
|
||||
discountActivityDetailRespVO.setEndTime( activity.getEndTime() );
|
||||
discountActivityDetailRespVO.setRemark( activity.getRemark() );
|
||||
discountActivityDetailRespVO.setId( activity.getId() );
|
||||
discountActivityDetailRespVO.setStatus( activity.getStatus() );
|
||||
discountActivityDetailRespVO.setCreateTime( activity.getCreateTime() );
|
||||
}
|
||||
if (!products.isEmpty()) {
|
||||
discountActivityDetailRespVO.setSpuId(products.get(0).getSpuId());
|
||||
}
|
||||
discountActivityDetailRespVO.setProducts( convertList2( products ) );
|
||||
|
||||
return discountActivityDetailRespVO;
|
||||
default DiscountActivityRespVO convert(DiscountActivityDO activity, List<DiscountProductDO> products) {
|
||||
return BeanUtils.toBean(activity, DiscountActivityRespVO.class).setProducts(convertList2(products));
|
||||
}
|
||||
|
||||
// =========== 比较是否相等 ==========
|
||||
/**
|
||||
* 比较两个限时折扣商品是否相等
|
||||
*
|
||||
* @param productDO 数据库中的商品
|
||||
* @param productVO 前端传入的商品
|
||||
* @return 是否匹配
|
||||
*/
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
default boolean isEquals(DiscountProductDO productDO, DiscountActivityBaseVO.Product productVO) {
|
||||
if (ObjectUtil.notEqual(productDO.getSpuId(), productVO.getSpuId())
|
||||
|| ObjectUtil.notEqual(productDO.getSkuId(), productVO.getSkuId())
|
||||
|| ObjectUtil.notEqual(productDO.getDiscountType(), productVO.getDiscountType())) {
|
||||
return false;
|
||||
}
|
||||
if (productDO.getDiscountType().equals(PromotionDiscountTypeEnum.PRICE.getType())) {
|
||||
return ObjectUtil.equal(productDO.getDiscountPrice(), productVO.getDiscountPrice());
|
||||
}
|
||||
if (productDO.getDiscountType().equals(PromotionDiscountTypeEnum.PERCENT.getType())) {
|
||||
return ObjectUtil.equal(productDO.getDiscountPercent(), productVO.getDiscountPercent());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 比较两个限时折扣商品是否相等
|
||||
* 注意,比较时忽略 id 编号
|
||||
*
|
||||
* @param productDO 商品 1
|
||||
* @param productVO 商品 2
|
||||
* @return 是否匹配
|
||||
*/
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
default boolean isEquals(DiscountProductDO productDO, DiscountProductDO productVO) {
|
||||
if (ObjectUtil.notEqual(productDO.getSpuId(), productVO.getSpuId())
|
||||
|| ObjectUtil.notEqual(productDO.getSkuId(), productVO.getSkuId())
|
||||
|| ObjectUtil.notEqual(productDO.getDiscountType(), productVO.getDiscountType())) {
|
||||
return false;
|
||||
}
|
||||
if (productDO.getDiscountType().equals(PromotionDiscountTypeEnum.PRICE.getType())) {
|
||||
return ObjectUtil.equal(productDO.getDiscountPrice(), productVO.getDiscountPrice());
|
||||
}
|
||||
if (productDO.getDiscountType().equals(PromotionDiscountTypeEnum.PERCENT.getType())) {
|
||||
return ObjectUtil.equal(productDO.getDiscountPercent(), productVO.getDiscountPercent());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -66,10 +66,16 @@ public class DiscountProductDO extends BaseDO {
|
||||
*/
|
||||
private Integer discountPrice;
|
||||
|
||||
/**
|
||||
* 活动标题
|
||||
*
|
||||
* 冗余 {@link DiscountActivityDO#getName()}
|
||||
*/
|
||||
private String activityName;
|
||||
/**
|
||||
* 活动状态
|
||||
*
|
||||
* 关联 {@link DiscountActivityDO#getStatus()}
|
||||
* 冗余 {@link DiscountActivityDO#getStatus()}
|
||||
*/
|
||||
private Integer activityStatus;
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
package cn.iocoder.yudao.module.promotion.dal.dataobject.point;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* 积分商城活动 DO
|
||||
*
|
||||
* @author HUIHUI
|
||||
*/
|
||||
@TableName(value = "promotion_point_activity", autoResultMap = true)
|
||||
@KeySequence("promotion_point_activity_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class PointActivityDO extends BaseDO {
|
||||
|
||||
/**
|
||||
* 积分商城活动编号
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
/**
|
||||
* 积分商城活动商品
|
||||
*/
|
||||
private Long spuId;
|
||||
/**
|
||||
* 活动状态
|
||||
*
|
||||
* 枚举 {@link CommonStatusEnum 对应的类}
|
||||
*/
|
||||
private Integer status;
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
/**
|
||||
* 排序
|
||||
*/
|
||||
private Integer sort;
|
||||
|
||||
/**
|
||||
* 积分商城活动库存(剩余库存积分兑换时扣减)
|
||||
*/
|
||||
private Integer stock;
|
||||
/**
|
||||
* 积分商城活动总库存
|
||||
*/
|
||||
private Integer totalStock;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package cn.iocoder.yudao.module.promotion.dal.dataobject.point;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.*;
|
||||
|
||||
/**
|
||||
* 积分商城商品 DO
|
||||
*
|
||||
* @author HUIHUI
|
||||
*/
|
||||
@TableName("promotion_point_product")
|
||||
@KeySequence("promotion_point_product_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class PointProductDO extends BaseDO {
|
||||
|
||||
/**
|
||||
* 积分商城商品编号
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
/**
|
||||
* 积分商城活动 id
|
||||
*
|
||||
* 关联 {@link PointActivityDO#getId()}
|
||||
*/
|
||||
private Long activityId;
|
||||
/**
|
||||
* 商品 SPU 编号
|
||||
*/
|
||||
private Long spuId;
|
||||
/**
|
||||
* 商品 SKU 编号
|
||||
*/
|
||||
private Long skuId;
|
||||
/**
|
||||
* 可兑换次数
|
||||
*/
|
||||
private Integer count;
|
||||
/**
|
||||
* 所需兑换积分
|
||||
*/
|
||||
private Integer point;
|
||||
/**
|
||||
* 所需兑换金额,单位:分
|
||||
*/
|
||||
private Integer price;
|
||||
/**
|
||||
* 积分商城商品库存
|
||||
*/
|
||||
private Integer stock;
|
||||
/**
|
||||
* 积分商城商品状态
|
||||
*
|
||||
* 枚举 {@link CommonStatusEnum 对应的类}
|
||||
*/
|
||||
private Integer activityStatus;
|
||||
|
||||
}
|
||||
@@ -6,14 +6,11 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity.BargainActivityPageReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 砍价活动 Mapper
|
||||
@@ -86,35 +83,13 @@ public interface BargainActivityMapper extends BaseMapperX<BargainActivityDO> {
|
||||
.last("LIMIT " + count));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询出指定 spuId 的 spu 参加的活动最接近现在的一条记录。多个的话,一个 spuId 对应一个最近的活动编号
|
||||
*
|
||||
* @param spuIds spu 编号
|
||||
* @param status 状态
|
||||
* @return 包含 spuId 和 activityId 的 map 对象列表
|
||||
*/
|
||||
default List<Map<String, Object>> selectSpuIdAndActivityIdMapsBySpuIdsAndStatus(Collection<Long> spuIds, Integer status) {
|
||||
return selectMaps(new QueryWrapper<BargainActivityDO>()
|
||||
.select("spu_id AS spuId, MAX(DISTINCT(id)) AS activityId") // 时间越大 id 也越大 直接用 id
|
||||
.in("spu_id", spuIds)
|
||||
.eq("status", status)
|
||||
.groupBy("spu_id"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定活动编号的活动列表且
|
||||
* 开始时间和结束时间小于给定时间 dateTime 的活动列表
|
||||
*
|
||||
* @param ids 活动编号
|
||||
* @param dateTime 指定日期
|
||||
* @return 活动列表
|
||||
*/
|
||||
default List<BargainActivityDO> selectListByIdsAndDateTimeLt(Collection<Long> ids, LocalDateTime dateTime) {
|
||||
return selectList(new LambdaQueryWrapperX<BargainActivityDO>()
|
||||
.in(BargainActivityDO::getId, ids)
|
||||
.lt(BargainActivityDO::getStartTime, dateTime)
|
||||
.gt(BargainActivityDO::getEndTime, dateTime)// 开始时间 < 指定时间 < 结束时间,也就是说获取指定时间段的活动
|
||||
.orderByDesc(BargainActivityDO::getCreateTime));
|
||||
default BargainActivityDO selectBySpuIdAndStatusAndNow(Long spuId, Integer status) {
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
return selectOne(new LambdaQueryWrapperX<BargainActivityDO>()
|
||||
.eq(BargainActivityDO::getSpuId, spuId)
|
||||
.eq(BargainActivityDO::getStatus, status)
|
||||
.lt(BargainActivityDO::getStartTime, now)
|
||||
.gt(BargainActivityDO::getEndTime, now)); // 开始时间 < now < 结束时间,也就是说获取指定时间段的活动
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,14 +6,10 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityPageReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 拼团活动 Mapper
|
||||
@@ -39,40 +35,13 @@ public interface CombinationActivityMapper extends BaseMapperX<CombinationActivi
|
||||
.eq(CombinationActivityDO::getStatus, status));
|
||||
}
|
||||
|
||||
default List<CombinationActivityDO> selectListByStatus(Integer status, Integer count) {
|
||||
return selectList(new LambdaQueryWrapperX<CombinationActivityDO>()
|
||||
default CombinationActivityDO selectBySpuIdAndStatusAndNow(Long spuId, Integer status) {
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
return selectOne(new LambdaQueryWrapperX<CombinationActivityDO>()
|
||||
.eq(CombinationActivityDO::getSpuId, spuId)
|
||||
.eq(CombinationActivityDO::getStatus, status)
|
||||
.last("LIMIT " + count));
|
||||
.lt(CombinationActivityDO::getStartTime, now)
|
||||
.gt(CombinationActivityDO::getEndTime, now)); // 开始时间 < now < 结束时间,也就是说获取指定时间段的活动
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询出指定 spuId 的 spu 参加的活动最接近现在的一条记录。多个的话,一个 spuId 对应一个最近的活动编号
|
||||
* @param spuIds spu 编号
|
||||
* @param status 状态
|
||||
* @return 包含 spuId 和 activityId 的 map 对象列表
|
||||
*/
|
||||
default List<Map<String, Object>> selectSpuIdAndActivityIdMapsBySpuIdsAndStatus(@Param("spuIds") Collection<Long> spuIds, @Param("status") Integer status) {
|
||||
return selectMaps(new QueryWrapper<CombinationActivityDO>()
|
||||
.select("spu_id AS spuId, MAX(DISTINCT(id)) AS activityId") // 时间越大 id 也越大 直接用 id
|
||||
.in("spu_id", spuIds)
|
||||
.eq("status", status)
|
||||
.groupBy("spu_id"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定活动编号的活动列表且
|
||||
* 开始时间和结束时间小于给定时间 dateTime 的活动列表
|
||||
*
|
||||
* @param ids 活动编号
|
||||
* @param dateTime 指定日期
|
||||
* @return 活动列表
|
||||
*/
|
||||
default List<CombinationActivityDO> selectListByIdsAndDateTimeLt(Collection<Long> ids, LocalDateTime dateTime) {
|
||||
return selectList(new LambdaQueryWrapperX<CombinationActivityDO>()
|
||||
.in(CombinationActivityDO::getId, ids)
|
||||
.lt(CombinationActivityDO::getStartTime, dateTime)
|
||||
.gt(CombinationActivityDO::getEndTime, dateTime)// 开始时间 < 指定时间 < 结束时间,也就是说获取指定时间段的活动
|
||||
.orderByDesc(CombinationActivityDO::getCreateTime));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -70,7 +70,7 @@ public interface CouponTemplateMapper extends BaseMapperX<CouponTemplateDO> {
|
||||
.in(CouponTemplateDO::getTakeType, canTakeTypes) // 2. 领取方式一致
|
||||
.and(ww -> ww.gt(CouponTemplateDO::getValidEndTime, LocalDateTime.now()) // 3.1 未过期
|
||||
.or().eq(CouponTemplateDO::getValidityType, CouponTemplateValidityTypeEnum.TERM.getType())) // 3.2 领取之后
|
||||
.apply(" (take_count < total_count OR total_count = -1 )"); // 4. 剩余数量大于 0,或者无限领取
|
||||
.apply(" (take_count < total_count OR total_count = -1)"); // 4. 剩余数量大于 0,或者无限领取
|
||||
}
|
||||
return canTakeConsumer;
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
package cn.iocoder.yudao.module.promotion.dal.mysql.discount;
|
||||
|
||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 限时折扣商城 Mapper
|
||||
@@ -18,10 +18,6 @@ import java.util.Map;
|
||||
@Mapper
|
||||
public interface DiscountProductMapper extends BaseMapperX<DiscountProductDO> {
|
||||
|
||||
default List<DiscountProductDO> selectListBySkuId(Collection<Long> skuIds) {
|
||||
return selectList(DiscountProductDO::getSkuId, skuIds);
|
||||
}
|
||||
|
||||
default List<DiscountProductDO> selectListByActivityId(Long activityId) {
|
||||
return selectList(DiscountProductDO::getActivityId, activityId);
|
||||
}
|
||||
@@ -30,22 +26,28 @@ public interface DiscountProductMapper extends BaseMapperX<DiscountProductDO> {
|
||||
return selectList(DiscountProductDO::getActivityId, activityIds);
|
||||
}
|
||||
|
||||
// TODO @zhangshuai:逻辑里,尽量避免写 join 语句哈,你可以看看这个查询,有什么办法优化?目前的一个思路,是分 2 次查询,性能也是 ok 的
|
||||
List<DiscountProductDO> getMatchDiscountProductList(@Param("skuIds") Collection<Long> skuIds);
|
||||
default List<DiscountProductDO> selectListBySpuIdsAndStatus(Collection<Long> spuIds, Integer status) {
|
||||
return selectList(new LambdaQueryWrapperX<DiscountProductDO>()
|
||||
.in(DiscountProductDO::getSpuId, spuIds)
|
||||
.eq(DiscountProductDO::getActivityStatus, status));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询出指定 spuId 的 spu 参加的活动最接近现在的一条记录。多个的话,一个 spuId 对应一个最近的活动编号
|
||||
*
|
||||
* @param spuIds spu 编号
|
||||
* @param status 状态
|
||||
* @return 包含 spuId 和 activityId 的 map 对象列表
|
||||
*/
|
||||
default List<Map<String, Object>> selectSpuIdAndActivityIdMapsBySpuIdsAndStatus(Collection<Long> spuIds, Integer status) {
|
||||
return selectMaps(new QueryWrapper<DiscountProductDO>()
|
||||
.select("spu_id AS spuId, MAX(DISTINCT(activity_id)) AS activityId")
|
||||
.in("spu_id", spuIds)
|
||||
.eq("activity_status", status)
|
||||
.groupBy("spu_id"));
|
||||
default void updateByActivityId(DiscountProductDO discountProductDO) {
|
||||
update(discountProductDO, new LambdaUpdateWrapper<DiscountProductDO>()
|
||||
.eq(DiscountProductDO::getActivityId, discountProductDO.getActivityId()));
|
||||
}
|
||||
|
||||
default void deleteByActivityId(Long activityId) {
|
||||
delete(DiscountProductDO::getActivityId, activityId);
|
||||
}
|
||||
|
||||
default List<DiscountProductDO> selectListBySkuIdsAndStatusAndNow(Collection<Long> skuIds, Integer status) {
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
return selectList(new LambdaQueryWrapperX<DiscountProductDO>()
|
||||
.in(DiscountProductDO::getSkuId, skuIds)
|
||||
.eq(DiscountProductDO::getActivityStatus,status)
|
||||
.lt(DiscountProductDO::getActivityStartTime, now)
|
||||
.gt(DiscountProductDO::getActivityEndTime, now));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package cn.iocoder.yudao.module.promotion.dal.mysql.point;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.point.vo.activity.PointActivityPageReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.point.PointActivityDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* 积分商城活动 Mapper
|
||||
*
|
||||
* @author HUIHUI
|
||||
*/
|
||||
@Mapper
|
||||
public interface PointActivityMapper extends BaseMapperX<PointActivityDO> {
|
||||
|
||||
default PageResult<PointActivityDO> selectPage(PointActivityPageReqVO reqVO) {
|
||||
return selectPage(reqVO, new LambdaQueryWrapperX<PointActivityDO>()
|
||||
.eqIfPresent(PointActivityDO::getSpuId, reqVO.getSpuId())
|
||||
.eqIfPresent(PointActivityDO::getStatus, reqVO.getStatus())
|
||||
.eqIfPresent(PointActivityDO::getRemark, reqVO.getRemark())
|
||||
.eqIfPresent(PointActivityDO::getSort, reqVO.getSort())
|
||||
.betweenIfPresent(PointActivityDO::getCreateTime, reqVO.getCreateTime())
|
||||
.orderByDesc(PointActivityDO::getId));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package cn.iocoder.yudao.module.promotion.dal.mysql.point;
|
||||
|
||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.point.PointProductDO;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 积分商城商品 Mapper
|
||||
*
|
||||
* @author HUIHUI
|
||||
*/
|
||||
@Mapper
|
||||
public interface PointProductMapper extends BaseMapperX<PointProductDO> {
|
||||
|
||||
default List<PointProductDO> selectListByActivityId(Collection<Long> activityIds) {
|
||||
return selectList(PointProductDO::getActivityId, activityIds);
|
||||
}
|
||||
|
||||
default List<PointProductDO> selectListByActivityId(Long activityId) {
|
||||
return selectList(PointProductDO::getActivityId, activityId);
|
||||
}
|
||||
|
||||
default void updateByActivityId(PointProductDO pointProductDO) {
|
||||
update(pointProductDO, new LambdaUpdateWrapper<PointProductDO>()
|
||||
.eq(PointProductDO::getActivityId, pointProductDO.getActivityId()));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityPageReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
@@ -30,29 +30,23 @@ public interface RewardActivityMapper extends BaseMapperX<RewardActivityDO> {
|
||||
.orderByDesc(RewardActivityDO::getId));
|
||||
}
|
||||
|
||||
default List<RewardActivityDO> selectListBySpuIdsAndStatus(Collection<Long> spuIds, Integer status) {
|
||||
default List<RewardActivityDO> selectListBySpuIdAndStatusAndNow(Collection<Long> spuIds,
|
||||
Collection<Long> categoryIds,
|
||||
Integer status) {
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
Function<Collection<Long>, String> productScopeValuesFindInSetFunc = ids -> ids.stream()
|
||||
.map(id -> StrUtil.format("FIND_IN_SET({}, product_scope_values) ", id))
|
||||
.collect(Collectors.joining(" OR "));
|
||||
return selectList(new QueryWrapper<RewardActivityDO>()
|
||||
.eq("status", status)
|
||||
.apply(productScopeValuesFindInSetFunc.apply(spuIds)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定活动编号的活动列表且
|
||||
* 开始时间和结束时间小于给定时间 dateTime 的活动列表
|
||||
*
|
||||
* @param status 状态
|
||||
* @param dateTime 指定日期
|
||||
* @return 活动列表
|
||||
*/
|
||||
default List<RewardActivityDO> selectListByStatusAndDateTimeLt(Integer status, LocalDateTime dateTime) {
|
||||
return selectList(new LambdaQueryWrapperX<RewardActivityDO>()
|
||||
.eq(RewardActivityDO::getStatus, status)
|
||||
.lt(RewardActivityDO::getStartTime, dateTime)
|
||||
.gt(RewardActivityDO::getEndTime, dateTime)// 开始时间 < 指定时间 < 结束时间,也就是说获取指定时间段的活动
|
||||
.orderByAsc(RewardActivityDO::getStartTime)
|
||||
.lt(RewardActivityDO::getStartTime, now)
|
||||
.gt(RewardActivityDO::getEndTime, now)
|
||||
.and(i -> i.eq(RewardActivityDO::getProductScope, PromotionProductScopeEnum.SPU.getScope())
|
||||
.and(i1 -> i1.apply(productScopeValuesFindInSetFunc.apply(spuIds)))
|
||||
.or(i1 -> i1.eq(RewardActivityDO::getProductScope, PromotionProductScopeEnum.ALL.getScope()))
|
||||
.or(i1 -> i1.eq(RewardActivityDO::getProductScope, PromotionProductScopeEnum.CATEGORY.getScope())
|
||||
.and(i2 -> i2.apply(productScopeValuesFindInSetFunc.apply(categoryIds)))))
|
||||
.orderByDesc(RewardActivityDO::getId)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,15 +8,11 @@ import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityPageReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityPageReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillActivityDO;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 秒杀活动 Mapper
|
||||
@@ -35,9 +31,9 @@ public interface SeckillActivityMapper extends BaseMapperX<SeckillActivityDO> {
|
||||
.orderByDesc(SeckillActivityDO::getId));
|
||||
}
|
||||
|
||||
default List<SeckillActivityDO> selectListByStatus(Integer status) {
|
||||
return selectList(new LambdaQueryWrapperX<SeckillActivityDO>()
|
||||
.eqIfPresent(SeckillActivityDO::getStatus, status));
|
||||
default List<SeckillActivityDO> selectListBySpuIdAndStatus(Long spuId, Integer status) {
|
||||
return selectList(SeckillActivityDO::getSpuId, spuId,
|
||||
SeckillActivityDO::getStatus, status);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -51,7 +47,7 @@ public interface SeckillActivityMapper extends BaseMapperX<SeckillActivityDO> {
|
||||
Assert.isTrue(count > 0);
|
||||
return update(null, new LambdaUpdateWrapper<SeckillActivityDO>()
|
||||
.eq(SeckillActivityDO::getId, id)
|
||||
.gt(SeckillActivityDO::getStock, count)
|
||||
.ge(SeckillActivityDO::getStock, count)
|
||||
.setSql("stock = stock - " + count));
|
||||
}
|
||||
|
||||
@@ -69,41 +65,21 @@ public interface SeckillActivityMapper extends BaseMapperX<SeckillActivityDO> {
|
||||
.setSql("stock = stock + " + count));
|
||||
}
|
||||
|
||||
default PageResult<SeckillActivityDO> selectPage(AppSeckillActivityPageReqVO pageReqVO, Integer status) {
|
||||
default PageResult<SeckillActivityDO> selectPage(AppSeckillActivityPageReqVO pageReqVO, Integer status, LocalDateTime dateTime) {
|
||||
return selectPage(pageReqVO, new LambdaQueryWrapperX<SeckillActivityDO>()
|
||||
.eqIfPresent(SeckillActivityDO::getStatus, status)
|
||||
.lt(SeckillActivityDO::getStartTime, dateTime)
|
||||
.gt(SeckillActivityDO::getEndTime, dateTime)// 开始时间 < 指定时间 < 结束时间,也就是说获取指定时间段的活动
|
||||
.apply(ObjectUtil.isNotNull(pageReqVO.getConfigId()), "FIND_IN_SET(" + pageReqVO.getConfigId() + ",config_ids) > 0"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询出指定 spuId 的 spu 参加的活动最接近现在的一条记录。多个的话,一个 spuId 对应一个最近的活动编号
|
||||
*
|
||||
* @param spuIds spu 编号
|
||||
* @param status 状态
|
||||
* @return 包含 spuId 和 activityId 的 map 对象列表
|
||||
*/
|
||||
default List<Map<String, Object>> selectSpuIdAndActivityIdMapsBySpuIdsAndStatus(@Param("spuIds") Collection<Long> spuIds, @Param("status") Integer status) {
|
||||
return selectMaps(new QueryWrapper<SeckillActivityDO>()
|
||||
.select("spu_id AS spuId, MAX(DISTINCT(id)) AS activityId") // 时间越大 id 也越大 直接用 id
|
||||
.in("spu_id", spuIds)
|
||||
.eq("status", status)
|
||||
.groupBy("spu_id"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定活动编号的活动列表且
|
||||
* 开始时间和结束时间小于给定时间 dateTime 的活动列表
|
||||
*
|
||||
* @param ids 活动编号
|
||||
* @param dateTime 指定日期
|
||||
* @return 活动列表
|
||||
*/
|
||||
default List<SeckillActivityDO> selectListByIdsAndDateTimeLt(Collection<Long> ids, LocalDateTime dateTime) {
|
||||
return selectList(new LambdaQueryWrapperX<SeckillActivityDO>()
|
||||
.in(SeckillActivityDO::getId, ids)
|
||||
.lt(SeckillActivityDO::getStartTime, dateTime)
|
||||
.gt(SeckillActivityDO::getEndTime, dateTime)// 开始时间 < 指定时间 < 结束时间,也就是说获取指定时间段的活动
|
||||
.orderByDesc(SeckillActivityDO::getCreateTime));
|
||||
default SeckillActivityDO selectBySpuIdAndStatusAndNow(Long spuId, Integer status) {
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
return selectOne(new LambdaQueryWrapperX<SeckillActivityDO>()
|
||||
.eq(SeckillActivityDO::getSpuId, spuId)
|
||||
.eq(SeckillActivityDO::getStatus, status)
|
||||
.lt(SeckillActivityDO::getStartTime, now)
|
||||
.gt(SeckillActivityDO::getEndTime, now)); // 开始时间 < now < 结束时间,也就是说获取指定时间段的活动
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,8 +8,6 @@ import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity.Ba
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO;
|
||||
import jakarta.validation.Valid;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -108,13 +106,11 @@ public interface BargainActivityService {
|
||||
List<BargainActivityDO> getBargainActivityListByCount(Integer count);
|
||||
|
||||
/**
|
||||
* 获取指定 spu 编号最近参加的活动,每个 spuId 只返回一条记录
|
||||
* 获得 SPU 进行中的砍价活动
|
||||
*
|
||||
* @param spuIds spu 编号
|
||||
* @param status 状态
|
||||
* @param dateTime 日期时间
|
||||
* @return 砍价活动列表
|
||||
* @param spuId SPU 编号数组
|
||||
* @return 砍价活动
|
||||
*/
|
||||
List<BargainActivityDO> getBargainActivityBySpuIdsAndStatusAndDateTimeLt(Collection<Long> spuIds, Integer status, LocalDateTime dateTime);
|
||||
BargainActivityDO getMatchBargainActivityBySpuId(Long spuId);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package cn.iocoder.yudao.module.promotion.service.bargain;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
@@ -21,11 +19,11 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.anyMatch;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
|
||||
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS;
|
||||
import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
|
||||
|
||||
@@ -194,15 +192,8 @@ public class BargainActivityServiceImpl implements BargainActivityService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BargainActivityDO> getBargainActivityBySpuIdsAndStatusAndDateTimeLt(Collection<Long> spuIds, Integer status, LocalDateTime dateTime) {
|
||||
// 1. 查询出指定 spuId 的 spu 参加的活动最接近现在的一条记录。多个的话,一个 spuId 对应一个最近的活动编号
|
||||
List<Map<String, Object>> spuIdAndActivityIdMaps = bargainActivityMapper.selectSpuIdAndActivityIdMapsBySpuIdsAndStatus(spuIds, status);
|
||||
if (CollUtil.isEmpty(spuIdAndActivityIdMaps)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
// 2. 查询活动详情
|
||||
return bargainActivityMapper.selectListByIdsAndDateTimeLt(
|
||||
convertSet(spuIdAndActivityIdMaps, map -> MapUtil.getLong(map, "activityId")), dateTime);
|
||||
public BargainActivityDO getMatchBargainActivityBySpuId(Long spuId) {
|
||||
return bargainActivityMapper.selectBySpuIdAndStatusAndNow(spuId, CommonStatusEnum.ENABLE.getStatus());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationA
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationProductDO;
|
||||
import jakarta.validation.Valid;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -109,22 +108,20 @@ public interface CombinationActivityService {
|
||||
PageResult<CombinationActivityDO> getCombinationActivityPage(PageParam pageParam);
|
||||
|
||||
/**
|
||||
* 获取指定活动、指定 sku 编号的商品
|
||||
* 获取指定活动、指定 SKU 编号的商品
|
||||
*
|
||||
* @param activityId 活动编号
|
||||
* @param skuId sku 编号
|
||||
* @param skuId SKU 编号
|
||||
* @return 活动商品信息
|
||||
*/
|
||||
CombinationProductDO selectByActivityIdAndSkuId(Long activityId, Long skuId);
|
||||
|
||||
/**
|
||||
* 获取指定 spu 编号最近参加的活动,每个 spuId 只返回一条记录
|
||||
* 获得 SPU 进行中的拼团活动
|
||||
*
|
||||
* @param spuIds spu 编号
|
||||
* @param status 状态
|
||||
* @param dateTime 日期时间
|
||||
* @return 拼团活动列表
|
||||
* @param spuId SPU 编号数组
|
||||
* @return 拼团活动
|
||||
*/
|
||||
List<CombinationActivityDO> getCombinationActivityBySpuIdsAndStatusAndDateTimeLt(Collection<Long> spuIds, Integer status, LocalDateTime dateTime);
|
||||
CombinationActivityDO getMatchCombinationActivityBySpuId(Long spuId);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package cn.iocoder.yudao.module.promotion.service.combination;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
@@ -25,14 +24,13 @@ import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList;
|
||||
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS;
|
||||
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS;
|
||||
import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
|
||||
@@ -178,7 +176,7 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
|
||||
combinationProductMapper.updateBatch(diffList.get(1));
|
||||
}
|
||||
if (CollUtil.isNotEmpty(diffList.get(2))) {
|
||||
combinationProductMapper.deleteBatchIds(CollectionUtils.convertList(diffList.get(2), CombinationProductDO::getId));
|
||||
combinationProductMapper.deleteByIds(CollectionUtils.convertList(diffList.get(2), CombinationProductDO::getId));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,15 +236,8 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CombinationActivityDO> getCombinationActivityBySpuIdsAndStatusAndDateTimeLt(Collection<Long> spuIds, Integer status, LocalDateTime dateTime) {
|
||||
// 1.查询出指定 spuId 的 spu 参加的活动最接近现在的一条记录。多个的话,一个 spuId 对应一个最近的活动编号
|
||||
List<Map<String, Object>> spuIdAndActivityIdMaps = combinationActivityMapper.selectSpuIdAndActivityIdMapsBySpuIdsAndStatus(spuIds, status);
|
||||
if (CollUtil.isEmpty(spuIdAndActivityIdMaps)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
// 2.查询活动详情
|
||||
return combinationActivityMapper.selectListByIdsAndDateTimeLt(
|
||||
convertSet(spuIdAndActivityIdMaps, map -> MapUtil.getLong(map, "activityId")), dateTime);
|
||||
public CombinationActivityDO getMatchCombinationActivityBySpuId(Long spuId) {
|
||||
return combinationActivityMapper.selectBySpuIdAndStatusAndNow(spuId, CommonStatusEnum.ENABLE.getStatus());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -279,7 +279,7 @@ public class CouponServiceImpl implements CouponService {
|
||||
}
|
||||
}
|
||||
// 校验领取方式
|
||||
if (ObjectUtil.notEqual(couponTemplate.getTakeType(), takeType.getValue())) {
|
||||
if (ObjectUtil.notEqual(couponTemplate.getTakeType(), takeType.getType())) {
|
||||
throw exception(COUPON_TEMPLATE_CANNOT_TAKE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,8 +57,10 @@ public class CouponTemplateServiceImpl implements CouponTemplateService {
|
||||
public void updateCouponTemplate(CouponTemplateUpdateReqVO updateReqVO) {
|
||||
// 校验存在
|
||||
CouponTemplateDO couponTemplate = validateCouponTemplateExists(updateReqVO.getId());
|
||||
// 校验发放数量不能过小
|
||||
if (updateReqVO.getTotalCount() < couponTemplate.getTakeCount()) {
|
||||
// 校验发放数量不能过小(仅在 CouponTakeTypeEnum.USER 用户领取时)
|
||||
if (CouponTakeTypeEnum.isUser(couponTemplate.getTakeType())
|
||||
&& updateReqVO.getTotalCount() > 0 // 大于 0 的原因,是因为 -1 不限制
|
||||
&& updateReqVO.getTotalCount() < couponTemplate.getTakeCount()) {
|
||||
throw exception(COUPON_TEMPLATE_TOTAL_COUNT_TOO_SMALL, couponTemplate.getTakeCount());
|
||||
}
|
||||
// 校验商品范围
|
||||
@@ -118,7 +120,7 @@ public class CouponTemplateServiceImpl implements CouponTemplateService {
|
||||
|
||||
@Override
|
||||
public List<CouponTemplateDO> getCouponTemplateListByTakeType(CouponTakeTypeEnum takeType) {
|
||||
return couponTemplateMapper.selectListByTakeType(takeType.getValue());
|
||||
return couponTemplateMapper.selectListByTakeType(takeType.getType());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -8,7 +8,6 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivit
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO;
|
||||
import jakarta.validation.Valid;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
@@ -27,7 +26,7 @@ public interface DiscountActivityService {
|
||||
* @param skuIds SKU 编号数组
|
||||
* @return 匹配的限时折扣商品
|
||||
*/
|
||||
List<DiscountProductDO> getMatchDiscountProductList(Collection<Long> skuIds);
|
||||
List<DiscountProductDO> getMatchDiscountProductListBySkuIds(Collection<Long> skuIds);
|
||||
|
||||
/**
|
||||
* 创建限时折扣活动
|
||||
@@ -90,15 +89,4 @@ public interface DiscountActivityService {
|
||||
*/
|
||||
List<DiscountProductDO> getDiscountProductsByActivityId(Collection<Long> activityIds);
|
||||
|
||||
/**
|
||||
* 获取指定 spu 编号最近参加的活动,每个 spuId 只返回一条记录
|
||||
*
|
||||
* @param spuIds spu 编号
|
||||
* @param status 状态
|
||||
* @param dateTime 当前日期时间
|
||||
* @return 折扣活动列表
|
||||
*/
|
||||
List<DiscountActivityDO> getDiscountActivityBySpuIdsAndStatusAndDateTimeLt(
|
||||
Collection<Long> spuIds, Integer status, LocalDateTime dateTime);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
package cn.iocoder.yudao.module.promotion.service.discount;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
|
||||
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityBaseVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityCreateReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityPageReqVO;
|
||||
@@ -15,23 +17,20 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivit
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO;
|
||||
import cn.iocoder.yudao.module.promotion.dal.mysql.discount.DiscountActivityMapper;
|
||||
import cn.iocoder.yudao.module.promotion.dal.mysql.discount.DiscountProductMapper;
|
||||
import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum;
|
||||
import cn.iocoder.yudao.module.promotion.util.PromotionUtils;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.hutool.core.collection.CollUtil.intersectionDistinct;
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen;
|
||||
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS;
|
||||
import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
|
||||
|
||||
/**
|
||||
@@ -48,16 +47,16 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
|
||||
@Resource
|
||||
private DiscountProductMapper discountProductMapper;
|
||||
|
||||
@Override
|
||||
public List<DiscountProductDO> getMatchDiscountProductList(Collection<Long> skuIds) {
|
||||
return discountProductMapper.getMatchDiscountProductList(skuIds);
|
||||
}
|
||||
@Resource
|
||||
private ProductSkuApi productSkuApi;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Long createDiscountActivity(DiscountActivityCreateReqVO createReqVO) {
|
||||
// 校验商品是否冲突
|
||||
validateDiscountActivityProductConflicts(null, createReqVO.getProducts());
|
||||
// 校验商品是否存在
|
||||
validateProductExists(createReqVO.getProducts());
|
||||
|
||||
// 插入活动
|
||||
DiscountActivityDO discountActivity = DiscountActivityConvert.INSTANCE.convert(createReqVO)
|
||||
@@ -65,7 +64,8 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
|
||||
discountActivityMapper.insert(discountActivity);
|
||||
// 插入商品
|
||||
List<DiscountProductDO> discountProducts = BeanUtils.toBean(createReqVO.getProducts(), DiscountProductDO.class,
|
||||
product -> product.setActivityId(discountActivity.getId()).setActivityStatus(discountActivity.getStatus())
|
||||
product -> product.setActivityId(discountActivity.getId())
|
||||
.setActivityName(discountActivity.getName()).setActivityStatus(discountActivity.getStatus())
|
||||
.setActivityStartTime(createReqVO.getStartTime()).setActivityEndTime(createReqVO.getEndTime()));
|
||||
discountProductMapper.insertBatch(discountProducts);
|
||||
// 返回
|
||||
@@ -82,36 +82,40 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
|
||||
}
|
||||
// 校验商品是否冲突
|
||||
validateDiscountActivityProductConflicts(updateReqVO.getId(), updateReqVO.getProducts());
|
||||
// 校验商品是否存在
|
||||
validateProductExists(updateReqVO.getProducts());
|
||||
|
||||
// 更新活动
|
||||
DiscountActivityDO updateObj = DiscountActivityConvert.INSTANCE.convert(updateReqVO)
|
||||
.setStatus(PromotionUtils.calculateActivityStatus(updateReqVO.getEndTime()));
|
||||
DiscountActivityDO updateObj = DiscountActivityConvert.INSTANCE.convert(updateReqVO);
|
||||
discountActivityMapper.updateById(updateObj);
|
||||
// 更新商品
|
||||
updateDiscountProduct(updateReqVO);
|
||||
updateDiscountProduct(updateObj, updateReqVO.getProducts());
|
||||
}
|
||||
|
||||
private void updateDiscountProduct(DiscountActivityUpdateReqVO updateReqVO) {
|
||||
// TODO @zhangshuai:这里的逻辑,可以优化下哈;参考 CombinationActivityServiceImpl 的 updateCombinationProduct,主要是 CollectionUtils.diffList 的使用哈;
|
||||
// 然后原先是使用 DiscountActivityConvert.INSTANCE.isEquals 对比,现在看看是不是简化就基于 skuId 对比就完事了;之前写的太精细,意义不大;
|
||||
List<DiscountProductDO> dbDiscountProducts = discountProductMapper.selectListByActivityId(updateReqVO.getId());
|
||||
// 计算要删除的记录
|
||||
List<Long> deleteIds = convertList(dbDiscountProducts, DiscountProductDO::getId,
|
||||
discountProductDO -> updateReqVO.getProducts().stream()
|
||||
.noneMatch(product -> DiscountActivityConvert.INSTANCE.isEquals(discountProductDO, product)));
|
||||
if (CollUtil.isNotEmpty(deleteIds)) {
|
||||
discountProductMapper.deleteBatchIds(deleteIds);
|
||||
private void updateDiscountProduct(DiscountActivityDO activity, List<DiscountActivityCreateReqVO.Product> products) {
|
||||
// 第一步,对比新老数据,获得添加、修改、删除的列表
|
||||
List<DiscountProductDO> newList = BeanUtils.toBean(products, DiscountProductDO.class,
|
||||
product -> product.setActivityId(activity.getId())
|
||||
.setActivityName(activity.getName()).setActivityStatus(activity.getStatus())
|
||||
.setActivityStartTime(activity.getStartTime()).setActivityEndTime(activity.getEndTime()));
|
||||
List<DiscountProductDO> oldList = discountProductMapper.selectListByActivityId(activity.getId());
|
||||
List<List<DiscountProductDO>> diffList = CollectionUtils.diffList(oldList, newList, (oldVal, newVal) -> {
|
||||
boolean same = ObjectUtil.equal(oldVal.getSkuId(), newVal.getSkuId());
|
||||
if (same) {
|
||||
newVal.setId(oldVal.getId());
|
||||
}
|
||||
return same;
|
||||
});
|
||||
|
||||
// 第二步,批量添加、修改、删除
|
||||
if (CollUtil.isNotEmpty(diffList.get(0))) {
|
||||
discountProductMapper.insertBatch(diffList.get(0));
|
||||
}
|
||||
// 计算新增的记录
|
||||
List<DiscountProductDO> newDiscountProducts = convertList(updateReqVO.getProducts(),
|
||||
product -> DiscountActivityConvert.INSTANCE.convert(product)
|
||||
.setActivityId(updateReqVO.getId())
|
||||
.setActivityStartTime(updateReqVO.getStartTime())
|
||||
.setActivityEndTime(updateReqVO.getEndTime()));
|
||||
newDiscountProducts.removeIf(product -> dbDiscountProducts.stream().anyMatch(
|
||||
dbProduct -> DiscountActivityConvert.INSTANCE.isEquals(dbProduct, product))); // 如果匹配到,说明是更新的
|
||||
if (CollectionUtil.isNotEmpty(newDiscountProducts)) {
|
||||
discountProductMapper.insertBatch(newDiscountProducts);
|
||||
if (CollUtil.isNotEmpty(diffList.get(1))) {
|
||||
discountProductMapper.updateBatch(diffList.get(1));
|
||||
}
|
||||
if (CollUtil.isNotEmpty(diffList.get(2))) {
|
||||
discountProductMapper.deleteByIds(convertList(diffList.get(2), DiscountProductDO::getId));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,22 +126,44 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
|
||||
* @param products 商品列表
|
||||
*/
|
||||
private void validateDiscountActivityProductConflicts(Long id, List<DiscountActivityBaseVO.Product> products) {
|
||||
if (CollUtil.isEmpty(products)) {
|
||||
return;
|
||||
}
|
||||
// 查询商品参加的活动
|
||||
// TODO @zhangshuai:下面 121 这个查询,是不是不用做呀;直接 convert 出 skuId 集合就 ok 啦;
|
||||
List<DiscountProductDO> list = discountProductMapper.selectListByActivityId(id);
|
||||
// TODO @zhangshuai:一般简单的 stream 方法,建议是使用 CollectionUtils,例如说这里是 convertList 对把。
|
||||
List<Long> skuIds = list.stream().map(item -> item.getSkuId()).collect(Collectors.toList());
|
||||
List<DiscountProductDO> matchDiscountProductList = getMatchDiscountProductList(skuIds);
|
||||
if (id != null) { // 排除自己这个活动
|
||||
matchDiscountProductList.removeIf(product -> id.equals(product.getActivityId()));
|
||||
}
|
||||
// 如果非空,则说明冲突
|
||||
if (CollUtil.isNotEmpty(matchDiscountProductList)) {
|
||||
throw exception(DISCOUNT_ACTIVITY_SPU_CONFLICTS);
|
||||
// 1.1 查询所有开启的折扣活动
|
||||
List<DiscountActivityDO> activityList = discountActivityMapper.selectList(DiscountActivityDO::getStatus,
|
||||
CommonStatusEnum.ENABLE.getStatus());
|
||||
if (id != null) { // 时排除自己
|
||||
activityList.removeIf(item -> ObjectUtil.equal(item.getId(), id));
|
||||
}
|
||||
// 1.2 查询活动下的所有商品
|
||||
List<DiscountProductDO> productList = discountProductMapper.selectListByActivityId(
|
||||
convertList(activityList, DiscountActivityDO::getId));
|
||||
Map<Long, List<DiscountProductDO>> productListMap = convertMultiMap(productList, DiscountProductDO::getActivityId);
|
||||
|
||||
// 2. 校验商品是否冲突
|
||||
activityList.forEach(item -> {
|
||||
findAndThen(productListMap, item.getId(), discountProducts -> {
|
||||
if (!intersectionDistinct(convertList(discountProducts, DiscountProductDO::getSpuId),
|
||||
convertList(products, DiscountActivityBaseVO.Product::getSpuId)).isEmpty()) {
|
||||
throw exception(DISCOUNT_ACTIVITY_SPU_CONFLICTS, item.getName());
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验活动商品是否都存在
|
||||
*
|
||||
* @param products 活动商品
|
||||
*/
|
||||
private void validateProductExists(List<DiscountActivityBaseVO.Product> products) {
|
||||
// 1.获得商品所有的 sku
|
||||
List<ProductSkuRespDTO> skus = productSkuApi.getSkuListBySpuId(
|
||||
convertList(products, DiscountActivityBaseVO.Product::getSpuId)).getCheckedData();
|
||||
Map<Long, ProductSkuRespDTO> skuMap = convertMap(skus, ProductSkuRespDTO::getId);
|
||||
// 2. 校验商品 sku 都存在
|
||||
products.forEach(product -> {
|
||||
if (!skuMap.containsKey(product.getSkuId())) {
|
||||
throw exception(SKU_NOT_EXISTS);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -148,9 +174,11 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
|
||||
throw exception(DISCOUNT_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED);
|
||||
}
|
||||
|
||||
// 更新
|
||||
DiscountActivityDO updateObj = new DiscountActivityDO().setId(id).setStatus(PromotionActivityStatusEnum.CLOSE.getStatus());
|
||||
discountActivityMapper.updateById(updateObj);
|
||||
// 更新活动状态
|
||||
discountActivityMapper.updateById(new DiscountActivityDO().setId(id).setStatus(CommonStatusEnum.DISABLE.getStatus()));
|
||||
// 更新活动商品状态
|
||||
discountProductMapper.updateByActivityId(new DiscountProductDO().setActivityId(id).setActivityStatus(
|
||||
CommonStatusEnum.DISABLE.getStatus()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -161,8 +189,10 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
|
||||
throw exception(DISCOUNT_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED);
|
||||
}
|
||||
|
||||
// 删除
|
||||
// 删除活动
|
||||
discountActivityMapper.deleteById(id);
|
||||
// 删除活动商品
|
||||
discountProductMapper.deleteByActivityId(id);
|
||||
}
|
||||
|
||||
private DiscountActivityDO validateDiscountActivityExists(Long id) {
|
||||
@@ -190,20 +220,12 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
|
||||
|
||||
@Override
|
||||
public List<DiscountProductDO> getDiscountProductsByActivityId(Collection<Long> activityIds) {
|
||||
return discountProductMapper.selectList("activity_id", activityIds);
|
||||
return discountProductMapper.selectList(DiscountProductDO::getActivityId, activityIds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DiscountActivityDO> getDiscountActivityBySpuIdsAndStatusAndDateTimeLt(Collection<Long> spuIds, Integer status, LocalDateTime dateTime) {
|
||||
// 1. 查询出指定 spuId 的 spu 参加的活动最接近现在的一条记录。多个的话,一个 spuId 对应一个最近的活动编号
|
||||
List<Map<String, Object>> spuIdAndActivityIdMaps = discountProductMapper.selectSpuIdAndActivityIdMapsBySpuIdsAndStatus(spuIds, status);
|
||||
if (CollUtil.isEmpty(spuIdAndActivityIdMaps)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// 2. 查询活动详情
|
||||
return discountActivityMapper.selectListByIdsAndDateTimeLt(
|
||||
convertSet(spuIdAndActivityIdMaps, map -> MapUtil.getLong(map, "activityId")), dateTime);
|
||||
public List<DiscountProductDO> getMatchDiscountProductListBySkuIds(Collection<Long> skuIds) {
|
||||
return discountProductMapper.selectListBySkuIdsAndStatusAndNow(skuIds, CommonStatusEnum.ENABLE.getStatus());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
package cn.iocoder.yudao.module.promotion.service.point;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.point.vo.activity.PointActivityPageReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.point.vo.activity.PointActivitySaveReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.point.PointActivityDO;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.point.PointProductDO;
|
||||
import jakarta.validation.Valid;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 积分商城活动 Service 接口
|
||||
*
|
||||
* @author HUIHUI
|
||||
*/
|
||||
public interface PointActivityService {
|
||||
|
||||
/**
|
||||
* 创建积分商城活动
|
||||
*
|
||||
* @param createReqVO 创建信息
|
||||
* @return 编号
|
||||
*/
|
||||
Long createPointActivity(@Valid PointActivitySaveReqVO createReqVO);
|
||||
|
||||
/**
|
||||
* 更新积分商城活动
|
||||
*
|
||||
* @param updateReqVO 更新信息
|
||||
*/
|
||||
void updatePointActivity(@Valid PointActivitySaveReqVO updateReqVO);
|
||||
|
||||
/**
|
||||
* 关闭积分商城活动
|
||||
*
|
||||
* @param id 编号
|
||||
*/
|
||||
void closePointActivity(Long id);
|
||||
|
||||
/**
|
||||
* 删除积分商城活动
|
||||
*
|
||||
* @param id 编号
|
||||
*/
|
||||
void deletePointActivity(Long id);
|
||||
|
||||
/**
|
||||
* 获得积分商城活动
|
||||
*
|
||||
* @param id 编号
|
||||
* @return 积分商城活动
|
||||
*/
|
||||
PointActivityDO getPointActivity(Long id);
|
||||
|
||||
/**
|
||||
* 获得积分商城活动分页
|
||||
*
|
||||
* @param pageReqVO 分页查询
|
||||
* @return 积分商城活动分页
|
||||
*/
|
||||
PageResult<PointActivityDO> getPointActivityPage(PointActivityPageReqVO pageReqVO);
|
||||
|
||||
/**
|
||||
* 获得积分商城活动列表
|
||||
*
|
||||
* @param ids 活动编号
|
||||
* @return 积分商城活动列表
|
||||
*/
|
||||
List<PointActivityDO> getPointActivityListByIds(Collection<Long> ids);
|
||||
|
||||
/**
|
||||
* 获得活动商品
|
||||
*
|
||||
* @param activityIds 活动编号
|
||||
* @return 获得活动商品
|
||||
*/
|
||||
List<PointProductDO> getPointProductListByActivityIds(Collection<Long> activityIds);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,247 @@
|
||||
package cn.iocoder.yudao.module.promotion.service.point;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
|
||||
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
|
||||
import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
|
||||
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.point.vo.activity.PointActivityPageReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.point.vo.activity.PointActivitySaveReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.point.vo.product.PointProductSaveReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.point.PointActivityDO;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.point.PointProductDO;
|
||||
import cn.iocoder.yudao.module.promotion.dal.mysql.point.PointActivityMapper;
|
||||
import cn.iocoder.yudao.module.promotion.dal.mysql.point.PointProductMapper;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.hutool.core.collection.CollUtil.intersectionDistinct;
|
||||
import static cn.hutool.core.collection.CollUtil.isNotEmpty;
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen;
|
||||
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS;
|
||||
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS;
|
||||
import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
|
||||
import static java.util.Collections.singletonList;
|
||||
|
||||
/**
|
||||
* 积分商城活动 Service 实现类
|
||||
*
|
||||
* @author HUIHUI
|
||||
*/
|
||||
@Service
|
||||
@Validated
|
||||
public class PointActivityServiceImpl implements PointActivityService {
|
||||
|
||||
@Resource
|
||||
private PointActivityMapper pointActivityMapper;
|
||||
@Resource
|
||||
private PointProductMapper pointProductMapper;
|
||||
|
||||
@Resource
|
||||
private ProductSpuApi productSpuApi;
|
||||
@Resource
|
||||
private ProductSkuApi productSkuApi;
|
||||
|
||||
private static List<PointProductDO> buildPointProductDO(PointActivityDO pointActivity, List<PointProductSaveReqVO> products) {
|
||||
return BeanUtils.toBean(products, PointProductDO.class, product ->
|
||||
product.setSpuId(pointActivity.getSpuId()).setActivityId(pointActivity.getId())
|
||||
.setActivityStatus(pointActivity.getStatus()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Long createPointActivity(PointActivitySaveReqVO createReqVO) {
|
||||
// 1.1 校验商品是否存在
|
||||
validateProductExists(createReqVO.getSpuId(), createReqVO.getProducts());
|
||||
// 1.2 校验商品是否已经参加别的活动
|
||||
validatePointActivityProductConflicts(null, createReqVO.getProducts());
|
||||
|
||||
// 2.1 插入积分商城活动
|
||||
PointActivityDO pointActivity = BeanUtils.toBean(createReqVO, PointActivityDO.class)
|
||||
.setStatus(CommonStatusEnum.ENABLE.getStatus())
|
||||
.setStock(getSumValue(createReqVO.getProducts(), PointProductSaveReqVO::getStock, Integer::sum));
|
||||
pointActivity.setTotalStock(pointActivity.getStock());
|
||||
pointActivityMapper.insert(pointActivity);
|
||||
// 2.2 插入积分商城活动商品
|
||||
pointProductMapper.insertBatch(buildPointProductDO(pointActivity, createReqVO.getProducts()));
|
||||
return pointActivity.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void updatePointActivity(PointActivitySaveReqVO updateReqVO) {
|
||||
// 1.1 校验存在
|
||||
PointActivityDO activity = validatePointActivityExists(updateReqVO.getId());
|
||||
if (CommonStatusEnum.DISABLE.getStatus().equals(activity.getStatus())) {
|
||||
throw exception(POINT_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED);
|
||||
}
|
||||
// 1.2 校验商品是否存在
|
||||
validateProductExists(updateReqVO.getSpuId(), updateReqVO.getProducts());
|
||||
// 1.3 校验商品是否已经参加别的活动
|
||||
validatePointActivityProductConflicts(updateReqVO.getId(), updateReqVO.getProducts());
|
||||
|
||||
// 2.1 更新积分商城活动
|
||||
PointActivityDO updateObj = BeanUtils.toBean(updateReqVO, PointActivityDO.class)
|
||||
.setStock(getSumValue(updateReqVO.getProducts(), PointProductSaveReqVO::getStock, Integer::sum));
|
||||
if (updateObj.getStock() > activity.getTotalStock()) { // 如果更新的库存大于原来的库存,则更新总库存
|
||||
updateObj.setTotalStock(updateObj.getStock());
|
||||
}
|
||||
pointActivityMapper.updateById(updateObj);
|
||||
// 2.2 更新商品
|
||||
updateSeckillProduct(updateObj, updateReqVO.getProducts());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void closePointActivity(Long id) {
|
||||
// 校验存在
|
||||
PointActivityDO pointActivity = validatePointActivityExists(id);
|
||||
if (CommonStatusEnum.DISABLE.getStatus().equals(pointActivity.getStatus())) {
|
||||
throw exception(POINT_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED);
|
||||
}
|
||||
|
||||
// 更新
|
||||
pointActivityMapper.updateById(new PointActivityDO().setId(id).setStatus(CommonStatusEnum.DISABLE.getStatus()));
|
||||
// 更新活动商品状态
|
||||
pointProductMapper.updateByActivityId(new PointProductDO().setActivityId(id).setActivityStatus(
|
||||
CommonStatusEnum.DISABLE.getStatus()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新秒杀商品
|
||||
*
|
||||
* @param activity 秒杀活动
|
||||
* @param products 该活动的最新商品配置
|
||||
*/
|
||||
private void updateSeckillProduct(PointActivityDO activity, List<PointProductSaveReqVO> products) {
|
||||
// 第一步,对比新老数据,获得添加、修改、删除的列表
|
||||
List<PointProductDO> newList = buildPointProductDO(activity, products);
|
||||
List<PointProductDO> oldList = pointProductMapper.selectListByActivityId(activity.getId());
|
||||
List<List<PointProductDO>> diffList = diffList(oldList, newList, (oldVal, newVal) -> {
|
||||
boolean same = ObjectUtil.equal(oldVal.getSkuId(), newVal.getSkuId());
|
||||
if (same) {
|
||||
newVal.setId(oldVal.getId());
|
||||
}
|
||||
return same;
|
||||
});
|
||||
|
||||
// 第二步,批量添加、修改、删除
|
||||
if (isNotEmpty(diffList.get(0))) {
|
||||
pointProductMapper.insertBatch(diffList.get(0));
|
||||
}
|
||||
if (isNotEmpty(diffList.get(1))) {
|
||||
pointProductMapper.updateBatch(diffList.get(1));
|
||||
}
|
||||
if (isNotEmpty(diffList.get(2))) {
|
||||
pointProductMapper.deleteByIds(convertList(diffList.get(2), PointProductDO::getId));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void deletePointActivity(Long id) {
|
||||
// 校验存在
|
||||
PointActivityDO pointActivity = validatePointActivityExists(id);
|
||||
if (CommonStatusEnum.ENABLE.getStatus().equals(pointActivity.getStatus())) {
|
||||
throw exception(POINT_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END);
|
||||
}
|
||||
|
||||
// 删除商城活动
|
||||
pointActivityMapper.deleteById(id);
|
||||
// 删除活动商品
|
||||
List<PointProductDO> products = pointProductMapper.selectListByActivityId(id);
|
||||
pointProductMapper.deleteByIds(convertSet(products, PointProductDO::getId));
|
||||
}
|
||||
|
||||
private PointActivityDO validatePointActivityExists(Long id) {
|
||||
PointActivityDO pointActivityDO = pointActivityMapper.selectById(id);
|
||||
if (pointActivityDO == null) {
|
||||
throw exception(POINT_ACTIVITY_NOT_EXISTS);
|
||||
}
|
||||
return pointActivityDO;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验秒杀商品是否都存在
|
||||
*
|
||||
* @param spuId 商品 SPU 编号
|
||||
* @param products 秒杀商品
|
||||
*/
|
||||
private void validateProductExists(Long spuId, List<PointProductSaveReqVO> products) {
|
||||
// 1. 校验商品 spu 是否存在
|
||||
ProductSpuRespDTO spu = productSpuApi.getSpu(spuId).getCheckedData();
|
||||
if (spu == null) {
|
||||
throw exception(SPU_NOT_EXISTS);
|
||||
}
|
||||
|
||||
// 2. 校验商品 sku 都存在
|
||||
List<ProductSkuRespDTO> skus = productSkuApi.getSkuListBySpuId(singletonList(spuId)).getCheckedData();
|
||||
Map<Long, ProductSkuRespDTO> skuMap = convertMap(skus, ProductSkuRespDTO::getId);
|
||||
products.forEach(product -> {
|
||||
if (!skuMap.containsKey(product.getSkuId())) {
|
||||
throw exception(SKU_NOT_EXISTS);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验商品是否冲突
|
||||
*
|
||||
* @param id 编号
|
||||
* @param products 商品列表
|
||||
*/
|
||||
private void validatePointActivityProductConflicts(Long id, List<PointProductSaveReqVO> products) {
|
||||
// 1.1 查询所有开启的积分商城活动
|
||||
List<PointActivityDO> activityList = pointActivityMapper.selectList(PointActivityDO::getStatus,
|
||||
CommonStatusEnum.ENABLE.getStatus());
|
||||
if (id != null) { // 更新时排除自己
|
||||
activityList.removeIf(item -> ObjectUtil.equal(item.getId(), id));
|
||||
}
|
||||
// 1.2 查询活动下的所有商品
|
||||
List<PointProductDO> productList = pointProductMapper.selectListByActivityId(
|
||||
convertList(activityList, PointActivityDO::getId));
|
||||
Map<Long, List<PointProductDO>> productListMap = convertMultiMap(productList, PointProductDO::getActivityId);
|
||||
|
||||
// 2. 校验商品是否冲突
|
||||
activityList.forEach(item -> {
|
||||
findAndThen(productListMap, item.getId(), discountProducts -> {
|
||||
if (!intersectionDistinct(convertList(discountProducts, PointProductDO::getSpuId),
|
||||
convertList(products, PointProductSaveReqVO::getSpuId)).isEmpty()) {
|
||||
throw exception(POINT_ACTIVITY_SPU_CONFLICTS);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public PointActivityDO getPointActivity(Long id) {
|
||||
return pointActivityMapper.selectById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<PointActivityDO> getPointActivityPage(PointActivityPageReqVO pageReqVO) {
|
||||
return pointActivityMapper.selectPage(pageReqVO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PointActivityDO> getPointActivityListByIds(Collection<Long> ids) {
|
||||
return pointActivityMapper.selectList(PointActivityDO::getId, ids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PointProductDO> getPointProductListByActivityIds(Collection<Long> activityIds) {
|
||||
return pointProductMapper.selectListByActivityId(activityIds);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,17 +1,23 @@
|
||||
package cn.iocoder.yudao.module.promotion.service.reward;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.number.MoneyUtils;
|
||||
import cn.iocoder.yudao.module.promotion.api.reward.dto.RewardActivityMatchRespDTO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityCreateReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityPageReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityUpdateReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO;
|
||||
import cn.iocoder.yudao.module.promotion.enums.common.PromotionConditionTypeEnum;
|
||||
import jakarta.validation.Valid;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getSumValue;
|
||||
|
||||
/**
|
||||
* 满减送活动 Service 接口
|
||||
*
|
||||
@@ -65,20 +71,35 @@ public interface RewardActivityService {
|
||||
PageResult<RewardActivityDO> getRewardActivityPage(RewardActivityPageReqVO pageReqVO);
|
||||
|
||||
/**
|
||||
* 基于指定的 SPU 编号数组,获得它们匹配的满减送活动
|
||||
* 获得 spuId 商品匹配的的满减送活动列表
|
||||
*
|
||||
* @param spuIds SPU 编号数组
|
||||
* @param spuIds SPU 编号数组
|
||||
* @return 满减送活动列表
|
||||
*/
|
||||
List<RewardActivityMatchRespDTO> getMatchRewardActivityList(Collection<Long> spuIds);
|
||||
List<RewardActivityMatchRespDTO> getMatchRewardActivityListBySpuIds(Collection<Long> spuIds);
|
||||
|
||||
/**
|
||||
* 获取指定 spu 编号最近参加的活动,每个 spuId 只返回一条记录
|
||||
*
|
||||
* @param status 状态
|
||||
* @param dateTime 当前日期时间
|
||||
* @return 满减送活动列表
|
||||
*/
|
||||
List<RewardActivityDO> getRewardActivityListByStatusAndDateTimeLt(Integer status, LocalDateTime dateTime);
|
||||
default String getRewardActivityRuleDescription(Integer conditionType, RewardActivityDO.Rule rule) {
|
||||
String description = "";
|
||||
if (PromotionConditionTypeEnum.PRICE.getType().equals(conditionType)) {
|
||||
description += StrUtil.format("满 {} 元", MoneyUtils.fenToYuanStr(rule.getLimit()));
|
||||
} else {
|
||||
description += StrUtil.format("满 {} 件", rule.getLimit());
|
||||
}
|
||||
List<String> tips = new ArrayList<>(10);
|
||||
if (rule.getDiscountPrice() != null) {
|
||||
tips.add(StrUtil.format("减 {}", MoneyUtils.fenToYuanStr(rule.getDiscountPrice())));
|
||||
}
|
||||
if (Boolean.TRUE.equals(rule.getFreeDelivery())) {
|
||||
tips.add("包邮");
|
||||
}
|
||||
if (rule.getPoint() != null && rule.getPoint() > 0) {
|
||||
tips.add(StrUtil.format("送 {} 积分", rule.getPoint()));
|
||||
}
|
||||
if (CollUtil.isNotEmpty(rule.getGiveCouponTemplateCounts())) {
|
||||
tips.add(StrUtil.format("送 {} 张优惠券",
|
||||
getSumValue(rule.getGiveCouponTemplateCounts().values(), count -> count, Integer::sum)));
|
||||
}
|
||||
return description + StrUtil.join("、", tips);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
package cn.iocoder.yudao.module.promotion.service.reward;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.product.api.category.ProductCategoryApi;
|
||||
import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
|
||||
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
|
||||
import cn.iocoder.yudao.module.promotion.api.reward.dto.RewardActivityMatchRespDTO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityBaseVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityCreateReqVO;
|
||||
@@ -13,19 +16,15 @@ import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivi
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO;
|
||||
import cn.iocoder.yudao.module.promotion.dal.mysql.reward.RewardActivityMapper;
|
||||
import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum;
|
||||
import cn.iocoder.yudao.module.promotion.util.PromotionUtils;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.*;
|
||||
|
||||
import static cn.hutool.core.collection.CollUtil.intersectionDistinct;
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.anyMatch;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
|
||||
import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
|
||||
|
||||
/**
|
||||
@@ -52,9 +51,9 @@ public class RewardActivityServiceImpl implements RewardActivityService {
|
||||
// 1.2 校验商品是否冲突
|
||||
validateRewardActivitySpuConflicts(null, createReqVO);
|
||||
|
||||
// 2. 插入
|
||||
// 插入
|
||||
RewardActivityDO rewardActivity = BeanUtils.toBean(createReqVO, RewardActivityDO.class)
|
||||
.setStatus(PromotionUtils.calculateActivityStatus(createReqVO.getEndTime()));
|
||||
.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
rewardActivityMapper.insert(rewardActivity);
|
||||
// 返回
|
||||
return rewardActivity.getId();
|
||||
@@ -73,8 +72,7 @@ public class RewardActivityServiceImpl implements RewardActivityService {
|
||||
validateRewardActivitySpuConflicts(updateReqVO.getId(), updateReqVO);
|
||||
|
||||
// 2. 更新
|
||||
RewardActivityDO updateObj = BeanUtils.toBean(updateReqVO, RewardActivityDO.class)
|
||||
.setStatus(PromotionUtils.calculateActivityStatus(updateReqVO.getEndTime()));
|
||||
RewardActivityDO updateObj = BeanUtils.toBean(updateReqVO, RewardActivityDO.class);
|
||||
rewardActivityMapper.updateById(updateObj);
|
||||
}
|
||||
|
||||
@@ -87,8 +85,7 @@ public class RewardActivityServiceImpl implements RewardActivityService {
|
||||
}
|
||||
|
||||
// 更新
|
||||
RewardActivityDO updateObj = new RewardActivityDO().setId(id).setStatus(CommonStatusEnum.DISABLE.getStatus());
|
||||
rewardActivityMapper.updateById(updateObj);
|
||||
rewardActivityMapper.updateById(new RewardActivityDO().setId(id).setStatus(CommonStatusEnum.DISABLE.getStatus()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -118,22 +115,61 @@ public class RewardActivityServiceImpl implements RewardActivityService {
|
||||
* @param rewardActivity 请求
|
||||
*/
|
||||
private void validateRewardActivitySpuConflicts(Long id, RewardActivityBaseVO rewardActivity) {
|
||||
List<RewardActivityDO> list = rewardActivityMapper.selectList(RewardActivityDO::getProductScope,
|
||||
rewardActivity.getProductScope(), RewardActivityDO::getStatus, CommonStatusEnum.ENABLE.getStatus());
|
||||
// 1. 获得开启的所有的活动
|
||||
List<RewardActivityDO> list = rewardActivityMapper.selectList(RewardActivityDO::getStatus, CommonStatusEnum.ENABLE.getStatus());
|
||||
if (id != null) { // 排除自己这个活动
|
||||
list.removeIf(activity -> id.equals(activity.getId()));
|
||||
}
|
||||
|
||||
// 情况一:全部商品参加
|
||||
if (PromotionProductScopeEnum.isAll(rewardActivity.getProductScope()) && !list.isEmpty()) {
|
||||
throw exception(REWARD_ACTIVITY_SCOPE_ALL_EXISTS);
|
||||
}
|
||||
if (PromotionProductScopeEnum.isSpu(rewardActivity.getProductScope()) || // 情况二:指定商品参加
|
||||
PromotionProductScopeEnum.isCategory(rewardActivity.getProductScope())) { // 情况三:指定商品类型参加
|
||||
if (anyMatch(list, item -> !intersectionDistinct(item.getProductScopeValues(),
|
||||
rewardActivity.getProductScopeValues()).isEmpty())) {
|
||||
throw exception(PromotionProductScopeEnum.isSpu(rewardActivity.getProductScope()) ?
|
||||
REWARD_ACTIVITY_SPU_CONFLICTS : REWARD_ACTIVITY_SCOPE_CATEGORY_EXISTS);
|
||||
// 2. 完全不允许重叠
|
||||
for (RewardActivityDO item : list) {
|
||||
// 2.1 校验满减送活动时间是否冲突,如果时段不冲突那么不同的时间段内则可以存在相同的商品范围
|
||||
if (!LocalDateTimeUtil.isOverlap(item.getStartTime(), item.getEndTime(),
|
||||
rewardActivity.getStartTime(), rewardActivity.getEndTime())) {
|
||||
continue;
|
||||
}
|
||||
// 2.2 校验商品范围是否重叠
|
||||
// 情况一:如果与该时间段内商品范围为全部的活动冲突,或 rewardActivity 商品范围为全部,那么则直接校验不通过
|
||||
// 例如说,rewardActivity 是全部活动,结果有个 db 里的 activity 是某个分类,它也是冲突的。也就是说,当前时间段内,有且仅有只能有一个活动!
|
||||
if (PromotionProductScopeEnum.isAll(item.getProductScope()) ||
|
||||
PromotionProductScopeEnum.isAll(rewardActivity.getProductScope())) {
|
||||
throw exception(REWARD_ACTIVITY_SCOPE_EXISTS, item.getName(),
|
||||
PromotionProductScopeEnum.isAll(item.getProductScope()) ?
|
||||
"该活动商品范围为全部已覆盖包含本活动范围" : "本活动商品范围为全部已覆盖包含了该活动商品范围");
|
||||
}
|
||||
// 情况二:如果与该时间段内商品范围为类别的活动冲突
|
||||
if (PromotionProductScopeEnum.isCategory(item.getProductScope())) {
|
||||
// 校验分类是否冲突
|
||||
if (PromotionProductScopeEnum.isCategory(rewardActivity.getProductScope())) {
|
||||
if (!intersectionDistinct(item.getProductScopeValues(), rewardActivity.getProductScopeValues()).isEmpty()) {
|
||||
throw exception(REWARD_ACTIVITY_SCOPE_EXISTS, item.getName(), "商品分类范围重叠");
|
||||
}
|
||||
}
|
||||
// 校验商品分类是否冲突
|
||||
if (PromotionProductScopeEnum.isSpu(rewardActivity.getProductScope())) {
|
||||
List<ProductSpuRespDTO> spuList = productSpuApi.getSpuList(rewardActivity.getProductScopeValues()).getCheckedData();
|
||||
if (!intersectionDistinct(item.getProductScopeValues(),
|
||||
convertSet(spuList, ProductSpuRespDTO::getCategoryId)).isEmpty()) {
|
||||
throw exception(REWARD_ACTIVITY_SCOPE_EXISTS, item.getName(), "该活动商品分类范围已包含本活动所选商品");
|
||||
}
|
||||
}
|
||||
}
|
||||
// 情况三:如果与该时间段内商品范围为商品的活动冲突
|
||||
if (PromotionProductScopeEnum.isSpu(item.getProductScope())) {
|
||||
// 校验商品是否冲突
|
||||
if (PromotionProductScopeEnum.isSpu(rewardActivity.getProductScope())) {
|
||||
if (!intersectionDistinct(item.getProductScopeValues(), rewardActivity.getProductScopeValues()).isEmpty()) {
|
||||
throw exception(REWARD_ACTIVITY_SCOPE_EXISTS, item.getName(), "活动商品范围所选商品重叠");
|
||||
}
|
||||
}
|
||||
// 校验商品分类是否冲突
|
||||
if (PromotionProductScopeEnum.isCategory(rewardActivity.getProductScope())) {
|
||||
List<ProductSpuRespDTO> spuList = productSpuApi.getSpuList(item.getProductScopeValues()).getCheckedData();
|
||||
if (!intersectionDistinct(rewardActivity.getProductScopeValues(),
|
||||
convertSet(spuList, ProductSpuRespDTO::getCategoryId)).isEmpty()) {
|
||||
throw exception(REWARD_ACTIVITY_SCOPE_EXISTS, item.getName(), "本活动商品分类范围包含了该活动所选商品");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -157,14 +193,47 @@ public class RewardActivityServiceImpl implements RewardActivityService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<RewardActivityMatchRespDTO> getMatchRewardActivityList(Collection<Long> spuIds) {
|
||||
List<RewardActivityDO> list = rewardActivityMapper.selectListBySpuIdsAndStatus(spuIds, CommonStatusEnum.ENABLE.getStatus());
|
||||
return BeanUtils.toBean(list, RewardActivityMatchRespDTO.class);
|
||||
}
|
||||
public List<RewardActivityMatchRespDTO> getMatchRewardActivityListBySpuIds(Collection<Long> spuIds) {
|
||||
// 1. 查询商品分类
|
||||
List<ProductSpuRespDTO> spuList = productSpuApi.getSpuList(spuIds).getCheckedData();
|
||||
if (CollUtil.isEmpty(spuList)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
Map<Long, ProductSpuRespDTO> spuMap = convertMap(spuList, ProductSpuRespDTO::getId);
|
||||
|
||||
@Override
|
||||
public List<RewardActivityDO> getRewardActivityListByStatusAndDateTimeLt(Integer status, LocalDateTime dateTime) {
|
||||
return rewardActivityMapper.selectListByStatusAndDateTimeLt(status, dateTime);
|
||||
// 2. 查询出指定 spuId 的 spu 参加的活动
|
||||
List<RewardActivityDO> activityList = rewardActivityMapper.selectListBySpuIdAndStatusAndNow(
|
||||
spuIds, convertSet(spuList, ProductSpuRespDTO::getCategoryId), CommonStatusEnum.ENABLE.getStatus());
|
||||
if (CollUtil.isEmpty(activityList)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// 3. 转换成 Response DTO
|
||||
return convertList(activityList, activity -> {
|
||||
RewardActivityMatchRespDTO activityDTO = BeanUtils.toBean(activity, RewardActivityMatchRespDTO.class);
|
||||
// 3.1 设置对应匹配的 spuIds
|
||||
activityDTO.setSpuIds(new ArrayList<>());
|
||||
for (Long spuId : spuIds) {
|
||||
if (PromotionProductScopeEnum.isAll(activityDTO.getProductScope())) {
|
||||
activityDTO.getSpuIds().add(spuId);
|
||||
} else if (PromotionProductScopeEnum.isSpu(activityDTO.getProductScope())) {
|
||||
if (CollUtil.contains(activityDTO.getProductScopeValues(), spuId)) {
|
||||
activityDTO.getSpuIds().add(spuId);
|
||||
}
|
||||
} else if (PromotionProductScopeEnum.isCategory(activityDTO.getProductScope())) {
|
||||
ProductSpuRespDTO spu = spuMap.get(spuId);
|
||||
if (spu != null && CollUtil.contains(activityDTO.getProductScopeValues(), spu.getCategoryId())) {
|
||||
activityDTO.getSpuIds().add(spuId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3.2 设置每个 Rule 的描述
|
||||
activityDTO.setRules(convertList(activity.getRules(), rule ->
|
||||
BeanUtils.toBean(rule, RewardActivityMatchRespDTO.Rule.class)
|
||||
.setDescription(getRewardActivityRuleDescription(activityDTO.getConditionType(), rule))));
|
||||
return activityDTO;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillActivityD
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillProductDO;
|
||||
import jakarta.validation.Valid;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
@@ -110,7 +109,7 @@ public interface SeckillActivityService {
|
||||
List<SeckillActivityDO> getSeckillActivityListByConfigIdAndStatus(Long configId, Integer status);
|
||||
|
||||
/**
|
||||
* 通过活动时段获取秒杀活动
|
||||
* 通过活动时段获取开始的秒杀活动
|
||||
*
|
||||
* @param pageReqVO 请求
|
||||
* @return 秒杀活动列表
|
||||
@@ -130,14 +129,12 @@ public interface SeckillActivityService {
|
||||
SeckillValidateJoinRespDTO validateJoinSeckill(Long activityId, Long skuId, Integer count);
|
||||
|
||||
/**
|
||||
* 获取指定 spu 编号最近参加的活动,每个 spuId 只返回一条记录
|
||||
* 获得 SPU 进行中的秒杀活动
|
||||
*
|
||||
* @param spuIds spu 编号
|
||||
* @param status 状态
|
||||
* @param dateTime 日期时间
|
||||
* @return 秒杀活动列表
|
||||
* @param spuId SPU 编号数组
|
||||
* @return 秒杀活动
|
||||
*/
|
||||
List<SeckillActivityDO> getSeckillActivityBySpuIdsAndStatusAndDateTimeLt(Collection<Long> spuIds, Integer status, LocalDateTime dateTime);
|
||||
SeckillActivityDO getMatchSeckillActivityBySpuId(Long spuId);
|
||||
|
||||
/**
|
||||
* 获得拼团活动列表
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package cn.iocoder.yudao.module.promotion.service.seckill;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
@@ -30,7 +28,6 @@ import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -56,8 +53,10 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
|
||||
private SeckillActivityMapper seckillActivityMapper;
|
||||
@Resource
|
||||
private SeckillProductMapper seckillProductMapper;
|
||||
|
||||
@Resource
|
||||
private SeckillConfigService seckillConfigService;
|
||||
|
||||
@Resource
|
||||
private ProductSpuApi productSpuApi;
|
||||
@Resource
|
||||
@@ -98,7 +97,7 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
|
||||
seckillConfigService.validateSeckillConfigExists(configIds);
|
||||
|
||||
// 2.1 查询所有开启的秒杀活动
|
||||
List<SeckillActivityDO> activityList = seckillActivityMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
List<SeckillActivityDO> activityList = seckillActivityMapper.selectListBySpuIdAndStatus(spuId, CommonStatusEnum.ENABLE.getStatus());
|
||||
if (activityId != null) { // 排除自己
|
||||
activityList.removeIf(item -> ObjectUtil.equal(item.getId(), activityId));
|
||||
}
|
||||
@@ -219,7 +218,7 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
|
||||
seckillProductMapper.updateBatch(diffList.get(1));
|
||||
}
|
||||
if (isNotEmpty(diffList.get(2))) {
|
||||
seckillProductMapper.deleteBatchIds(convertList(diffList.get(2), SeckillProductDO::getId));
|
||||
seckillProductMapper.deleteByIds(convertList(diffList.get(2), SeckillProductDO::getId));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,7 +248,7 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
|
||||
seckillActivityMapper.deleteById(id);
|
||||
// 删除活动商品
|
||||
List<SeckillProductDO> products = seckillProductMapper.selectListByActivityId(id);
|
||||
seckillProductMapper.deleteBatchIds(convertSet(products, SeckillProductDO::getId));
|
||||
seckillProductMapper.deleteByIds(convertSet(products, SeckillProductDO::getId));
|
||||
}
|
||||
|
||||
private SeckillActivityDO validateSeckillActivityExists(Long id) {
|
||||
@@ -289,7 +288,7 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
|
||||
|
||||
@Override
|
||||
public PageResult<SeckillActivityDO> getSeckillActivityAppPageByConfigId(AppSeckillActivityPageReqVO pageReqVO) {
|
||||
return seckillActivityMapper.selectPage(pageReqVO, CommonStatusEnum.ENABLE.getStatus());
|
||||
return seckillActivityMapper.selectPage(pageReqVO, CommonStatusEnum.ENABLE.getStatus(), LocalDateTime.now());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -325,15 +324,8 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SeckillActivityDO> getSeckillActivityBySpuIdsAndStatusAndDateTimeLt(Collection<Long> spuIds, Integer status, LocalDateTime dateTime) {
|
||||
// 1.查询出指定 spuId 的 spu 参加的活动最接近现在的一条记录。多个的话,一个 spuId 对应一个最近的活动编号
|
||||
List<Map<String, Object>> spuIdAndActivityIdMaps = seckillActivityMapper.selectSpuIdAndActivityIdMapsBySpuIdsAndStatus(spuIds, status);
|
||||
if (CollUtil.isEmpty(spuIdAndActivityIdMaps)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
// 2.查询活动详情
|
||||
return seckillActivityMapper.selectListByIdsAndDateTimeLt(
|
||||
convertSet(spuIdAndActivityIdMaps, map -> MapUtil.getLong(map, "activityId")), dateTime);
|
||||
public SeckillActivityDO getMatchSeckillActivityBySpuId(Long spuId) {
|
||||
return seckillActivityMapper.selectBySpuIdAndStatusAndNow(spuId, CommonStatusEnum.ENABLE.getStatus());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
package cn.iocoder.yudao.module.promotion.util;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 活动工具类
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public class PromotionUtils {
|
||||
|
||||
/**
|
||||
* 根据时间,计算活动状态
|
||||
*
|
||||
* @param endTime 结束时间
|
||||
* @return 活动状态
|
||||
*/
|
||||
public static Integer calculateActivityStatus(LocalDateTime endTime) {
|
||||
return LocalDateTimeUtils.beforeNow(endTime) ? CommonStatusEnum.DISABLE.getStatus() : CommonStatusEnum.ENABLE.getStatus();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="cn.iocoder.yudao.module.promotion.dal.mysql.discount.DiscountProductMapper">
|
||||
|
||||
|
||||
<select id="getMatchDiscountProductList" resultType="cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO">
|
||||
SELECT pdp.*
|
||||
FROM promotion_discount_product pdp
|
||||
LEFT JOIN promotion_discount_activity pda
|
||||
ON pdp.activity_id = pda.id
|
||||
<where>
|
||||
<if test="skuIds != null and skuIds.size > 0">
|
||||
AND pdp.sku_id in
|
||||
<foreach collection="skuIds" item="skuId" index="index" open="(" close=")" separator=",">
|
||||
#{skuId}
|
||||
</foreach>
|
||||
</if>
|
||||
AND pda.start_time <= CURRENT_TIME AND pda.end_time >= CURRENT_TIME
|
||||
AND pda.`status` = 20
|
||||
AND pda.deleted != 1
|
||||
</where>
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.trade.controller.app.aftersale;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
|
||||
import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleCreateReqVO;
|
||||
import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleDeliveryReqVO;
|
||||
import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleRespVO;
|
||||
@@ -32,7 +31,6 @@ public class AppAfterSaleController {
|
||||
|
||||
@GetMapping(value = "/page")
|
||||
@Operation(summary = "获得售后分页")
|
||||
@PreAuthenticated
|
||||
public CommonResult<PageResult<AppAfterSaleRespVO>> getAfterSalePage(PageParam pageParam) {
|
||||
return success(AfterSaleConvert.INSTANCE.convertPage02(
|
||||
afterSaleService.getAfterSalePage(getLoginUserId(), pageParam)));
|
||||
@@ -41,21 +39,18 @@ public class AppAfterSaleController {
|
||||
@GetMapping(value = "/get")
|
||||
@Operation(summary = "获得售后订单")
|
||||
@Parameter(name = "id", description = "售后编号", required = true, example = "1")
|
||||
@PreAuthenticated
|
||||
public CommonResult<AppAfterSaleRespVO> getAfterSale(@RequestParam("id") Long id) {
|
||||
return success(AfterSaleConvert.INSTANCE.convert(afterSaleService.getAfterSale(getLoginUserId(), id)));
|
||||
}
|
||||
|
||||
@PostMapping(value = "/create")
|
||||
@Operation(summary = "申请售后")
|
||||
@PreAuthenticated
|
||||
public CommonResult<Long> createAfterSale(@RequestBody AppAfterSaleCreateReqVO createReqVO) {
|
||||
return success(afterSaleService.createAfterSale(getLoginUserId(), createReqVO));
|
||||
}
|
||||
|
||||
@PutMapping(value = "/delivery")
|
||||
@Operation(summary = "退回货物")
|
||||
@PreAuthenticated
|
||||
public CommonResult<Boolean> deliveryAfterSale(@RequestBody AppAfterSaleDeliveryReqVO deliveryReqVO) {
|
||||
afterSaleService.deliveryAfterSale(getLoginUserId(), deliveryReqVO);
|
||||
return success(true);
|
||||
@@ -64,7 +59,6 @@ public class AppAfterSaleController {
|
||||
@DeleteMapping(value = "/cancel")
|
||||
@Operation(summary = "取消售后")
|
||||
@Parameter(name = "id", description = "售后编号", required = true, example = "1")
|
||||
@PreAuthenticated
|
||||
public CommonResult<Boolean> cancelAfterSale(@RequestParam("id") Long id) {
|
||||
afterSaleService.cancelAfterSale(getLoginUserId(), id);
|
||||
return success(true);
|
||||
|
||||
@@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.trade.controller.app.aftersale;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
|
||||
import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.log.AppAfterSaleLogRespVO;
|
||||
import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.AfterSaleLogDO;
|
||||
import cn.iocoder.yudao.module.trade.service.aftersale.AfterSaleLogService;
|
||||
@@ -34,7 +33,6 @@ public class AppAfterSaleLogController {
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "获得售后日志列表")
|
||||
@Parameter(name = "afterSaleId", description = "售后编号", required = true, example = "1")
|
||||
@PreAuthenticated
|
||||
public CommonResult<List<AppAfterSaleLogRespVO>> getAfterSaleLogList(
|
||||
@RequestParam("afterSaleId") Long afterSaleId) {
|
||||
List<AfterSaleLogDO> logs = afterSaleLogService.getAfterSaleLogList(afterSaleId);
|
||||
|
||||
@@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.trade.controller.app.brokerage;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
|
||||
import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.record.AppBrokerageProductPriceRespVO;
|
||||
import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.record.AppBrokerageRecordPageReqVO;
|
||||
import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.record.AppBrokerageRecordRespVO;
|
||||
@@ -37,7 +36,6 @@ public class AppBrokerageRecordController {
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得分销记录分页")
|
||||
@PreAuthenticated
|
||||
public CommonResult<PageResult<AppBrokerageRecordRespVO>> getBrokerageRecordPage(@Valid AppBrokerageRecordPageReqVO pageReqVO) {
|
||||
PageResult<BrokerageRecordDO> pageResult = brokerageRecordService.getBrokerageRecordPage(
|
||||
BrokerageRecordConvert.INSTANCE.convert(pageReqVO, getLoginUserId()));
|
||||
@@ -46,7 +44,6 @@ public class AppBrokerageRecordController {
|
||||
|
||||
@GetMapping("/get-product-brokerage-price")
|
||||
@Operation(summary = "获得商品的分销金额")
|
||||
@PreAuthenticated
|
||||
public CommonResult<AppBrokerageProductPriceRespVO> getProductBrokeragePrice(@RequestParam("spuId") Long spuId) {
|
||||
return success(brokerageRecordService.calculateProductBrokeragePrice(getLoginUserId(), spuId));
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.trade.controller.app.brokerage;
|
||||
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
|
||||
import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
|
||||
import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
|
||||
import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.*;
|
||||
@@ -55,7 +54,6 @@ public class AppBrokerageUserController {
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得个人分销信息")
|
||||
@PreAuthenticated
|
||||
public CommonResult<AppBrokerageUserRespVO> getBrokerageUser() {
|
||||
Optional<BrokerageUserDO> user = Optional.ofNullable(brokerageUserService.getOrCreateBrokerageUser(getLoginUserId()));
|
||||
// 返回数据
|
||||
@@ -68,14 +66,12 @@ public class AppBrokerageUserController {
|
||||
|
||||
@PutMapping("/bind")
|
||||
@Operation(summary = "绑定推广员")
|
||||
@PreAuthenticated
|
||||
public CommonResult<Boolean> bindBrokerageUser(@Valid @RequestBody AppBrokerageUserBindReqVO reqVO) {
|
||||
return success(brokerageUserService.bindBrokerageUser(getLoginUserId(), reqVO.getBindUserId()));
|
||||
}
|
||||
|
||||
@GetMapping("/get-summary")
|
||||
@Operation(summary = "获得个人分销统计")
|
||||
@PreAuthenticated
|
||||
public CommonResult<AppBrokerageUserMySummaryRespVO> getBrokerageUserSummary() {
|
||||
// 查询当前登录用户信息
|
||||
Long userId = getLoginUserId();
|
||||
@@ -101,7 +97,6 @@ public class AppBrokerageUserController {
|
||||
|
||||
@GetMapping("/rank-page-by-user-count")
|
||||
@Operation(summary = "获得分销用户排行分页(基于用户量)")
|
||||
@PreAuthenticated
|
||||
public CommonResult<PageResult<AppBrokerageUserRankByUserCountRespVO>> getBrokerageUserRankPageByUserCount(AppBrokerageUserRankPageReqVO pageReqVO) {
|
||||
// 分页查询
|
||||
PageResult<AppBrokerageUserRankByUserCountRespVO> pageResult = brokerageUserService.getBrokerageUserRankPageByUserCount(pageReqVO);
|
||||
@@ -112,7 +107,6 @@ public class AppBrokerageUserController {
|
||||
|
||||
@GetMapping("/rank-page-by-price")
|
||||
@Operation(summary = "获得分销用户排行分页(基于佣金)")
|
||||
@PreAuthenticated
|
||||
public CommonResult<PageResult<AppBrokerageUserRankByPriceRespVO>> getBrokerageUserChildSummaryPageByPrice(AppBrokerageUserRankPageReqVO pageReqVO) {
|
||||
// 分页查询
|
||||
PageResult<AppBrokerageUserRankByPriceRespVO> pageResult = brokerageRecordService.getBrokerageUserChildSummaryPageByPrice(pageReqVO);
|
||||
@@ -123,7 +117,6 @@ public class AppBrokerageUserController {
|
||||
|
||||
@GetMapping("/child-summary-page")
|
||||
@Operation(summary = "获得下级分销统计分页")
|
||||
@PreAuthenticated
|
||||
public CommonResult<PageResult<AppBrokerageUserChildSummaryRespVO>> getBrokerageUserChildSummaryPage(
|
||||
AppBrokerageUserChildSummaryPageReqVO pageReqVO) {
|
||||
PageResult<AppBrokerageUserChildSummaryRespVO> pageResult = brokerageUserService.getBrokerageUserChildSummaryPage(pageReqVO, getLoginUserId());
|
||||
@@ -133,7 +126,6 @@ public class AppBrokerageUserController {
|
||||
@GetMapping("/get-rank-by-price")
|
||||
@Operation(summary = "获得分销用户排行(基于佣金)")
|
||||
@Parameter(name = "times", description = "时间段", required = true)
|
||||
@PreAuthenticated
|
||||
public CommonResult<Integer> getRankByPrice(
|
||||
@RequestParam("times") @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) LocalDateTime[] times) {
|
||||
return success(brokerageRecordService.getUserRankByPrice(getLoginUserId(), times));
|
||||
|
||||
@@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.trade.controller.app.brokerage;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
|
||||
import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.withdraw.AppBrokerageWithdrawCreateReqVO;
|
||||
import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.withdraw.AppBrokerageWithdrawPageReqVO;
|
||||
import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.withdraw.AppBrokerageWithdrawRespVO;
|
||||
@@ -33,7 +32,6 @@ public class AppBrokerageWithdrawController {
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得分销提现分页")
|
||||
@PreAuthenticated
|
||||
public CommonResult<PageResult<AppBrokerageWithdrawRespVO>> getBrokerageWithdrawPage(AppBrokerageWithdrawPageReqVO pageReqVO) {
|
||||
PageResult<BrokerageWithdrawDO> pageResult = brokerageWithdrawService.getBrokerageWithdrawPage(
|
||||
BrokerageWithdrawConvert.INSTANCE.convert(pageReqVO, getLoginUserId()));
|
||||
@@ -42,7 +40,6 @@ public class AppBrokerageWithdrawController {
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建分销提现")
|
||||
@PreAuthenticated
|
||||
public CommonResult<Long> createBrokerageWithdraw(@RequestBody @Valid AppBrokerageWithdrawCreateReqVO createReqVO) {
|
||||
return success(brokerageWithdrawService.createBrokerageWithdraw(getLoginUserId(), createReqVO));
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package cn.iocoder.yudao.module.trade.controller.app.cart;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
|
||||
import cn.iocoder.yudao.module.trade.controller.app.cart.vo.*;
|
||||
import cn.iocoder.yudao.module.trade.service.cart.CartService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
@@ -32,14 +31,12 @@ public class AppCartController {
|
||||
|
||||
@PostMapping("/add")
|
||||
@Operation(summary = "添加购物车商品")
|
||||
@PreAuthenticated
|
||||
public CommonResult<Long> addCart(@Valid @RequestBody AppCartAddReqVO addCountReqVO) {
|
||||
return success(cartService.addCart(getLoginUserId(), addCountReqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update-count")
|
||||
@Operation(summary = "更新购物车商品数量")
|
||||
@PreAuthenticated
|
||||
public CommonResult<Boolean> updateCartCount(@Valid @RequestBody AppCartUpdateCountReqVO updateReqVO) {
|
||||
cartService.updateCartCount(getLoginUserId(), updateReqVO);
|
||||
return success(true);
|
||||
@@ -47,7 +44,6 @@ public class AppCartController {
|
||||
|
||||
@PutMapping("/update-selected")
|
||||
@Operation(summary = "更新购物车商品选中")
|
||||
@PreAuthenticated
|
||||
public CommonResult<Boolean> updateCartSelected(@Valid @RequestBody AppCartUpdateSelectedReqVO updateReqVO) {
|
||||
cartService.updateCartSelected(getLoginUserId(), updateReqVO);
|
||||
return success(true);
|
||||
@@ -55,7 +51,6 @@ public class AppCartController {
|
||||
|
||||
@PutMapping("/reset")
|
||||
@Operation(summary = "重置购物车商品")
|
||||
@PreAuthenticated
|
||||
public CommonResult<Boolean> resetCart(@Valid @RequestBody AppCartResetReqVO updateReqVO) {
|
||||
cartService.resetCart(getLoginUserId(), updateReqVO);
|
||||
return success(true);
|
||||
@@ -64,7 +59,6 @@ public class AppCartController {
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除购物车商品")
|
||||
@Parameter(name = "ids", description = "购物车商品编号", required = true, example = "1024,2048")
|
||||
@PreAuthenticated
|
||||
public CommonResult<Boolean> deleteCart(@RequestParam("ids") List<Long> ids) {
|
||||
cartService.deleteCart(getLoginUserId(), ids);
|
||||
return success(true);
|
||||
@@ -72,14 +66,12 @@ public class AppCartController {
|
||||
|
||||
@GetMapping("get-count")
|
||||
@Operation(summary = "查询用户在购物车中的商品数量")
|
||||
@PreAuthenticated
|
||||
public CommonResult<Integer> getCartCount() {
|
||||
return success(cartService.getCartCount(getLoginUserId()));
|
||||
}
|
||||
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "查询用户的购物车列表")
|
||||
@PreAuthenticated
|
||||
public CommonResult<AppCartListRespVO> getCartList() {
|
||||
return success(cartService.getCartList(getLoginUserId()));
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO;
|
||||
import cn.iocoder.yudao.module.trade.service.config.TradeConfigService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
@@ -36,6 +37,7 @@ public class AppTradeConfigController {
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得交易配置")
|
||||
@PermitAll
|
||||
public CommonResult<AppTradeConfigRespVO> getTradeConfig() {
|
||||
TradeConfigDO config = ObjUtil.defaultIfNull(tradeConfigService.getTradeConfig(), new TradeConfigDO());
|
||||
return success(TradeConfigConvert.INSTANCE.convert02(config).setTencentLbsKey(tencentLbsKey));
|
||||
|
||||
@@ -8,6 +8,7 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO;
|
||||
import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@@ -30,6 +31,7 @@ public class AppDeliverExpressController {
|
||||
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "获得快递公司列表")
|
||||
@PermitAll
|
||||
public CommonResult<List<AppDeliveryExpressRespVO>> getDeliveryExpressList() {
|
||||
List<DeliveryExpressDO> list = deliveryExpressService.getDeliveryExpressListByStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
list.sort(Comparator.comparing(DeliveryExpressDO::getSort));
|
||||
|
||||
@@ -10,6 +10,7 @@ import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.Parameters;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@@ -36,6 +37,7 @@ public class AppDeliverPickUpStoreController {
|
||||
@Parameter(name = "latitude", description = "精度", example = "110"),
|
||||
@Parameter(name = "longitude", description = "纬度", example = "120")
|
||||
})
|
||||
@PermitAll
|
||||
public CommonResult<List<AppDeliveryPickUpStoreRespVO>> getDeliveryPickUpStoreList(
|
||||
@RequestParam(value = "latitude", required = false) Double latitude,
|
||||
@RequestParam(value = "longitude", required = false) Double longitude) {
|
||||
@@ -47,6 +49,7 @@ public class AppDeliverPickUpStoreController {
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得自提门店")
|
||||
@Parameter(name = "id", description = "门店编号")
|
||||
@PermitAll
|
||||
public CommonResult<AppDeliveryPickUpStoreRespVO> getOrder(@RequestParam("id") Long id) {
|
||||
DeliveryPickUpStoreDO store = deliveryPickUpStoreService.getDeliveryPickUpStore(id);
|
||||
return success(DeliveryPickUpStoreConvert.INSTANCE.convert03(store));
|
||||
|
||||
@@ -62,3 +62,8 @@ tenant-id: {{appTenentId}}
|
||||
GET {{appApi}}/trade/order/get-express-track-list?id=70
|
||||
Authorization: Bearer {{appToken}}
|
||||
tenant-id: {{appTenentId}}
|
||||
|
||||
### /trade-order/settlement-product 获得商品结算信息
|
||||
GET {{appApi}}/trade/order/settlement-product?spuIds=633
|
||||
Authorization: Bearer {{appToken}}
|
||||
tenant-id: {{appTenentId}}
|
||||
@@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.trade.controller.app.order;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
|
||||
import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO;
|
||||
import cn.iocoder.yudao.module.trade.controller.app.order.vo.*;
|
||||
import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemCommentCreateReqVO;
|
||||
@@ -17,11 +16,14 @@ import cn.iocoder.yudao.module.trade.service.aftersale.AfterSaleService;
|
||||
import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService;
|
||||
import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService;
|
||||
import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService;
|
||||
import cn.iocoder.yudao.module.trade.service.price.TradePriceService;
|
||||
import com.google.common.collect.Maps;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.Parameters;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
@@ -47,23 +49,30 @@ public class AppTradeOrderController {
|
||||
private TradeOrderQueryService tradeOrderQueryService;
|
||||
@Resource
|
||||
private DeliveryExpressService deliveryExpressService;
|
||||
|
||||
@Resource
|
||||
private AfterSaleService afterSaleService;
|
||||
@Resource
|
||||
private TradePriceService priceService;
|
||||
|
||||
@Resource
|
||||
private TradeOrderProperties tradeOrderProperties;
|
||||
|
||||
@GetMapping("/settlement")
|
||||
@Operation(summary = "获得订单结算信息")
|
||||
@PreAuthenticated
|
||||
public CommonResult<AppTradeOrderSettlementRespVO> settlementOrder(@Valid AppTradeOrderSettlementReqVO settlementReqVO) {
|
||||
return success(tradeOrderUpdateService.settlementOrder(getLoginUserId(), settlementReqVO));
|
||||
}
|
||||
|
||||
@GetMapping("/settlement-product")
|
||||
@Operation(summary = "获得商品结算信息", description = "用于商品列表、商品详情,获得参与活动后的价格信息")
|
||||
@Parameter(name = "spuIds", description = "商品 SPU 编号数组")
|
||||
@PermitAll
|
||||
public CommonResult<List<AppTradeProductSettlementRespVO>> settlementProduct(@RequestParam("spuIds") List<Long> spuIds) {
|
||||
return success(priceService.calculateProductPrice(getLoginUserId(), spuIds));
|
||||
}
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建订单")
|
||||
@PreAuthenticated
|
||||
public CommonResult<AppTradeOrderCreateRespVO> createOrder(@Valid @RequestBody AppTradeOrderCreateReqVO createReqVO) {
|
||||
TradeOrderDO order = tradeOrderUpdateService.createOrder(getLoginUserId(), createReqVO);
|
||||
return success(new AppTradeOrderCreateRespVO().setId(order.getId()).setPayOrderId(order.getPayOrderId()));
|
||||
@@ -79,28 +88,37 @@ public class AppTradeOrderController {
|
||||
|
||||
@GetMapping("/get-detail")
|
||||
@Operation(summary = "获得交易订单")
|
||||
@Parameter(name = "id", description = "交易订单编号")
|
||||
@PreAuthenticated
|
||||
public CommonResult<AppTradeOrderDetailRespVO> getOrder(@RequestParam("id") Long id) {
|
||||
// 查询订单
|
||||
@Parameters({
|
||||
@Parameter(name = "id", description = "交易订单编号"),
|
||||
@Parameter(name = "sync", description = "是否同步支付状态", example = "true")
|
||||
})
|
||||
public CommonResult<AppTradeOrderDetailRespVO> getOrderDetail(@RequestParam("id") Long id,
|
||||
@RequestParam(value = "sync", required = false) Boolean sync) {
|
||||
// 1.1 查询订单
|
||||
TradeOrderDO order = tradeOrderQueryService.getOrder(getLoginUserId(), id);
|
||||
if (order == null) {
|
||||
return success(null);
|
||||
}
|
||||
// 1.2 sync 仅在等待支付
|
||||
if (Boolean.TRUE.equals(sync)
|
||||
&& TradeOrderStatusEnum.isUnpaid(order.getStatus()) && !order.getPayStatus()) {
|
||||
tradeOrderUpdateService.syncOrderPayStatusQuietly(order.getId(), order.getPayOrderId());
|
||||
// 重新查询,因为同步后,可能会有变化
|
||||
order = tradeOrderQueryService.getOrder(id);
|
||||
}
|
||||
|
||||
// 查询订单项
|
||||
// 2.1 查询订单项
|
||||
List<TradeOrderItemDO> orderItems = tradeOrderQueryService.getOrderItemListByOrderId(order.getId());
|
||||
// 查询物流公司
|
||||
// 2.2 查询物流公司
|
||||
DeliveryExpressDO express = order.getLogisticsId() != null && order.getLogisticsId() > 0 ?
|
||||
deliveryExpressService.getDeliveryExpress(order.getLogisticsId()) : null;
|
||||
// 最终组合
|
||||
// 2.3 最终组合
|
||||
return success(TradeOrderConvert.INSTANCE.convert02(order, orderItems, tradeOrderProperties, express));
|
||||
}
|
||||
|
||||
@GetMapping("/get-express-track-list")
|
||||
@Operation(summary = "获得交易订单的物流轨迹")
|
||||
@Parameter(name = "id", description = "交易订单编号")
|
||||
@PreAuthenticated
|
||||
public CommonResult<List<AppOrderExpressTrackRespDTO>> getOrderExpressTrackList(@RequestParam("id") Long id) {
|
||||
return success(TradeOrderConvert.INSTANCE.convertList02(
|
||||
tradeOrderQueryService.getExpressTrackList(id, getLoginUserId())));
|
||||
@@ -108,7 +126,6 @@ public class AppTradeOrderController {
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得交易订单分页")
|
||||
@PreAuthenticated
|
||||
public CommonResult<PageResult<AppTradeOrderPageItemRespVO>> getOrderPage(AppTradeOrderPageReqVO reqVO) {
|
||||
// 查询订单
|
||||
PageResult<TradeOrderDO> pageResult = tradeOrderQueryService.getOrderPage(getLoginUserId(), reqVO);
|
||||
@@ -121,7 +138,6 @@ public class AppTradeOrderController {
|
||||
|
||||
@GetMapping("/get-count")
|
||||
@Operation(summary = "获得交易订单数量")
|
||||
@PreAuthenticated
|
||||
public CommonResult<Map<String, Long>> getOrderCount() {
|
||||
Map<String, Long> orderCount = Maps.newLinkedHashMapWithExpectedSize(5);
|
||||
// 全部
|
||||
@@ -146,7 +162,6 @@ public class AppTradeOrderController {
|
||||
@PutMapping("/receive")
|
||||
@Operation(summary = "确认交易订单收货")
|
||||
@Parameter(name = "id", description = "交易订单编号")
|
||||
@PreAuthenticated
|
||||
public CommonResult<Boolean> receiveOrder(@RequestParam("id") Long id) {
|
||||
tradeOrderUpdateService.receiveOrderByMember(getLoginUserId(), id);
|
||||
return success(true);
|
||||
@@ -155,7 +170,6 @@ public class AppTradeOrderController {
|
||||
@DeleteMapping("/cancel")
|
||||
@Operation(summary = "取消交易订单")
|
||||
@Parameter(name = "id", description = "交易订单编号")
|
||||
@PreAuthenticated
|
||||
public CommonResult<Boolean> cancelOrder(@RequestParam("id") Long id) {
|
||||
tradeOrderUpdateService.cancelOrderByMember(getLoginUserId(), id);
|
||||
return success(true);
|
||||
@@ -164,7 +178,6 @@ public class AppTradeOrderController {
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除交易订单")
|
||||
@Parameter(name = "id", description = "交易订单编号")
|
||||
@PreAuthenticated
|
||||
public CommonResult<Boolean> deleteOrder(@RequestParam("id") Long id) {
|
||||
tradeOrderUpdateService.deleteOrder(getLoginUserId(), id);
|
||||
return success(true);
|
||||
@@ -175,7 +188,6 @@ public class AppTradeOrderController {
|
||||
@GetMapping("/item/get")
|
||||
@Operation(summary = "获得交易订单项")
|
||||
@Parameter(name = "id", description = "交易订单项编号")
|
||||
@PreAuthenticated
|
||||
public CommonResult<AppTradeOrderItemRespVO> getOrderItem(@RequestParam("id") Long id) {
|
||||
TradeOrderItemDO item = tradeOrderQueryService.getOrderItem(getLoginUserId(), id);
|
||||
return success(TradeOrderConvert.INSTANCE.convert03(item));
|
||||
@@ -183,7 +195,6 @@ public class AppTradeOrderController {
|
||||
|
||||
@PostMapping("/item/create-comment")
|
||||
@Operation(summary = "创建交易订单项的评价")
|
||||
@PreAuthenticated
|
||||
public CommonResult<Long> createOrderItemComment(@RequestBody AppTradeOrderItemCommentCreateReqVO createReqVO) {
|
||||
return success(tradeOrderUpdateService.createOrderItemCommentByMember(getLoginUserId(), createReqVO));
|
||||
}
|
||||
|
||||
@@ -2,9 +2,8 @@ package cn.iocoder.yudao.module.trade.controller.app.order.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import jakarta.validation.constraints.AssertTrue;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "用户 App - 交易订单创建 Request VO")
|
||||
@Data
|
||||
|
||||
@@ -6,13 +6,13 @@ import cn.iocoder.yudao.framework.common.validation.Mobile;
|
||||
import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.AssertTrue;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "用户 App - 交易订单结算 Request VO")
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package cn.iocoder.yudao.module.trade.controller.app.order.vo;
|
||||
|
||||
import cn.iocoder.yudao.module.trade.controller.app.base.property.AppProductPropertyValueDetailRespVO;
|
||||
import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
@@ -34,6 +35,13 @@ public class AppTradeOrderSettlementRespVO {
|
||||
@Schema(description = "总积分", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
|
||||
private Integer totalPoint;
|
||||
|
||||
/**
|
||||
* 营销活动数组
|
||||
*
|
||||
* 只对应 {@link TradePriceCalculateRespBO.Price#items} 商品匹配的活动
|
||||
*/
|
||||
private List<TradePriceCalculateRespBO.Promotion> promotions;
|
||||
|
||||
@Schema(description = "购物项")
|
||||
@Data
|
||||
public static class Item {
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
package cn.iocoder.yudao.module.trade.controller.app.order.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Schema(description = "用户 App - 商品结算信息 Response VO")
|
||||
@Data
|
||||
public class AppTradeProductSettlementRespVO {
|
||||
|
||||
@Schema(description = "SPU 商品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Long spuId;
|
||||
|
||||
@Schema(description = "SKU 价格信息数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private List<Sku> skus;
|
||||
|
||||
@Schema(description = "满减送活动信息", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private RewardActivity rewardActivity;
|
||||
|
||||
@Schema(description = "SKU 价格信息")
|
||||
@Data
|
||||
public static class Sku implements Serializable {
|
||||
|
||||
@Schema(description = "商品 SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "优惠后价格,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
|
||||
private Integer promotionPrice;
|
||||
|
||||
@Schema(description = "营销类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "4")
|
||||
private Integer promotionType; // 对应 PromotionTypeEnum 枚举,目前只有 4 和 6 两种
|
||||
|
||||
@Schema(description = "营销编号", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private Long promotionId; // 目前只有限时折扣活动的编号
|
||||
|
||||
@Schema(description = "活动结束时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime promotionEndTime;
|
||||
|
||||
}
|
||||
|
||||
@Schema(description = "满减送活动信息")
|
||||
@Data
|
||||
public static class RewardActivity {
|
||||
|
||||
@Schema(description = "满减活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "条件类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Integer conditionType;
|
||||
|
||||
@Schema(description = "优惠规则的数组", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private List<RewardActivityRule> rules;
|
||||
|
||||
}
|
||||
|
||||
@Schema(description = "优惠规则")
|
||||
@Data
|
||||
public static class RewardActivityRule {
|
||||
|
||||
@Schema(description = "优惠门槛", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") // 1. 满 N 元,单位:分; 2. 满 N 件
|
||||
private Integer limit;
|
||||
|
||||
@Schema(description = "优惠价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
|
||||
private Integer discountPrice;
|
||||
|
||||
@Schema(description = "是否包邮", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
|
||||
private Boolean freeDelivery;
|
||||
|
||||
@Schema(description = "赠送的积分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
|
||||
private Integer point;
|
||||
|
||||
@Schema(description = "赠送的优惠劵编号的数组")
|
||||
private Map<Long, Integer> giveCouponTemplateCounts;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -46,8 +46,7 @@ public interface AfterSaleConvert {
|
||||
@Mapping(source = "afterSale.refundPrice", target = "price"),
|
||||
@Mapping(source = "orderProperties.payAppKey", target = "appKey")
|
||||
})
|
||||
PayRefundCreateReqDTO convert(String userIp, AfterSaleDO afterSale,
|
||||
TradeOrderProperties orderProperties);
|
||||
PayRefundCreateReqDTO convert(String userIp, AfterSaleDO afterSale, TradeOrderProperties orderProperties);
|
||||
|
||||
MemberUserRespVO convert(MemberUserRespDTO bean);
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties
|
||||
import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService;
|
||||
import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService;
|
||||
import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -44,7 +45,6 @@ import org.springframework.transaction.support.TransactionSynchronization;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
@@ -386,7 +386,7 @@ public class AfterSaleServiceImpl implements AfterSaleService {
|
||||
public void afterCommit() {
|
||||
// 创建退款单
|
||||
PayRefundCreateReqDTO createReqDTO = AfterSaleConvert.INSTANCE.convert(userIp, afterSale, tradeOrderProperties)
|
||||
.setReason(StrUtil.format("退款【{}】", afterSale.getSpuName()));
|
||||
.setReason(StrUtil.format("退款【{}】", afterSale.getSpuName()));;
|
||||
Long payRefundId = payRefundApi.createRefund(createReqDTO).getCheckedData();
|
||||
// 更新售后单的退款单号
|
||||
tradeAfterSaleMapper.updateById(new AfterSaleDO().setId(afterSale.getId()).setPayRefundId(payRefundId));
|
||||
|
||||
@@ -23,10 +23,10 @@ import cn.iocoder.yudao.module.trade.framework.delivery.core.client.ExpressClien
|
||||
import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackQueryReqDTO;
|
||||
import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackRespDTO;
|
||||
import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import java.util.*;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
@@ -215,7 +215,7 @@ public class TradeOrderQueryServiceImpl implements TradeOrderQueryService {
|
||||
* @return 物流轨迹
|
||||
*/
|
||||
@Cacheable(cacheNames = RedisKeyConstants.EXPRESS_TRACK, key = "#code + '-' + #logisticsNo + '-' + #receiverMobile",
|
||||
condition = "#result != null && #result.length() > 0")
|
||||
unless = "#result == null")
|
||||
public List<ExpressTrackRespDTO> getExpressTrackList(String code, String logisticsNo, String receiverMobile) {
|
||||
return expressClientFactory.getDefaultExpressClient().getExpressTrackList(new ExpressTrackQueryReqDTO()
|
||||
.setExpressCode(code).setLogisticsNo(logisticsNo).setPhone(receiverMobile));
|
||||
|
||||
@@ -49,6 +49,17 @@ public interface TradeOrderUpdateService {
|
||||
*/
|
||||
void updateOrderPaid(Long id, Long payOrderId);
|
||||
|
||||
/**
|
||||
* 同步订单的支付状态
|
||||
*
|
||||
* 1. Quietly 表示,即使同步失败,也不会抛出异常
|
||||
* 2. 什么时候回出现异常?因为是主动同步,可能和支付模块的回调通知 {@link #updateOrderPaid(Long, Long)} 存在并发冲突,导致抛出异常
|
||||
*
|
||||
* @param id 订单编号
|
||||
* @param payOrderId 支付订单编号
|
||||
*/
|
||||
void syncOrderPayStatusQuietly(Long id, Long payOrderId);
|
||||
|
||||
/**
|
||||
* 【管理员】发货交易订单
|
||||
*
|
||||
|
||||
@@ -9,7 +9,6 @@ import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import cn.iocoder.yudao.framework.common.core.KeyValue;
|
||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.number.MoneyUtils;
|
||||
@@ -166,7 +165,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
|
||||
TradePriceCalculateReqBO calculateReqBO = TradeOrderConvert.INSTANCE.convert(userId, settlementReqVO, cartList);
|
||||
calculateReqBO.getItems().forEach(item -> Assert.isTrue(item.getSelected(), // 防御性编程,保证都是选中的
|
||||
"商品({}) 未设置为选中", item.getSkuId()));
|
||||
return tradePriceService.calculatePrice(calculateReqBO);
|
||||
return tradePriceService.calculateOrderPrice(calculateReqBO);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -269,12 +268,24 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@TradeOrderLog(operateType = TradeOrderOperateTypeEnum.MEMBER_PAY)
|
||||
public void updateOrderPaid(Long id, Long payOrderId) {
|
||||
// 1. 校验并获得交易订单(可支付)
|
||||
KeyValue<TradeOrderDO, PayOrderRespDTO> orderResult = validateOrderPayable(id, payOrderId);
|
||||
TradeOrderDO order = orderResult.getKey();
|
||||
PayOrderRespDTO payOrder = orderResult.getValue();
|
||||
// 1.1 校验订单是否存在
|
||||
TradeOrderDO order = validateOrderExists(id);
|
||||
// 1.2 校验订单已支付
|
||||
if (!TradeOrderStatusEnum.isUnpaid(order.getStatus()) || order.getPayStatus()) {
|
||||
// 特殊:如果订单已支付,且支付单号相同,直接返回,说明重复回调
|
||||
if (ObjectUtil.equals(order.getPayOrderId(), payOrderId)) {
|
||||
log.warn("[updateOrderPaid][order({}) 已支付,且支付单号相同({}),直接返回]", order, payOrderId);
|
||||
return;
|
||||
}
|
||||
log.error("[updateOrderPaid][order({}) 支付单不匹配({}),请进行处理!order 数据是:{}]",
|
||||
id, payOrderId, JsonUtils.toJsonString(order));
|
||||
throw exception(ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR);
|
||||
}
|
||||
|
||||
// 2. 更新 TradeOrderDO 状态为已支付,等待发货
|
||||
// 2. 校验支付订单的合法性
|
||||
PayOrderRespDTO payOrder = validatePayOrderPaid(order, payOrderId);
|
||||
|
||||
// 3. 更新 TradeOrderDO 状态为已支付,等待发货
|
||||
int updateCount = tradeOrderMapper.updateByIdAndStatus(id, order.getStatus(),
|
||||
new TradeOrderDO().setStatus(TradeOrderStatusEnum.UNDELIVERED.getStatus()).setPayStatus(true)
|
||||
.setPayTime(LocalDateTime.now()).setPayChannelCode(payOrder.getChannelCode()));
|
||||
@@ -282,66 +293,65 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
|
||||
throw exception(ORDER_UPDATE_PAID_STATUS_NOT_UNPAID);
|
||||
}
|
||||
|
||||
// 3. 执行 TradeOrderHandler 的后置处理
|
||||
// 4. 执行 TradeOrderHandler 的后置处理
|
||||
List<TradeOrderItemDO> orderItems = tradeOrderItemMapper.selectListByOrderId(id);
|
||||
tradeOrderHandlers.forEach(handler -> handler.afterPayOrder(order, orderItems));
|
||||
|
||||
// 4. 记录订单日志
|
||||
// 5. 记录订单日志
|
||||
TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), TradeOrderStatusEnum.UNDELIVERED.getStatus());
|
||||
TradeOrderLogUtils.setUserInfo(order.getUserId(), UserTypeEnum.MEMBER.getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验交易订单满足被支付的条件
|
||||
* <p>
|
||||
* 1. 交易订单未支付
|
||||
* 2. 支付单已支付
|
||||
*
|
||||
* @param id 交易订单编号
|
||||
* @param payOrderId 支付订单编号
|
||||
* @return 交易订单
|
||||
*/
|
||||
private KeyValue<TradeOrderDO, PayOrderRespDTO> validateOrderPayable(Long id, Long payOrderId) {
|
||||
// 校验订单是否存在
|
||||
TradeOrderDO order = validateOrderExists(id);
|
||||
// 校验订单未支付
|
||||
if (!TradeOrderStatusEnum.isUnpaid(order.getStatus()) || order.getPayStatus()) {
|
||||
log.error("[validateOrderPaid][order({}) 不处于待支付状态,请进行处理!order 数据是:{}]",
|
||||
id, JsonUtils.toJsonString(order));
|
||||
throw exception(ORDER_UPDATE_PAID_STATUS_NOT_UNPAID);
|
||||
}
|
||||
// 校验支付订单匹配
|
||||
if (ObjectUtil.notEqual(order.getPayOrderId(), payOrderId)) { // 支付单号
|
||||
log.error("[validateOrderPaid][order({}) 支付单不匹配({}),请进行处理!order 数据是:{}]",
|
||||
id, payOrderId, JsonUtils.toJsonString(order));
|
||||
throw exception(ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR);
|
||||
}
|
||||
|
||||
// 校验支付单是否存在
|
||||
@Override
|
||||
public void syncOrderPayStatusQuietly(Long id, Long payOrderId) {
|
||||
PayOrderRespDTO payOrder = payOrderApi.getOrder(payOrderId).getCheckedData();
|
||||
if (payOrder == null) {
|
||||
log.error("[validateOrderPaid][order({}) payOrder({}) 不存在,请进行处理!]", id, payOrderId);
|
||||
return;
|
||||
}
|
||||
if (!PayOrderStatusEnum.isSuccess(payOrder.getStatus())) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
getSelf().updateOrderPaid(id, payOrderId);
|
||||
} catch (Throwable e) {
|
||||
log.warn("[syncOrderPayStatusQuietly][id({}) payOrderId({}) 同步支付状态失败]", id, payOrderId, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验支付订单的合法性
|
||||
*
|
||||
* @param order 交易订单
|
||||
* @param payOrderId 支付订单编号
|
||||
* @return 支付订单
|
||||
*/
|
||||
private PayOrderRespDTO validatePayOrderPaid(TradeOrderDO order, Long payOrderId) {
|
||||
// 1. 校验支付单是否存在
|
||||
PayOrderRespDTO payOrder = payOrderApi.getOrder(payOrderId).getCheckedData();
|
||||
if (payOrder == null) {
|
||||
log.error("[validatePayOrderPaid][order({}) payOrder({}) 不存在,请进行处理!]", order.getId(), payOrderId);
|
||||
throw exception(ORDER_NOT_FOUND);
|
||||
}
|
||||
// 校验支付单已支付
|
||||
|
||||
// 2.1 校验支付单已支付
|
||||
if (!PayOrderStatusEnum.isSuccess(payOrder.getStatus())) {
|
||||
log.error("[validateOrderPaid][order({}) payOrder({}) 未支付,请进行处理!payOrder 数据是:{}]",
|
||||
id, payOrderId, JsonUtils.toJsonString(payOrder));
|
||||
log.error("[validatePayOrderPaid][order({}) payOrder({}) 未支付,请进行处理!payOrder 数据是:{}]",
|
||||
order.getId(), payOrderId, JsonUtils.toJsonString(payOrder));
|
||||
throw exception(ORDER_UPDATE_PAID_FAIL_PAY_ORDER_STATUS_NOT_SUCCESS);
|
||||
}
|
||||
// 校验支付金额一致
|
||||
// 2.2 校验支付金额一致
|
||||
if (ObjectUtil.notEqual(payOrder.getPrice(), order.getPayPrice())) {
|
||||
log.error("[validateOrderPaid][order({}) payOrder({}) 支付金额不匹配,请进行处理!order 数据是:{},payOrder 数据是:{}]",
|
||||
id, payOrderId, JsonUtils.toJsonString(order), JsonUtils.toJsonString(payOrder));
|
||||
log.error("[validatePayOrderPaid][order({}) payOrder({}) 支付金额不匹配,请进行处理!order 数据是:{},payOrder 数据是:{}]",
|
||||
order.getId(), payOrderId, JsonUtils.toJsonString(order), JsonUtils.toJsonString(payOrder));
|
||||
throw exception(ORDER_UPDATE_PAID_FAIL_PAY_PRICE_NOT_MATCH);
|
||||
}
|
||||
// 校验支付订单匹配(二次)
|
||||
if (ObjectUtil.notEqual(payOrder.getMerchantOrderId(), id.toString())) {
|
||||
log.error("[validateOrderPaid][order({}) 支付单不匹配({}),请进行处理!payOrder 数据是:{}]",
|
||||
id, payOrderId, JsonUtils.toJsonString(payOrder));
|
||||
// 2.2 校验支付订单匹配(二次)
|
||||
if (ObjectUtil.notEqual(payOrder.getMerchantOrderId(), order.getId().toString())) {
|
||||
log.error("[validatePayOrderPaid][order({}) 支付单不匹配({}),请进行处理!payOrder 数据是:{}]",
|
||||
order.getId(), payOrderId, JsonUtils.toJsonString(payOrder));
|
||||
throw exception(ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR);
|
||||
}
|
||||
return new KeyValue<>(order, payOrder);
|
||||
return payOrder;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -375,7 +385,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
|
||||
|
||||
// 3. 记录订单日志
|
||||
TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), TradeOrderStatusEnum.DELIVERED.getStatus(),
|
||||
MapUtil.<String, Object>builder().put("expressName", express != null ? express.getName() : "")
|
||||
MapUtil.<String, Object>builder().put("deliveryName", express != null ? express.getName() : "")
|
||||
.put("logisticsNo", express != null ? deliveryReqVO.getLogisticsNo() : "").build());
|
||||
|
||||
// 4.1 发送站内信
|
||||
@@ -676,7 +686,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
|
||||
tradeOrderItemMapper.updateBatch(updateItems);
|
||||
|
||||
// 4. 更新支付订单
|
||||
payOrderApi.updatePayOrderPrice(order.getPayOrderId(), newPayPrice).getCheckedData();
|
||||
payOrderApi.updatePayOrderPrice(order.getPayOrderId(), newPayPrice).checkError();
|
||||
|
||||
// 5. 记录订单日志
|
||||
TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), order.getStatus(),
|
||||
@@ -887,7 +897,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
|
||||
.setAppKey(tradeOrderProperties.getPayAppKey()).setUserIp(getClientIP()) // 支付应用
|
||||
.setMerchantOrderId(String.valueOf(order.getId())) // 支付单号
|
||||
.setMerchantRefundId(String.valueOf(order.getId()))
|
||||
.setReason(TradeOrderCancelTypeEnum.COMBINATION_CLOSE.getName()).setPrice(order.getPayPrice())).getCheckedData(); // 价格信息
|
||||
.setReason(TradeOrderCancelTypeEnum.COMBINATION_CLOSE.getName()).setPrice(order.getPayPrice())).checkError(); // 价格信息
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -51,7 +51,7 @@ public class TradeCombinationOrderHandler implements TradeOrderHandler {
|
||||
// 1. 校验是否满足拼团活动相关限制
|
||||
TradeOrderItemDO item = orderItems.get(0);
|
||||
combinationRecordApi.validateCombinationRecord(order.getUserId(), order.getCombinationActivityId(),
|
||||
order.getCombinationHeadId(), item.getSkuId(), item.getCount());
|
||||
order.getCombinationHeadId(), item.getSkuId(), item.getCount()).checkError();
|
||||
|
||||
// 2. 校验该用户是否存在未支付的拼团活动订单,避免一个拼团可以下多个单子了
|
||||
TradeOrderDO activityOrder = orderQueryService.getOrderByUserIdAndStatusAndCombination(
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
package cn.iocoder.yudao.module.trade.service.price;
|
||||
|
||||
import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeProductSettlementRespVO;
|
||||
import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
|
||||
import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
|
||||
|
||||
import jakarta.validation.Valid;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 价格计算 Service 接口
|
||||
*
|
||||
@@ -13,11 +15,20 @@ import jakarta.validation.Valid;
|
||||
public interface TradePriceService {
|
||||
|
||||
/**
|
||||
* 价格计算
|
||||
* 【订单】价格计算
|
||||
*
|
||||
* @param calculateReqDTO 计算信息
|
||||
* @return 计算结果
|
||||
*/
|
||||
TradePriceCalculateRespBO calculatePrice(@Valid TradePriceCalculateReqBO calculateReqDTO);
|
||||
TradePriceCalculateRespBO calculateOrderPrice(@Valid TradePriceCalculateReqBO calculateReqDTO);
|
||||
|
||||
/**
|
||||
* 【商品】价格计算,用于商品列表、商品详情
|
||||
*
|
||||
* @param userId 用户编号,允许为空
|
||||
* @param spuIds 商品 SPU 编号数组
|
||||
* @return 计算结果
|
||||
*/
|
||||
List<AppTradeProductSettlementRespVO> calculateProductPrice(Long userId, List<Long> spuIds);
|
||||
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user