diff --git a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/giftvoucher/GiftVoucherApi.java b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/giftvoucher/GiftVoucherApi.java new file mode 100644 index 0000000..6de51db --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/giftvoucher/GiftVoucherApi.java @@ -0,0 +1,17 @@ +package cn.iocoder.yudao.module.promotion.api.giftvoucher; + +import cn.iocoder.yudao.module.promotion.api.giftvoucher.dto.GiftVoucherRespDTO; +import cn.iocoder.yudao.module.promotion.api.giftvoucher.dto.GiftVoucherUseReqDTO; + +/** + * 优惠劵 API 接口 + * + * @author 芋道源码 + */ +public interface GiftVoucherApi { + + + GiftVoucherRespDTO getGiftVoucherById(Long giftVoucherId); + + void useGiftVoucher(GiftVoucherUseReqDTO giftVoucherUseReqDTO); +} diff --git a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/giftvoucher/dto/GiftVoucherRespDTO.java b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/giftvoucher/dto/GiftVoucherRespDTO.java new file mode 100644 index 0000000..922bf03 --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/giftvoucher/dto/GiftVoucherRespDTO.java @@ -0,0 +1,73 @@ +package cn.iocoder.yudao.module.promotion.api.giftvoucher.dto; + +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 提货劵 Response DTO + * + * @author 茂县源码 + */ +@Data +public class GiftVoucherRespDTO{ + + /** + * 提货劵编号 + */ + private Long id; + /** + * 提货劵模板编号 + */ + private Long templateId; + /** + * 提货劵名 + */ + private String name; + /** + * 提货劵状态 + * + * 1-未使用 + * 2-已使用 + * 3-已失效 + */ + private Integer status; + /** + * 商品范围编号的数组 + */ + private List productScopeValues; +// private String productScopeValues; + /** + * 可购买商品数量 + */ + private Integer productCount; + /** + * 用户编号 + */ + private Long userId; + /** + * 领取类型 + * + * 1 - 用户主动领取 + * 2 - 后台自动发放 + */ + private Integer takeType; + /** + * 生效开始时间 + */ + private LocalDateTime validStartTime; + /** + * 生效结束时间 + */ + private LocalDateTime validEndTime; + /** + * 使用订单号 + */ + private Long useOrderId; + /** + * 使用时间 + */ + private LocalDateTime useTime; + +} \ No newline at end of file diff --git a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/giftvoucher/dto/GiftVoucherUseReqDTO.java b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/giftvoucher/dto/GiftVoucherUseReqDTO.java new file mode 100644 index 0000000..4b5b95b --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/giftvoucher/dto/GiftVoucherUseReqDTO.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.promotion.api.giftvoucher.dto; + +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** + * 提货劵使用 Request DTO + * + * @author 芋道源码 + */ +@Data +public class GiftVoucherUseReqDTO { + + /** + * 优惠劵编号 + */ + @NotNull(message = "提货劵编号不能为空") + private Long id; + + /** + * 用户编号 + */ + @NotNull(message = "用户编号不能为空") + private Long userId; + + /** + * 订单编号 + */ + @NotNull(message = "订单编号不能为空") + private Long orderId; + +} diff --git a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java index 514cb27..6e39e07 100644 --- a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java +++ b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java @@ -138,4 +138,15 @@ public interface ErrorCodeConstants { // ========== 客服消息 1-013-020-000 ========== ErrorCode KEFU_MESSAGE_NOT_EXISTS = new ErrorCode(1_013_020_000, "客服消息不存在"); + // ========== 提货券模板 1-013-021-000 ========== + ErrorCode GIFT_VOUCHER_TEMPLATE_NOT_EXISTS = new ErrorCode(1_013_021_000, "提货券模板不存在"); + ErrorCode GIFT_VOUCHER_TEMPLATE_USER_ALREADY_TAKE = new ErrorCode(1_013_021_001, "用户已领取过此提货券"); + ErrorCode GIFT_VOUCHER_STATUS_NOT_UNUSED = new ErrorCode(1_013_021_002, "提货劵不处于待使用状态"); + + // ========== 提货劵 1-013-022-000 ========== + ErrorCode GIFT_VOUCHER_NOT_EXISTS = new ErrorCode(1_013_022_000, "提货劵不存在"); + ErrorCode GIFT_VOUCHER_TEMPLATE_CANNOT_TAKE = new ErrorCode(1_013_022_001, "领取方式不正确"); + ErrorCode GIFT_VOUCHER_TEMPLATE_EXPIRED = new ErrorCode(1_013_022_002, "提货券模板已过期"); + ErrorCode GIFT_VOUCHER_TEMPLATE_NOT_ENOUGH = new ErrorCode(1_013_022_003, "当前剩余数量不够领取"); + } diff --git a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/giftvoucher/GiftVoucherStatusEnum.java b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/giftvoucher/GiftVoucherStatusEnum.java new file mode 100644 index 0000000..3cf60b1 --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/giftvoucher/GiftVoucherStatusEnum.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.promotion.enums.giftvoucher; + +import cn.iocoder.yudao.framework.common.core.ArrayValuable; +import cn.iocoder.yudao.module.promotion.enums.diy.DiyPageEnum; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * 提货劵状态枚举 + * + * @author 芋道源码 + */ +@AllArgsConstructor +@Getter +public enum GiftVoucherStatusEnum implements ArrayValuable { + + UNUSED(1, "未使用"), + USED(2, "已使用"), + EXPIRE(3, "已过期"); + + private static final Integer[] ARRAYS = Arrays.stream(values()).map(GiftVoucherStatusEnum::getStatus).toArray(Integer[]::new); + + /** + * 值 + */ + private final Integer status; + /** + * 名字 + */ + private final String name; + + @Override + public Integer[] array() { + return ARRAYS; + } + +} diff --git a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/giftvoucher/GiftVoucherTemplateValidityTypeEnum.java b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/giftvoucher/GiftVoucherTemplateValidityTypeEnum.java new file mode 100644 index 0000000..7c81ccb --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/giftvoucher/GiftVoucherTemplateValidityTypeEnum.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.promotion.enums.giftvoucher; + +import cn.iocoder.yudao.framework.common.core.ArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * 优惠劵模板的有限期类型的枚举 + * + * @author 芋道源码 + */ +@AllArgsConstructor +@Getter +public enum GiftVoucherTemplateValidityTypeEnum implements ArrayValuable { + + DATE(1, "固定日期"), + TERM(2, "领取之后"), + ; + + private static final Integer[] ARRAYS = Arrays.stream(values()).map(GiftVoucherTemplateValidityTypeEnum::getType).toArray(Integer[]::new); + + /** + * 值 + */ + private final Integer type; + /** + * 名字 + */ + private final String name; + + @Override + public Integer[] array() { + return ARRAYS; + } + +} diff --git a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/giftvoucher/GiftVoucherTypeEnum.java b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/giftvoucher/GiftVoucherTypeEnum.java new file mode 100644 index 0000000..d7da51c --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/giftvoucher/GiftVoucherTypeEnum.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.module.promotion.enums.giftvoucher; + +import cn.iocoder.yudao.framework.common.core.ArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; +import java.util.Objects; + +/** + * 优惠劵领取方式 + * + * @author 芋道源码 + */ +@AllArgsConstructor +@Getter +public enum GiftVoucherTypeEnum implements ArrayValuable { + + USER(1, "扫码领取"), // 用户可扫码直接领取 + ADMIN(2, "指定发放"), // 后台指定会员赠送优惠劵 + ; + + public static final Integer[] ARRAYS = Arrays.stream(values()).map(GiftVoucherTypeEnum::getType).toArray(Integer[]::new); + + /** + * 值 + */ + private final Integer type; + /** + * 名字 + */ + private final String name; + + @Override + public Integer[] array() { + return ARRAYS; + } + + public static boolean isUser(Integer type) { + return Objects.equals(USER.getType(), type); + } + +} diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/giftvoucher/GiftVoucherApiImpl.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/giftvoucher/GiftVoucherApiImpl.java new file mode 100644 index 0000000..34f328e --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/giftvoucher/GiftVoucherApiImpl.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.promotion.api.giftvoucher; + + +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.promotion.api.giftvoucher.dto.GiftVoucherRespDTO; +import cn.iocoder.yudao.module.promotion.api.giftvoucher.dto.GiftVoucherUseReqDTO; +import cn.iocoder.yudao.module.promotion.service.giftvoucher.GiftVoucherService; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; + +/** + * 优惠劵 API 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class GiftVoucherApiImpl implements GiftVoucherApi { + + @Resource + private GiftVoucherService giftVoucherService; + + + @Override + public GiftVoucherRespDTO getGiftVoucherById(Long giftVoucherId) { + return BeanUtils.toBean(giftVoucherService.getGiftVoucher(giftVoucherId), GiftVoucherRespDTO.class); + } + + @Override + public void useGiftVoucher(GiftVoucherUseReqDTO giftVoucherUseReqDTO) { + giftVoucherService.useGiftVoucher(giftVoucherUseReqDTO); + } +} diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/giftvoucher/GiftVoucherController.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/giftvoucher/GiftVoucherController.java new file mode 100644 index 0000000..962a72f --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/giftvoucher/GiftVoucherController.java @@ -0,0 +1,102 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.giftvoucher; + +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.promotion.controller.admin.giftvoucher.vo.giftvoucher.GiftVoucherPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.giftvoucher.vo.giftvoucher.GiftVoucherRespVO; +import cn.iocoder.yudao.module.promotion.controller.admin.giftvoucher.vo.giftvoucher.GiftVoucherSaveReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.giftvoucher.vo.giftvoucher.GiftVoucherSendReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.giftvoucher.GiftVoucherDO; +import cn.iocoder.yudao.module.promotion.service.giftvoucher.GiftVoucherService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.util.List; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 提货劵") +@RestController +@RequestMapping("/promotion/gift-voucher") +@Validated +public class GiftVoucherController { + + @Resource + private GiftVoucherService giftVoucherService; + + @PostMapping("/create") + @Operation(summary = "创建提货劵") + @PreAuthorize("@ss.hasPermission('promotion:gift-voucher:create')") + public CommonResult createGiftVoucher(@Valid @RequestBody GiftVoucherSaveReqVO createReqVO) { + return success(giftVoucherService.createGiftVoucher(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新提货劵") + @PreAuthorize("@ss.hasPermission('promotion:gift-voucher:update')") + public CommonResult updateGiftVoucher(@Valid @RequestBody GiftVoucherSaveReqVO updateReqVO) { + giftVoucherService.updateGiftVoucher(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除提货劵") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('promotion:gift-voucher:delete')") + public CommonResult deleteGiftVoucher(@RequestParam("id") Long id) { + giftVoucherService.deleteGiftVoucher(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得提货劵") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('promotion:gift-voucher:query')") + public CommonResult getGiftVoucher(@RequestParam("id") Long id) { + GiftVoucherDO giftVoucher = giftVoucherService.getGiftVoucher(id); + return success(BeanUtils.toBean(giftVoucher, GiftVoucherRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得提货劵分页") + @PreAuthorize("@ss.hasPermission('promotion:gift-voucher:query')") + public CommonResult> getGiftVoucherPage(@Valid GiftVoucherPageReqVO pageReqVO) { + PageResult pageResult = giftVoucherService.getGiftVoucherPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, GiftVoucherRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出提货劵 Excel") + @PreAuthorize("@ss.hasPermission('promotion:gift-voucher:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportGiftVoucherExcel(@Valid GiftVoucherPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = giftVoucherService.getGiftVoucherPage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "提货劵.xls", "数据", GiftVoucherRespVO.class, + BeanUtils.toBean(list, GiftVoucherRespVO.class)); + } + + @PostMapping("/send") + @Operation(summary = "发送提货券") + @PreAuthorize("@ss.hasPermission('promotion:coupon:send')") + public CommonResult sendGiftVoucher(@Valid @RequestBody GiftVoucherSendReqVO reqVO) { + giftVoucherService.takeGiftVoucherByAdmin(reqVO.getTemplateId(), reqVO.getUserIds()); + return success(true); + } + +} \ No newline at end of file diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/giftvoucher/GiftVoucherTemplateController.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/giftvoucher/GiftVoucherTemplateController.java new file mode 100644 index 0000000..d354c15 --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/giftvoucher/GiftVoucherTemplateController.java @@ -0,0 +1,96 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.giftvoucher; + +import cn.iocoder.yudao.module.promotion.controller.admin.giftvoucher.vo.template.GiftVoucherTemplatePageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.giftvoucher.vo.template.GiftVoucherTemplateRespVO; +import cn.iocoder.yudao.module.promotion.controller.admin.giftvoucher.vo.template.GiftVoucherTemplateSaveReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.giftvoucher.GiftVoucherTemplateDO; +import cn.iocoder.yudao.module.promotion.service.giftvoucher.GiftVoucherTemplateService; +import org.springframework.web.bind.annotation.*; +import javax.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.security.access.prepost.PreAuthorize; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Operation; + +import javax.validation.*; +import javax.servlet.http.*; +import java.util.*; +import java.io.IOException; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; + +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*; + + +@Tag(name = "管理后台 - 提货券模板") +@RestController +@RequestMapping("/promotion/gift-voucher-template") +@Validated +public class GiftVoucherTemplateController { + + @Resource + private GiftVoucherTemplateService giftVoucherTemplateService; + + @PostMapping("/create") + @Operation(summary = "创建提货券模板") + @PreAuthorize("@ss.hasPermission('promotion:gift-voucher-template:create')") + public CommonResult createGiftVoucherTemplate(@Valid @RequestBody GiftVoucherTemplateSaveReqVO createReqVO) { + return success(giftVoucherTemplateService.createGiftVoucherTemplate(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新提货券模板") + @PreAuthorize("@ss.hasPermission('promotion:gift-voucher-template:update')") + public CommonResult updateGiftVoucherTemplate(@Valid @RequestBody GiftVoucherTemplateSaveReqVO updateReqVO) { + giftVoucherTemplateService.updateGiftVoucherTemplate(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除提货券模板") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('promotion:gift-voucher-template:delete')") + public CommonResult deleteGiftVoucherTemplate(@RequestParam("id") Long id) { + giftVoucherTemplateService.deleteGiftVoucherTemplate(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得提货券模板") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('promotion:gift-voucher-template:query')") + public CommonResult getGiftVoucherTemplate(@RequestParam("id") Long id) { + GiftVoucherTemplateDO giftVoucherTemplate = giftVoucherTemplateService.getGiftVoucherTemplate(id); + return success(BeanUtils.toBean(giftVoucherTemplate, GiftVoucherTemplateRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得提货券模板分页") + @PreAuthorize("@ss.hasPermission('promotion:gift-voucher-template:query')") + public CommonResult> getGiftVoucherTemplatePage(@Valid GiftVoucherTemplatePageReqVO pageReqVO) { + PageResult pageResult = giftVoucherTemplateService.getGiftVoucherTemplatePage(pageReqVO); + return success(BeanUtils.toBean(pageResult, GiftVoucherTemplateRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出提货券模板 Excel") + @PreAuthorize("@ss.hasPermission('promotion:gift-voucher-template:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportGiftVoucherTemplateExcel(@Valid GiftVoucherTemplatePageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = giftVoucherTemplateService.getGiftVoucherTemplatePage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "提货券模板.xls", "数据", GiftVoucherTemplateRespVO.class, + BeanUtils.toBean(list, GiftVoucherTemplateRespVO.class)); + } + +} \ No newline at end of file diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/giftvoucher/vo/giftvoucher/GiftVoucherPageReqVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/giftvoucher/vo/giftvoucher/GiftVoucherPageReqVO.java new file mode 100644 index 0000000..8045471 --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/giftvoucher/vo/giftvoucher/GiftVoucherPageReqVO.java @@ -0,0 +1,58 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.giftvoucher.vo.giftvoucher; + +import lombok.*; +import java.util.*; +import io.swagger.v3.oas.annotations.media.Schema; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 提货劵分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class GiftVoucherPageReqVO extends PageParam { + + @Schema(description = "提货劵模板编号", example = "7305") + private Long templateId; + + @Schema(description = "提货劵名", example = "王五") + private String name; + + @Schema(description = "提货劵状态", example = "2") + private Integer status; + + @Schema(description = "商品范围编号的数组") + private String productScopeValues; + + @Schema(description = "用户编号", example = "17286") + private Long userId; + + @Schema(description = "领取类型", example = "1") + private Integer takeType; + + @Schema(description = "生效开始时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] validStartTime; + + @Schema(description = "生效结束时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] validEndTime; + + @Schema(description = "使用订单号", example = "23301") + private Long useOrderId; + + @Schema(description = "使用时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] useTime; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + + @Schema(description = "可购买商品数量", example = "18952") + private Integer productCount; + +} \ No newline at end of file diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/giftvoucher/vo/giftvoucher/GiftVoucherRespVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/giftvoucher/vo/giftvoucher/GiftVoucherRespVO.java new file mode 100644 index 0000000..3601183 --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/giftvoucher/vo/giftvoucher/GiftVoucherRespVO.java @@ -0,0 +1,67 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.giftvoucher.vo.giftvoucher; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; +import com.alibaba.excel.annotation.*; + +@Schema(description = "管理后台 - 提货劵 Response VO") +@Data +@ExcelIgnoreUnannotated +public class GiftVoucherRespVO { + + @Schema(description = "提货劵编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17673") + @ExcelProperty("提货劵编号") + private Long id; + + @Schema(description = "提货劵模板编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "7305") + @ExcelProperty("提货劵模板编号") + private Long templateId; + + @Schema(description = "提货劵名", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五") + @ExcelProperty("提货劵名") + private String name; + + @Schema(description = "提货劵状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @ExcelProperty("提货劵状态") + private Integer status; + + @Schema(description = "商品范围编号的数组") + @ExcelProperty("商品范围编号的数组") + private String productScopeValues; + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17286") + @ExcelProperty("用户编号") + private Long userId; + + @Schema(description = "领取类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty("领取类型") + private Integer takeType; + + @Schema(description = "生效开始时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("生效开始时间") + private LocalDateTime validStartTime; + + @Schema(description = "生效结束时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("生效结束时间") + private LocalDateTime validEndTime; + + @Schema(description = "使用订单号", example = "23301") + @ExcelProperty("使用订单号") + private Long useOrderId; + + @Schema(description = "使用时间") + @ExcelProperty("使用时间") + private LocalDateTime useTime; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + + @Schema(description = "可购买商品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "18952") + @ExcelProperty("可购买商品数量") + private Integer productCount; + +} \ No newline at end of file diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/giftvoucher/vo/giftvoucher/GiftVoucherSaveReqVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/giftvoucher/vo/giftvoucher/GiftVoucherSaveReqVO.java new file mode 100644 index 0000000..ca4633a --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/giftvoucher/vo/giftvoucher/GiftVoucherSaveReqVO.java @@ -0,0 +1,58 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.giftvoucher.vo.giftvoucher; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import javax.validation.constraints.*; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 提货劵新增/修改 Request VO") +@Data +public class GiftVoucherSaveReqVO { + + @Schema(description = "提货劵编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17673") + private Long id; + + @Schema(description = "提货劵模板编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "7305") + @NotNull(message = "提货劵模板编号不能为空") + private Long templateId; + + @Schema(description = "提货劵名", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五") + @NotEmpty(message = "提货劵名不能为空") + private String name; + + @Schema(description = "提货劵状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @NotNull(message = "提货劵状态") + private Integer status; + + @Schema(description = "商品范围编号的数组") + private String productScopeValues; + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17286") + @NotNull(message = "用户编号不能为空") + private Long userId; + + @Schema(description = "领取类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "领取类型") + private Integer takeType; + + @Schema(description = "生效开始时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "生效开始时间不能为空") + private LocalDateTime validStartTime; + + @Schema(description = "生效结束时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "生效结束时间不能为空") + private LocalDateTime validEndTime; + + @Schema(description = "使用订单号", example = "23301") + private Long useOrderId; + + @Schema(description = "使用时间") + private LocalDateTime useTime; + + @Schema(description = "可购买商品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "18952") + @NotNull(message = "可购买商品数量不能为空") + private Integer productCount; + +} \ No newline at end of file diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/giftvoucher/vo/giftvoucher/GiftVoucherSendReqVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/giftvoucher/vo/giftvoucher/GiftVoucherSendReqVO.java new file mode 100644 index 0000000..5c6e347 --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/giftvoucher/vo/giftvoucher/GiftVoucherSendReqVO.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.giftvoucher.vo.giftvoucher; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.ToString; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.Set; + +@Schema(description = "管理后台 - 提货劵发放 Request VO") +@Data +@ToString(callSuper = true) +public class GiftVoucherSendReqVO { + + @Schema(description = "提货劵模板编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "提货劵模板编号不能为空") + private Long templateId; + + @Schema(description = "用户编号列表", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1, 2]") + @NotEmpty(message = "用户编号列表不能为空") + private Set userIds; + +} diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/giftvoucher/vo/template/GiftVoucherTemplatePageReqVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/giftvoucher/vo/template/GiftVoucherTemplatePageReqVO.java new file mode 100644 index 0000000..b100b65 --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/giftvoucher/vo/template/GiftVoucherTemplatePageReqVO.java @@ -0,0 +1,68 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.giftvoucher.vo.template; + +import lombok.*; +import io.swagger.v3.oas.annotations.media.Schema; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 提货券模板分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class GiftVoucherTemplatePageReqVO extends PageParam { + + @Schema(description = "提货券名", example = "赵六") + private String name; + + @Schema(description = "提货券描述", example = "你猜") + private String description; + + @Schema(description = "状态", example = "2") + private Integer status; + + @Schema(description = "发放数量, -1 - 则表示不限制", example = "23927") + private Integer totalCount; + + @Schema(description = "每人限领个数, -1 - 则表示不限制", example = "31760") + private Integer takeLimitCount; + + @Schema(description = "领取方式", example = "1") + private Integer takeType; + + @Schema(description = "商品范围编号的数组") + private String productScopeValues; + + @Schema(description = "生效日期类型", example = "1") + private Integer validityType; + + @Schema(description = "固定日期-生效开始时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] validStartTime; + + @Schema(description = "固定日期-生效结束时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] validEndTime; + + @Schema(description = "领取日期-开始天数") + private Integer fixedStartTerm; + + @Schema(description = "领取日期-结束天数") + private Integer fixedEndTerm; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + + @Schema(description = "领取提货券的数量", example = "1818") + private Integer takeCount; + + @Schema(description = "使用提货券的次数", example = "25128") + private Integer useCount; + + @Schema(description = "可购买商品数量", example = "22134") + private Integer productCount; + +} \ No newline at end of file diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/giftvoucher/vo/template/GiftVoucherTemplateRespVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/giftvoucher/vo/template/GiftVoucherTemplateRespVO.java new file mode 100644 index 0000000..9ed71b5 --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/giftvoucher/vo/template/GiftVoucherTemplateRespVO.java @@ -0,0 +1,82 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.giftvoucher.vo.template; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; + +import java.time.LocalDateTime; +import com.alibaba.excel.annotation.*; + +@Schema(description = "管理后台 - 提货券模板 Response VO") +@Data +@ExcelIgnoreUnannotated +public class GiftVoucherTemplateRespVO { + + @Schema(description = "模板编号,自增唯一。", requiredMode = Schema.RequiredMode.REQUIRED, example = "13004") + @ExcelProperty("模板编号,自增唯一。") + private Long id; + + @Schema(description = "提货券名", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六") + @ExcelProperty("提货券名") + private String name; + + @Schema(description = "提货券描述", example = "你猜") + @ExcelProperty("提货券描述") + private String description; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @ExcelProperty("状态") + private Integer status; + + @Schema(description = "发放数量, -1 - 则表示不限制", requiredMode = Schema.RequiredMode.REQUIRED, example = "23927") + @ExcelProperty("发放数量, -1 - 则表示不限制") + private Integer totalCount; + + @Schema(description = "每人限领个数, -1 - 则表示不限制", requiredMode = Schema.RequiredMode.REQUIRED, example = "31760") + @ExcelProperty("每人限领个数, -1 - 则表示不限制") + private Integer takeLimitCount; + + @Schema(description = "领取方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty("领取方式") + private Integer takeType; + + @Schema(description = "商品范围编号的数组") + @ExcelProperty("商品范围编号的数组") + private String productScopeValues; + + @Schema(description = "生效日期类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty("生效日期类型") + private Integer validityType; + + @Schema(description = "固定日期-生效开始时间") + @ExcelProperty("固定日期-生效开始时间") + private LocalDateTime validStartTime; + + @Schema(description = "固定日期-生效结束时间") + @ExcelProperty("固定日期-生效结束时间") + private LocalDateTime validEndTime; + + @Schema(description = "领取日期-开始天数") + @ExcelProperty("领取日期-开始天数") + private Integer fixedStartTerm; + + @Schema(description = "领取日期-结束天数") + @ExcelProperty("领取日期-结束天数") + private Integer fixedEndTerm; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + + @Schema(description = "领取提货券的数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1818") + @ExcelProperty("领取提货券的数量") + private Integer takeCount; + + @Schema(description = "使用提货券的次数", requiredMode = Schema.RequiredMode.REQUIRED, example = "25128") + @ExcelProperty("使用提货券的次数") + private Integer useCount; + + @Schema(description = "可购买商品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "22134") + @ExcelProperty("可购买商品数量") + private Integer productCount; + +} \ No newline at end of file diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/giftvoucher/vo/template/GiftVoucherTemplateSaveReqVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/giftvoucher/vo/template/GiftVoucherTemplateSaveReqVO.java new file mode 100644 index 0000000..bac6b91 --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/giftvoucher/vo/template/GiftVoucherTemplateSaveReqVO.java @@ -0,0 +1,70 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.giftvoucher.vo.template; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; + +import javax.validation.constraints.*; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 提货券模板新增/修改 Request VO") +@Data +public class GiftVoucherTemplateSaveReqVO { + + @Schema(description = "模板编号,自增唯一。", requiredMode = Schema.RequiredMode.REQUIRED, example = "13004") + private Long id; + + @Schema(description = "提货券名", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六") + @NotEmpty(message = "提货券名不能为空") + private String name; + + @Schema(description = "提货券描述", example = "你猜") + private String description; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @NotNull(message = "状态不能为空") + private Integer status; + + @Schema(description = "发放数量, -1 - 则表示不限制", requiredMode = Schema.RequiredMode.REQUIRED, example = "23927") + @NotNull(message = "发放数量, -1 - 则表示不限制不能为空") + private Integer totalCount; + + @Schema(description = "每人限领个数, -1 - 则表示不限制", requiredMode = Schema.RequiredMode.REQUIRED, example = "31760") + @NotNull(message = "每人限领个数, -1 - 则表示不限制不能为空") + private Integer takeLimitCount; + + @Schema(description = "领取方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "领取方式不能为空") + private Integer takeType; + + @Schema(description = "商品范围编号的数组") + private String productScopeValues; + + @Schema(description = "生效日期类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "生效日期类型不能为空") + private Integer validityType; + + @Schema(description = "固定日期-生效开始时间") + private LocalDateTime validStartTime; + + @Schema(description = "固定日期-生效结束时间") + private LocalDateTime validEndTime; + + @Schema(description = "领取日期-开始天数") + private Integer fixedStartTerm; + + @Schema(description = "领取日期-结束天数") + private Integer fixedEndTerm; + + @Schema(description = "领取提货券的数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1818") + @NotNull(message = "领取提货券的数量不能为空") + private Integer takeCount; + + @Schema(description = "使用提货券的次数", requiredMode = Schema.RequiredMode.REQUIRED, example = "25128") + @NotNull(message = "使用提货券的次数不能为空") + private Integer useCount; + + @Schema(description = "可购买商品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "22134") + @NotNull(message = "可购买商品数量不能为空") + private Integer productCount; + +} \ No newline at end of file diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/giftvoucher/AppGiftVoucherController.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/giftvoucher/AppGiftVoucherController.java new file mode 100644 index 0000000..5c96204 --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/giftvoucher/AppGiftVoucherController.java @@ -0,0 +1,80 @@ +package cn.iocoder.yudao.module.promotion.controller.app.giftvoucher; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.promotion.controller.app.giftvoucher.vo.AppGiftVoucherPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.app.giftvoucher.vo.AppGiftVoucherRespVO; +import cn.iocoder.yudao.module.promotion.controller.app.giftvoucher.vo.AppGiftVoucherTakeReqVO; +import cn.iocoder.yudao.module.promotion.convert.giftvoucher.GiftVoucherConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.giftvoucher.GiftVoucherDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.giftvoucher.GiftVoucherTemplateDO; +import cn.iocoder.yudao.module.promotion.enums.giftvoucher.GiftVoucherTypeEnum; +import cn.iocoder.yudao.module.promotion.service.giftvoucher.GiftVoucherService; +import cn.iocoder.yudao.module.promotion.service.giftvoucher.GiftVoucherTemplateService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.Collections; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +@Tag(name = "用户 App - 我的提货劵列表") +@RestController +@RequestMapping("/promotion/gift-voucher") +@Validated +public class AppGiftVoucherController { + + @Resource + private GiftVoucherService giftVoucherService; + @Resource + private GiftVoucherTemplateService giftVoucherTemplateService; + + @PostMapping("/take") + @Operation(summary = "领取提货劵") + @Parameter(name = "templateId", description = "提货劵模板编号", required = true, example = "1024") + public CommonResult takeGiftVoucher(@Valid @RequestBody AppGiftVoucherTakeReqVO reqVO) { + // 1. 领取提货劵 + Long userId = getLoginUserId(); + giftVoucherService.takeGiftVoucher(reqVO.getTemplateId(), CollUtil.newHashSet(userId), GiftVoucherTypeEnum.USER); + + // 2. 检查是否可以继续领取 + GiftVoucherTemplateDO giftVoucherTemplate = giftVoucherTemplateService.getGiftVoucherTemplate(reqVO.getTemplateId()); + boolean canTakeAgain = true; + if (giftVoucherTemplate.getTakeLimitCount() != null && giftVoucherTemplate.getTakeLimitCount() > 0) { + Integer takeCount = giftVoucherService.getTakeCount(reqVO.getTemplateId(), userId); + canTakeAgain = takeCount < giftVoucherTemplate.getTakeLimitCount(); + } + return success(canTakeAgain); + } + + @GetMapping("/page") + @Operation(summary = "我的提货劵列表") + public CommonResult> getGiftVoucherPage(AppGiftVoucherPageReqVO pageReqVO) { + PageResult pageResult = giftVoucherService.getGiftVoucherPage( + GiftVoucherConvert.INSTANCE.convert(pageReqVO, Collections.singleton(getLoginUserId()))); + return success(BeanUtils.toBean(pageResult, AppGiftVoucherRespVO.class)); + } + + @GetMapping("/get") + @Operation(summary = "获得提货劵") + @Parameter(name = "id", description = "优惠劵编号", required = true, example = "1024") + public CommonResult getGiftVoucher(@RequestParam("id") Long id) { + GiftVoucherDO giftVoucherDO = giftVoucherService.getGiftVoucherByUserId(getLoginUserId(), id); + return success(BeanUtils.toBean(giftVoucherDO, AppGiftVoucherRespVO.class)); + } + + @GetMapping(value = "/get-unused-count") + @Operation(summary = "获得未使用的提货劵数量") + public CommonResult getUnusedCouponCount() { + return success(giftVoucherService.getUnusedCouponCount(getLoginUserId())); + } + +} diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/giftvoucher/vo/AppGiftVoucherPageReqVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/giftvoucher/vo/AppGiftVoucherPageReqVO.java new file mode 100644 index 0000000..3aacf79 --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/giftvoucher/vo/AppGiftVoucherPageReqVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.promotion.controller.app.giftvoucher.vo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.promotion.enums.coupon.CouponStatusEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "用户 App - 提货劵分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class AppGiftVoucherPageReqVO extends PageParam { + + @Schema(description = "提货劵状态", example = "1") + @InEnum(value = CouponStatusEnum.class, message = "提货劵状态,必须是 {value}") + private Integer status; + +} diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/giftvoucher/vo/AppGiftVoucherRespVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/giftvoucher/vo/AppGiftVoucherRespVO.java new file mode 100644 index 0000000..1db4acb --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/giftvoucher/vo/AppGiftVoucherRespVO.java @@ -0,0 +1,71 @@ +package cn.iocoder.yudao.module.promotion.controller.app.giftvoucher.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 提货劵 Response VO") +@Data +@ExcelIgnoreUnannotated +public class AppGiftVoucherRespVO { + + @Schema(description = "提货劵编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "16947") + @ExcelProperty("提货劵编号") + private Long id; + + @Schema(description = "提货劵名", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") + @ExcelProperty("提货劵名") + private String name; + + @Schema(description = "提货劵状态 * * 1-未使用 * 2-已使用 * 3-已失效", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @ExcelProperty("提货劵状态 * * 1-未使用 * 2-已使用 * 3-已失效") + private Integer status; + + @Schema(description = "商品 SPU 编号", example = "9673") + @ExcelProperty("商品 SPU 编号") + private Long spuId; + + @Schema(description = "商品 SKU 编号", example = "28153") + @ExcelProperty("商品 SKU 编号") + private Long skuId; + + @Schema(description = "可购买商品数量", example = "2") + @ExcelProperty("可购买商品数量") + private Integer productCount; + + @Schema(description = "提货券流水号", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("提货券流水号") + private String no; + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2975") + @ExcelProperty("用户编号") + private Long userId; + + @Schema(description = "领取类型 * * 1 - 用户主动领取 * 2 - 后台自动发放", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @ExcelProperty("领取类型 * * 1 - 用户主动领取 * 2 - 后台自动发放") + private Integer takeType; + + @Schema(description = "生效开始时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("生效开始时间") + private LocalDateTime validStartTime; + + @Schema(description = "生效结束时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("生效结束时间") + private LocalDateTime validEndTime; + + @Schema(description = "使用订单号", example = "27627") + @ExcelProperty("使用订单号") + private Long useOrderId; + + @Schema(description = "使用时间") + @ExcelProperty("使用时间") + private LocalDateTime useTime; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/giftvoucher/vo/AppGiftVoucherTakeReqVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/giftvoucher/vo/AppGiftVoucherTakeReqVO.java new file mode 100644 index 0000000..65bc114 --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/giftvoucher/vo/AppGiftVoucherTakeReqVO.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.promotion.controller.app.giftvoucher.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +@Schema(description = "用户 App - 提货劵领取 Request VO") +@Data +public class AppGiftVoucherTakeReqVO { + + @Schema(description = "提货劵模板编号", example = "1") + @NotNull(message = "提货劵模板编号不能为空") + private Long templateId; + +} diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/giftvoucher/GiftVoucherConvert.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/giftvoucher/GiftVoucherConvert.java new file mode 100644 index 0000000..00fb280 --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/giftvoucher/GiftVoucherConvert.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.module.promotion.convert.giftvoucher; + + +import cn.iocoder.yudao.module.promotion.controller.admin.giftvoucher.vo.giftvoucher.GiftVoucherPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.app.giftvoucher.vo.AppGiftVoucherPageReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.giftvoucher.GiftVoucherDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.giftvoucher.GiftVoucherTemplateDO; +import cn.iocoder.yudao.module.promotion.enums.giftvoucher.GiftVoucherStatusEnum; +import cn.iocoder.yudao.module.promotion.enums.giftvoucher.GiftVoucherTemplateValidityTypeEnum; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.time.LocalDateTime; +import java.util.Collection; + +/** + * 提货劵 Convert + * + * @author 芋道源码 + */ +@Mapper +public interface GiftVoucherConvert { + + GiftVoucherConvert INSTANCE = Mappers.getMapper(GiftVoucherConvert.class); + + default GiftVoucherDO convert(GiftVoucherTemplateDO template, Long userId) { + GiftVoucherDO giftVoucherDO = new GiftVoucherDO() + .setTemplateId(template.getId()) + .setName(template.getName()) + .setTakeType(template.getTakeType()) + .setStatus(GiftVoucherStatusEnum.UNUSED.getStatus()) + .setProductScopeValues(template.getProductScopeValues()) + .setProductCount(template.getProductCount()) + .setUserId(userId); + if (GiftVoucherTemplateValidityTypeEnum.DATE.getType().equals(template.getValidityType())) { + giftVoucherDO.setValidStartTime(template.getValidStartTime()); + giftVoucherDO.setValidEndTime(template.getValidEndTime()); + } else if (GiftVoucherTemplateValidityTypeEnum.TERM.getType().equals(template.getValidityType())) { + giftVoucherDO.setValidStartTime(LocalDateTime.now().plusDays(template.getFixedStartTerm())); + giftVoucherDO.setValidEndTime(LocalDateTime.now().plusDays(template.getFixedEndTerm())); + } + return giftVoucherDO; + } + + GiftVoucherPageReqVO convert(AppGiftVoucherPageReqVO pageReqVO, Collection userIds); + +} diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/giftvoucher/GiftVoucherDO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/giftvoucher/GiftVoucherDO.java new file mode 100644 index 0000000..21d1a10 --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/giftvoucher/GiftVoucherDO.java @@ -0,0 +1,90 @@ +package cn.iocoder.yudao.module.promotion.dal.dataobject.giftvoucher; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.mybatis.core.type.LongListTypeHandler; +import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 提货劵 DO + * + * @author 小如之家 + */ +@TableName("promotion_gift_voucher") +@KeySequence("promotion_gift_voucher_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class GiftVoucherDO extends BaseDO { + + /** + * 提货劵编号 + */ + @TableId + private Long id; + /** + * 提货劵模板编号 + */ + private Long templateId; + /** + * 提货劵名 + */ + private String name; + /** + * 提货劵状态 + *

+ * 1-未使用 + * 2-已使用 + * 3-已失效 + */ + private Integer status; + /** + * 商品范围编号的数组 + * + * 冗余 {@link GiftVoucherTemplateDO#getProductScopeValues()} + */ + @TableField(typeHandler = LongListTypeHandler.class) + private List productScopeValues; + /** + * 可购买商品数量 + */ + private Integer productCount; + /** + * 用户编号 + */ + private Long userId; + /** + * 领取类型 + *

+ * 1 - 用户主动领取 + * 2 - 后台自动发放 + */ + private Integer takeType; + /** + * 生效开始时间 + */ + private LocalDateTime validStartTime; + /** + * 生效结束时间 + */ + private LocalDateTime validEndTime; + /** + * 使用订单号 + */ + private Long useOrderId; + /** + * 使用时间 + */ + private LocalDateTime useTime; + +} \ No newline at end of file diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/giftvoucher/GiftVoucherTemplateDO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/giftvoucher/GiftVoucherTemplateDO.java new file mode 100644 index 0000000..cb22a90 --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/giftvoucher/GiftVoucherTemplateDO.java @@ -0,0 +1,95 @@ +package cn.iocoder.yudao.module.promotion.dal.dataobject.giftvoucher; + +import cn.iocoder.yudao.framework.mybatis.core.type.LongListTypeHandler; +import lombok.*; +import java.util.*; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.*; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; + +/** + * 提货券模板 DO + * + * @author 小如之家 + */ +@TableName("promotion_gift_voucher_template") +@KeySequence("promotion_gift_voucher_template_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class GiftVoucherTemplateDO extends BaseDO { + + /** + * 模板编号,自增唯一。 + */ + @TableId + private Long id; + /** + * 提货券名 + */ + private String name; + /** + * 提货券描述 + */ + private String description; + /** + * 状态 + */ + private Integer status; + /** + * 发放数量, -1 - 则表示不限制 + */ + private Integer totalCount; + /** + * 每人限领个数, -1 - 则表示不限制 + */ + private Integer takeLimitCount; + /** + * 领取方式 + */ + private Integer takeType; + /** + * 商品范围编号的数组 + */ + @TableField(typeHandler = LongListTypeHandler.class) + private List productScopeValues; + /** + * 生效日期类型 + */ + private Integer validityType; + /** + * 固定日期-生效开始时间 + */ + private LocalDateTime validStartTime; + /** + * 固定日期-生效结束时间 + */ + private LocalDateTime validEndTime; + /** + * 领取日期-开始天数 + */ + private Integer fixedStartTerm; + /** + * 领取日期-结束天数 + */ + private Integer fixedEndTerm; + /** + * 领取提货券的数量 + */ + private Integer takeCount; + /** + * 使用提货券的次数 + */ + private Integer useCount; + /** + * 可购买商品数量 + */ + private Integer productCount; + +} \ No newline at end of file diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/giftvoucher/GiftVoucherMapper.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/giftvoucher/GiftVoucherMapper.java new file mode 100644 index 0000000..b73bd4b --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/giftvoucher/GiftVoucherMapper.java @@ -0,0 +1,93 @@ +package cn.iocoder.yudao.module.promotion.dal.mysql.giftvoucher; + +import java.time.LocalDateTime; +import java.util.*; + +import cn.hutool.core.map.MapUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.promotion.controller.admin.giftvoucher.vo.giftvoucher.GiftVoucherPageReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.giftvoucher.GiftVoucherDO; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.github.yulichang.toolkit.MPJWrappers; +import org.apache.ibatis.annotations.Mapper; +import cn.iocoder.yudao.module.promotion.controller.admin.giftvoucher.vo.*; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + +/** + * 提货劵 Mapper + * + * @author 小如之家 + */ +@Mapper +public interface GiftVoucherMapper extends BaseMapperX { + + default PageResult selectPage(GiftVoucherPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(GiftVoucherDO::getTemplateId, reqVO.getTemplateId()) + .likeIfPresent(GiftVoucherDO::getName, reqVO.getName()) + .eqIfPresent(GiftVoucherDO::getStatus, reqVO.getStatus()) + .eqIfPresent(GiftVoucherDO::getProductScopeValues, reqVO.getProductScopeValues()) + .eqIfPresent(GiftVoucherDO::getUserId, reqVO.getUserId()) + .eqIfPresent(GiftVoucherDO::getTakeType, reqVO.getTakeType()) + .betweenIfPresent(GiftVoucherDO::getValidStartTime, reqVO.getValidStartTime()) + .betweenIfPresent(GiftVoucherDO::getValidEndTime, reqVO.getValidEndTime()) + .eqIfPresent(GiftVoucherDO::getUseOrderId, reqVO.getUseOrderId()) + .betweenIfPresent(GiftVoucherDO::getUseTime, reqVO.getUseTime()) + .betweenIfPresent(GiftVoucherDO::getCreateTime, reqVO.getCreateTime()) + .eqIfPresent(GiftVoucherDO::getProductCount, reqVO.getProductCount()) + .orderByDesc(GiftVoucherDO::getId)); + } + + default List selectListByTemplateIdAndUserIds(Long templateId, Set userIds){ + return selectList(new LambdaQueryWrapperX() + .eq(GiftVoucherDO::getTemplateId, templateId) + .in(GiftVoucherDO::getUserId, userIds) + ); + } + + default GiftVoucherDO getGiftVoucherByUserId(Long userId, Long id){ + return selectOne(new LambdaQueryWrapperX() + .eq(GiftVoucherDO::getUserId, userId) + .eq(GiftVoucherDO::getId, id)); + } + + default Long selectCountByUserIdAndStatus(Long userId, Integer status){ + return selectCount(new LambdaQueryWrapperX() + .eq(GiftVoucherDO::getUserId, userId) + .eq(GiftVoucherDO::getStatus, status)); + } + + default Map selectCountByUserIdAndTemplateIdIn(Long userId, Collection templateIds) { + String templateIdAlias = "templateId"; + String countAlias = "count"; + List> list = selectMaps(MPJWrappers.lambdaJoin(GiftVoucherDO.class) + .selectAs(GiftVoucherDO::getTemplateId, templateIdAlias) + .selectCount(GiftVoucherDO::getId, countAlias) + .eq(GiftVoucherDO::getUserId, userId) + .in(GiftVoucherDO::getTemplateId, templateIds) + .groupBy(GiftVoucherDO::getTemplateId)); + return convertMap(list, map -> MapUtil.getLong(map, templateIdAlias), map -> MapUtil.getInt(map, countAlias)); + } + + default GiftVoucherDO selectByTemplateIdAndUserId(Long id, Long userId){ + return selectOne(new LambdaQueryWrapperX() + .eq(GiftVoucherDO::getId, id) + .eq(GiftVoucherDO::getUserId, userId)); + } + + default int updateByIdAndStatus(Long id, Integer status, GiftVoucherDO giftVoucherDO){ + return update(giftVoucherDO, new LambdaUpdateWrapper() + .eq(GiftVoucherDO::getId, id).eq(GiftVoucherDO::getStatus, status)); + } + + default List selectListByStatusAndValidEndTimeLe(Integer status, LocalDateTime validEndTime){ + return selectList(new LambdaQueryWrapperX() + .eq(GiftVoucherDO::getStatus, status) + .le(GiftVoucherDO::getValidEndTime, validEndTime) + ); + } +} \ No newline at end of file diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/giftvoucher/GiftVoucherTemplateMapper.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/giftvoucher/GiftVoucherTemplateMapper.java new file mode 100644 index 0000000..ea823bc --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/giftvoucher/GiftVoucherTemplateMapper.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.promotion.dal.mysql.giftvoucher; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.promotion.controller.admin.giftvoucher.vo.template.GiftVoucherTemplatePageReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.giftvoucher.GiftVoucherTemplateDO; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import org.apache.ibatis.annotations.Mapper; + +/** + * 提货券模板 Mapper + * + * @author 小如之家 + */ +@Mapper +public interface GiftVoucherTemplateMapper extends BaseMapperX { + + default PageResult selectPage(GiftVoucherTemplatePageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(GiftVoucherTemplateDO::getName, reqVO.getName()) + .eqIfPresent(GiftVoucherTemplateDO::getDescription, reqVO.getDescription()) + .eqIfPresent(GiftVoucherTemplateDO::getStatus, reqVO.getStatus()) + .eqIfPresent(GiftVoucherTemplateDO::getTotalCount, reqVO.getTotalCount()) + .eqIfPresent(GiftVoucherTemplateDO::getTakeLimitCount, reqVO.getTakeLimitCount()) + .eqIfPresent(GiftVoucherTemplateDO::getTakeType, reqVO.getTakeType()) + .eqIfPresent(GiftVoucherTemplateDO::getProductScopeValues, reqVO.getProductScopeValues()) + .eqIfPresent(GiftVoucherTemplateDO::getValidityType, reqVO.getValidityType()) + .betweenIfPresent(GiftVoucherTemplateDO::getValidStartTime, reqVO.getValidStartTime()) + .betweenIfPresent(GiftVoucherTemplateDO::getValidEndTime, reqVO.getValidEndTime()) + .eqIfPresent(GiftVoucherTemplateDO::getFixedStartTerm, reqVO.getFixedStartTerm()) + .eqIfPresent(GiftVoucherTemplateDO::getFixedEndTerm, reqVO.getFixedEndTerm()) + .betweenIfPresent(GiftVoucherTemplateDO::getCreateTime, reqVO.getCreateTime()) + .eqIfPresent(GiftVoucherTemplateDO::getTakeCount, reqVO.getTakeCount()) + .eqIfPresent(GiftVoucherTemplateDO::getUseCount, reqVO.getUseCount()) + .eqIfPresent(GiftVoucherTemplateDO::getProductCount, reqVO.getProductCount()) + .orderByDesc(GiftVoucherTemplateDO::getId)); + } + + default void updateTakeCount(Long id, int incrCount){ + update(null, new LambdaUpdateWrapper() + .eq(GiftVoucherTemplateDO::getId, id) + .setSql("take_count = take_count + " + incrCount)); + } +} \ No newline at end of file diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/job/giftvoucher/GiftVoucherExpireJob.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/job/giftvoucher/GiftVoucherExpireJob.java new file mode 100644 index 0000000..72f6e9e --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/job/giftvoucher/GiftVoucherExpireJob.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.promotion.job.giftvoucher; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; +import cn.iocoder.yudao.framework.tenant.core.job.TenantJob; +import cn.iocoder.yudao.module.promotion.service.giftvoucher.GiftVoucherService; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 提货券过期 Job + * + * @author owen + */ +@Component +public class GiftVoucherExpireJob implements JobHandler { + + @Resource + private GiftVoucherService giftVoucherService; + + @Override + @TenantJob + public String execute(String param) { + int count = giftVoucherService.expireGiftVoucher(); + return StrUtil.format("过期提货券 {} 个", count); + } + +} diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/giftvoucher/GiftVoucherService.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/giftvoucher/GiftVoucherService.java new file mode 100644 index 0000000..b8227e9 --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/giftvoucher/GiftVoucherService.java @@ -0,0 +1,97 @@ +package cn.iocoder.yudao.module.promotion.service.giftvoucher; + +import java.util.*; +import javax.validation.*; + +import cn.hutool.core.map.MapUtil; +import cn.iocoder.yudao.module.promotion.api.giftvoucher.dto.GiftVoucherUseReqDTO; +import cn.iocoder.yudao.module.promotion.controller.admin.giftvoucher.vo.*; +import cn.iocoder.yudao.module.promotion.controller.admin.giftvoucher.vo.giftvoucher.GiftVoucherPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.giftvoucher.vo.giftvoucher.GiftVoucherSaveReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.giftvoucher.GiftVoucherDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTakeTypeEnum; +import cn.iocoder.yudao.module.promotion.enums.giftvoucher.GiftVoucherTypeEnum; + +/** + * 提货劵 Service 接口 + * + * @author 小如之家 + */ +public interface GiftVoucherService { + + /** + * 创建提货劵 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createGiftVoucher(@Valid GiftVoucherSaveReqVO createReqVO); + + /** + * 更新提货劵 + * + * @param updateReqVO 更新信息 + */ + void updateGiftVoucher(@Valid GiftVoucherSaveReqVO updateReqVO); + + /** + * 删除提货劵 + * + * @param id 编号 + */ + void deleteGiftVoucher(Long id); + + /** + * 获得提货劵 + * + * @param id 编号 + * @return 提货劵 + */ + GiftVoucherDO getGiftVoucher(Long id); + + /** + * 获得提货劵分页 + * + * @param pageReqVO 分页查询 + * @return 提货劵分页 + */ + PageResult getGiftVoucherPage(GiftVoucherPageReqVO pageReqVO); + + /** + * 领取优惠券 + * + * @param templateId 提货券模板编号 + * @param userIds 用户编号列表 + * @param takeType 领取方式 + * @return key: userId, value: 优惠券编号列表 + */ + Map> takeGiftVoucher(Long templateId, Set userIds, GiftVoucherTypeEnum takeType); + + default Map> takeGiftVoucherByAdmin(Long templateId, Set userIds){ + return takeGiftVoucher(templateId, userIds, GiftVoucherTypeEnum.ADMIN); + } + + GiftVoucherDO getGiftVoucherByUserId(Long userId, Long id); + + Long getUnusedCouponCount(Long userId); + + /** + * 获取会员领取指定提货券的数量 + * + * @param templateId 提货券模板编号 + * @param userId 用户编号 + * @return 领取提货券的数量 + */ + default Integer getTakeCount(Long templateId, Long userId) { + Map map = getTakeCountMapByTemplateIds(Collections.singleton(templateId), userId); + return MapUtil.getInt(map, templateId, 0); + } + + Map getTakeCountMapByTemplateIds(Collection templateIds, Long userId); + + void useGiftVoucher(GiftVoucherUseReqDTO giftVoucherUseReqDTO); + + int expireGiftVoucher(); +} \ No newline at end of file diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/giftvoucher/GiftVoucherServiceImpl.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/giftvoucher/GiftVoucherServiceImpl.java new file mode 100644 index 0000000..1783152 --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/giftvoucher/GiftVoucherServiceImpl.java @@ -0,0 +1,245 @@ +package cn.iocoder.yudao.module.promotion.service.giftvoucher; + +import cn.hutool.core.collection.CollStreamUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; +import cn.iocoder.yudao.module.promotion.api.giftvoucher.dto.GiftVoucherUseReqDTO; +import cn.iocoder.yudao.module.promotion.controller.admin.giftvoucher.vo.giftvoucher.GiftVoucherPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.giftvoucher.vo.giftvoucher.GiftVoucherSaveReqVO; +import cn.iocoder.yudao.module.promotion.convert.giftvoucher.GiftVoucherConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.giftvoucher.GiftVoucherTemplateDO; +import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTakeTypeEnum; +import cn.iocoder.yudao.module.promotion.enums.giftvoucher.GiftVoucherStatusEnum; +import cn.iocoder.yudao.module.promotion.enums.giftvoucher.GiftVoucherTemplateValidityTypeEnum; +import cn.iocoder.yudao.module.promotion.enums.giftvoucher.GiftVoucherTypeEnum; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import javax.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.*; +import java.util.stream.Collectors; + +import cn.iocoder.yudao.module.promotion.controller.admin.giftvoucher.vo.*; +import cn.iocoder.yudao.module.promotion.dal.dataobject.giftvoucher.GiftVoucherDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; + +import cn.iocoder.yudao.module.promotion.dal.mysql.giftvoucher.GiftVoucherMapper; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap; +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; + +/** + * 提货劵 Service 实现类 + * + * @author 小如之家 + */ +@Service +@Validated +@Slf4j +public class GiftVoucherServiceImpl implements GiftVoucherService { + + @Resource + private GiftVoucherMapper giftVoucherMapper; + + @Resource + private GiftVoucherTemplateService giftVoucherTemplateService; + + @Override + public Long createGiftVoucher(GiftVoucherSaveReqVO createReqVO) { + // 插入 + GiftVoucherDO giftVoucher = BeanUtils.toBean(createReqVO, GiftVoucherDO.class); + giftVoucherMapper.insert(giftVoucher); + // 返回 + return giftVoucher.getId(); + } + + @Override + public void updateGiftVoucher(GiftVoucherSaveReqVO updateReqVO) { + // 校验存在 + validateGiftVoucherExists(updateReqVO.getId()); + // 更新 + GiftVoucherDO updateObj = BeanUtils.toBean(updateReqVO, GiftVoucherDO.class); + giftVoucherMapper.updateById(updateObj); + } + + @Override + public void deleteGiftVoucher(Long id) { + // 校验存在 + validateGiftVoucherExists(id); + // 删除 + giftVoucherMapper.deleteById(id); + } + + private void validateGiftVoucherExists(Long id) { + if (giftVoucherMapper.selectById(id) == null) { + throw exception(GIFT_VOUCHER_NOT_EXISTS); + } + } + + @Override + public GiftVoucherDO getGiftVoucher(Long id) { + return giftVoucherMapper.selectById(id); + } + + @Override + public PageResult getGiftVoucherPage(GiftVoucherPageReqVO pageReqVO) { + return giftVoucherMapper.selectPage(pageReqVO); + } + + + @Override + public Map> takeGiftVoucher(Long templateId, Set userIds, GiftVoucherTypeEnum takeType) { + GiftVoucherTemplateDO template = giftVoucherTemplateService.getGiftVoucherTemplate(templateId); + // 1. 过滤掉达到领取限制的用户 + removeTakeLimitUser(userIds, template); + // 2. 校验提货劵是否可以领取 + validateGiftVoucherTemplateCanTake(template, userIds, takeType); + + // 3. 批量保存优惠劵 + List giftVoucherList = convertList(userIds, userId -> GiftVoucherConvert.INSTANCE.convert(template, userId)); + giftVoucherMapper.insertBatch(giftVoucherList); + + // 4. 增加优惠劵模板的领取数量 + giftVoucherTemplateService.updateGiftVoucherTemplateTakeCount(templateId, userIds.size()); + + return convertMultiMap(giftVoucherList, GiftVoucherDO::getUserId, GiftVoucherDO::getId); + } + + @Override + public GiftVoucherDO getGiftVoucherByUserId(Long userId, Long id) { + return giftVoucherMapper.getGiftVoucherByUserId(userId, id); + } + + @Override + public Long getUnusedCouponCount(Long userId) { + return giftVoucherMapper.selectCountByUserIdAndStatus(userId, GiftVoucherStatusEnum.UNUSED.getStatus()); + } + + @Override + public Map getTakeCountMapByTemplateIds(Collection templateIds, Long userId) { + if (CollUtil.isEmpty(templateIds)) { + return Collections.emptyMap(); + } + return giftVoucherMapper.selectCountByUserIdAndTemplateIdIn(userId, templateIds); + } + + @Override + public void useGiftVoucher(GiftVoucherUseReqDTO giftVoucherUseReqDTO) { + // 校验状态 + GiftVoucherDO giftVoucher = giftVoucherMapper.selectByTemplateIdAndUserId(giftVoucherUseReqDTO.getId(), giftVoucherUseReqDTO.getUserId()); + if (ObjectUtil.notEqual(giftVoucher.getStatus(), GiftVoucherStatusEnum.UNUSED.getStatus())) { + throw exception(GIFT_VOUCHER_STATUS_NOT_UNUSED); + } + // 校验有效期;为避免定时器没跑,实际优惠劵已经过期 + if (!LocalDateTimeUtils.isBetween(giftVoucher.getValidStartTime(), giftVoucher.getValidEndTime())) { + throw exception(COUPON_VALID_TIME_NOT_NOW); + } + + // 更新状态 + int updateCount = giftVoucherMapper.updateByIdAndStatus(giftVoucherUseReqDTO.getId(), GiftVoucherStatusEnum.UNUSED.getStatus(), + new GiftVoucherDO().setStatus(GiftVoucherStatusEnum.USED.getStatus()) + .setUseOrderId(giftVoucherUseReqDTO.getOrderId()).setUseTime(LocalDateTime.now())); + if (updateCount == 0) { + throw exception(GIFT_VOUCHER_STATUS_NOT_UNUSED); + } + } + + @Override + public int expireGiftVoucher() { + // 1. 查询待过期的优惠券 + List list = giftVoucherMapper.selectListByStatusAndValidEndTimeLe( + GiftVoucherStatusEnum.UNUSED.getStatus(), LocalDateTime.now()); + if (CollUtil.isEmpty(list)) { + return 0; + } + + // 2. 遍历执行 + int count = 0; + for (GiftVoucherDO giftVoucher : list) { + try { + boolean success = expireGiftVoucherOne(giftVoucher); + if (success) { + count++; + } + } catch (Exception e) { + log.error("[expireCoupon][giftVoucher({}) 更新为已过期失败]", giftVoucher.getId(), e); + } + } + return count; + } + + /** + * 过期单个提货劵 + * + * @param giftVoucher 提货劵 + * @return 是否过期成功 + */ + private boolean expireGiftVoucherOne(GiftVoucherDO giftVoucher) { + // 更新记录状态 + int updateRows = giftVoucherMapper.updateByIdAndStatus(giftVoucher.getId(), GiftVoucherStatusEnum.UNUSED.getStatus(), + new GiftVoucherDO().setStatus(GiftVoucherStatusEnum.EXPIRE.getStatus())); + if (updateRows == 0) { + log.error("[expireCoupon][coupon({}) 更新为已过期失败]", giftVoucher.getId()); + return false; + } + log.info("[expireCoupon][coupon({}) 更新为已过期成功]", giftVoucher.getId()); + return true; + } + + /** + * 过滤掉达到领取限制的用户 + * + * @param userIds + * @param template + */ + private void removeTakeLimitUser(Set userIds, GiftVoucherTemplateDO template) { + if (template.getTakeLimitCount() <= 0) { + return; + } + // 查询已领过券的用户 + List alreadyTakeCoupons = giftVoucherMapper.selectListByTemplateIdAndUserIds(template.getId(), userIds); + if (CollUtil.isEmpty(alreadyTakeCoupons)) { + return; + } + // 移除达到领取限制的用户 + Map userTakeCountMap = CollStreamUtil.groupBy(alreadyTakeCoupons, GiftVoucherDO::getUserId, Collectors.summingInt(c -> 1)); + userIds.removeIf(userId -> MapUtil.getInt(userTakeCountMap, userId, 0) >= template.getTakeLimitCount()); + } + + private void validateGiftVoucherTemplateCanTake(GiftVoucherTemplateDO template, Set userIds, GiftVoucherTypeEnum takeType) { + // 如果所有用户都领取过,则抛出异常 + if (CollUtil.isEmpty(userIds)) { + throw exception(GIFT_VOUCHER_TEMPLATE_USER_ALREADY_TAKE); + } + + // 校验模板 + if (template == null) { + throw exception(GIFT_VOUCHER_TEMPLATE_NOT_EXISTS); + } + // 校验剩余数量 + if (template.getTotalCount()>=0) { + if (template.getTakeCount() + userIds.size() > template.getTotalCount()) { + throw exception(GIFT_VOUCHER_TEMPLATE_NOT_ENOUGH); + } + } + // 校验"固定日期"的有效期类型是否过期 + if (GiftVoucherTemplateValidityTypeEnum.DATE.getType().equals(template.getValidityType())) { + if (LocalDateTimeUtils.beforeNow(template.getValidEndTime())) { + throw exception(GIFT_VOUCHER_TEMPLATE_EXPIRED); + } + } + // 校验领取方式 + if (ObjectUtil.notEqual(template.getTakeType(), takeType.getType())) { + throw exception(GIFT_VOUCHER_TEMPLATE_CANNOT_TAKE); + } + } +} \ No newline at end of file diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/giftvoucher/GiftVoucherTemplateService.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/giftvoucher/GiftVoucherTemplateService.java new file mode 100644 index 0000000..357c826 --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/giftvoucher/GiftVoucherTemplateService.java @@ -0,0 +1,56 @@ +package cn.iocoder.yudao.module.promotion.service.giftvoucher; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.controller.admin.giftvoucher.vo.template.GiftVoucherTemplatePageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.giftvoucher.vo.template.GiftVoucherTemplateSaveReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.giftvoucher.GiftVoucherTemplateDO; + +import javax.validation.Valid; + +/** + * 提货券模板 Service 接口 + * + * @author 小如之家 + */ +public interface GiftVoucherTemplateService { + + /** + * 创建提货券模板 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createGiftVoucherTemplate(@Valid GiftVoucherTemplateSaveReqVO createReqVO); + + /** + * 更新提货券模板 + * + * @param updateReqVO 更新信息 + */ + void updateGiftVoucherTemplate(@Valid GiftVoucherTemplateSaveReqVO updateReqVO); + + /** + * 删除提货券模板 + * + * @param id 编号 + */ + void deleteGiftVoucherTemplate(Long id); + + /** + * 获得提货券模板 + * + * @param id 编号 + * @return 提货券模板 + */ + GiftVoucherTemplateDO getGiftVoucherTemplate(Long id); + + /** + * 获得提货券模板分页 + * + * @param pageReqVO 分页查询 + * @return 提货券模板分页 + */ + PageResult getGiftVoucherTemplatePage(GiftVoucherTemplatePageReqVO pageReqVO); + + void updateGiftVoucherTemplateTakeCount(Long id, int incrCount); +} \ No newline at end of file diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/giftvoucher/GiftVoucherTemplateServiceImpl.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/giftvoucher/GiftVoucherTemplateServiceImpl.java new file mode 100644 index 0000000..2b72c49 --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/giftvoucher/GiftVoucherTemplateServiceImpl.java @@ -0,0 +1,75 @@ +package cn.iocoder.yudao.module.promotion.service.giftvoucher; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.promotion.controller.admin.giftvoucher.vo.template.GiftVoucherTemplatePageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.giftvoucher.vo.template.GiftVoucherTemplateSaveReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.giftvoucher.GiftVoucherTemplateDO; +import cn.iocoder.yudao.module.promotion.dal.mysql.giftvoucher.GiftVoucherTemplateMapper; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.GIFT_VOUCHER_TEMPLATE_NOT_EXISTS; + +/** + * 提货券模板 Service 实现类 + * + * @author 小如之家 + */ +@Service +@Validated +public class GiftVoucherTemplateServiceImpl implements GiftVoucherTemplateService { + + @Resource + private GiftVoucherTemplateMapper giftVoucherTemplateMapper; + + @Override + public Long createGiftVoucherTemplate(GiftVoucherTemplateSaveReqVO createReqVO) { + // 插入 + GiftVoucherTemplateDO giftVoucherTemplate = BeanUtils.toBean(createReqVO, GiftVoucherTemplateDO.class); + giftVoucherTemplateMapper.insert(giftVoucherTemplate); + // 返回 + return giftVoucherTemplate.getId(); + } + + @Override + public void updateGiftVoucherTemplate(GiftVoucherTemplateSaveReqVO updateReqVO) { + // 校验存在 + validateGiftVoucherTemplateExists(updateReqVO.getId()); + // 更新 + GiftVoucherTemplateDO updateObj = BeanUtils.toBean(updateReqVO, GiftVoucherTemplateDO.class); + giftVoucherTemplateMapper.updateById(updateObj); + } + + @Override + public void deleteGiftVoucherTemplate(Long id) { + // 校验存在 + validateGiftVoucherTemplateExists(id); + // 删除 + giftVoucherTemplateMapper.deleteById(id); + } + + private void validateGiftVoucherTemplateExists(Long id) { + if (giftVoucherTemplateMapper.selectById(id) == null) { + throw exception(GIFT_VOUCHER_TEMPLATE_NOT_EXISTS); + } + } + + @Override + public GiftVoucherTemplateDO getGiftVoucherTemplate(Long id) { + return giftVoucherTemplateMapper.selectById(id); + } + + @Override + public PageResult getGiftVoucherTemplatePage(GiftVoucherTemplatePageReqVO pageReqVO) { + return giftVoucherTemplateMapper.selectPage(pageReqVO); + } + + @Override + public void updateGiftVoucherTemplateTakeCount(Long id, int incrCount) { + giftVoucherTemplateMapper.updateTakeCount(id, incrCount); + } +} \ No newline at end of file diff --git a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java index 9231b35..aa0a20b 100644 --- a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java +++ b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java @@ -104,4 +104,11 @@ public interface ErrorCodeConstants { ErrorCode BROKERAGE_WITHDRAW_MIN_PRICE = new ErrorCode(1_011_008_002, "提现金额不能低于 {} 元"); ErrorCode BROKERAGE_WITHDRAW_USER_BALANCE_NOT_ENOUGH = new ErrorCode(1_011_008_003, "您当前最多可提现 {} 元"); + + // ========== 提货券 模块 1-011-009-000 ========== + ErrorCode BUILD_ORDER_GIFT_VOUCHER_CAN_NOT_USE = new ErrorCode(1_011_009_000, "该提货劵无法使用,原因:{}」"); + ErrorCode BUILD_ORDER_GIFT_VOUCHER_SKU_NOT_EXISTS = new ErrorCode(1_011_009_001, "商品 SKU 不存在"); + ErrorCode BUILD_ORDER_GIFT_VOUCHER_STOCK_NOT_ENOUGH = new ErrorCode(1_011_009_002, "商品 SKU 库存不足"); + ErrorCode BUILD_ORDER_GIFT_VOUCHER_SPU_NOT_EXISTS = new ErrorCode(1_011_009_003, "商品 SPU 不存在"); + ErrorCode BUILD_ORDER_GIFT_VOUCHER_SPU_NOT_ENABLE = new ErrorCode(1_011_009_004, "商品 SPU【{}】不处于上架状态"); } diff --git a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderTypeEnum.java b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderTypeEnum.java index 9462456..4443cdf 100644 --- a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderTypeEnum.java +++ b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderTypeEnum.java @@ -21,6 +21,7 @@ public enum TradeOrderTypeEnum implements ArrayValuable { BARGAIN(2, "砍价订单"), COMBINATION(3, "拼团订单"), POINT(4, "积分商城"), + GIFTVOUCHER(5, "提货券订单"), ; public static final Integer[] ARRAYS = Arrays.stream(values()).map(TradeOrderTypeEnum::getType).toArray(Integer[]::new); diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java index 742c4a0..f46e5f9 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java @@ -87,6 +87,13 @@ public class AppTradeOrderController { return success(new AppTradeOrderCreateRespVO().setId(order.getId()).setPayOrderId(order.getPayOrderId())); } + @PostMapping("/create-giftvoucher") + @Operation(summary = "创建提货码订单") + public CommonResult createGiftVoucherOrder(@Valid @RequestBody AppGiftVoucherOrderSettlementReqVO createReqVO) { + TradeOrderDO order = tradeOrderUpdateService.createGiftVoucherOrder(getLoginUserId(), createReqVO); + return success(order.getId()); + } + @PostMapping("/update-paid") @Operation(summary = "更新订单为已支付") // 由 pay-module 支付服务,进行回调,可见 PayNotifyJob @PermitAll diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppGiftVoucherOrderSettlementReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppGiftVoucherOrderSettlementReqVO.java new file mode 100644 index 0000000..b53f7a6 --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppGiftVoucherOrderSettlementReqVO.java @@ -0,0 +1,83 @@ +package cn.iocoder.yudao.module.trade.controller.app.order.vo; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.framework.common.validation.Mobile; +import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum; +import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.Valid; +import javax.validation.constraints.AssertTrue; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.List; + +@Schema(description = "用户 App - 交易订单结算 Request VO") +@Data +@Valid +public class AppGiftVoucherOrderSettlementReqVO { + + @Schema(description = "商品项数组", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "商品不能为空") + private List items; + + @Schema(description = "提货劵编号", example = "1024") + private Long giftVoucherId; + + // ========== 配送相关相关字段 ========== + @Schema(description = "配送方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @InEnum(value = DeliveryTypeEnum.class, message = "配送方式不正确") + private Integer deliveryType; + + @Schema(description = "收件地址编号", example = "1") + private Long addressId; + + @Schema(description = "自提门店编号", example = "1088") + private Long pickUpStoreId; + @Schema(description = "收件人名称", example = "芋艿") // 选择门店自提时,该字段为联系人名 + private String receiverName; + @Schema(description = "收件人手机", example = "15601691300") // 选择门店自提时,该字段为联系人手机 + @Mobile(message = "收件人手机格式不正确") + private String receiverMobile; + + @Schema(description = "备注", example = "这个是我的订单哟") + private String remark; + + @AssertTrue(message = "配送方式不能为空") + @JsonIgnore + public boolean isDeliveryTypeNotNull() { + return deliveryType != null; + } + + @AssertTrue(message = "提货商品每次只能购买一种规格") + @JsonIgnore + public boolean isValidActivityItems() { + // 校验订单项是否超出 + return items.size() == 1; + } + + @Data + @Schema(description = "用户 App - 商品项") + @Valid + public static class Item { + + @Schema(description = "商品 SKU 编号", example = "2048") + @NotNull(message = "商品 SKU 编号不能为空") + private Long skuId; + + @Schema(description = "购买数量", example = "1") + @Min(value = 1, message = "购买数量最小值为 {value}") + private Integer count; + + @AssertTrue(message = "商品不正确") + @JsonIgnore + public boolean isValid() { + // 组合一:skuId + count 使用商品 SKU + return skuId != null && count != null; + } + + } + +} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java index 45462a5..cdf52d2 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java @@ -34,6 +34,7 @@ import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEn import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackRespDTO; import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties; import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageAddReqBO; +import cn.iocoder.yudao.module.trade.service.order.bo.GiftVoucherCalculateRespBO; import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; import org.mapstruct.Mapper; @@ -286,4 +287,18 @@ public interface TradeOrderConvert { }) CombinationRecordCreateReqDTO convert(TradeOrderDO order, TradeOrderItemDO item); + default List convertGiftVoucherOrderList(TradeOrderDO order, GiftVoucherCalculateRespBO calculateRespBO){ + return CollectionUtils.convertList(calculateRespBO.getItems(), item -> { + TradeOrderItemDO orderItem = convert(item); + orderItem.setUserId(order.getUserId()); + orderItem.setAfterSaleStatus(TradeOrderItemAfterSaleStatusEnum.NONE.getStatus()); + orderItem.setCommentStatus(false); + return orderItem; + }); + } + + TradeOrderItemDO convert(GiftVoucherCalculateRespBO.OrderItem item); + + TradeOrderDO convert(Long userId, GiftVoucherCalculateRespBO calculateRespBO); + } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java index bd6ed90..2069cd5 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java @@ -360,4 +360,10 @@ public class TradeOrderDO extends BaseDO { */ private Long pointActivityId; + /** + * 提货劵编号 + */ + private Long giftVoucherId; + + } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateService.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateService.java index 03a48e7..4577869 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateService.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateService.java @@ -4,6 +4,7 @@ import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDeliver import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderRemarkReqVO; import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderUpdateAddressReqVO; import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderUpdatePriceReqVO; +import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppGiftVoucherOrderSettlementReqVO; import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO; import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderSettlementReqVO; import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderSettlementRespVO; @@ -220,4 +221,5 @@ public interface TradeOrderUpdateService { */ void updateOrderGiveCouponIds(Long userId, Long orderId, List giveCouponIds); + TradeOrderDO createGiftVoucherOrder(Long userId, AppGiftVoucherOrderSettlementReqVO createReqVO); } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java index b9d7297..bab577f 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java @@ -12,6 +12,7 @@ import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.extra.spring.SpringUtil; import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; @@ -27,13 +28,18 @@ import cn.iocoder.yudao.module.product.api.comment.ProductCommentApi; import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO; import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; +import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; import cn.iocoder.yudao.module.product.enums.sku.ProductSkuPurchaseBizTypeEnum; +import cn.iocoder.yudao.module.promotion.api.giftvoucher.GiftVoucherApi; +import cn.iocoder.yudao.module.promotion.api.giftvoucher.dto.GiftVoucherRespDTO; import cn.iocoder.yudao.module.system.api.social.SocialClientApi; import cn.iocoder.yudao.module.system.api.social.dto.SocialWxaSubscribeMessageSendReqDTO; import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDeliveryReqVO; import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderRemarkReqVO; import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderUpdateAddressReqVO; import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderUpdatePriceReqVO; +import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppGiftVoucherOrderSettlementReqVO; import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO; import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderSettlementReqVO; import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderSettlementRespVO; @@ -57,6 +63,7 @@ import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService; import cn.iocoder.yudao.module.trade.service.delivery.DeliveryPickUpStoreService; import cn.iocoder.yudao.module.trade.service.message.TradeMessageService; import cn.iocoder.yudao.module.trade.service.message.bo.TradeOrderMessageWhenDeliveryOrderReqBO; +import cn.iocoder.yudao.module.trade.service.order.bo.GiftVoucherCalculateRespBO; import cn.iocoder.yudao.module.trade.service.order.handler.TradeOrderHandler; import cn.iocoder.yudao.module.trade.service.price.TradePriceService; import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; @@ -84,6 +91,7 @@ import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.min import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getTerminal; import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.BUILD_ORDER_GIFT_VOUCHER_SPU_NOT_ENABLE; import static cn.iocoder.yudao.module.trade.enums.MessageTemplateConstants.WXA_ORDER_DELIVERY; /** @@ -129,10 +137,15 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { public PayRefundApi payRefundApi; @Resource public ProductSkuApi productSkuApi; + @Resource + public ProductSpuApi productSpuApi; @Resource private TradeOrderProperties tradeOrderProperties; + @Resource + private GiftVoucherApi giftVoucherApi; + // =================== Order =================== public List findUserSuccessOrderItem(Long payUserId, List skuIdList, ProductSkuPurchaseBizTypeEnum status) { @@ -987,6 +1000,130 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { tradeOrderMapper.updateById(new TradeOrderDO().setId(orderId).setGiveCouponIds(giveCouponIds)); } + @Override + public TradeOrderDO createGiftVoucherOrder(Long userId, AppGiftVoucherOrderSettlementReqVO createReqVO) { + + // 1 构建订单 + GiftVoucherCalculateRespBO giftVoucherCalculateRespBO=giftVoucherCalculate(userId, createReqVO); + TradeOrderDO order = buildGiftVoucherOrder(userId, giftVoucherCalculateRespBO); + List orderItems = buildGiftVoucherOrderItems(order,giftVoucherCalculateRespBO); + + // 2. 订单创建前的逻辑 + tradeOrderHandlers.forEach(handler -> handler.beforeOrderCreate(order, orderItems)); + + // 3. 保存订单 + tradeOrderMapper.insert(order); + orderItems.forEach(orderItem -> orderItem.setOrderId(order.getId())); + tradeOrderItemMapper.insertBatch(orderItems); + + // 4. 订单创建后的逻辑 + tradeOrderHandlers.forEach(handler -> handler.afterOrderCreate(order, orderItems)); + // 5. 插入订单日志 + TradeOrderLogUtils.setOrderInfo(order.getId(), null, order.getStatus()); + return order; + } + + private TradeOrderDO buildGiftVoucherOrder(Long userId, GiftVoucherCalculateRespBO calculateRespBO) { + return TradeOrderConvert.INSTANCE.convert(userId,calculateRespBO); + } + + private List buildGiftVoucherOrderItems(TradeOrderDO order, GiftVoucherCalculateRespBO calculateRespBO) { + + return TradeOrderConvert.INSTANCE.convertGiftVoucherOrderList(order,calculateRespBO); + } + + private GiftVoucherCalculateRespBO giftVoucherCalculate(Long userId, AppGiftVoucherOrderSettlementReqVO createReqVO) { + //看提货券是否可用 + GiftVoucherRespDTO giftVoucher=giftVoucherApi.getGiftVoucherById(createReqVO.getGiftVoucherId()); + if (null == giftVoucher) { + throw exception(BUILD_ORDER_GIFT_VOUCHER_CAN_NOT_USE, "提货劵不存在"); + } + if (giftVoucher.getStatus()!=1){ + throw exception(BUILD_ORDER_GIFT_VOUCHER_CAN_NOT_USE, "提货劵已使用或已失效"); + } + if (LocalDateTimeUtils.beforeNow(giftVoucher.getValidEndTime())) { + throw exception(BUILD_ORDER_GIFT_VOUCHER_CAN_NOT_USE,"提货券已过期"); + } + if (LocalDateTimeUtils.afterNow(giftVoucher.getValidStartTime())) { + throw exception(BUILD_ORDER_GIFT_VOUCHER_CAN_NOT_USE,"提货券未生效"); + } + + if (!Objects.equals(createReqVO.getItems().get(0).getCount(), giftVoucher.getProductCount())){ + throw exception(BUILD_ORDER_GIFT_VOUCHER_CAN_NOT_USE,"购买商品数量与提货券可购买数量不一致"); + } + if (!Objects.equals(userId, giftVoucher.getUserId())){ + throw exception(BUILD_ORDER_GIFT_VOUCHER_CAN_NOT_USE,"当前用户与提货券用户不一致"); + } + + if (createReqVO.getItems().size()>1){ + throw exception(BUILD_ORDER_GIFT_VOUCHER_CAN_NOT_USE,"提货券只允许购买一种商品"); + } + //看商品是否可用 + ProductSkuRespDTO sku = productSkuApi.getSku(createReqVO.getItems().get(0).getSkuId()); + if (null == sku) { + throw exception(BUILD_ORDER_GIFT_VOUCHER_SKU_NOT_EXISTS); + } + if(sku.getStock()()); // 初始化 items + } + order.getItems().add(orderItem); + return order; + } + /** * 创建单个订单的评论 * diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/bo/GiftVoucherCalculateRespBO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/bo/GiftVoucherCalculateRespBO.java new file mode 100644 index 0000000..4b0351d --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/bo/GiftVoucherCalculateRespBO.java @@ -0,0 +1,156 @@ +package cn.iocoder.yudao.module.trade.service.order.bo; + +import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; +import lombok.Data; + +import java.util.List; + +/** + * 提货券构建订单 Response BO + * + * @author 芋道源码 + */ +@Data +public class GiftVoucherCalculateRespBO extends TradeOrderDO { + + + + /** + * 订单项数组 + */ + private List items; + + /** + * 订单商品 SKU + */ + @Data + public static class OrderItem { + + /** + * SPU 编号 + */ + private Long spuId; + /** + * SKU 编号 + */ + private Long skuId; + /** + * 购买数量 + */ + private Integer count; + /** + * 购物车项的编号 + */ + private Long cartId; + /** + * 是否选中 + */ + private Boolean selected; + + /** + * 商品原价(单),单位:分 + * + * 对应 ProductSkuDO 的 price 字段 + * 对应 taobao 的 order.price 字段 + */ + private Integer price; + /** + * 优惠金额(总),单位:分 + * + * 对应 taobao 的 order.discount_fee 字段 + */ + private Integer discountPrice; + /** + * 运费金额(总),单位:分 + */ + private Integer deliveryPrice; + /** + * 优惠劵减免金额,单位:分 + * + * 对应 taobao 的 trade.coupon_fee 字段 + */ + private Integer couponPrice; + /** + * 积分抵扣的金额,单位:分 + * + * 对应 taobao 的 trade.point_fee 字段 + */ + private Integer pointPrice; + /** + * 使用的积分 + */ + private Integer usePoint; + /** + * VIP 减免金额,单位:分 + */ + private Integer vipPrice; + /** + * 应付金额(总),单位:分 + * + * = {@link #price} * {@link #count} + * - {@link #couponPrice} + * - {@link #pointPrice} + * - {@link #discountPrice} + * + {@link #deliveryPrice} + * - {@link #vipPrice} + */ + private Integer payPrice; + + // ========== 商品 SPU 信息 ========== + /** + * 商品名 + */ + private String spuName; + /** + * 商品图片 + * + * 优先级:SKU.picUrl > SPU.picUrl + */ + private String picUrl; + /** + * 分类编号 + */ + private Long categoryId; + + // ========== 物流相关字段 ========= + + /** + * 配送方式数组 + * + * 对应 DeliveryTypeEnum 枚举 + */ + private List deliveryTypes; + + /** + * 物流配置模板编号 + * + * 对应 TradeDeliveryExpressTemplateDO 的 id 编号 + */ + private Long deliveryTemplateId; + + // ========== 商品 SKU 信息 ========== + /** + * 商品重量,单位:kg 千克 + */ + private Double weight; + /** + * 商品体积,单位:m^3 平米 + */ + private Double volume; + + /** + * 商品属性数组 + */ + private List properties; + + /** + * 赠送的积分 + */ + private Integer givePoint; + + } + + + +} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeDeviceOrderHandler.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeDeviceOrderHandler.java index eceb078..8e80954 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeDeviceOrderHandler.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeDeviceOrderHandler.java @@ -32,7 +32,7 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.ORDER_RECEIVE_FAIL_STATUS_NOT_OVERPAY; /** - * 优惠劵的 {@link TradeOrderHandler} 实现类 + * 贩卖机出货的 {@link TradeOrderHandler} 实现类 * * @author 芋道源码 */ @@ -182,6 +182,7 @@ public class TradeDeviceOrderHandler implements TradeOrderHandler { } }else { System.out.println("提货柜订单spu列表为空"); + log.error("订单:{},提货柜订单spu列表为空",order.getNo()); } } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeGiftVoucherOrderHandler.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeGiftVoucherOrderHandler.java new file mode 100644 index 0000000..4eef2ca --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeGiftVoucherOrderHandler.java @@ -0,0 +1,190 @@ +package cn.iocoder.yudao.module.trade.service.order.handler; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; +import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; +import cn.iocoder.yudao.module.product.enums.spu.ProductSpuTypesEnum; +import cn.iocoder.yudao.module.promotion.api.giftvoucher.GiftVoucherApi; +import cn.iocoder.yudao.module.promotion.api.giftvoucher.dto.GiftVoucherUseReqDTO; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; +import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum; +import cn.iocoder.yudao.module.trade.service.order.bo.DispenseRequestBo; +import cn.iocoder.yudao.module.trade.service.order.bo.DispenseResponseBo; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.*; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.List; +import java.util.stream.Collectors; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.ORDER_RECEIVE_FAIL_STATUS_NOT_OVERPAY; + +/** + * 提货劵的 {@link TradeOrderHandler} 实现类 + * + * @author 芋道源码 + */ +@Component +@Slf4j +public class TradeGiftVoucherOrderHandler implements TradeOrderHandler { + + @Resource + private GiftVoucherApi giftVoucherApi; + + @Resource + private ProductSpuApi productSpuApi; + + @Resource + private ProductSkuApi productSkuApi; + + @Resource + private AdminUserApi adminUserApi; + + @Resource + private TradeOrderMapper tradeOrderMapper; + + // TOKEN + @Value("${xr.cabinet.token}") + private String token; + + //API_URL + @Value("${xr.cabinet.api_url}") + private String api_url; + + @Override + public void afterOrderCreate(TradeOrderDO order, List orderItems) { + if (order.getGiftVoucherId() == null || order.getGiftVoucherId() <= 0) { + return; + } + //提货券商品的贩卖机出货 + //商品SPU ID列表 + List spuIds = orderItems.stream() + .map(TradeOrderItemDO::getSpuId) + .distinct() + .collect(Collectors.toList()); +// if(null==spuIds && spuIds.size()<=0){ +// System.out.println("商品SPU ID列表 为空"); +// return; +// } + //查询spu表 + List spuList = productSpuApi.getSpuList(spuIds); + //判断商品类型是否有不是提货柜商品的 + if (CollUtil.isNotEmpty(spuList)) { + boolean hasNonDevice = spuList.stream() + .anyMatch(spu -> !ProductSpuTypesEnum.ENABLE.getTypes().equals(spu.getTypes())); + if (hasNonDevice) { + //订单中包含非提货柜商品 + log.info("订单中包含非提货柜商品"); + }else { + //判断是不是有不同机器的订单(一个创建人是一台机器) + boolean isSingleCreator = spuList.stream() + .map(ProductSpuRespDTO::getCreator) //获取每个商品的Creator + .distinct() //去重Creator + .count() == 1; // 判断是否只有一个唯一的创建人 + if (isSingleCreator) { + // 只有一个Creator的逻辑处理 + System.out.println("订单明细中只有一个商品创建人"); + //查询商品创建人的设备IMEI + AdminUserRespDTO user = adminUserApi.getUser(Long.valueOf(spuList.get(0).getCreator())); + if (user == null|| user.getDeviceId() == null){ + return; + } + //获取商品通道 + List skuIds = orderItems.stream() + .map(TradeOrderItemDO::getSkuId) + .distinct() + .collect(Collectors.toList()); + if(CollUtil.isEmpty(skuIds)){ + return; + } + List skuList = productSkuApi.getSkuList(skuIds); + //判断是不是有不同通道类型的订单 + boolean isSingleCabinetType = skuList.stream() + .map(ProductSkuRespDTO::getCabinetType) //获取每个商品的Creator + .distinct() //去重Creator + .count() == 1; // 判断是否只有一个唯一的创建人 + if (isSingleCabinetType) { + DispenseRequestBo request = new DispenseRequestBo(); + request.setDeviceId(user.getDeviceId()); + StringBuilder message= new StringBuilder(skuList.get(0).getCabinetType() + ","); + //遍历订单明细 + for (int i = 0; i < orderItems.size(); i++) { + TradeOrderItemDO orderItem = orderItems.get(i); + ProductSkuRespDTO sku = productSkuApi.getSku(orderItem.getSkuId()); + message.append(sku.getCabinetChannel()).append("&").append(orderItem.getCount()); + if (i != orderItems.size() - 1) { + message.append(","); + } + } + request.setMessage(message.toString()); + // 设置请求头 + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + headers.set("Authorization", token); + + // 创建请求实体 + HttpEntity requestEntity = new HttpEntity<>(request, headers); + + // 创建RestTemplate + RestTemplate restTemplate = new RestTemplate(); + + try { + // 发送请求并解析响应 + ResponseEntity response = restTemplate.exchange( + api_url, + HttpMethod.POST, + requestEntity, + DispenseResponseBo.class + ); + + DispenseResponseBo body = response.getBody(); + if (body != null) { + System.out.println("响应结果: " + body); + if (body.getCode() == 0) { + System.out.println("出货成功!详情: " + body.getData()); + } else { + System.out.println("操作失败!原因: " + body.getMsg()); + log.error("订单--{}:[出货失败]:原因: {}",order.getNo(), body.getMsg()); + } + } + // 3. 更新 TradeOrderDO 状态为已完成 + TradeOrderDO tradeOrderDO = tradeOrderMapper.selectById(order.getId()); + int updateCount = tradeOrderMapper.updateByIdAndStatus(tradeOrderDO.getId(), tradeOrderDO.getStatus(), + new TradeOrderDO().setStatus(TradeOrderStatusEnum.COMPLETED.getStatus()).setReceiveTime(LocalDateTime.now())); + if (updateCount == 0) { + throw exception(ORDER_RECEIVE_FAIL_STATUS_NOT_OVERPAY); + } + } catch (Exception e) { + System.err.println("请求异常: " + e.getMessage()); + log.error("订单--{}:[出货异常]:原因: {}",order.getNo(), e.getMessage()); + } + }else { + System.out.println("订单明细中包含多个通道类型"); + log.error("订单:{},明细中包含多个通道类型",order.getNo()); + } + } else { + System.out.println("订单明细中包含多个商品创建人"); + log.error("订单:{},明细中包含多个商品创建人",order.getNo()); + } + } + }else { + System.out.println("提货柜订单spu列表为空"); + log.error("订单:{},提货柜订单spu列表为空",order.getNo()); + } + // 提货券更改为已使用 + giftVoucherApi.useGiftVoucher(new GiftVoucherUseReqDTO().setId(order.getGiftVoucherId()).setUserId(order.getUserId()) + .setOrderId(order.getId())); + } + +} diff --git a/yudao-server/src/main/resources/application-local.yaml b/yudao-server/src/main/resources/application-local.yaml index 05ee6fd..ce33a4c 100644 --- a/yudao-server/src/main/resources/application-local.yaml +++ b/yudao-server/src/main/resources/application-local.yaml @@ -80,7 +80,7 @@ spring: host: 127.0.0.1 # 地址 port: 6379 # 端口 database: 10 # 数据库索引 - # password: 123456 # 密码,建议生产环境开启 + password: 123456 # 密码,建议生产环境开启 --- #################### 定时任务相关配置 #################### diff --git a/yudao-server/src/main/resources/application.yaml b/yudao-server/src/main/resources/application.yaml index b60047e..a107521 100644 --- a/yudao-server/src/main/resources/application.yaml +++ b/yudao-server/src/main/resources/application.yaml @@ -3,8 +3,8 @@ spring: name: yudao-server profiles: - # active: prod - active: local + active: prod +# active: local main: allow-circular-references: true # 允许循环依赖,因为项目是三层架构,无法避免这个情况。