将 onemall 老代码,统一到归档目录,后续不断迁移移除
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
package cn.iocoder.mall.promotionservice;
|
||||
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableDiscoveryClient
|
||||
@EnableFeignClients(basePackages = {"cn.iocoder.mall.productservice.rpc"})
|
||||
public class PromotionServiceApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(PromotionServiceApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package cn.iocoder.mall.promotionservice.config;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
|
||||
@Configuration
|
||||
@EnableAsync(proxyTargetClass = true) // 开启 Spring Async 异步的功能
|
||||
public class AsyncConfiguration {
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package cn.iocoder.mall.promotionservice.config;
|
||||
|
||||
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
|
||||
import com.baomidou.mybatisplus.core.injector.ISqlInjector;
|
||||
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
@Configuration
|
||||
@MapperScan("cn.iocoder.mall.promotionservice.dal.mysql.mapper") // 扫描对应的 Mapper 接口
|
||||
@EnableTransactionManagement(proxyTargetClass = true) // 启动事务管理。
|
||||
public class DatabaseConfiguration {
|
||||
|
||||
// 数据库连接池 Druid
|
||||
|
||||
@Bean
|
||||
public ISqlInjector sqlInjector() {
|
||||
return new DefaultSqlInjector(); // MyBatis Plus 逻辑删除
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PaginationInterceptor paginationInterceptor() {
|
||||
return new PaginationInterceptor(); // MyBatis Plus 分页插件
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package cn.iocoder.mall.promotionservice.controller;
|
||||
|
||||
import cn.iocoder.common.framework.vo.CommonResult;
|
||||
import cn.iocoder.common.framework.vo.PageResult;
|
||||
import cn.iocoder.mall.promotion.api.rpc.banner.dto.*;
|
||||
import cn.iocoder.mall.promotionservice.manager.banner.BannerManager;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.common.framework.vo.CommonResult.success;
|
||||
|
||||
/**
|
||||
* Title:
|
||||
* Description:
|
||||
*
|
||||
* @author zhuyang
|
||||
* @version 1.0 2021/10/9
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/promotion/banner")
|
||||
public class BannerController {
|
||||
|
||||
@Autowired
|
||||
private BannerManager bannerManager;
|
||||
|
||||
@PostMapping("createBanner")
|
||||
public CommonResult<Integer> createBanner(@RequestBody BannerCreateReqDTO createDTO) {
|
||||
return success(bannerManager.createBanner(createDTO));
|
||||
}
|
||||
|
||||
@PostMapping("updateBanner")
|
||||
public CommonResult<Boolean> updateBanner(@RequestBody BannerUpdateReqDTO updateDTO) {
|
||||
bannerManager.updateBanner(updateDTO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PostMapping("deleteBanner")
|
||||
public CommonResult<Boolean> deleteBanner(@RequestBody Integer bannerId) {
|
||||
bannerManager.deleteBanner(bannerId);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PostMapping("listBanners")
|
||||
public CommonResult<List<BannerRespDTO>> listBanners(@RequestBody BannerListReqDTO listDTO) {
|
||||
return success(bannerManager.listBanners(listDTO));
|
||||
}
|
||||
|
||||
@PostMapping("pageBanner")
|
||||
public CommonResult<PageResult<BannerRespDTO>> pageBanner(@RequestBody BannerPageReqDTO pageDTO) {
|
||||
return success(bannerManager.pageBanner(pageDTO));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package cn.iocoder.mall.promotionservice.controller;
|
||||
|
||||
import cn.iocoder.common.framework.vo.CommonResult;
|
||||
import cn.iocoder.common.framework.vo.PageResult;
|
||||
import cn.iocoder.mall.promotion.api.rpc.coupon.dto.card.*;
|
||||
import cn.iocoder.mall.promotionservice.manager.coupon.CouponCardManager;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.common.framework.vo.CommonResult.success;
|
||||
|
||||
/**
|
||||
* Title:
|
||||
* Description:
|
||||
*
|
||||
* @author zhuyang
|
||||
* @version 1.0 2021/10/9
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/coupon/card")
|
||||
public class CouponCardController {
|
||||
|
||||
@Autowired
|
||||
private CouponCardManager couponCardManager;
|
||||
|
||||
@PostMapping("pageCouponCard")
|
||||
public CommonResult<PageResult<CouponCardRespDTO>> pageCouponCard(@RequestBody CouponCardPageReqDTO pageReqDTO) {
|
||||
return success(couponCardManager.pageCouponCard(pageReqDTO));
|
||||
}
|
||||
|
||||
@PostMapping("createCouponCard")
|
||||
public CommonResult<Integer> createCouponCard(@RequestBody CouponCardCreateReqDTO createReqDTO) {
|
||||
return success(couponCardManager.createCouponCard(createReqDTO));
|
||||
}
|
||||
|
||||
@PostMapping("useCouponCard")
|
||||
public CommonResult<Boolean> useCouponCard(@RequestBody CouponCardUseReqDTO useReqDTO) {
|
||||
return success(couponCardManager.useCouponCard(useReqDTO));
|
||||
}
|
||||
|
||||
@PostMapping("cancelUseCouponCard")
|
||||
public CommonResult<Boolean> cancelUseCouponCard(@RequestBody CouponCardCancelUseReqDTO cancelUseReqDTO) {
|
||||
return success(couponCardManager.cancelUseCouponCard(cancelUseReqDTO));
|
||||
}
|
||||
|
||||
@PostMapping("listAvailableCouponCards")
|
||||
public CommonResult<List<CouponCardAvailableRespDTO>> listAvailableCouponCards(@RequestBody CouponCardAvailableListReqDTO listReqDTO) {
|
||||
return success(couponCardManager.listAvailableCouponCards(listReqDTO));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package cn.iocoder.mall.promotionservice.controller;
|
||||
|
||||
import cn.iocoder.common.framework.vo.CommonResult;
|
||||
import cn.iocoder.common.framework.vo.PageResult;
|
||||
import cn.iocoder.mall.promotion.api.rpc.coupon.dto.template.*;
|
||||
import cn.iocoder.mall.promotionservice.manager.coupon.CouponTemplateManager;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import static cn.iocoder.common.framework.vo.CommonResult.success;
|
||||
|
||||
/**
|
||||
* Title:
|
||||
* Description:
|
||||
*
|
||||
* @author zhuyang
|
||||
* @version 1.0 2021/10/9
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/coupon/template")
|
||||
public class CouponTemplateController {
|
||||
|
||||
@Autowired
|
||||
private CouponTemplateManager couponTemplateManager;
|
||||
|
||||
// ========== 通用逻辑 =========
|
||||
|
||||
@GetMapping("getCouponTemplate")
|
||||
public CommonResult<CouponTemplateRespDTO> getCouponTemplate(@RequestParam("couponTemplateId") Integer couponTemplateId) {
|
||||
return success(couponTemplateManager.getCouponTemplate(couponTemplateId));
|
||||
}
|
||||
|
||||
@PostMapping("pageCouponTemplate")
|
||||
public CommonResult<PageResult<CouponTemplateRespDTO>> pageCouponTemplate(@RequestBody CouponTemplatePageReqDTO pageDTO) {
|
||||
return success(couponTemplateManager.pageCouponTemplate(pageDTO));
|
||||
}
|
||||
|
||||
@PostMapping("updateCouponTemplateStatus")
|
||||
public CommonResult<Boolean> updateCouponTemplateStatus(@RequestBody CouponCardTemplateUpdateStatusReqDTO updateStatusReqDTO) {
|
||||
couponTemplateManager.updateCouponTemplateStatus(updateStatusReqDTO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
// ========== 优惠劵模板 ==========
|
||||
|
||||
@PostMapping("createCouponCardTemplate")
|
||||
public CommonResult<Integer> createCouponCardTemplate(@RequestBody CouponCardTemplateCreateReqDTO createDTO) {
|
||||
return success(couponTemplateManager.createCouponCardTemplate(createDTO));
|
||||
}
|
||||
|
||||
@PostMapping("updateCouponCardTemplate")
|
||||
public CommonResult<Boolean> updateCouponCardTemplate(@RequestBody CouponCardTemplateUpdateReqDTO updateDTO) {
|
||||
couponTemplateManager.updateCouponCardTemplate(updateDTO);
|
||||
return success(true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package cn.iocoder.mall.promotionservice.controller;
|
||||
|
||||
import cn.iocoder.common.framework.vo.CommonResult;
|
||||
import cn.iocoder.mall.promotion.api.rpc.price.dto.PriceProductCalcReqDTO;
|
||||
import cn.iocoder.mall.promotion.api.rpc.price.dto.PriceProductCalcRespDTO;
|
||||
import cn.iocoder.mall.promotionservice.manager.price.PriceManager;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import static cn.iocoder.common.framework.vo.CommonResult.success;
|
||||
|
||||
/**
|
||||
* Title:
|
||||
* Description:
|
||||
*
|
||||
* @author zhuyang
|
||||
* @version 1.0 2021/10/9
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/promotion/price")
|
||||
public class PriceController {
|
||||
|
||||
@Autowired
|
||||
private PriceManager priceManager;
|
||||
|
||||
@PostMapping("calcProductPrice")
|
||||
public CommonResult<PriceProductCalcRespDTO> calcProductPrice(@RequestBody PriceProductCalcReqDTO calcReqDTO) {
|
||||
return success(priceManager.calcProductPrice(calcReqDTO));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package cn.iocoder.mall.promotionservice.controller;
|
||||
|
||||
import cn.iocoder.common.framework.vo.CommonResult;
|
||||
import cn.iocoder.common.framework.vo.PageResult;
|
||||
import cn.iocoder.mall.promotion.api.rpc.recommend.dto.*;
|
||||
import cn.iocoder.mall.promotionservice.manager.recommend.ProductRecommendManager;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.common.framework.vo.CommonResult.success;
|
||||
|
||||
/**
|
||||
* Title:
|
||||
* Description:
|
||||
*
|
||||
* @author zhuyang
|
||||
* @version 1.0 2021/10/9
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/promotion/prod/recommend")
|
||||
public class ProductRecommendController {
|
||||
|
||||
@Autowired
|
||||
private ProductRecommendManager productRecommendManager;
|
||||
|
||||
|
||||
@PostMapping("createProductRecommend")
|
||||
public CommonResult<Integer> createProductRecommend(@RequestBody ProductRecommendCreateReqDTO createDTO) {
|
||||
return success(productRecommendManager.createProductRecommend(createDTO));
|
||||
}
|
||||
|
||||
@PostMapping("updateProductRecommend")
|
||||
public CommonResult<Boolean> updateProductRecommend(@RequestBody ProductRecommendUpdateReqDTO updateDTO) {
|
||||
productRecommendManager.updateProductRecommend(updateDTO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("deleteProductRecommend")
|
||||
public CommonResult<Boolean> deleteProductRecommend(@RequestParam("productRecommendId") Integer productRecommendId) {
|
||||
productRecommendManager.deleteProductRecommend(productRecommendId);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PostMapping("listProductRecommends")
|
||||
public CommonResult<List<ProductRecommendRespDTO>> listProductRecommends(@RequestBody ProductRecommendListReqDTO listReqDTO) {
|
||||
return success(productRecommendManager.listProductRecommends(listReqDTO));
|
||||
}
|
||||
|
||||
@PostMapping("pageProductRecommend")
|
||||
public CommonResult<PageResult<ProductRecommendRespDTO>> pageProductRecommend(@RequestBody ProductRecommendPageReqDTO pageDTO) {
|
||||
return success(productRecommendManager.pageProductRecommend(pageDTO));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package cn.iocoder.mall.promotionservice.controller;
|
||||
|
||||
import cn.iocoder.common.framework.vo.CommonResult;
|
||||
import cn.iocoder.common.framework.vo.PageResult;
|
||||
import cn.iocoder.mall.promotion.api.rpc.activity.dto.PromotionActivityListReqDTO;
|
||||
import cn.iocoder.mall.promotion.api.rpc.activity.dto.PromotionActivityPageReqDTO;
|
||||
import cn.iocoder.mall.promotion.api.rpc.activity.dto.PromotionActivityRespDTO;
|
||||
import cn.iocoder.mall.promotionservice.manager.activity.PromotionActivityManager;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.common.framework.vo.CommonResult.success;
|
||||
|
||||
/**
|
||||
* Title:
|
||||
* Description:
|
||||
*
|
||||
* @author zhuyang
|
||||
* @version 1.0 2021/10/9
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/promotion/activity")
|
||||
public class PromotionActivityController {
|
||||
@Autowired
|
||||
private PromotionActivityManager promotionActivityManager;
|
||||
|
||||
@PostMapping("pagePromotionActivity")
|
||||
public CommonResult<PageResult<PromotionActivityRespDTO>> pagePromotionActivity(@RequestBody PromotionActivityPageReqDTO pageReqDTO) {
|
||||
return success(promotionActivityManager.pagePromotionActivity(pageReqDTO));
|
||||
}
|
||||
@PostMapping("listPromotionActivities")
|
||||
public CommonResult<List<PromotionActivityRespDTO>> listPromotionActivities(@RequestBody PromotionActivityListReqDTO listReqDTO) {
|
||||
return success(promotionActivityManager.listPromotionActivities(listReqDTO));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package cn.iocoder.mall.promotionservice.convert.activity;
|
||||
|
||||
import cn.iocoder.common.framework.vo.PageResult;
|
||||
import cn.iocoder.mall.promotion.api.rpc.activity.dto.PromotionActivityRespDTO;
|
||||
import cn.iocoder.mall.promotionservice.dal.mysql.dataobject.activity.PromotionActivityDO;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface PromotionActivityConvert {
|
||||
|
||||
PromotionActivityConvert INSTANCE = Mappers.getMapper(PromotionActivityConvert.class);
|
||||
|
||||
List<PromotionActivityRespDTO> convertList(List<PromotionActivityDO> list);
|
||||
|
||||
@Mapping(source = "records", target = "list")
|
||||
PageResult<PromotionActivityRespDTO> convertPage(IPage<PromotionActivityDO> page);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package cn.iocoder.mall.promotionservice.convert.banner;
|
||||
|
||||
import cn.iocoder.common.framework.vo.PageResult;
|
||||
import cn.iocoder.mall.promotion.api.rpc.banner.dto.BannerCreateReqDTO;
|
||||
import cn.iocoder.mall.promotion.api.rpc.banner.dto.BannerRespDTO;
|
||||
import cn.iocoder.mall.promotion.api.rpc.banner.dto.BannerUpdateReqDTO;
|
||||
import cn.iocoder.mall.promotionservice.dal.mysql.dataobject.banner.BannerDO;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface BannerConvert {
|
||||
|
||||
BannerConvert INSTANCE = Mappers.getMapper(BannerConvert.class);
|
||||
|
||||
BannerDO convert(BannerCreateReqDTO bean);
|
||||
|
||||
BannerDO convert(BannerUpdateReqDTO bean);
|
||||
|
||||
@Mapping(source = "records", target = "list")
|
||||
PageResult<BannerRespDTO> convertPage(IPage<BannerDO> page);
|
||||
|
||||
List<BannerRespDTO> convertList(List<BannerDO> list);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package cn.iocoder.mall.promotionservice.convert.coupon;
|
||||
|
||||
import cn.iocoder.common.framework.vo.PageResult;
|
||||
import cn.iocoder.mall.promotion.api.rpc.coupon.dto.card.CouponCardAvailableRespDTO;
|
||||
import cn.iocoder.mall.promotion.api.rpc.coupon.dto.card.CouponCardRespDTO;
|
||||
import cn.iocoder.mall.promotionservice.dal.mysql.dataobject.coupon.CouponCardDO;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.Named;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
@Mapper
|
||||
public interface CouponCardConvert {
|
||||
|
||||
CouponCardConvert INSTANCE = Mappers.getMapper(CouponCardConvert.class);
|
||||
|
||||
CouponCardRespDTO convert(CouponCardDO bean);
|
||||
|
||||
@Mapping(source = "records", target = "list")
|
||||
PageResult<CouponCardRespDTO> convertPage(IPage<CouponCardDO> page);
|
||||
|
||||
@Named("convertCouponCardDOToCouponCardAvailableRespDTO") // 避免生成的方法名的冲突
|
||||
CouponCardAvailableRespDTO convert01(CouponCardDO bean);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package cn.iocoder.mall.promotionservice.convert.coupon;
|
||||
|
||||
import cn.iocoder.common.framework.util.StringUtils;
|
||||
import cn.iocoder.common.framework.vo.PageResult;
|
||||
import cn.iocoder.mall.promotion.api.rpc.coupon.dto.template.CouponCardTemplateCreateReqDTO;
|
||||
import cn.iocoder.mall.promotion.api.rpc.coupon.dto.template.CouponCardTemplateUpdateReqDTO;
|
||||
import cn.iocoder.mall.promotion.api.rpc.coupon.dto.template.CouponTemplateRespDTO;
|
||||
import cn.iocoder.mall.promotionservice.dal.mysql.dataobject.coupon.CouponTemplateDO;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.Named;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface CouponTemplateConvert {
|
||||
|
||||
CouponTemplateConvert INSTANCE = Mappers.getMapper(CouponTemplateConvert.class);
|
||||
|
||||
@Mapping(source = "rangeValues", target = "rangeValues", qualifiedByName = "translateStringToIntList")
|
||||
CouponTemplateRespDTO convert(CouponTemplateDO bean);
|
||||
|
||||
CouponTemplateDO convert(CouponCardTemplateCreateReqDTO bean);
|
||||
|
||||
CouponTemplateDO convert(CouponCardTemplateUpdateReqDTO bean);
|
||||
|
||||
@Mapping(source = "records", target = "list")
|
||||
PageResult<CouponTemplateRespDTO> convertPage(IPage<CouponTemplateDO> couponTemplatePage);
|
||||
|
||||
@Named("translateStringToIntList")
|
||||
default List<Integer> translateStringToIntList(String str) {
|
||||
return StringUtils.splitToInt(str, ",");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package cn.iocoder.mall.promotionservice.convert.recommend;
|
||||
|
||||
import cn.iocoder.common.framework.vo.PageResult;
|
||||
import cn.iocoder.mall.promotion.api.rpc.recommend.dto.ProductRecommendCreateReqDTO;
|
||||
import cn.iocoder.mall.promotion.api.rpc.recommend.dto.ProductRecommendRespDTO;
|
||||
import cn.iocoder.mall.promotion.api.rpc.recommend.dto.ProductRecommendUpdateReqDTO;
|
||||
import cn.iocoder.mall.promotionservice.dal.mysql.dataobject.recommend.ProductRecommendDO;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface ProductRecommendConvert {
|
||||
|
||||
ProductRecommendConvert INSTANCE = Mappers.getMapper(ProductRecommendConvert.class);
|
||||
|
||||
List<ProductRecommendRespDTO> convertList(List<ProductRecommendDO> list);
|
||||
|
||||
@Mapping(source = "records", target = "list")
|
||||
PageResult<ProductRecommendRespDTO> convertPage(IPage<ProductRecommendDO> page);
|
||||
|
||||
ProductRecommendDO convert(ProductRecommendCreateReqDTO bean);
|
||||
|
||||
ProductRecommendDO convert(ProductRecommendUpdateReqDTO bean);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
package cn.iocoder.mall.promotionservice.dal.mysql.dataobject.activity;
|
||||
|
||||
import cn.iocoder.mall.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.mall.promotion.api.enums.activity.PromotionActivityStatusEnum;
|
||||
import cn.iocoder.mall.promotion.api.enums.activity.PromotionActivityTypeEnum;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 促销活动 DO
|
||||
*/
|
||||
@TableName(value = "promotion_activity", autoResultMap = true)
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Accessors(chain = true)
|
||||
public class PromotionActivityDO extends BaseDO {
|
||||
|
||||
/**
|
||||
* 活动编号
|
||||
*/
|
||||
private Integer id;
|
||||
/**
|
||||
* 活动标题
|
||||
*/
|
||||
private String title;
|
||||
/**
|
||||
* 活动类型
|
||||
*
|
||||
* 参见 {@link PromotionActivityTypeEnum} 枚举
|
||||
*/
|
||||
private Integer activityType;
|
||||
// /**
|
||||
// * 促销类型
|
||||
// * // TODO 芋艿 https://jos.jd.com/api/complexTemplate.htm?webPamer=promotion_v_o&groupName=%E4%BF%83%E9%94%80API&id=54&restName=jingdong.seller.promotion.list&isMulti=false 促销类型,可选值:单品促销(1),赠品促销(4),套装促销(6),总价促销(10)
|
||||
// */
|
||||
// private Integer promotionType;
|
||||
/**
|
||||
* 活动状态
|
||||
*
|
||||
* 参见 {@link PromotionActivityStatusEnum} 枚举
|
||||
*/
|
||||
private Integer status;
|
||||
/**
|
||||
* 开始时间
|
||||
*/
|
||||
private Date startTime;
|
||||
/**
|
||||
* 结束时间
|
||||
*/
|
||||
private Date endTime;
|
||||
/**
|
||||
* 失效时间
|
||||
*/
|
||||
private Date invalidTime;
|
||||
/**
|
||||
* 删除时间
|
||||
*/
|
||||
private Date deleteTime;
|
||||
/**
|
||||
* 限制折扣字符串,使用 JSON 序列化成字符串存储
|
||||
*/
|
||||
@TableField(typeHandler = FastjsonTypeHandler.class)
|
||||
private TimeLimitedDiscount timeLimitedDiscount;
|
||||
/**
|
||||
* 满减送字符串,使用 JSON 序列化成字符串存储
|
||||
*/
|
||||
@TableField(typeHandler = FastjsonTypeHandler.class)
|
||||
private FullPrivilege fullPrivilege;
|
||||
|
||||
/**
|
||||
* 限制折扣
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public static class TimeLimitedDiscount {
|
||||
|
||||
/**
|
||||
* 商品折扣
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public static class Item {
|
||||
|
||||
/**
|
||||
* 商品 SPU 编号
|
||||
*/
|
||||
private Integer spuId;
|
||||
/**
|
||||
* 优惠类型
|
||||
*/
|
||||
private Integer preferentialType;
|
||||
/**
|
||||
* 优惠值
|
||||
*/
|
||||
private Integer preferentialValue;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 每人每种限购多少
|
||||
*
|
||||
* 当 quota = 0 时,表示不限购
|
||||
*/
|
||||
private Integer quota;
|
||||
/**
|
||||
* 商品折扣数组
|
||||
*/
|
||||
private List<Item> items;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 满减送
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public static class FullPrivilege {
|
||||
|
||||
/**
|
||||
* 优惠
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public static class Privilege {
|
||||
|
||||
/**
|
||||
* 满足类型
|
||||
*
|
||||
* 1 - 金额
|
||||
* 2 - 件数
|
||||
*/
|
||||
private Integer meetType;
|
||||
/**
|
||||
* 满足值
|
||||
*/
|
||||
private Integer meetValue;
|
||||
/**
|
||||
* 优惠类型
|
||||
*/
|
||||
private Integer preferentialType;
|
||||
/**
|
||||
* 优惠值
|
||||
*/
|
||||
private Integer preferentialValue;
|
||||
// /**
|
||||
// * 是否包邮
|
||||
// */
|
||||
// private Boolean isPostage;
|
||||
// /**
|
||||
// * 积分
|
||||
// */
|
||||
// private Integer score;
|
||||
// /**
|
||||
// * 优惠劵(码)分组编号
|
||||
// */
|
||||
// private Integer couponTemplateId;
|
||||
// /**
|
||||
// * 优惠劵(码)数量
|
||||
// */
|
||||
// private Integer couponNum;
|
||||
// /**
|
||||
// * 赠品编号
|
||||
// */
|
||||
// private Integer presentId;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 可用范围的类型
|
||||
*
|
||||
* 参见 {@link cn.iocoder.mall.promotion.api.enums.RangeTypeEnum} 枚举
|
||||
* 暂时只用 “所有可用” + “PRODUCT_INCLUDE_PRT”
|
||||
*/
|
||||
private Integer rangeType;
|
||||
/**
|
||||
* 指定可用商品列表
|
||||
*/
|
||||
private List<Integer> rangeValues;
|
||||
/**
|
||||
* 是否循环
|
||||
*/
|
||||
private Boolean cycled;
|
||||
/**
|
||||
* 优惠数组
|
||||
*/
|
||||
private List<Privilege> privileges;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package cn.iocoder.mall.promotionservice.dal.mysql.dataobject.banner;
|
||||
|
||||
import cn.iocoder.mall.mybatis.core.dataobject.DeletableDO;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* Banner 广告页
|
||||
*/
|
||||
@TableName("banner")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Accessors(chain = true)
|
||||
public class BannerDO extends DeletableDO {
|
||||
|
||||
/**
|
||||
* 编号
|
||||
*/
|
||||
private Integer id;
|
||||
/**
|
||||
* 标题
|
||||
*/
|
||||
private String title;
|
||||
/**
|
||||
* 跳转链接
|
||||
*/
|
||||
private String url;
|
||||
/**
|
||||
* 图片链接
|
||||
*/
|
||||
private String picUrl;
|
||||
/**
|
||||
* 排序
|
||||
*/
|
||||
private Integer sort;
|
||||
/**
|
||||
* 状态
|
||||
*
|
||||
* {@link cn.iocoder.common.framework.enums.CommonStatusEnum}
|
||||
*/
|
||||
private Integer status;
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String memo;
|
||||
|
||||
// TODO 芋艿 点击次数。&& 其他数据相关
|
||||
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
package cn.iocoder.mall.promotionservice.dal.mysql.dataobject.coupon;
|
||||
|
||||
import cn.iocoder.mall.mybatis.core.dataobject.BaseDO;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 优惠劵 DO
|
||||
*/
|
||||
@TableName("coupon_card")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Accessors(chain = true)
|
||||
public class CouponCardDO extends BaseDO {
|
||||
|
||||
// ========== 基本信息 BEGIN ==========
|
||||
/**
|
||||
* 优惠劵编号
|
||||
*/
|
||||
private Integer id;
|
||||
/**
|
||||
* 优惠劵(码)分组编号,{@link CouponTemplateDO} 的 id
|
||||
*/
|
||||
private Integer templateId;
|
||||
/**
|
||||
* 优惠劵名
|
||||
*
|
||||
* 冗余自 {@link CouponTemplateDO} 的 title
|
||||
*
|
||||
* TODO 芋艿,暂时不考虑冗余的更新
|
||||
*/
|
||||
private String title;
|
||||
// /**
|
||||
// * 核销码
|
||||
// */
|
||||
// private String verifyCode;
|
||||
/**
|
||||
* 优惠码状态
|
||||
*
|
||||
* 1-未使用
|
||||
* 2-已使用
|
||||
* 3-已失效
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
// ========== 基本信息 END ==========
|
||||
|
||||
// ========== 领取情况 BEGIN ==========
|
||||
/**
|
||||
* 用户编号
|
||||
*/
|
||||
private Integer userId;
|
||||
/**
|
||||
* 领取类型
|
||||
*
|
||||
* 1 - 用户主动领取
|
||||
* 2 - 后台自动发放
|
||||
*/
|
||||
private Integer takeType;
|
||||
// ========== 领取情况 END ==========
|
||||
|
||||
// ========== 使用规则 BEGIN ==========
|
||||
/**
|
||||
* 是否设置满多少金额可用,单位:分
|
||||
*/
|
||||
private Integer priceAvailable;
|
||||
/**
|
||||
* 生效开始时间
|
||||
*/
|
||||
private Date validStartTime;
|
||||
/**
|
||||
* 生效结束时间
|
||||
*/
|
||||
private Date validEndTime;
|
||||
// ========== 使用规则 END ==========
|
||||
|
||||
// ========== 使用效果 BEGIN ==========
|
||||
/**
|
||||
* 优惠类型
|
||||
*
|
||||
* 1-代金卷
|
||||
* 2-折扣卷
|
||||
*/
|
||||
private Integer preferentialType;
|
||||
/**
|
||||
* 折扣
|
||||
*/
|
||||
private Integer percentOff;
|
||||
/**
|
||||
* 优惠金额,单位:分。
|
||||
*/
|
||||
private Integer priceOff;
|
||||
/**
|
||||
* 折扣上限,仅在 {@link #preferentialType} 等于 2 时生效。
|
||||
*
|
||||
* 例如,折扣上限为 20 元,当使用 8 折优惠券,订单金额为 1000 元时,最高只可折扣 20 元,而非 80 元。
|
||||
*/
|
||||
private Integer discountPriceLimit;
|
||||
// ========== 使用效果 END ==========
|
||||
|
||||
// ========== 使用情况 BEGIN ==========
|
||||
// /**
|
||||
// * 使用订单号
|
||||
// */
|
||||
// private Integer usedOrderId; // TODO 芋艿,暂时不考虑这个字段
|
||||
// /**
|
||||
// * 订单中优惠面值,单位:分
|
||||
// */
|
||||
// private Integer usedPrice; // TODO 芋艿,暂时不考虑这个字段
|
||||
/**
|
||||
* 使用时间
|
||||
*/
|
||||
private Date usedTime;
|
||||
|
||||
// TODO 芋艿,后续要加优惠劵的使用日志,因为下单后,可能会取消。
|
||||
|
||||
// ========== 使用情况 END ==========
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package cn.iocoder.mall.promotionservice.dal.mysql.dataobject.coupon;
|
||||
|
||||
import cn.iocoder.mall.mybatis.core.dataobject.BaseDO;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 优惠码
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class CouponCodeDO extends BaseDO {
|
||||
|
||||
/**
|
||||
* 编号
|
||||
*/
|
||||
private Integer id;
|
||||
/**
|
||||
* 模板编号 {@link CouponTemplateDO} 的 id
|
||||
*/
|
||||
private Integer templateId;
|
||||
/**
|
||||
* 优惠码
|
||||
*/
|
||||
private Integer code;
|
||||
/**
|
||||
* 领取时间
|
||||
*/
|
||||
private Date takeTime;
|
||||
/**
|
||||
* 领取用户编号
|
||||
*/
|
||||
private Integer userId;
|
||||
/**
|
||||
* 领取的优惠劵编号
|
||||
*/
|
||||
private Integer couponId;
|
||||
|
||||
// TODO 芋艿,后续要考虑状态的追踪
|
||||
|
||||
}
|
||||
@@ -0,0 +1,237 @@
|
||||
package cn.iocoder.mall.promotionservice.dal.mysql.dataobject.coupon;
|
||||
|
||||
import cn.iocoder.mall.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.mall.promotion.api.enums.PreferentialTypeEnum;
|
||||
import cn.iocoder.mall.promotion.api.enums.RangeTypeEnum;
|
||||
import cn.iocoder.mall.promotion.api.enums.coupon.template.CouponTemplateDateTypeEnum;
|
||||
import cn.iocoder.mall.promotion.api.enums.coupon.template.CouponTemplateStatusEnum;
|
||||
import cn.iocoder.mall.promotion.api.enums.coupon.template.CouponTemplateTypeEnum;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 优惠劵(码)模板 DO
|
||||
*
|
||||
* 当用户领取时,会生成 {@link CouponCardDO} 优惠劵(码)。
|
||||
*/
|
||||
@TableName("coupon_template")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Accessors(chain = true)
|
||||
public class CouponTemplateDO extends BaseDO {
|
||||
|
||||
// ========== 基本信息 BEGIN ==========
|
||||
/**
|
||||
* 模板编号,自增唯一。
|
||||
*/
|
||||
private Integer id;
|
||||
/**
|
||||
* 标题
|
||||
*/
|
||||
private String title;
|
||||
/**
|
||||
* 使用说明
|
||||
*/
|
||||
private String description;
|
||||
/**
|
||||
* 类型
|
||||
*
|
||||
* 枚举 {@link CouponTemplateTypeEnum}
|
||||
*
|
||||
* 1-优惠劵
|
||||
* 2-优惠码
|
||||
*/
|
||||
private Integer type;
|
||||
/**
|
||||
* 优惠码状态
|
||||
*
|
||||
* 枚举 {@link CouponTemplateStatusEnum}
|
||||
*
|
||||
* 当优惠劵(码)开启中,可以手动操作,设置禁用中。
|
||||
*/
|
||||
private Integer status;
|
||||
// /**
|
||||
// * 是否可分享领取链接
|
||||
// */
|
||||
// private Boolean isShare;
|
||||
// /**
|
||||
// * 设置为失效时间
|
||||
// */
|
||||
// private Date invalidTime;
|
||||
// /**
|
||||
// * 删除时间
|
||||
// */
|
||||
// private Date deleteTime;
|
||||
|
||||
// ========== 基本信息 END ==========
|
||||
|
||||
// ========== 领取规则 BEGIN ==========
|
||||
// /**
|
||||
// * 是否限制领用者的等级
|
||||
// *
|
||||
// * 0-不限制
|
||||
// * 大于0-领用者必须是这个等级编号
|
||||
// *
|
||||
// * 【优惠劵独有】
|
||||
// */
|
||||
// private Integer needUserLevel;
|
||||
/**
|
||||
* 每人限领个数
|
||||
*
|
||||
* null - 则表示不限制
|
||||
*/
|
||||
private Integer quota;
|
||||
/**
|
||||
* 发行总量
|
||||
*/
|
||||
private Integer total;
|
||||
// ========== 领取规则 END ==========
|
||||
|
||||
// ========== 使用规则 BEGIN ==========
|
||||
// /**
|
||||
// * 是否仅原价购买商品时可用
|
||||
// *
|
||||
// * true-是
|
||||
// * false-否
|
||||
// */
|
||||
// private Boolean isForbidPreference;
|
||||
/**
|
||||
* 是否设置满多少金额可用,单位:分
|
||||
*
|
||||
* 0-不限制
|
||||
* 大于0-多少金额可用
|
||||
*/
|
||||
private Integer priceAvailable;
|
||||
/**
|
||||
* 可用范围的类型
|
||||
*
|
||||
* 枚举 {@link RangeTypeEnum}
|
||||
*
|
||||
* 10-全部(ALL):所有可用
|
||||
* 20-部分(PART):部分商品可用,或指定商品可用
|
||||
* 21-部分(PART):部分商品不可用,或指定商品可用
|
||||
* 30-部分(PART):部分分类可用,或指定商品可用
|
||||
* 31-部分(PART):部分分类不可用,或指定商品可用
|
||||
*/
|
||||
private Integer rangeType;
|
||||
/**
|
||||
* 指定商品 / 分类列表,使用逗号分隔商品编号
|
||||
*/
|
||||
private String rangeValues;
|
||||
/**
|
||||
* 生效日期类型
|
||||
*
|
||||
* 枚举 {@link CouponTemplateDateTypeEnum}
|
||||
*
|
||||
* 1-固定日期
|
||||
* 2-领取日期:领到券 {@link #fixedStartTerm} 日开始 N 天内有效
|
||||
*/
|
||||
private Integer dateType;
|
||||
/**
|
||||
* 固定日期-生效开始时间
|
||||
*/
|
||||
private Date validStartTime;
|
||||
/**
|
||||
* 固定日期-生效结束时间
|
||||
*/
|
||||
private Date validEndTime;
|
||||
/**
|
||||
* 领取日期-开始天数
|
||||
*
|
||||
* 例如,0-当天;1-次天
|
||||
*/
|
||||
private Integer fixedStartTerm;
|
||||
/**
|
||||
* 领取日期-结束天数
|
||||
*/
|
||||
private Integer fixedEndTerm;
|
||||
// /**
|
||||
// * 是否到期前4天发送提醒
|
||||
// *
|
||||
// * true-发送
|
||||
// * false-不发送
|
||||
// */
|
||||
// private Boolean expireNotice;
|
||||
// ========== 使用规则 END ==========
|
||||
|
||||
// ========== 使用效果 BEGIN ==========
|
||||
/**
|
||||
* 优惠类型
|
||||
*
|
||||
* 枚举 {@link PreferentialTypeEnum}
|
||||
*
|
||||
* 1-代金卷
|
||||
* 2-折扣卷
|
||||
*/
|
||||
private Integer preferentialType;
|
||||
/**
|
||||
* 折扣百分比。
|
||||
*
|
||||
* 例如,80% 为 80。
|
||||
* 当 100% 为 100 ,则代表免费。
|
||||
*/
|
||||
private Integer percentOff;
|
||||
// /**
|
||||
// * 是否是随机优惠券
|
||||
// *
|
||||
// * true-随机
|
||||
// * false-不随机
|
||||
// *
|
||||
// * 【优惠劵独有】
|
||||
// */
|
||||
// private Boolean isRandom;
|
||||
/**
|
||||
* 优惠金额,单位:分
|
||||
*/
|
||||
// * 当 {@link #isRandom} 为 true 时,代表随机优惠金额的下限
|
||||
private Integer priceOff;
|
||||
// /**
|
||||
// * 优惠金额上限
|
||||
// *
|
||||
// * 【优惠劵独有】
|
||||
// */
|
||||
// private Integer valueRandomTo;
|
||||
/**
|
||||
* 折扣上限,仅在 {@link #preferentialType} 等于 2 时生效。
|
||||
*
|
||||
* 例如,折扣上限为 20 元,当使用 8 折优惠券,订单金额为 1000 元时,最高只可折扣 20 元,而非 80 元。
|
||||
*/
|
||||
private Integer discountPriceLimit;
|
||||
// ========== 使用效果 END ==========
|
||||
|
||||
// ========== 统计信息 BEGIN ==========
|
||||
// /**
|
||||
// * 领取优惠券的人数
|
||||
// */
|
||||
// private Integer statFetchUserNum;
|
||||
/**
|
||||
* 领取优惠券的次数
|
||||
*/
|
||||
private Integer statFetchNum;
|
||||
// /**
|
||||
// * 使用优惠券的次数
|
||||
// */
|
||||
// private Integer statUseNum;
|
||||
// ========== 统计信息 END ==========
|
||||
|
||||
// ========== 优惠码 BEGIN ==========
|
||||
/**
|
||||
* 码类型
|
||||
*
|
||||
* 1-一卡一码(UNIQUE)
|
||||
* 2-通用码(GENERAL)
|
||||
*
|
||||
* 【优惠码独有】 @see CouponCodeDO
|
||||
*/
|
||||
private Integer codeType;
|
||||
/**
|
||||
* 通用码
|
||||
*/
|
||||
private String commonCode;
|
||||
// ========== 优惠码 BEGIN ==========
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package cn.iocoder.mall.promotionservice.dal.mysql.dataobject.recommend;
|
||||
|
||||
|
||||
import cn.iocoder.mall.mybatis.core.dataobject.DeletableDO;
|
||||
import cn.iocoder.mall.promotion.api.enums.recommend.ProductRecommendTypeEnum;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 商品推荐 DO
|
||||
*/
|
||||
@TableName("product_recommend")
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class ProductRecommendDO extends DeletableDO {
|
||||
|
||||
/**
|
||||
* 编号
|
||||
*/
|
||||
private Integer id;
|
||||
/**
|
||||
* 类型
|
||||
*
|
||||
* {@link ProductRecommendTypeEnum}
|
||||
*/
|
||||
private Integer type;
|
||||
/**
|
||||
* 商品 Spu 编号
|
||||
*/
|
||||
private Integer productSpuId;
|
||||
// TODO 芋艿,商品 spu 名
|
||||
/**
|
||||
* 排序
|
||||
*/
|
||||
private Integer sort;
|
||||
/**
|
||||
* 状态
|
||||
*
|
||||
* {@link cn.iocoder.common.framework.enums.CommonStatusEnum}
|
||||
*/
|
||||
private Integer status;
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String memo;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package cn.iocoder.mall.promotionservice.dal.mysql.mapper.activity;
|
||||
|
||||
import cn.iocoder.mall.mybatis.core.query.QueryWrapperX;
|
||||
import cn.iocoder.mall.promotion.api.rpc.activity.dto.PromotionActivityListReqDTO;
|
||||
import cn.iocoder.mall.promotion.api.rpc.activity.dto.PromotionActivityPageReqDTO;
|
||||
import cn.iocoder.mall.promotionservice.dal.mysql.dataobject.activity.PromotionActivityDO;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface PromotionActivityMapper extends BaseMapper<PromotionActivityDO> {
|
||||
|
||||
default List<PromotionActivityDO> selectListByStatus(Collection<Integer> statuses) {
|
||||
return selectList(new QueryWrapper<PromotionActivityDO>().in("status", statuses));
|
||||
}
|
||||
|
||||
default IPage<PromotionActivityDO> selectPage(PromotionActivityPageReqDTO pageReqDTO) {
|
||||
return selectPage(new Page<>(pageReqDTO.getPageNo(), pageReqDTO.getPageSize()),
|
||||
new QueryWrapperX<PromotionActivityDO>().likeIfPresent("title", pageReqDTO.getTitle())
|
||||
.eqIfPresent("activity_type", pageReqDTO.getActivityType())
|
||||
.inIfPresent("status", pageReqDTO.getStatuses()));
|
||||
}
|
||||
|
||||
default List<PromotionActivityDO> selectList(PromotionActivityListReqDTO listReqDTO) {
|
||||
return selectList(new QueryWrapperX<PromotionActivityDO>().inIfPresent("id", listReqDTO.getActiveIds()));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package cn.iocoder.mall.promotionservice.dal.mysql.mapper.banner;
|
||||
|
||||
import cn.iocoder.mall.mybatis.core.query.QueryWrapperX;
|
||||
import cn.iocoder.mall.promotion.api.rpc.banner.dto.BannerListReqDTO;
|
||||
import cn.iocoder.mall.promotion.api.rpc.banner.dto.BannerPageReqDTO;
|
||||
import cn.iocoder.mall.promotionservice.dal.mysql.dataobject.banner.BannerDO;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface BannerMapper extends BaseMapper<BannerDO> {
|
||||
|
||||
default List<BannerDO> selectList(BannerListReqDTO listReqDTO) {
|
||||
return selectList(new QueryWrapperX<BannerDO>().eqIfPresent("status", listReqDTO.getStatus()));
|
||||
}
|
||||
|
||||
default IPage<BannerDO> selectPage(BannerPageReqDTO pageReqDTO) {
|
||||
return selectPage(new Page<>(pageReqDTO.getPageNo(), pageReqDTO.getPageSize()),
|
||||
new QueryWrapperX<BannerDO>().likeIfPresent("title", pageReqDTO.getTitle()));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package cn.iocoder.mall.promotionservice.dal.mysql.mapper.coupon;
|
||||
|
||||
import cn.iocoder.mall.mybatis.core.query.QueryWrapperX;
|
||||
import cn.iocoder.mall.promotion.api.rpc.coupon.dto.card.CouponCardPageReqDTO;
|
||||
import cn.iocoder.mall.promotionservice.dal.mysql.dataobject.coupon.CouponCardDO;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface CouponCardMapper extends BaseMapper<CouponCardDO> {
|
||||
|
||||
default List<CouponCardDO> selectListByUserIdAndStatus(Integer userId, Integer status) {
|
||||
return selectList(new QueryWrapper<CouponCardDO>().eq("user_id", userId)
|
||||
.eq("status", status));
|
||||
}
|
||||
|
||||
default int selectCountByUserIdAndTemplateId(Integer userId, Integer templateId) {
|
||||
return selectCount(new QueryWrapper<CouponCardDO>().eq("user_id", userId)
|
||||
.eq("template_id", templateId));
|
||||
}
|
||||
|
||||
default int updateByIdAndStatus(Integer id, Integer status, CouponCardDO updateObj) {
|
||||
return update(updateObj, new QueryWrapper<CouponCardDO>().eq("id", id)
|
||||
.eq("status", status));
|
||||
}
|
||||
|
||||
default IPage<CouponCardDO> selectPage(CouponCardPageReqDTO pageReqDTO) {
|
||||
return selectPage(new Page<>(pageReqDTO.getPageNo(), pageReqDTO.getPageSize()),
|
||||
new QueryWrapperX<CouponCardDO>().eqIfPresent("user_id", pageReqDTO.getUserId())
|
||||
.eqIfPresent("status", pageReqDTO.getStatus()));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package cn.iocoder.mall.promotionservice.dal.mysql.mapper.coupon;
|
||||
|
||||
import cn.iocoder.mall.mybatis.core.query.QueryWrapperX;
|
||||
import cn.iocoder.mall.promotion.api.rpc.coupon.dto.template.CouponTemplatePageReqDTO;
|
||||
import cn.iocoder.mall.promotionservice.dal.mysql.dataobject.coupon.CouponTemplateDO;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface CouponTemplateMapper extends BaseMapper<CouponTemplateDO> {
|
||||
|
||||
default IPage<CouponTemplateDO> selectPage(CouponTemplatePageReqDTO pageReqDTO) {
|
||||
return selectPage(new Page<>(pageReqDTO.getPageNo(), pageReqDTO.getPageSize()),
|
||||
new QueryWrapperX<CouponTemplateDO>().eqIfPresent("type", pageReqDTO.getType())
|
||||
.likeIfPresent("title", pageReqDTO.getTitle())
|
||||
.eqIfPresent("status", pageReqDTO.getStatus())
|
||||
.eqIfPresent("preferential_type", pageReqDTO.getPreferentialType()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新优惠劵模板已领取的数量
|
||||
*
|
||||
* 如果超过领取上限,则返回 0
|
||||
*
|
||||
* @param id 优惠劵模板编号
|
||||
* @return 更新数量
|
||||
*/
|
||||
int updateStatFetchNumIncr(@Param("id") Integer id);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package cn.iocoder.mall.promotionservice.dal.mysql.mapper.recommend;
|
||||
|
||||
import cn.iocoder.mall.mybatis.core.query.QueryWrapperX;
|
||||
import cn.iocoder.mall.promotion.api.rpc.recommend.dto.ProductRecommendListReqDTO;
|
||||
import cn.iocoder.mall.promotion.api.rpc.recommend.dto.ProductRecommendPageReqDTO;
|
||||
import cn.iocoder.mall.promotionservice.dal.mysql.dataobject.recommend.ProductRecommendDO;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface ProductRecommendMapper extends BaseMapper<ProductRecommendDO> {
|
||||
|
||||
default ProductRecommendDO selectByProductSpuIdAndType(Integer productSpuId, Integer type) {
|
||||
return selectOne(new QueryWrapper<ProductRecommendDO>().eq("product_spu_id", productSpuId)
|
||||
.eq("type", type));
|
||||
}
|
||||
|
||||
default List<ProductRecommendDO> selectList(ProductRecommendListReqDTO listReqDTO) {
|
||||
return selectList(new QueryWrapperX<ProductRecommendDO>().eqIfPresent("type", listReqDTO.getType())
|
||||
.eqIfPresent("status", listReqDTO.getStatus()));
|
||||
}
|
||||
|
||||
default IPage<ProductRecommendDO> selectPage(ProductRecommendPageReqDTO pageReqDTO) {
|
||||
return selectPage(new Page<>(pageReqDTO.getPageNo(), pageReqDTO.getPageSize()),
|
||||
new QueryWrapperX<ProductRecommendDO>().eqIfPresent("type", pageReqDTO.getType()));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package cn.iocoder.mall.promotionservice.manager.activity;
|
||||
|
||||
import cn.iocoder.common.framework.vo.PageResult;
|
||||
import cn.iocoder.mall.promotion.api.rpc.activity.dto.PromotionActivityListReqDTO;
|
||||
import cn.iocoder.mall.promotion.api.rpc.activity.dto.PromotionActivityPageReqDTO;
|
||||
import cn.iocoder.mall.promotion.api.rpc.activity.dto.PromotionActivityRespDTO;
|
||||
import cn.iocoder.mall.promotionservice.service.activity.PromotionActivityService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 促销活动 Manager
|
||||
*/
|
||||
@Service
|
||||
@Validated
|
||||
public class PromotionActivityManager {
|
||||
|
||||
@Autowired
|
||||
private PromotionActivityService promotionActivityService;
|
||||
|
||||
public List<PromotionActivityRespDTO> listPromotionActivities(PromotionActivityListReqDTO listReqDTO) {
|
||||
return promotionActivityService.listPromotionActivities(listReqDTO);
|
||||
}
|
||||
|
||||
public PageResult<PromotionActivityRespDTO> pagePromotionActivity(PromotionActivityPageReqDTO pageReqDTO) {
|
||||
return promotionActivityService.pagePromotionActivity(pageReqDTO);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package cn.iocoder.mall.promotionservice.manager.banner;
|
||||
|
||||
import cn.iocoder.common.framework.vo.PageResult;
|
||||
import cn.iocoder.mall.promotion.api.rpc.banner.dto.*;
|
||||
import cn.iocoder.mall.promotionservice.service.banner.BannerService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Banner Manager
|
||||
*/
|
||||
@Service
|
||||
@Valid
|
||||
public class BannerManager {
|
||||
|
||||
@Autowired
|
||||
private BannerService bannerService;
|
||||
|
||||
public Integer createBanner(BannerCreateReqDTO createDTO) {
|
||||
return bannerService.createBanner(createDTO);
|
||||
}
|
||||
|
||||
public void updateBanner(BannerUpdateReqDTO updateDTO) {
|
||||
bannerService.updateBanner(updateDTO);
|
||||
}
|
||||
|
||||
public void deleteBanner(Integer bannerId) {
|
||||
bannerService.deleteBanner(bannerId);
|
||||
}
|
||||
|
||||
public List<BannerRespDTO> listBanners(BannerListReqDTO listDTO) {
|
||||
return bannerService.listBanners(listDTO);
|
||||
}
|
||||
|
||||
public PageResult<BannerRespDTO> pageBanner(BannerPageReqDTO pageDTO) {
|
||||
return bannerService.pageBanner(pageDTO);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package cn.iocoder.mall.promotionservice.manager.coupon;
|
||||
|
||||
import cn.iocoder.common.framework.vo.PageResult;
|
||||
import cn.iocoder.mall.promotion.api.rpc.coupon.dto.card.*;
|
||||
import cn.iocoder.mall.promotionservice.service.coupon.CouponCardService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
@Validated
|
||||
public class CouponCardManager {
|
||||
|
||||
@Autowired
|
||||
private CouponCardService couponCardService;
|
||||
|
||||
public PageResult<CouponCardRespDTO> pageCouponCard(CouponCardPageReqDTO pageReqDTO) {
|
||||
return couponCardService.pageCouponCard(pageReqDTO);
|
||||
}
|
||||
|
||||
public Integer createCouponCard(CouponCardCreateReqDTO createReqDTO) {
|
||||
return couponCardService.createCouponCard(createReqDTO.getUserId(), createReqDTO.getCouponTemplateId());
|
||||
}
|
||||
|
||||
public Boolean useCouponCard(CouponCardUseReqDTO useReqDTO) {
|
||||
couponCardService.useCouponCard(useReqDTO.getUserId(), useReqDTO.getCouponCardId());
|
||||
return true;
|
||||
}
|
||||
|
||||
public Boolean cancelUseCouponCard(CouponCardCancelUseReqDTO cancelUseReqDTO) {
|
||||
couponCardService.cancelUseCouponCard(cancelUseReqDTO.getUserId(), cancelUseReqDTO.getCouponCardId());
|
||||
return true;
|
||||
}
|
||||
|
||||
public List<CouponCardAvailableRespDTO> listAvailableCouponCards(CouponCardAvailableListReqDTO listReqDTO) {
|
||||
return couponCardService.listAvailableCouponCards(listReqDTO);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package cn.iocoder.mall.promotionservice.manager.coupon;
|
||||
|
||||
import cn.iocoder.common.framework.vo.PageResult;
|
||||
import cn.iocoder.mall.promotion.api.rpc.coupon.dto.template.*;
|
||||
import cn.iocoder.mall.promotionservice.service.coupon.CouponTemplateService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 优惠劵(码)模板 Manager
|
||||
*/
|
||||
@Service
|
||||
public class CouponTemplateManager {
|
||||
|
||||
@Autowired
|
||||
private CouponTemplateService couponTemplateService;
|
||||
|
||||
// ========== 通用逻辑 =========
|
||||
|
||||
public CouponTemplateRespDTO getCouponTemplate(Integer couponTemplateId) {
|
||||
return couponTemplateService.getCouponTemplate(couponTemplateId);
|
||||
}
|
||||
|
||||
public PageResult<CouponTemplateRespDTO> pageCouponTemplate(CouponTemplatePageReqDTO pageDTO) {
|
||||
return couponTemplateService.pageCouponTemplate(pageDTO);
|
||||
}
|
||||
|
||||
public void updateCouponTemplateStatus(CouponCardTemplateUpdateStatusReqDTO updateStatusReqDTO) {
|
||||
couponTemplateService.updateCouponTemplateStatus(updateStatusReqDTO.getId(), updateStatusReqDTO.getStatus());
|
||||
}
|
||||
|
||||
// ========== 优惠劵模板 ==========
|
||||
|
||||
public Integer createCouponCardTemplate(CouponCardTemplateCreateReqDTO createDTO) {
|
||||
return couponTemplateService.createCouponCardTemplate(createDTO);
|
||||
}
|
||||
|
||||
|
||||
public void updateCouponCardTemplate(CouponCardTemplateUpdateReqDTO updateDTO) {
|
||||
couponTemplateService.updateCouponCardTemplate(updateDTO);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,379 @@
|
||||
package cn.iocoder.mall.promotionservice.manager.price;
|
||||
|
||||
import cn.iocoder.common.framework.exception.util.ServiceExceptionUtil;
|
||||
import cn.iocoder.common.framework.util.CollectionUtils;
|
||||
import cn.iocoder.common.framework.vo.CommonResult;
|
||||
import cn.iocoder.mall.productservice.rpc.sku.ProductSkuFeign;
|
||||
import cn.iocoder.mall.productservice.rpc.sku.dto.ProductSkuListQueryReqDTO;
|
||||
import cn.iocoder.mall.productservice.rpc.sku.dto.ProductSkuRespDTO;
|
||||
import cn.iocoder.mall.productservice.rpc.spu.ProductSpuFeign;
|
||||
import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuRespDTO;
|
||||
import cn.iocoder.mall.promotion.api.enums.MeetTypeEnum;
|
||||
import cn.iocoder.mall.promotion.api.enums.PreferentialTypeEnum;
|
||||
import cn.iocoder.mall.promotion.api.enums.RangeTypeEnum;
|
||||
import cn.iocoder.mall.promotion.api.enums.activity.PromotionActivityStatusEnum;
|
||||
import cn.iocoder.mall.promotion.api.enums.activity.PromotionActivityTypeEnum;
|
||||
import cn.iocoder.mall.promotion.api.rpc.activity.dto.PromotionActivityRespDTO;
|
||||
import cn.iocoder.mall.promotion.api.rpc.coupon.dto.card.CouponCardRespDTO;
|
||||
import cn.iocoder.mall.promotion.api.rpc.coupon.dto.template.CouponTemplateRespDTO;
|
||||
import cn.iocoder.mall.promotion.api.rpc.price.dto.PriceProductCalcReqDTO;
|
||||
import cn.iocoder.mall.promotion.api.rpc.price.dto.PriceProductCalcRespDTO;
|
||||
import cn.iocoder.mall.promotionservice.service.activity.PromotionActivityService;
|
||||
import cn.iocoder.mall.promotionservice.service.coupon.CouponCardService;
|
||||
import cn.iocoder.mall.promotionservice.service.coupon.CouponTemplateService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.iocoder.mall.promotion.api.enums.PromotionErrorCodeConstants.*;
|
||||
|
||||
@Service
|
||||
@Validated
|
||||
public class PriceManager {
|
||||
|
||||
@Autowired
|
||||
private ProductSkuFeign productSkuFeign;
|
||||
@Autowired
|
||||
private ProductSpuFeign productSpuFeign;
|
||||
|
||||
@Autowired
|
||||
private PromotionActivityService promotionActivityService;
|
||||
@Autowired
|
||||
private CouponCardService couponCardService;
|
||||
@Autowired
|
||||
private CouponTemplateService couponTemplateService;
|
||||
|
||||
public PriceProductCalcRespDTO calcProductPrice(PriceProductCalcReqDTO calcReqDTO) {
|
||||
// TODO 芋艿,补充一些表单校验。例如说,需要传入用户编号。
|
||||
// 校验商品都存在
|
||||
Map<Integer, PriceProductCalcReqDTO.Item> calcProductItemDTOMap = CollectionUtils.convertMap(
|
||||
calcReqDTO.getItems(), PriceProductCalcReqDTO.Item::getSkuId);
|
||||
CommonResult<List<ProductSkuRespDTO>> listProductSkusResult = productSkuFeign.listProductSkus(
|
||||
new ProductSkuListQueryReqDTO().setProductSkuIds(calcProductItemDTOMap.keySet()));
|
||||
listProductSkusResult.checkError();
|
||||
if (calcReqDTO.getItems().size() != listProductSkusResult.getData().size()) {
|
||||
throw ServiceExceptionUtil.exception(PRICE_PRODUCT_SKU_NOT_EXISTS);
|
||||
}
|
||||
// TODO 库存相关
|
||||
// 查询促销活动
|
||||
List<PromotionActivityRespDTO> activityRespDTOs = promotionActivityService.listPromotionActivitiesBySpuIds(
|
||||
CollectionUtils.convertSet(listProductSkusResult.getData(), ProductSkuRespDTO::getSpuId),
|
||||
Collections.singleton(PromotionActivityStatusEnum.RUN.getValue()));
|
||||
// 拼装结果(主要是计算价格)
|
||||
PriceProductCalcRespDTO calcRespDTO = new PriceProductCalcRespDTO();
|
||||
// 1. 创建初始的每一项的数组
|
||||
List<PriceProductCalcRespDTO.Item> calcItemRespDTOs = this.initCalcOrderPriceItems(
|
||||
listProductSkusResult.getData(), calcProductItemDTOMap);
|
||||
// 2. 计算【限时折扣】促销
|
||||
this.modifyPriceByTimeLimitDiscount(calcItemRespDTOs, activityRespDTOs);
|
||||
// 3. 计算【满减送】促销
|
||||
List<PriceProductCalcRespDTO.ItemGroup> itemGroups = this.groupByFullPrivilege(calcItemRespDTOs, activityRespDTOs);
|
||||
calcRespDTO.setItemGroups(itemGroups);
|
||||
// 4. 计算优惠劵 TODO 芋艿:未详细测试;
|
||||
if (calcReqDTO.getCouponCardId() != null) {
|
||||
Integer result = this.modifyPriceByCouponCard(calcReqDTO.getUserId(), calcReqDTO.getCouponCardId(), itemGroups);
|
||||
calcRespDTO.setCouponCardDiscountTotal(result);
|
||||
}
|
||||
// 5. 计算最终的价格
|
||||
int buyTotal = 0;
|
||||
int discountTotal = 0;
|
||||
int presentTotal = 0;
|
||||
for (PriceProductCalcRespDTO.ItemGroup itemGroup : calcRespDTO.getItemGroups()) {
|
||||
buyTotal += itemGroup.getItems().stream().mapToInt(item -> item.getSelected() ? item.getBuyTotal() : 0).sum();
|
||||
discountTotal += itemGroup.getItems().stream().mapToInt(item -> item.getSelected() ? item.getDiscountTotal() : 0).sum();
|
||||
presentTotal += itemGroup.getItems().stream().mapToInt(item -> item.getSelected() ? item.getPresentTotal() : 0).sum();
|
||||
}
|
||||
Assert.isTrue(buyTotal - discountTotal == presentTotal,
|
||||
String.format("价格合计( %d - %d == %d )不正确", buyTotal, discountTotal, presentTotal));
|
||||
calcRespDTO.setFee(new PriceProductCalcRespDTO.Fee(buyTotal, discountTotal, 0, presentTotal));
|
||||
return calcRespDTO;
|
||||
}
|
||||
|
||||
private List<PriceProductCalcRespDTO.Item> initCalcOrderPriceItems(List<ProductSkuRespDTO> skus,
|
||||
Map<Integer, PriceProductCalcReqDTO.Item> calcProductItemDTOMap) {
|
||||
// 获得商品分类 Map
|
||||
CommonResult<List<ProductSpuRespDTO>> listProductSpusResult = productSpuFeign.listProductSpus(CollectionUtils.convertSet(skus, ProductSkuRespDTO::getSpuId));
|
||||
listProductSpusResult.checkError();
|
||||
Map<Integer, Integer> spuIdCategoryIdMap = CollectionUtils.convertMap(listProductSpusResult.getData(), // SPU 编号与 Category 编号的映射
|
||||
ProductSpuRespDTO::getId, ProductSpuRespDTO::getCid);
|
||||
// 生成商品列表
|
||||
List<PriceProductCalcRespDTO.Item> items = new ArrayList<>();
|
||||
for (ProductSkuRespDTO sku : skus) {
|
||||
PriceProductCalcRespDTO.Item item = new PriceProductCalcRespDTO.Item();
|
||||
items.add(item);
|
||||
// 将基本信息,复制到 item 中
|
||||
PriceProductCalcReqDTO.Item calcOrderItem = calcProductItemDTOMap.get(sku.getId());
|
||||
item.setSpuId(sku.getSpuId()).setSkuId(sku.getId());
|
||||
item.setCid(spuIdCategoryIdMap.get(sku.getSpuId()));
|
||||
item.setSelected(calcOrderItem.getSelected());
|
||||
item.setBuyQuantity(calcOrderItem.getQuantity());
|
||||
// 计算初始价格
|
||||
item.setOriginPrice(sku.getPrice());
|
||||
item.setBuyPrice(sku.getPrice());
|
||||
item.setPresentPrice(sku.getPrice());
|
||||
item.setBuyTotal(sku.getPrice() * calcOrderItem.getQuantity());
|
||||
item.setDiscountTotal(0);
|
||||
item.setPresentTotal(item.getBuyTotal());
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
private void modifyPriceByTimeLimitDiscount(List<PriceProductCalcRespDTO.Item> items, List<PromotionActivityRespDTO> activityList) {
|
||||
for (PriceProductCalcRespDTO.Item item : items) {
|
||||
// 获得符合条件的限时折扣
|
||||
PromotionActivityRespDTO timeLimitedDiscount = activityList.stream()
|
||||
.filter(activity -> PromotionActivityTypeEnum.TIME_LIMITED_DISCOUNT.getValue().equals(activity.getActivityType())
|
||||
&& activity.getTimeLimitedDiscount().getItems().stream().anyMatch(item0 -> item0.getSpuId().equals(item.getSpuId())))
|
||||
.findFirst().orElse(null);
|
||||
if (timeLimitedDiscount == null) {
|
||||
continue;
|
||||
}
|
||||
// 计算价格
|
||||
Integer newBuyPrice = calcSkuPriceByTimeLimitDiscount(item, timeLimitedDiscount);
|
||||
if (newBuyPrice.equals(item.getBuyPrice())) { // 未优惠
|
||||
continue;
|
||||
}
|
||||
// 设置优惠
|
||||
item.setActivityId(timeLimitedDiscount.getId());
|
||||
// 设置价格
|
||||
item.setBuyPrice(newBuyPrice);
|
||||
item.setBuyTotal(newBuyPrice * item.getBuyQuantity());
|
||||
item.setPresentTotal(item.getBuyTotal() - item.getDiscountTotal());
|
||||
item.setPresentPrice(item.getPresentTotal() / item.getBuyQuantity());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算指定 SKU 在限时折扣下的价格
|
||||
*
|
||||
* @param sku SKU
|
||||
* @param timeLimitedDiscount 限时折扣促销。
|
||||
* 传入的该活动,要保证该 SKU 在该促销下一定有优惠。
|
||||
* @return 计算后的价格
|
||||
*/
|
||||
private Integer calcSkuPriceByTimeLimitDiscount(PriceProductCalcRespDTO.Item sku, PromotionActivityRespDTO timeLimitedDiscount) {
|
||||
if (timeLimitedDiscount == null) {
|
||||
return sku.getBuyPrice();
|
||||
}
|
||||
// 获得对应的优惠项
|
||||
PromotionActivityRespDTO.TimeLimitedDiscount.Item item = timeLimitedDiscount.getTimeLimitedDiscount().getItems().stream()
|
||||
.filter(item0 -> item0.getSpuId().equals(sku.getSpuId()))
|
||||
.findFirst().orElse(null);
|
||||
if (item == null) {
|
||||
throw new IllegalArgumentException(String.format("折扣活动(%s) 不存在商品(%s) 的优惠配置",
|
||||
timeLimitedDiscount.toString(), sku.toString()));
|
||||
}
|
||||
// 计算价格
|
||||
if (PreferentialTypeEnum.PRICE.getValue().equals(item.getPreferentialType())) { // 减价
|
||||
int presentPrice = sku.getBuyPrice() - item.getPreferentialValue();
|
||||
return presentPrice >= 0 ? presentPrice : sku.getBuyPrice(); // 如果计算优惠价格小于 0 ,则说明无法使用优惠。
|
||||
}
|
||||
if (PreferentialTypeEnum.DISCOUNT.getValue().equals(item.getPreferentialType())) { // 打折
|
||||
return sku.getBuyPrice() * item.getPreferentialValue() / 100;
|
||||
}
|
||||
throw new IllegalArgumentException(String.format("折扣活动(%s) 的优惠类型不正确", timeLimitedDiscount.toString()));
|
||||
}
|
||||
|
||||
private List<PriceProductCalcRespDTO.ItemGroup> groupByFullPrivilege(List<PriceProductCalcRespDTO.Item> items, List<PromotionActivityRespDTO> activityList) {
|
||||
List<PriceProductCalcRespDTO.ItemGroup> itemGroups = new ArrayList<>();
|
||||
// 获得所有满减送促销
|
||||
List<PromotionActivityRespDTO> fullPrivileges = activityList.stream()
|
||||
.filter(activity -> PromotionActivityTypeEnum.FULL_PRIVILEGE.getValue().equals(activity.getActivityType()))
|
||||
.collect(Collectors.toList());
|
||||
// 基于满减送促销,进行分组
|
||||
if (!fullPrivileges.isEmpty()) {
|
||||
items = new ArrayList<>(items); // 因为下面会修改数组,进行浅拷贝,避免影响传入的 items 。
|
||||
for (PromotionActivityRespDTO fullPrivilege : fullPrivileges) {
|
||||
// 创建 fullPrivilege 对应的分组
|
||||
PriceProductCalcRespDTO.ItemGroup itemGroup = new PriceProductCalcRespDTO.ItemGroup()
|
||||
.setActivityId(fullPrivilege.getId())
|
||||
.setItems(new ArrayList<>());
|
||||
// 筛选商品到分组中
|
||||
for (Iterator<PriceProductCalcRespDTO.Item> iterator = items.iterator(); iterator.hasNext(); ) {
|
||||
PriceProductCalcRespDTO.Item item = iterator.next();
|
||||
if (!isSpuMatchFullPrivilege(item.getSpuId(), fullPrivilege)) {
|
||||
continue;
|
||||
}
|
||||
itemGroup.getItems().add(item);
|
||||
iterator.remove();
|
||||
}
|
||||
// 如果匹配到,则添加到 itemGroups 中
|
||||
if (!itemGroup.getItems().isEmpty()) {
|
||||
itemGroups.add(itemGroup);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 处理未参加活动的商品,形成一个分组
|
||||
if (!items.isEmpty()) {
|
||||
itemGroups.add(new PriceProductCalcRespDTO.ItemGroup().setItems(items));
|
||||
}
|
||||
// 计算每个分组的价格
|
||||
Map<Integer, PromotionActivityRespDTO> activityMap = CollectionUtils.convertMap(activityList, PromotionActivityRespDTO::getId);
|
||||
for (PriceProductCalcRespDTO.ItemGroup itemGroup : itemGroups) {
|
||||
itemGroup.setActivityDiscountTotal(calcSkuPriceByFullPrivilege(itemGroup, activityMap.get(itemGroup.getActivityId())));
|
||||
}
|
||||
// 返回结果
|
||||
return itemGroups;
|
||||
}
|
||||
|
||||
private boolean isSpuMatchFullPrivilege(Integer spuId, PromotionActivityRespDTO activity) {
|
||||
Assert.isTrue(PromotionActivityTypeEnum.FULL_PRIVILEGE.getValue().equals(activity.getActivityType()),
|
||||
"传入的必须的促销活动必须是满减送");
|
||||
PromotionActivityRespDTO.FullPrivilege fullPrivilege = activity.getFullPrivilege();
|
||||
if (RangeTypeEnum.ALL.getValue().equals(fullPrivilege.getRangeType())) {
|
||||
return true;
|
||||
} else if (RangeTypeEnum.PRODUCT_INCLUDE_PART.getValue().equals(fullPrivilege.getRangeType())) {
|
||||
return fullPrivilege.getRangeValues().contains(spuId);
|
||||
}
|
||||
throw new IllegalArgumentException(String.format("促销活动(%s) 可用范围的类型是不正确", activity.toString()));
|
||||
}
|
||||
|
||||
private Integer calcSkuPriceByFullPrivilege(PriceProductCalcRespDTO.ItemGroup itemGroup, PromotionActivityRespDTO activity) {
|
||||
if (itemGroup.getActivityId() == null) {
|
||||
return null;
|
||||
}
|
||||
Assert.isTrue(PromotionActivityTypeEnum.FULL_PRIVILEGE.getValue().equals(activity.getActivityType()),
|
||||
"传入的必须的满减送活动必须是满减送");
|
||||
// 获得优惠信息
|
||||
List<PriceProductCalcRespDTO.Item> items = itemGroup.getItems().stream().filter(PriceProductCalcRespDTO.Item::getSelected)
|
||||
.collect(Collectors.toList());
|
||||
Integer itemCnt = items.stream().mapToInt(PriceProductCalcRespDTO.Item::getBuyQuantity).sum();
|
||||
Integer originalTotal = items.stream().mapToInt(PriceProductCalcRespDTO.Item::getPresentTotal).sum();
|
||||
List<PromotionActivityRespDTO.FullPrivilege.Privilege> privileges = activity.getFullPrivilege().getPrivileges().stream()
|
||||
.filter(privilege -> {
|
||||
if (MeetTypeEnum.PRICE.getValue().equals(privilege.getMeetType())) {
|
||||
return originalTotal >= privilege.getMeetValue();
|
||||
}
|
||||
if (MeetTypeEnum.QUANTITY.getValue().equals(privilege.getMeetType())) {
|
||||
return itemCnt >= privilege.getMeetValue();
|
||||
}
|
||||
throw new IllegalArgumentException(String.format("满减送活动(%s) 的匹配(%s)不正确",
|
||||
activity.toString(), privilege.toString()));
|
||||
}).collect(Collectors.toList());
|
||||
// 获得不到优惠信息,返回原始价格
|
||||
if (privileges.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
// 获得到优惠信息,进行价格计算
|
||||
PromotionActivityRespDTO.FullPrivilege.Privilege privilege = privileges.get(privileges.size() - 1);
|
||||
Integer presentTotal;
|
||||
if (PreferentialTypeEnum.PRICE.getValue().equals(privilege.getPreferentialType())) { // 减价
|
||||
// 计算循环次数。这样,后续优惠的金额就是相乘了
|
||||
Integer cycleCount = 1;
|
||||
if (activity.getFullPrivilege().getCycled()) {
|
||||
if (MeetTypeEnum.PRICE.getValue().equals(privilege.getMeetType())) {
|
||||
cycleCount = originalTotal / privilege.getMeetValue();
|
||||
} else if (MeetTypeEnum.QUANTITY.getValue().equals(privilege.getMeetType())) {
|
||||
cycleCount = itemCnt / privilege.getMeetValue();
|
||||
}
|
||||
}
|
||||
presentTotal = originalTotal - cycleCount * privilege.getMeetValue();
|
||||
if (presentTotal < 0) { // 如果计算优惠价格小于 0 ,则说明无法使用优惠。
|
||||
presentTotal = originalTotal;
|
||||
}
|
||||
} else if (PreferentialTypeEnum.DISCOUNT.getValue().equals(privilege.getPreferentialType())) { // 打折
|
||||
presentTotal = originalTotal * privilege.getPreferentialValue() / 100;
|
||||
} else {
|
||||
throw new IllegalArgumentException(String.format("满减送促销(%s) 的优惠类型不正确", activity.toString()));
|
||||
}
|
||||
int discountTotal = originalTotal - presentTotal;
|
||||
if (discountTotal == 0) {
|
||||
return null;
|
||||
}
|
||||
// 按比例,拆分 presentTotal
|
||||
splitDiscountPriceToItems(items, discountTotal, presentTotal);
|
||||
// 返回优惠金额
|
||||
return originalTotal - presentTotal;
|
||||
}
|
||||
|
||||
private Integer modifyPriceByCouponCard(Integer userId, Integer couponCardId, List<PriceProductCalcRespDTO.ItemGroup> itemGroups) {
|
||||
Assert.isTrue(couponCardId != null, "优惠劵编号不能为空");
|
||||
// 查询优惠劵
|
||||
CouponCardRespDTO couponCard = couponCardService.getCouponCard(userId, couponCardId);
|
||||
if (couponCard == null) {
|
||||
throw ServiceExceptionUtil.exception(COUPON_CARD_NOT_EXISTS);
|
||||
}
|
||||
CouponTemplateRespDTO couponTemplate = couponTemplateService.getCouponTemplate(couponCardId);
|
||||
if (couponTemplate == null) {
|
||||
throw ServiceExceptionUtil.exception(COUPON_TEMPLATE_NOT_EXISTS);
|
||||
}
|
||||
// 获得匹配的商品
|
||||
List<PriceProductCalcRespDTO.Item> items = new ArrayList<>();
|
||||
if (RangeTypeEnum.ALL.getValue().equals(couponTemplate.getRangeType())) {
|
||||
itemGroups.forEach(itemGroup -> items.addAll(itemGroup.getItems()));
|
||||
} else if (RangeTypeEnum.PRODUCT_INCLUDE_PART.getValue().equals(couponTemplate.getRangeType())) {
|
||||
itemGroups.forEach(itemGroup -> items.forEach(item -> {
|
||||
if (couponTemplate.getRangeValues().contains(item.getSpuId())) {
|
||||
items.add(item);
|
||||
}
|
||||
}));
|
||||
} else if (RangeTypeEnum.PRODUCT_EXCLUDE_PART.getValue().equals(couponTemplate.getRangeType())) {
|
||||
itemGroups.forEach(itemGroup -> items.forEach(item -> {
|
||||
if (!couponTemplate.getRangeValues().contains(item.getSpuId())) {
|
||||
items.add(item);
|
||||
}
|
||||
}));
|
||||
} else if (RangeTypeEnum.CATEGORY_INCLUDE_PART.getValue().equals(couponTemplate.getRangeType())) {
|
||||
itemGroups.forEach(itemGroup -> items.forEach(item -> {
|
||||
if (couponTemplate.getRangeValues().contains(item.getCid())) {
|
||||
items.add(item);
|
||||
}
|
||||
}));
|
||||
} else if (RangeTypeEnum.CATEGORY_EXCLUDE_PART.getValue().equals(couponTemplate.getRangeType())) {
|
||||
itemGroups.forEach(itemGroup -> items.forEach(item -> {
|
||||
if (!couponTemplate.getRangeValues().contains(item.getCid())) {
|
||||
items.add(item);
|
||||
}
|
||||
}));
|
||||
}
|
||||
// 判断是否符合条件
|
||||
int originalTotal = items.stream().mapToInt(PriceProductCalcRespDTO.Item::getPresentTotal).sum(); // 此处,指的是以优惠劵视角的原价
|
||||
if (originalTotal == 0 || originalTotal < couponCard.getPriceAvailable()) {
|
||||
throw ServiceExceptionUtil.exception(COUPON_CARD_NOT_MATCH); // TODO 芋艿,这种情况,会出现错误码的提示,无法格式化出来。另外,这块的最佳实践,找人讨论下。
|
||||
}
|
||||
// 计算价格
|
||||
// 获得到优惠信息,进行价格计算
|
||||
int presentTotal;
|
||||
if (PreferentialTypeEnum.PRICE.getValue().equals(couponCard.getPreferentialType())) { // 减价
|
||||
// 计算循环次数。这样,后续优惠的金额就是相乘了
|
||||
presentTotal = originalTotal - couponCard.getPriceOff();
|
||||
Assert.isTrue(presentTotal > 0, "计算后,价格为负数:" + presentTotal);
|
||||
} else if (PreferentialTypeEnum.DISCOUNT.getValue().equals(couponCard.getPreferentialType())) { // 打折
|
||||
presentTotal = originalTotal * couponCard.getPercentOff() / 100;
|
||||
if (couponCard.getDiscountPriceLimit() != null // 空,代表不限制优惠上限
|
||||
&& originalTotal - presentTotal > couponCard.getDiscountPriceLimit()) {
|
||||
presentTotal = originalTotal - couponCard.getDiscountPriceLimit();
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException(String.format("优惠劵(%s) 的优惠类型不正确", couponCard.toString()));
|
||||
}
|
||||
int discountTotal = originalTotal - presentTotal;
|
||||
Assert.isTrue(discountTotal > 0, "计算后,不产生优惠:" + discountTotal);
|
||||
// 按比例,拆分 presentTotal
|
||||
splitDiscountPriceToItems(items, discountTotal, presentTotal);
|
||||
// 返回优惠金额
|
||||
return originalTotal - presentTotal;
|
||||
}
|
||||
|
||||
private void splitDiscountPriceToItems(List<PriceProductCalcRespDTO.Item> items, Integer discountTotal, Integer presentTotal) {
|
||||
for (int i = 0; i < items.size(); i++) {
|
||||
PriceProductCalcRespDTO.Item item = items.get(i);
|
||||
Integer discountPart;
|
||||
if (i < items.size() - 1) { // 减一的原因,是因为拆分时,如果按照比例,可能会出现.所以最后一个,使用反减
|
||||
discountPart = (int) (discountTotal * (1.0D * item.getPresentTotal() / presentTotal));
|
||||
discountTotal -= discountPart;
|
||||
} else {
|
||||
discountPart = discountTotal;
|
||||
}
|
||||
Assert.isTrue(discountPart > 0, "优惠金额必须大于 0");
|
||||
item.setDiscountTotal(item.getDiscountTotal() + discountPart);
|
||||
item.setPresentTotal(item.getBuyTotal() - item.getDiscountTotal());
|
||||
item.setPresentPrice(item.getPresentTotal() / item.getBuyQuantity());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package cn.iocoder.mall.promotionservice.manager.recommend;
|
||||
|
||||
import cn.iocoder.common.framework.exception.util.ServiceExceptionUtil;
|
||||
import cn.iocoder.common.framework.vo.CommonResult;
|
||||
import cn.iocoder.common.framework.vo.PageResult;
|
||||
import cn.iocoder.mall.productservice.rpc.spu.ProductSpuFeign;
|
||||
import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuRespDTO;
|
||||
import cn.iocoder.mall.promotion.api.rpc.recommend.dto.*;
|
||||
import cn.iocoder.mall.promotionservice.service.recommend.ProductRecommendService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.mall.promotion.api.enums.PromotionErrorCodeConstants.PRODUCT_RECOMMEND_PRODUCT_NOT_EXISTS;
|
||||
|
||||
/**
|
||||
* 商品推荐 Manager
|
||||
*/
|
||||
@Service
|
||||
@Validated
|
||||
public class ProductRecommendManager {
|
||||
|
||||
@Autowired
|
||||
private ProductSpuFeign productSpuFeign;
|
||||
|
||||
@Autowired
|
||||
private ProductRecommendService productRecommendService;
|
||||
|
||||
public List<ProductRecommendRespDTO> listProductRecommends(ProductRecommendListReqDTO listReqDTO) {
|
||||
return productRecommendService.listProductRecommends(listReqDTO);
|
||||
}
|
||||
|
||||
public PageResult<ProductRecommendRespDTO> pageProductRecommend(ProductRecommendPageReqDTO pageReqDTO) {
|
||||
return productRecommendService.pageProductRecommend(pageReqDTO);
|
||||
}
|
||||
|
||||
public Integer createProductRecommend(ProductRecommendCreateReqDTO createReqDTO) {
|
||||
// 校验商品不存在
|
||||
checkProductSpu(createReqDTO.getProductSpuId());
|
||||
// 创建商品推荐
|
||||
return productRecommendService.createProductRecommend(createReqDTO);
|
||||
}
|
||||
|
||||
public void updateProductRecommend(ProductRecommendUpdateReqDTO updateReqDTO) {
|
||||
// 校验商品不存在
|
||||
checkProductSpu(updateReqDTO.getProductSpuId());
|
||||
// 更新商品推荐
|
||||
productRecommendService.updateProductRecommend(updateReqDTO);
|
||||
}
|
||||
|
||||
public void deleteProductRecommend(Integer productRecommendId) {
|
||||
productRecommendService.deleteProductRecommend(productRecommendId);
|
||||
}
|
||||
|
||||
private void checkProductSpu(Integer productSpuId) {
|
||||
CommonResult<ProductSpuRespDTO> getProductSpuResult = productSpuFeign.getProductSpu(productSpuId);
|
||||
getProductSpuResult.checkError();
|
||||
if (getProductSpuResult.getData() == null) {
|
||||
throw ServiceExceptionUtil.exception(PRODUCT_RECOMMEND_PRODUCT_NOT_EXISTS);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package cn.iocoder.mall.promotionservice.service.activity;
|
||||
|
||||
import cn.iocoder.common.framework.vo.PageResult;
|
||||
import cn.iocoder.mall.promotion.api.enums.RangeTypeEnum;
|
||||
import cn.iocoder.mall.promotion.api.enums.activity.PromotionActivityTypeEnum;
|
||||
import cn.iocoder.mall.promotion.api.rpc.activity.dto.PromotionActivityListReqDTO;
|
||||
import cn.iocoder.mall.promotion.api.rpc.activity.dto.PromotionActivityPageReqDTO;
|
||||
import cn.iocoder.mall.promotion.api.rpc.activity.dto.PromotionActivityRespDTO;
|
||||
import cn.iocoder.mall.promotionservice.convert.activity.PromotionActivityConvert;
|
||||
import cn.iocoder.mall.promotionservice.dal.mysql.dataobject.activity.PromotionActivityDO;
|
||||
import cn.iocoder.mall.promotionservice.dal.mysql.mapper.activity.PromotionActivityMapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@Service
|
||||
@Validated
|
||||
public class PromotionActivityService {
|
||||
|
||||
@Autowired
|
||||
private PromotionActivityMapper promotionActivityMapper;
|
||||
|
||||
public List<PromotionActivityRespDTO> listPromotionActivities(PromotionActivityListReqDTO listReqDTO) {
|
||||
List<PromotionActivityDO> activityList = promotionActivityMapper.selectList(listReqDTO);
|
||||
return PromotionActivityConvert.INSTANCE.convertList(activityList);
|
||||
}
|
||||
|
||||
public List<PromotionActivityRespDTO> listPromotionActivitiesBySpuIds(Collection<Integer> spuIds, Collection<Integer> activityStatuses) {
|
||||
if (spuIds.isEmpty() || activityStatuses.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
// 查询指定状态的促销活动
|
||||
List<PromotionActivityDO> activityList = promotionActivityMapper.selectListByStatus(activityStatuses);
|
||||
if (activityList.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
// 匹配商品
|
||||
for (Iterator<PromotionActivityDO> iterator = activityList.iterator(); iterator.hasNext();) {
|
||||
PromotionActivityDO activity = iterator.next();
|
||||
boolean matched = false;
|
||||
for (Integer spuId : spuIds) {
|
||||
if (PromotionActivityTypeEnum.TIME_LIMITED_DISCOUNT.getValue().equals(activity.getActivityType())) {
|
||||
matched = isSpuMatchTimeLimitDiscount(spuId, activity);
|
||||
} else if (PromotionActivityTypeEnum.FULL_PRIVILEGE.getValue().equals(activity.getActivityType())) {
|
||||
matched = isSpuMatchFullPrivilege(spuId, activity);
|
||||
}
|
||||
if (matched) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// 不匹配,则进行移除
|
||||
if (!matched) {
|
||||
iterator.remove();
|
||||
} else { // 匹配,则做一些后续的处理
|
||||
// 如果是限时折扣,移除不在 spuId 数组中的折扣规则
|
||||
if (PromotionActivityTypeEnum.TIME_LIMITED_DISCOUNT.getValue().equals(activity.getActivityType())) {
|
||||
activity.getTimeLimitedDiscount().getItems().removeIf(item -> !spuIds.contains(item.getSpuId()));
|
||||
}
|
||||
}
|
||||
}
|
||||
// 返回最终结果
|
||||
return PromotionActivityConvert.INSTANCE.convertList(activityList);
|
||||
}
|
||||
|
||||
public PageResult<PromotionActivityRespDTO> pagePromotionActivity(PromotionActivityPageReqDTO pageReqDTO) {
|
||||
IPage<PromotionActivityDO> promotionActivityPage = promotionActivityMapper.selectPage(pageReqDTO);
|
||||
return PromotionActivityConvert.INSTANCE.convertPage(promotionActivityPage);
|
||||
}
|
||||
|
||||
private boolean isSpuMatchTimeLimitDiscount(Integer spuId, PromotionActivityDO activity) {
|
||||
Assert.isTrue(PromotionActivityTypeEnum.TIME_LIMITED_DISCOUNT.getValue().equals(activity.getActivityType()),
|
||||
"传入的必须的促销活动必须是限时折扣");
|
||||
return activity.getTimeLimitedDiscount().getItems().stream()
|
||||
.anyMatch(item -> spuId.equals(item.getSpuId()));
|
||||
}
|
||||
|
||||
private boolean isSpuMatchFullPrivilege(Integer spuId, PromotionActivityDO activity) {
|
||||
Assert.isTrue(PromotionActivityTypeEnum.FULL_PRIVILEGE.getValue().equals(activity.getActivityType()),
|
||||
"传入的必须的促销活动必须是满减送");
|
||||
PromotionActivityDO.FullPrivilege fullPrivilege = activity.getFullPrivilege();
|
||||
if (RangeTypeEnum.ALL.getValue().equals(fullPrivilege.getRangeType())) {
|
||||
return true;
|
||||
} else if (RangeTypeEnum.PRODUCT_INCLUDE_PART.getValue().equals(fullPrivilege.getRangeType())) {
|
||||
return fullPrivilege.getRangeValues().contains(spuId);
|
||||
} else {
|
||||
throw new IllegalArgumentException(String.format("促销活动(%s) 可用范围的类型是不正确", activity.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package cn.iocoder.mall.promotionservice.service.banner;
|
||||
|
||||
import cn.iocoder.common.framework.exception.util.ServiceExceptionUtil;
|
||||
import cn.iocoder.common.framework.vo.PageResult;
|
||||
import cn.iocoder.mall.promotion.api.rpc.banner.dto.*;
|
||||
import cn.iocoder.mall.promotionservice.convert.banner.BannerConvert;
|
||||
import cn.iocoder.mall.promotionservice.dal.mysql.dataobject.banner.BannerDO;
|
||||
import cn.iocoder.mall.promotionservice.dal.mysql.mapper.banner.BannerMapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.mall.promotion.api.enums.PromotionErrorCodeConstants.BANNER_NOT_EXISTS;
|
||||
|
||||
|
||||
@Service
|
||||
@Validated
|
||||
public class BannerService {
|
||||
|
||||
@Autowired
|
||||
private BannerMapper bannerMapper;
|
||||
|
||||
/**
|
||||
* 获得 Banner 列表
|
||||
*
|
||||
* @param listReqDTO Banner 列表查询
|
||||
* @return Banner 列表
|
||||
*/
|
||||
public List<BannerRespDTO> listBanners(BannerListReqDTO listReqDTO) {
|
||||
List<BannerDO> banners = bannerMapper.selectList(listReqDTO);
|
||||
return BannerConvert.INSTANCE.convertList(banners);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得 Banner 分页
|
||||
*
|
||||
* @param bannerPageDTO Banner 分页查询
|
||||
* @return Banner 分页结果
|
||||
*/
|
||||
public PageResult<BannerRespDTO> pageBanner(BannerPageReqDTO bannerPageDTO) {
|
||||
IPage<BannerDO> bannerPage = bannerMapper.selectPage(bannerPageDTO);
|
||||
return BannerConvert.INSTANCE.convertPage(bannerPage);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建 Banner
|
||||
*
|
||||
* @param createReqDTO 创建 Banner 信息
|
||||
* @return banner
|
||||
*/
|
||||
public Integer createBanner(@Valid BannerCreateReqDTO createReqDTO) {
|
||||
// 插入到数据库
|
||||
BannerDO bannerDO = BannerConvert.INSTANCE.convert(createReqDTO);
|
||||
bannerMapper.insert(bannerDO);
|
||||
// 返回
|
||||
return bannerDO.getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新 Banner
|
||||
*
|
||||
* @param updateReqDTO 更新 Banner 信息
|
||||
*/
|
||||
public void updateBanner(@Valid BannerUpdateReqDTO updateReqDTO) {
|
||||
// 校验更新的 Banner 是否存在
|
||||
if (bannerMapper.selectById(updateReqDTO.getId()) == null) {
|
||||
throw ServiceExceptionUtil.exception(BANNER_NOT_EXISTS);
|
||||
}
|
||||
// 更新到数据库
|
||||
BannerDO updateObject = BannerConvert.INSTANCE.convert(updateReqDTO);
|
||||
bannerMapper.updateById(updateObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除 Banner
|
||||
*
|
||||
* @param bannerId Banner 编号
|
||||
*/
|
||||
public void deleteBanner(Integer bannerId) {
|
||||
// 校验 Banner 存在
|
||||
if (bannerMapper.selectById(bannerId) == null) {
|
||||
throw ServiceExceptionUtil.exception(BANNER_NOT_EXISTS);
|
||||
}
|
||||
// 更新到数据库
|
||||
bannerMapper.deleteById(bannerId);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,258 @@
|
||||
package cn.iocoder.mall.promotionservice.service.coupon;
|
||||
|
||||
import cn.iocoder.common.framework.exception.util.ServiceExceptionUtil;
|
||||
import cn.iocoder.common.framework.util.CollectionUtils;
|
||||
import cn.iocoder.common.framework.util.DateUtil;
|
||||
import cn.iocoder.common.framework.util.StringUtils;
|
||||
import cn.iocoder.common.framework.vo.PageResult;
|
||||
import cn.iocoder.mall.promotion.api.enums.PromotionErrorCodeConstants;
|
||||
import cn.iocoder.mall.promotion.api.enums.RangeTypeEnum;
|
||||
import cn.iocoder.mall.promotion.api.enums.coupon.card.CouponCardStatusEnum;
|
||||
import cn.iocoder.mall.promotion.api.enums.coupon.card.CouponCardTakeTypeEnum;
|
||||
import cn.iocoder.mall.promotion.api.enums.coupon.template.CouponTemplateDateTypeEnum;
|
||||
import cn.iocoder.mall.promotion.api.enums.coupon.template.CouponTemplateStatusEnum;
|
||||
import cn.iocoder.mall.promotion.api.enums.coupon.template.CouponTemplateTypeEnum;
|
||||
import cn.iocoder.mall.promotion.api.rpc.coupon.dto.card.CouponCardAvailableListReqDTO;
|
||||
import cn.iocoder.mall.promotion.api.rpc.coupon.dto.card.CouponCardAvailableRespDTO;
|
||||
import cn.iocoder.mall.promotion.api.rpc.coupon.dto.card.CouponCardPageReqDTO;
|
||||
import cn.iocoder.mall.promotion.api.rpc.coupon.dto.card.CouponCardRespDTO;
|
||||
import cn.iocoder.mall.promotionservice.convert.coupon.CouponCardConvert;
|
||||
import cn.iocoder.mall.promotionservice.dal.mysql.dataobject.coupon.CouponCardDO;
|
||||
import cn.iocoder.mall.promotionservice.dal.mysql.dataobject.coupon.CouponTemplateDO;
|
||||
import cn.iocoder.mall.promotionservice.dal.mysql.mapper.coupon.CouponCardMapper;
|
||||
import cn.iocoder.mall.promotionservice.dal.mysql.mapper.coupon.CouponTemplateMapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 优惠劵 Service
|
||||
*/
|
||||
@Service
|
||||
@Validated
|
||||
public class CouponCardService {
|
||||
|
||||
@Autowired
|
||||
private CouponCardMapper couponCardMapper;
|
||||
@Autowired
|
||||
private CouponTemplateMapper couponTemplateMapper;
|
||||
|
||||
/**
|
||||
* 获得用户的优惠劵
|
||||
*
|
||||
* @param userId 用户编号
|
||||
* @param couponCardId 优惠劵编号
|
||||
* @return 优惠劵
|
||||
*/
|
||||
public CouponCardRespDTO getCouponCard(Integer userId, Integer couponCardId) {
|
||||
CouponCardDO card = couponCardMapper.selectById(couponCardId);
|
||||
if (card == null) {
|
||||
return null;
|
||||
}
|
||||
if (!Objects.equals(userId, card.getUserId())) {
|
||||
return null;
|
||||
}
|
||||
return CouponCardConvert.INSTANCE.convert(card);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得优惠劵分页
|
||||
*
|
||||
* @param pageReqDTO 优惠劵分页查询
|
||||
* @return 优惠劵分页结果
|
||||
*/
|
||||
public PageResult<CouponCardRespDTO> pageCouponCard(CouponCardPageReqDTO pageReqDTO) {
|
||||
IPage<CouponCardDO> couponCardDOPage = couponCardMapper.selectPage(pageReqDTO);
|
||||
return CouponCardConvert.INSTANCE.convertPage(couponCardDOPage);
|
||||
}
|
||||
|
||||
/**
|
||||
* 给用户添加优惠劵
|
||||
*
|
||||
* @param userId 用户编号
|
||||
* @param couponTemplateId 优惠劵模板编号
|
||||
* @return 优惠劵编号
|
||||
*/
|
||||
@Transactional
|
||||
public Integer createCouponCard(Integer userId, Integer couponTemplateId) {
|
||||
// 校验 CouponCardTemplate 存在
|
||||
CouponTemplateDO template = couponTemplateMapper.selectById(couponTemplateId);
|
||||
if (template == null) {
|
||||
throw ServiceExceptionUtil.exception(PromotionErrorCodeConstants.COUPON_TEMPLATE_NOT_EXISTS.getCode());
|
||||
}
|
||||
// 校验 CouponCardTemplate 是 CARD
|
||||
if (!CouponTemplateTypeEnum.CARD.getValue().equals(template.getType())) {
|
||||
throw ServiceExceptionUtil.exception(PromotionErrorCodeConstants.COUPON_TEMPLATE_NOT_CARD.getCode());
|
||||
}
|
||||
// 校验 CouponCardTemplate 状态是否开启
|
||||
if (!CouponTemplateStatusEnum.ENABLE.getValue().equals(template.getStatus())) {
|
||||
throw ServiceExceptionUtil.exception(PromotionErrorCodeConstants.COUPON_TEMPLATE_STATUS_NOT_ENABLE.getCode());
|
||||
}
|
||||
// 校验 CouponCardTemplate 是否到达可领取的上限
|
||||
if (template.getStatFetchNum() > template.getTotal()) {
|
||||
throw ServiceExceptionUtil.exception(PromotionErrorCodeConstants.COUPON_TEMPLATE_TOTAL_NOT_ENOUGH.getCode());
|
||||
}
|
||||
// 校验单人可领取优惠劵是否到达上限
|
||||
if (couponCardMapper.selectCountByUserIdAndTemplateId(userId, couponTemplateId) > template.getQuota()) {
|
||||
throw ServiceExceptionUtil.exception(PromotionErrorCodeConstants.COUPON_TEMPLATE_CARD_ADD_EXCEED_QUOTA.getCode());
|
||||
}
|
||||
// 增加优惠劵已领取量
|
||||
int updateTemplateCount = couponTemplateMapper.updateStatFetchNumIncr(couponTemplateId);
|
||||
if (updateTemplateCount == 0) { // 超过 CouponCardTemplate 发放量
|
||||
throw ServiceExceptionUtil.exception(PromotionErrorCodeConstants.COUPON_TEMPLATE_CARD_ADD_EXCEED_QUOTA.getCode());
|
||||
}
|
||||
// 创建优惠劵
|
||||
// 1. 基本信息 + 领取情况
|
||||
CouponCardDO card = new CouponCardDO()
|
||||
.setTemplateId(couponTemplateId)
|
||||
.setTitle(template.getTitle())
|
||||
.setStatus(CouponCardStatusEnum.UNUSED.getValue())
|
||||
.setUserId(userId)
|
||||
.setTakeType(CouponCardTakeTypeEnum.BY_USER.getValue()); // TODO 需要改
|
||||
// 2. 使用规则
|
||||
card.setPriceAvailable(template.getPriceAvailable());
|
||||
setCouponCardValidTime(card, template);
|
||||
// 3. 使用效果
|
||||
card.setPreferentialType(template.getPreferentialType())
|
||||
.setPriceOff(template.getPriceOff())
|
||||
.setPercentOff(template.getPercentOff()).setDiscountPriceLimit(template.getDiscountPriceLimit());
|
||||
// 保存优惠劵模板到数据库
|
||||
couponCardMapper.insert(card);
|
||||
// 返回成功
|
||||
return card.getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户使用优惠劵
|
||||
*
|
||||
* @param userId 用户编号
|
||||
* @param couponCardId 优惠劵编号
|
||||
*/
|
||||
public void useCouponCard(Integer userId, Integer couponCardId) {
|
||||
// 查询优惠劵
|
||||
CouponCardDO card = couponCardMapper.selectById(couponCardId);
|
||||
if (card == null) {
|
||||
throw ServiceExceptionUtil.exception(PromotionErrorCodeConstants.COUPON_CARD_NOT_EXISTS.getCode());
|
||||
}
|
||||
if (!userId.equals(card.getUserId())) {
|
||||
throw ServiceExceptionUtil.exception(PromotionErrorCodeConstants.COUPON_CARD_ERROR_USER.getCode());
|
||||
}
|
||||
if (!CouponCardStatusEnum.UNUSED.getValue().equals(card.getStatus())) {
|
||||
throw ServiceExceptionUtil.exception(PromotionErrorCodeConstants.COUPON_CARD_STATUS_NOT_UNUSED.getCode());
|
||||
}
|
||||
if (DateUtil.isBetween(card.getValidStartTime(), card.getValidEndTime())) { // 为避免定时器没跑,实际优惠劵已经过期
|
||||
throw ServiceExceptionUtil.exception(PromotionErrorCodeConstants.COUPON_CARD_STATUS_NOT_UNUSED.getCode());
|
||||
}
|
||||
// 更新优惠劵已使用
|
||||
int updateCount = couponCardMapper.updateByIdAndStatus(card.getId(), CouponCardStatusEnum.UNUSED.getValue(),
|
||||
new CouponCardDO().setStatus(CouponCardStatusEnum.USED.getValue()).setUsedTime(new Date()));
|
||||
if (updateCount == 0) {
|
||||
throw ServiceExceptionUtil.exception(PromotionErrorCodeConstants.COUPON_CARD_STATUS_NOT_UNUSED.getCode());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户取消使用优惠劵
|
||||
*
|
||||
* @param userId 用户编号
|
||||
* @param couponCardId 优惠劵编号
|
||||
*/
|
||||
public void cancelUseCouponCard(Integer userId, Integer couponCardId) {
|
||||
// 查询优惠劵
|
||||
CouponCardDO card = couponCardMapper.selectById(couponCardId);
|
||||
if (card == null) {
|
||||
throw ServiceExceptionUtil.exception(PromotionErrorCodeConstants.COUPON_CARD_NOT_EXISTS.getCode());
|
||||
}
|
||||
if (!userId.equals(card.getUserId())) {
|
||||
throw ServiceExceptionUtil.exception(PromotionErrorCodeConstants.COUPON_CARD_ERROR_USER.getCode());
|
||||
}
|
||||
if (!CouponCardStatusEnum.USED.getValue().equals(card.getStatus())) {
|
||||
throw ServiceExceptionUtil.exception(PromotionErrorCodeConstants.COUPON_CARD_STATUS_NOT_USED.getCode());
|
||||
}
|
||||
// 更新优惠劵已使用
|
||||
int updateCount = couponCardMapper.updateByIdAndStatus(card.getId(), CouponCardStatusEnum.USED.getValue(),
|
||||
new CouponCardDO().setStatus(CouponCardStatusEnum.UNUSED.getValue())); // TODO 芋艿,usedTime 未设置空,后面处理。
|
||||
if (updateCount == 0) {
|
||||
throw ServiceExceptionUtil.exception(PromotionErrorCodeConstants.COUPON_CARD_STATUS_NOT_USED.getCode());
|
||||
}
|
||||
// 有一点要注意,更新会未使用时,优惠劵可能已经过期了,直接让定时器跑过期,这里不做处理。
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得用户优惠劵的可用信息列表
|
||||
*
|
||||
* @param listReqDTO 查询信息
|
||||
* @return 优惠劵的可用信息列表
|
||||
*/
|
||||
public List<CouponCardAvailableRespDTO> listAvailableCouponCards(CouponCardAvailableListReqDTO listReqDTO) {
|
||||
// 查询用户未使用的优惠劵列表
|
||||
List<CouponCardDO> cards = couponCardMapper.selectListByUserIdAndStatus(listReqDTO.getUserId(), CouponCardStatusEnum.UNUSED.getValue());
|
||||
if (cards.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
// 查询优惠劵模板集合
|
||||
Map<Integer, CouponTemplateDO> templates = CollectionUtils.convertMap(
|
||||
couponTemplateMapper.selectBatchIds(CollectionUtils.convertSet(cards, CouponCardDO::getTemplateId)),
|
||||
CouponTemplateDO::getId);
|
||||
// 逐个判断是否可用
|
||||
return cards.stream().map(card -> {
|
||||
CouponCardAvailableRespDTO availableCard = CouponCardConvert.INSTANCE.convert01(card);
|
||||
availableCard.setUnavailableReason(isMatch(card, templates.get(card.getTemplateId()), listReqDTO.getItems()));
|
||||
availableCard.setAvailable(availableCard.getUnavailableReason() == null);
|
||||
return availableCard;
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 匹配商品是否可以使用指定优惠劵
|
||||
*
|
||||
* @param card 优惠劵
|
||||
* @param template 优惠劵模板
|
||||
* @param items 商品 SKU 数组
|
||||
* @return 如果不匹配,返回原因
|
||||
*/
|
||||
private String isMatch(CouponCardDO card, CouponTemplateDO template, List<CouponCardAvailableListReqDTO.Item> items) {
|
||||
int totalPrice = 0;
|
||||
if (RangeTypeEnum.ALL.getValue().equals(template.getRangeType())) {
|
||||
totalPrice = items.stream().mapToInt(spu -> spu.getPrice() * spu.getQuantity()).sum();
|
||||
} else if (RangeTypeEnum.PRODUCT_INCLUDE_PART.getValue().equals(template.getRangeType())) {
|
||||
List<Integer> spuIds = StringUtils.splitToInt(template.getRangeValues(), ",");
|
||||
totalPrice = items.stream().mapToInt(spu -> spuIds.contains(spu.getSpuId()) ? spu.getPrice() * spu.getQuantity() : 0).sum();
|
||||
} else if (RangeTypeEnum.PRODUCT_EXCLUDE_PART.getValue().equals(template.getRangeType())) {
|
||||
List<Integer> spuIds = StringUtils.splitToInt(template.getRangeValues(), ",");
|
||||
totalPrice = items.stream().mapToInt(spu -> !spuIds.contains(spu.getSpuId()) ? spu.getPrice() * spu.getQuantity() : 0).sum();
|
||||
} else if (RangeTypeEnum.CATEGORY_INCLUDE_PART.getValue().equals(template.getRangeType())) {
|
||||
List<Integer> spuIds = StringUtils.splitToInt(template.getRangeValues(), ",");
|
||||
totalPrice = items.stream().mapToInt(spu -> spuIds.contains(spu.getCid()) ? spu.getPrice() * spu.getQuantity() : 0).sum();
|
||||
} else if (RangeTypeEnum.CATEGORY_EXCLUDE_PART.getValue().equals(template.getRangeType())) {
|
||||
List<Integer> spuIds = StringUtils.splitToInt(template.getRangeValues(), ",");
|
||||
totalPrice = items.stream().mapToInt(spu -> !spuIds.contains(spu.getCid()) ? spu.getPrice() * spu.getQuantity() : 0).sum();
|
||||
}
|
||||
// 总价为 0 时,说明优惠劵丫根不匹配
|
||||
if (totalPrice == 0) {
|
||||
return "优惠劵不匹配";
|
||||
}
|
||||
// 如果不满足金额
|
||||
if (totalPrice < card.getPriceAvailable()) {
|
||||
return String.format("差 %1$,.2f 元可用优惠劵", (card.getPriceAvailable() - totalPrice) / 100D);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void setCouponCardValidTime(CouponCardDO card, CouponTemplateDO template) {
|
||||
if (CouponTemplateDateTypeEnum.FIXED_DATE.getValue().equals(template.getDateType())) {
|
||||
card.setValidStartTime(template.getValidStartTime()).setValidEndTime(template.getValidEndTime());
|
||||
} else if (CouponTemplateDateTypeEnum.FIXED_TERM.getValue().equals(template.getDateType())) {
|
||||
Date validStartTime = DateUtil.getDayBegin(new Date());
|
||||
card.setValidStartTime(DateUtil.addDate(validStartTime, Calendar.DAY_OF_YEAR, template.getFixedStartTerm()));
|
||||
Date validEndTime = DateUtil.getDayEnd(card.getValidStartTime());
|
||||
card.setValidEndTime(DateUtil.addDate(validEndTime, Calendar.DAY_OF_YEAR, template.getFixedEndTerm() - 1));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
package cn.iocoder.mall.promotionservice.service.coupon;
|
||||
|
||||
import cn.iocoder.common.framework.exception.util.ServiceExceptionUtil;
|
||||
import cn.iocoder.common.framework.vo.PageResult;
|
||||
import cn.iocoder.mall.promotion.api.enums.PreferentialTypeEnum;
|
||||
import cn.iocoder.mall.promotion.api.enums.PromotionErrorCodeConstants;
|
||||
import cn.iocoder.mall.promotion.api.enums.coupon.template.CouponTemplateDateTypeEnum;
|
||||
import cn.iocoder.mall.promotion.api.enums.coupon.template.CouponTemplateStatusEnum;
|
||||
import cn.iocoder.mall.promotion.api.enums.coupon.template.CouponTemplateTypeEnum;
|
||||
import cn.iocoder.mall.promotion.api.rpc.coupon.dto.template.CouponCardTemplateCreateReqDTO;
|
||||
import cn.iocoder.mall.promotion.api.rpc.coupon.dto.template.CouponCardTemplateUpdateReqDTO;
|
||||
import cn.iocoder.mall.promotion.api.rpc.coupon.dto.template.CouponTemplatePageReqDTO;
|
||||
import cn.iocoder.mall.promotion.api.rpc.coupon.dto.template.CouponTemplateRespDTO;
|
||||
import cn.iocoder.mall.promotionservice.convert.coupon.CouponTemplateConvert;
|
||||
import cn.iocoder.mall.promotionservice.dal.mysql.dataobject.coupon.CouponTemplateDO;
|
||||
import cn.iocoder.mall.promotionservice.dal.mysql.mapper.coupon.CouponTemplateMapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import static cn.iocoder.common.framework.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST;
|
||||
|
||||
/**
|
||||
* 优惠劵模板 Service
|
||||
*/
|
||||
@Service
|
||||
@Validated
|
||||
public class CouponTemplateService {
|
||||
|
||||
@Autowired
|
||||
private CouponTemplateMapper couponTemplateMapper;
|
||||
|
||||
// ========== 通用逻辑 =========
|
||||
|
||||
/**
|
||||
* 获得优惠劵(码)模板
|
||||
*
|
||||
* @param couponCardId 优惠劵模板编号
|
||||
* @return 优惠劵(码)模板
|
||||
*/
|
||||
public CouponTemplateRespDTO getCouponTemplate(Integer couponCardId) {
|
||||
return CouponTemplateConvert.INSTANCE.convert(couponTemplateMapper.selectById(couponCardId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得优惠劵(码)分页
|
||||
*
|
||||
* @param pageDTO 分页条件
|
||||
* @return 优惠劵(码)分页
|
||||
*/
|
||||
public PageResult<CouponTemplateRespDTO> pageCouponTemplate(CouponTemplatePageReqDTO pageDTO) {
|
||||
IPage<CouponTemplateDO> couponTemplatePage = couponTemplateMapper.selectPage(pageDTO);
|
||||
return CouponTemplateConvert.INSTANCE.convertPage(couponTemplatePage);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新优惠劵(码)模板的状态
|
||||
*
|
||||
* @param couponTemplateId 优惠劵模板编号
|
||||
* @param status 状态
|
||||
*/
|
||||
public void updateCouponTemplateStatus(Integer couponTemplateId, Integer status) {
|
||||
// 校验 CouponCardTemplate 存在
|
||||
CouponTemplateDO template = couponTemplateMapper.selectById(couponTemplateId);
|
||||
if (template == null) {
|
||||
throw ServiceExceptionUtil.exception(PromotionErrorCodeConstants.COUPON_TEMPLATE_NOT_EXISTS.getCode());
|
||||
}
|
||||
// 更新到数据库
|
||||
CouponTemplateDO updateTemplateDO = new CouponTemplateDO().setId(couponTemplateId).setStatus(status);
|
||||
couponTemplateMapper.updateById(updateTemplateDO);
|
||||
}
|
||||
|
||||
private Boolean checkCouponTemplateDateType(Integer dateType, Date validStartTime, Date validEndTime, Integer fixedStartTerm, Integer fixedEndTerm) {
|
||||
// TODO 芋艿:后续这种类型的校验,看看怎么优化到对象里
|
||||
if (CouponTemplateDateTypeEnum.FIXED_DATE.getValue().equals(dateType)) { // 固定日期
|
||||
if (validStartTime == null) {
|
||||
throw ServiceExceptionUtil.exception(BAD_REQUEST, "生效开始时间不能为空");
|
||||
}
|
||||
if (validEndTime == null) {
|
||||
throw ServiceExceptionUtil.exception(BAD_REQUEST, "生效结束时间不能为空");
|
||||
}
|
||||
if (validStartTime.after(validEndTime)) {
|
||||
throw ServiceExceptionUtil.exception(BAD_REQUEST, "生效开始时间不能大于生效结束时间");
|
||||
}
|
||||
} else if (CouponTemplateDateTypeEnum.FIXED_TERM.getValue().equals(dateType)) { // 领取日期
|
||||
if (fixedStartTerm == null) {
|
||||
throw ServiceExceptionUtil.exception(BAD_REQUEST, "领取日期开始时间不能为空");
|
||||
}
|
||||
if (fixedEndTerm == null) {
|
||||
throw ServiceExceptionUtil.exception(BAD_REQUEST, "领取日期结束时间不能为空");
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("未知的生效日期类型:" + dateType);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private Boolean checkCouponTemplatePreferentialType(Integer preferentialType, Integer percentOff,
|
||||
Integer priceOff, Integer priceAvailable) {
|
||||
if (PreferentialTypeEnum.PRICE.getValue().equals(preferentialType)) {
|
||||
if (priceOff == null) {
|
||||
throw ServiceExceptionUtil.exception(BAD_REQUEST, "优惠金额不能为空");
|
||||
}
|
||||
if (priceOff >= priceAvailable) {
|
||||
throw ServiceExceptionUtil.exception(BAD_REQUEST, "优惠金额不能d大于等于使用金额门槛");
|
||||
}
|
||||
} else if (PreferentialTypeEnum.DISCOUNT.getValue().equals(preferentialType)) {
|
||||
if (percentOff == null) {
|
||||
throw ServiceExceptionUtil.exception(BAD_REQUEST, "折扣百分比不能为空");
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("未知的优惠类型:" + preferentialType);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// ========== 优惠劵模板 ==========
|
||||
|
||||
/**
|
||||
* 添加优惠劵模板
|
||||
*
|
||||
* @param createReqDTO 优惠劵模板添加信息
|
||||
* @return 优惠劵模板编号
|
||||
*/
|
||||
public Integer createCouponCardTemplate(CouponCardTemplateCreateReqDTO createReqDTO) {
|
||||
// 校验生效日期相关
|
||||
checkCouponTemplateDateType(createReqDTO.getDateType(),
|
||||
createReqDTO.getValidStartTime(), createReqDTO.getValidEndTime(),
|
||||
createReqDTO.getFixedStartTerm(), createReqDTO.getFixedEndTerm());
|
||||
// 校验优惠类型
|
||||
checkCouponTemplatePreferentialType(createReqDTO.getPreferentialType(), createReqDTO.getPercentOff(),
|
||||
createReqDTO.getPriceOff(), createReqDTO.getPriceAvailable());
|
||||
// 保存优惠劵模板到数据库
|
||||
CouponTemplateDO template = CouponTemplateConvert.INSTANCE.convert(createReqDTO)
|
||||
.setType(CouponTemplateTypeEnum.CARD.getValue())
|
||||
.setStatus(CouponTemplateStatusEnum.ENABLE.getValue())
|
||||
.setStatFetchNum(0);
|
||||
couponTemplateMapper.insert(template);
|
||||
// 返回成功
|
||||
return template.getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新优惠劵模板
|
||||
*
|
||||
* @param updateReqDTO 优惠劵模板修改信息
|
||||
*/
|
||||
public void updateCouponCardTemplate(CouponCardTemplateUpdateReqDTO updateReqDTO) {
|
||||
// 校验 CouponCardTemplate 存在
|
||||
CouponTemplateDO template = couponTemplateMapper.selectById(updateReqDTO.getId());
|
||||
if (template == null) {
|
||||
throw ServiceExceptionUtil.exception(PromotionErrorCodeConstants.COUPON_TEMPLATE_NOT_EXISTS.getCode());
|
||||
}
|
||||
// 校验 CouponCardTemplate 是 CARD
|
||||
if (!CouponTemplateTypeEnum.CARD.getValue().equals(template.getType())) {
|
||||
throw ServiceExceptionUtil.exception(PromotionErrorCodeConstants.COUPON_TEMPLATE_NOT_CARD.getCode());
|
||||
}
|
||||
// 校验发放数量不能减少
|
||||
if (updateReqDTO.getTotal() < template.getTotal()) {
|
||||
throw ServiceExceptionUtil.exception(PromotionErrorCodeConstants.COUPON_TEMPLATE_TOTAL_CAN_NOT_REDUCE.getCode());
|
||||
}
|
||||
// 更新优惠劵模板到数据库
|
||||
CouponTemplateDO updateTemplateDO = CouponTemplateConvert.INSTANCE.convert(updateReqDTO);
|
||||
couponTemplateMapper.updateById(updateTemplateDO);
|
||||
}
|
||||
|
||||
// ========== 优惠码模板 TODO 芋艿:以后开发 ==========
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
package cn.iocoder.mall.promotionservice.service.recommend;
|
||||
|
||||
import cn.iocoder.common.framework.exception.util.ServiceExceptionUtil;
|
||||
import cn.iocoder.common.framework.vo.PageResult;
|
||||
import cn.iocoder.mall.promotion.api.rpc.recommend.dto.*;
|
||||
import cn.iocoder.mall.promotionservice.convert.recommend.ProductRecommendConvert;
|
||||
import cn.iocoder.mall.promotionservice.dal.mysql.dataobject.recommend.ProductRecommendDO;
|
||||
import cn.iocoder.mall.promotionservice.dal.mysql.mapper.recommend.ProductRecommendMapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.mall.promotion.api.enums.PromotionErrorCodeConstants.PRODUCT_RECOMMEND_EXISTS;
|
||||
import static cn.iocoder.mall.promotion.api.enums.PromotionErrorCodeConstants.PRODUCT_RECOMMEND_NOT_EXISTS;
|
||||
|
||||
/**
|
||||
* 商品推荐 Service
|
||||
*/
|
||||
@Service
|
||||
@Validated
|
||||
public class ProductRecommendService {
|
||||
|
||||
@Autowired
|
||||
private ProductRecommendMapper productRecommendMapper;
|
||||
|
||||
/**
|
||||
* 获得商品推荐列表
|
||||
*
|
||||
* @param listReqDTO 列表查询 DTO
|
||||
* @return 商品推荐列表
|
||||
*/
|
||||
public List<ProductRecommendRespDTO> listProductRecommends(ProductRecommendListReqDTO listReqDTO) {
|
||||
List<ProductRecommendDO> productRecommends = productRecommendMapper.selectList(listReqDTO);
|
||||
return ProductRecommendConvert.INSTANCE.convertList(productRecommends);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得商品推荐分页
|
||||
*
|
||||
* @param pageReqDTO 分页查询 DTO
|
||||
* @return 商品推荐分页
|
||||
*/
|
||||
public PageResult<ProductRecommendRespDTO> pageProductRecommend(ProductRecommendPageReqDTO pageReqDTO) {
|
||||
IPage<ProductRecommendDO> productRecommendPage = productRecommendMapper.selectPage(pageReqDTO);
|
||||
return ProductRecommendConvert.INSTANCE.convertPage(productRecommendPage);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建商品推荐
|
||||
*
|
||||
* @param createReqDTO 商品推荐信息
|
||||
* @return 商品推荐编号
|
||||
*/
|
||||
public Integer createProductRecommend(ProductRecommendCreateReqDTO createReqDTO) {
|
||||
// 校验商品是否已经推荐
|
||||
if (productRecommendMapper.selectByProductSpuIdAndType(createReqDTO.getProductSpuId(), createReqDTO.getType()) != null) {
|
||||
throw ServiceExceptionUtil.exception(PRODUCT_RECOMMEND_EXISTS);
|
||||
}
|
||||
// 保存到数据库
|
||||
ProductRecommendDO productRecommend = ProductRecommendConvert.INSTANCE.convert(createReqDTO);
|
||||
productRecommendMapper.insert(productRecommend);
|
||||
// 返回成功
|
||||
return productRecommend.getId();
|
||||
}
|
||||
|
||||
public void updateProductRecommend(ProductRecommendUpdateReqDTO updateReqDTO) {
|
||||
// 校验更新的商品推荐存在
|
||||
if (productRecommendMapper.selectById(updateReqDTO.getId()) == null) {
|
||||
throw ServiceExceptionUtil.exception(PRODUCT_RECOMMEND_NOT_EXISTS);
|
||||
}
|
||||
// 校验商品是否已经推荐
|
||||
ProductRecommendDO existProductRecommend = productRecommendMapper.selectByProductSpuIdAndType(updateReqDTO.getProductSpuId(), updateReqDTO.getType());
|
||||
if (existProductRecommend != null && !existProductRecommend.getId().equals(updateReqDTO.getId())) {
|
||||
throw ServiceExceptionUtil.exception(PRODUCT_RECOMMEND_EXISTS.getCode());
|
||||
}
|
||||
// 更新到数据库
|
||||
ProductRecommendDO updateProductRecommend = ProductRecommendConvert.INSTANCE.convert(updateReqDTO);
|
||||
productRecommendMapper.updateById(updateProductRecommend);
|
||||
}
|
||||
|
||||
public void deleteProductRecommend(Integer productRecommendId) {
|
||||
// 校验更新的商品推荐存在
|
||||
if (productRecommendMapper.selectById(productRecommendId) == null) {
|
||||
throw ServiceExceptionUtil.exception(PRODUCT_RECOMMEND_NOT_EXISTS);
|
||||
}
|
||||
// 更新到数据库
|
||||
productRecommendMapper.deleteById(productRecommendId);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
spring:
|
||||
# 数据源配置项
|
||||
datasource:
|
||||
url: jdbc:mysql://localhost:3306/mall_promotion?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT
|
||||
driver-class-name: com.mysql.jdbc.Driver
|
||||
username: root
|
||||
password: zhuyang
|
||||
# Spring Cloud 配置项
|
||||
cloud:
|
||||
nacos:
|
||||
# Spring Cloud Nacos Discovery 配置项
|
||||
discovery:
|
||||
server-addr: localhost:8848 # Nacos 服务器地址
|
||||
namespace: dev # Nacos 命名空间
|
||||
|
||||
# Dubbo 配置项
|
||||
dubbo:
|
||||
# Dubbo 注册中心
|
||||
registry:
|
||||
# address: spring-cloud://localhost:8848 # 指定 Dubbo 服务注册中心的地址
|
||||
address: nacos://localhost:8848?namespace=dev # 指定 Dubbo 服务注册中心的地址
|
||||
@@ -0,0 +1,24 @@
|
||||
spring:
|
||||
# 数据源配置项
|
||||
datasource:
|
||||
url: jdbc:mysql://localhost:3306/mall_promotion?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT
|
||||
driver-class-name: com.mysql.jdbc.Driver
|
||||
username: root
|
||||
password: zhuyang
|
||||
# Spring Cloud 配置项
|
||||
cloud:
|
||||
nacos:
|
||||
# Spring Cloud Nacos Discovery 配置项
|
||||
discovery:
|
||||
server-addr: localhost:8848 # Nacos 服务器地址
|
||||
namespace: dev # Nacos 命名空间
|
||||
|
||||
# Dubbo 配置项
|
||||
dubbo:
|
||||
# Dubbo 注册中心
|
||||
registry:
|
||||
# address: spring-cloud://localhost:8848 # 指定 Dubbo 服务注册中心的地址
|
||||
address: nacos://localhost:8848?namespace=dev # 指定 Dubbo 服务注册中心的地址
|
||||
# Dubbo 服务提供者的配置
|
||||
provider:
|
||||
tag: ${DUBBO_TAG} # Dubbo 路由分组
|
||||
@@ -0,0 +1,64 @@
|
||||
spring:
|
||||
# Application 的配置项
|
||||
application:
|
||||
name: promotion-service
|
||||
# Profile 的配置项
|
||||
profiles:
|
||||
active: local
|
||||
|
||||
# MyBatis Plus 配置项
|
||||
mybatis-plus:
|
||||
configuration:
|
||||
map-underscore-to-camel-case: true # 虽然默认为 true ,但是还是显示去指定下。
|
||||
global-config:
|
||||
db-config:
|
||||
id-type: auto
|
||||
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
|
||||
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
|
||||
mapper-locations: classpath*:mapper/*.xml
|
||||
type-aliases-package: cn.iocoder.mall.promotionservice.dal.mysql.dataobject
|
||||
|
||||
# Dubbo 配置项
|
||||
dubbo:
|
||||
# Spring Cloud Alibaba Dubbo 专属配置
|
||||
cloud:
|
||||
subscribed-services: '' # 设置订阅的应用列表,默认为 * 订阅所有应用
|
||||
# Dubbo 提供者的协议
|
||||
protocol:
|
||||
name: dubbo
|
||||
port: -1
|
||||
# Dubbo 提供服务的扫描基础包
|
||||
scan:
|
||||
base-packages: cn.iocoder.mall.promotionservice.rpc
|
||||
# Dubbo 服务提供者的配置
|
||||
provider:
|
||||
filter: -exception
|
||||
validation: true # 开启 Provider 参数校验
|
||||
version: 1.0.0 # 服务的版本号
|
||||
# Dubbo 服务消费者的配置
|
||||
consumer:
|
||||
ErrorCodeRpc:
|
||||
version: 1.0.0
|
||||
ProductSkuRpc:
|
||||
version: 1.0.0
|
||||
ProductSpuRpc:
|
||||
version: 1.0.0
|
||||
|
||||
# RocketMQ 配置项
|
||||
rocketmq:
|
||||
name-server: localhost:9876
|
||||
producer:
|
||||
group: ${spring.application.name}-producer-group
|
||||
|
||||
# Actuator 监控配置项
|
||||
management:
|
||||
server.port: 38085 # 独立端口,避免被暴露出去
|
||||
endpoints.web.exposure.include: '*' # 暴露所有监控端点
|
||||
server.port: ${management.server.port} # 设置使用 Actuator 的服务器端口,因为 RPC 服务不需要 Web 端口
|
||||
|
||||
# Mall 配置项
|
||||
mall:
|
||||
# 错误码配置项对应 ErrorCodeProperties 配置类
|
||||
error-code:
|
||||
group: ${spring.application.name}
|
||||
constants-class: cn.iocoder.mall.promotionservice.enums.PromotionErrorCodeConstants
|
||||
@@ -0,0 +1,12 @@
|
||||
<?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.mall.promotionservice.dal.mysql.mapper.coupon.CouponTemplateMapper">
|
||||
|
||||
<update id="updateStatFetchNumIncr" parameterType="Integer">
|
||||
UPDATE coupon_template
|
||||
SET stat_fetch_Num = stat_fetch_Num + 1
|
||||
WHERE id = #{id}
|
||||
AND total > stat_fetch_Num
|
||||
</update>
|
||||
|
||||
</mapper>
|
||||
Reference in New Issue
Block a user