This commit is contained in:
Owen 2025-01-09 22:22:25 +08:00
parent bcf4875336
commit 66658793de
20 changed files with 919 additions and 3 deletions

View File

@ -45,4 +45,5 @@ public interface ErrorCodeConstants {
ErrorCode SUPERIOR_API_LOG_NOT_EXISTS = new ErrorCode(1_823_003_005, "订单接口记录不存在");
ErrorCode BLACK_LIST_NOT_EXISTS = new ErrorCode(1_824_003_005, "黑名单不存在");
ErrorCode SMS_TASK_NOT_EXISTS = new ErrorCode(1_824_123_005, "短信任务不存在");
}

View File

@ -0,0 +1,95 @@
package cn.iocoder.yudao.module.haoka.controller.admin.smstask;
import org.springframework.web.bind.annotation.*;
import jakarta.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 jakarta.validation.constraints.*;
import jakarta.validation.*;
import jakarta.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.*;
import cn.iocoder.yudao.module.haoka.controller.admin.smstask.vo.*;
import cn.iocoder.yudao.module.haoka.dal.dataobject.smstask.SmsTaskDO;
import cn.iocoder.yudao.module.haoka.service.smstask.SmsTaskService;
@Tag(name = "管理后台 - 短信任务")
@RestController
@RequestMapping("/haoka/sms-task")
@Validated
public class SmsTaskController {
@Resource
private SmsTaskService smsTaskService;
@PostMapping("/create")
@Operation(summary = "创建短信任务")
@PreAuthorize("@ss.hasPermission('haoka:sms-task:create')")
public CommonResult<Long> createSmsTask(@Valid @RequestBody SmsTaskSaveReqVO createReqVO) {
return success(smsTaskService.createSmsTask(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新短信任务")
@PreAuthorize("@ss.hasPermission('haoka:sms-task:update')")
public CommonResult<Boolean> updateSmsTask(@Valid @RequestBody SmsTaskSaveReqVO updateReqVO) {
smsTaskService.updateSmsTask(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除短信任务")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('haoka:sms-task:delete')")
public CommonResult<Boolean> deleteSmsTask(@RequestParam("id") Long id) {
smsTaskService.deleteSmsTask(id);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得短信任务")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('haoka:sms-task:query')")
public CommonResult<SmsTaskRespVO> getSmsTask(@RequestParam("id") Long id) {
SmsTaskDO smsTask = smsTaskService.getSmsTask(id);
return success(BeanUtils.toBean(smsTask, SmsTaskRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得短信任务分页")
@PreAuthorize("@ss.hasPermission('haoka:sms-task:query')")
public CommonResult<PageResult<SmsTaskRespVO>> getSmsTaskPage(@Valid SmsTaskPageReqVO pageReqVO) {
PageResult<SmsTaskDO> pageResult = smsTaskService.getSmsTaskPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, SmsTaskRespVO.class));
}
@GetMapping("/export-excel")
@Operation(summary = "导出短信任务 Excel")
@PreAuthorize("@ss.hasPermission('haoka:sms-task:export')")
@ApiAccessLog(operateType = EXPORT)
public void exportSmsTaskExcel(@Valid SmsTaskPageReqVO pageReqVO,
HttpServletResponse response) throws IOException {
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<SmsTaskDO> list = smsTaskService.getSmsTaskPage(pageReqVO).getList();
// 导出 Excel
ExcelUtils.write(response, "短信任务.xls", "数据", SmsTaskRespVO.class,
BeanUtils.toBean(list, SmsTaskRespVO.class));
}
}

View File

@ -0,0 +1,49 @@
package cn.iocoder.yudao.module.haoka.controller.admin.smstask.vo;
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 SmsTaskPageReqVO extends PageParam {
@Schema(description = "任务名称", example = "张三")
private String name;
@Schema(description = "订单状态", example = "1")
private Long orderStatus;
@Schema(description = "订单来源")
private String orderSourceList;
@Schema(description = "商品名称")
private String orderOnSaleProductList;
@Schema(description = "是否外呼", example = "1")
private Integer callStatus;
@Schema(description = "发送时间段")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Integer[] sendTime;
@Schema(description = "短信渠道", example = "6730")
private Long smsChannelId;
@Schema(description = "短信类型", example = "2")
private Integer smsType;
@Schema(description = "短信内容", example = "4943")
private String smsTemplateCode;
@Schema(description = "测试手机")
private String testPhone;
}

View File

@ -0,0 +1,76 @@
package cn.iocoder.yudao.module.haoka.controller.admin.smstask.vo;
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.*;
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
@Schema(description = "管理后台 - 短信任务 Response VO")
@Data
@ExcelIgnoreUnannotated
public class SmsTaskRespVO {
@Schema(description = "ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "11858")
@ExcelProperty("ID")
private Long id;
@Schema(description = "任务名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三")
@ExcelProperty("任务名称")
private String name;
@Schema(description = "订单状态", example = "1")
@ExcelProperty(value = "订单状态", converter = DictConvert.class)
@DictFormat("haoka_order_status") // TODO 代码优化建议设置到对应的 DictTypeConstants 枚举类中
private Long orderStatus;
@Schema(description = "订单来源")
@ExcelProperty("订单来源")
private String orderSourceList;
@Schema(description = "商品名称")
@ExcelProperty("商品名称")
private String orderOnSaleProductList;
@Schema(description = "是否外呼", example = "1")
@ExcelProperty("是否外呼")
private Integer callStatus;
@Schema(description = "发送时间段", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("发送时间段")
private Integer sendTime;
@Schema(description = "短信渠道", requiredMode = Schema.RequiredMode.REQUIRED, example = "6730")
@ExcelProperty("短信渠道")
private Long smsChannelId;
@Schema(description = "短信类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
@ExcelProperty("短信类型")
private Integer smsType;
@Schema(description = "短信内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "4943")
@ExcelProperty("短信内容")
private String smsTemplateCode;
@Schema(description = "测试手机")
@ExcelProperty("测试手机")
private String testPhone;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建时间")
private LocalDateTime createTime;
@Schema(description = "是否启用", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty(value = "是否启用", converter = DictConvert.class)
@DictFormat("infra_boolean_string") // TODO 代码优化建议设置到对应的 DictTypeConstants 枚举类中
private Boolean active;
@Schema(description = "退款状态", example = "1")
@ExcelProperty(value = "退款状态", converter = DictConvert.class)
@DictFormat("haoka_order_refund_status") // TODO 代码优化建议设置到对应的 DictTypeConstants 枚举类中
private String refundStatus;
}

View File

@ -0,0 +1,57 @@
package cn.iocoder.yudao.module.haoka.controller.admin.smstask.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import jakarta.validation.constraints.*;
@Schema(description = "管理后台 - 短信任务新增/修改 Request VO")
@Data
public class SmsTaskSaveReqVO {
@Schema(description = "ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "11858")
private Long id;
@Schema(description = "任务名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三")
@NotEmpty(message = "任务名称不能为空")
private String name;
@Schema(description = "订单状态", example = "1")
private Long orderStatus;
@Schema(description = "订单来源")
private String orderSourceList;
@Schema(description = "商品名称")
private String orderOnSaleProductList;
@Schema(description = "是否外呼", example = "1")
private Integer callStatus;
@Schema(description = "发送时间段", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "发送时间段不能为空")
private Integer sendTime;
@Schema(description = "短信渠道", requiredMode = Schema.RequiredMode.REQUIRED, example = "6730")
@NotNull(message = "短信渠道不能为空")
private Long smsChannelId;
@Schema(description = "短信类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
@NotNull(message = "短信类型不能为空")
private Integer smsType;
@Schema(description = "短信内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "4943")
@NotNull(message = "短信内容不能为空")
private String smsTemplateCode;
@Schema(description = "测试手机")
private String testPhone;
@Schema(description = "是否启用", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "是否启用不能为空")
private Boolean active;
@Schema(description = "退款状态", example = "1")
private String refundStatus;
}

View File

@ -0,0 +1,89 @@
package cn.iocoder.yudao.module.haoka.dal.dataobject.smstask;
import lombok.*;
import java.util.*;
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("haoka_sms_task")
@KeySequence("haoka_sms_task_seq") // 用于 OraclePostgreSQLKingbaseDB2H2 数据库的主键自增如果是 MySQL 等数据库可不写
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class SmsTaskDO extends BaseDO {
/**
* ID
*/
@TableId
private Long id;
/**
* 任务名称
*/
private String name;
/**
* 订单状态
*
* 枚举 {@link TODO haoka_order_status 对应的类}
*/
private Long orderStatus;
/**
* 订单来源
*/
private String orderSourceList;
/**
* 商品名称
*/
private String orderOnSaleProductList;
/**
* 是否外呼
*/
private Integer callStatus;
/**
* 发送时间段
*/
private Integer sendTime;
/**
* 短信渠道
*/
private Long smsChannelId;
/**
* 短信类型
*/
private Integer smsType;
/**
* 短信内容
*/
private String smsTemplateCode;
/**
* 测试手机
*/
private String testPhone;
/**
* 部门ID
*/
private Long deptId;
/**
* 是否启用
*
* 枚举 {@link TODO infra_boolean_string 对应的类}
*/
private Boolean active;
/**
* 退款状态
*
* 枚举 {@link TODO haoka_order_refund_status 对应的类}
*/
private String refundStatus;
}

View File

@ -0,0 +1,35 @@
package cn.iocoder.yudao.module.haoka.dal.mysql.smstask;
import java.util.*;
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.haoka.dal.dataobject.smstask.SmsTaskDO;
import org.apache.ibatis.annotations.Mapper;
import cn.iocoder.yudao.module.haoka.controller.admin.smstask.vo.*;
/**
* 短信任务 Mapper
*
* @author 超级管理员
*/
@Mapper
public interface SmsTaskMapper extends BaseMapperX<SmsTaskDO> {
default PageResult<SmsTaskDO> selectPage(SmsTaskPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<SmsTaskDO>()
.likeIfPresent(SmsTaskDO::getName, reqVO.getName())
.eqIfPresent(SmsTaskDO::getOrderStatus, reqVO.getOrderStatus())
.eqIfPresent(SmsTaskDO::getOrderSourceList, reqVO.getOrderSourceList())
.eqIfPresent(SmsTaskDO::getOrderOnSaleProductList, reqVO.getOrderOnSaleProductList())
.eqIfPresent(SmsTaskDO::getCallStatus, reqVO.getCallStatus())
.betweenIfPresent(SmsTaskDO::getSendTime, reqVO.getSendTime())
.eqIfPresent(SmsTaskDO::getSmsChannelId, reqVO.getSmsChannelId())
.eqIfPresent(SmsTaskDO::getSmsType, reqVO.getSmsType())
.eqIfPresent(SmsTaskDO::getSmsTemplateCode, reqVO.getSmsTemplateCode())
.eqIfPresent(SmsTaskDO::getTestPhone, reqVO.getTestPhone())
.orderByDesc(SmsTaskDO::getId));
}
}

View File

@ -8,6 +8,7 @@ import cn.iocoder.yudao.module.haoka.service.api.ApiDealStrategyService;
import cn.iocoder.yudao.module.haoka.service.api.models.OrderApiCreateParam;
import cn.iocoder.yudao.module.haoka.service.api.models.OrderApiCreateResp;
import cn.iocoder.yudao.module.haoka.service.onsaleproduct.OnSaleProductService;
import cn.iocoder.yudao.module.haoka.service.smstask.SmsTaskService;
import cn.iocoder.yudao.module.haoka.utils.SnowflakeId;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
@ -42,6 +43,9 @@ public class OrdersServiceImpl extends ServiceImpl<OrdersMapper, OrdersDO> imple
@Qualifier(ApiFrom.ApiDealStrategyImpl)
private ApiDealStrategyService apiDealStrategyService;
@Resource
private SmsTaskService smsTaskService;
// 19547688 -> 电信 19547688 湖南电信号码+号码ID
@Override
public Long createOrders(OrdersSaveReqVO createReqVO) {
@ -83,6 +87,17 @@ public class OrdersServiceImpl extends ServiceImpl<OrdersMapper, OrdersDO> imple
updateObj.setSuperiorApiId(oldOrderDo.getSuperiorApiId());
ordersMapper.updateById(updateObj);
smsTaskService.sendSMS(
updateObj.getStatus(),
updateObj.getId(),
updateObj.getSource(),
updateObj.getOnSaleProductId(),
updateObj.getRefundStatus(),
updateObj.getCallStatus(),
updateObj.getAddressMobile(),
updateObj
);
}
@Override

View File

@ -0,0 +1,68 @@
package cn.iocoder.yudao.module.haoka.service.smstask;
import java.util.*;
import cn.iocoder.yudao.module.haoka.dal.dataobject.orders.OrdersDO;
import jakarta.validation.*;
import cn.iocoder.yudao.module.haoka.controller.admin.smstask.vo.*;
import cn.iocoder.yudao.module.haoka.dal.dataobject.smstask.SmsTaskDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
/**
* 短信任务 Service 接口
*
* @author 超级管理员
*/
public interface SmsTaskService {
/**
* 创建短信任务
*
* @param createReqVO 创建信息
* @return 编号
*/
Long createSmsTask(@Valid SmsTaskSaveReqVO createReqVO);
/**
* 更新短信任务
*
* @param updateReqVO 更新信息
*/
void updateSmsTask(@Valid SmsTaskSaveReqVO updateReqVO);
/**
* 删除短信任务
*
* @param id 编号
*/
void deleteSmsTask(Long id);
/**
* 获得短信任务
*
* @param id 编号
* @return 短信任务
*/
SmsTaskDO getSmsTask(Long id);
/**
* 获得短信任务分页
*
* @param pageReqVO 分页查询
* @return 短信任务分页
*/
PageResult<SmsTaskDO> getSmsTaskPage(SmsTaskPageReqVO pageReqVO);
/**
* @param orderStatus
* @param orderId
* @param source
* @param onSaleProductId
* @param refundStatus
* @param callStatus
* @param sentToPhone
*/
public void sendSMS(Long orderStatus, Long orderId, String source, Long onSaleProductId,
String refundStatus, Long callStatus, String sentToPhone, OrdersDO ordersDO);
}

View File

@ -0,0 +1,169 @@
package cn.iocoder.yudao.module.haoka.service.smstask;
import cn.hutool.core.collection.CollectionUtil;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.haoka.api.liantong.util.StringUtils;
import cn.iocoder.yudao.module.haoka.dal.dataobject.orders.OrdersDO;
import cn.iocoder.yudao.module.haoka.dal.dataobject.superiorapi.SuperiorApiDO;
import cn.iocoder.yudao.module.haoka.service.superiorapi.SuperiorApiService;
import cn.iocoder.yudao.module.haoka.utils.SnowflakeId;
import cn.iocoder.yudao.module.system.api.sms.SmsSendApi;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import cn.iocoder.yudao.module.haoka.controller.admin.smstask.vo.*;
import cn.iocoder.yudao.module.haoka.dal.dataobject.smstask.SmsTaskDO;
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.haoka.dal.mysql.smstask.SmsTaskMapper;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.haoka.enums.ErrorCodeConstants.*;
/**
* 短信任务 Service 实现类
*
* @author 超级管理员
*/
@Slf4j
@Service
@Validated
public class SmsTaskServiceImpl implements SmsTaskService {
@Resource
private SmsTaskMapper smsTaskMapper;
@Override
public Long createSmsTask(SmsTaskSaveReqVO createReqVO) {
// 插入
SmsTaskDO smsTask = BeanUtils.toBean(createReqVO, SmsTaskDO.class);
smsTask.setId(SnowflakeId.generate());
smsTaskMapper.insert(smsTask);
// 返回
return smsTask.getId();
}
@Override
public void updateSmsTask(SmsTaskSaveReqVO updateReqVO) {
// 校验存在
validateSmsTaskExists(updateReqVO.getId());
// 更新
SmsTaskDO updateObj = BeanUtils.toBean(updateReqVO, SmsTaskDO.class);
smsTaskMapper.updateById(updateObj);
}
@Override
public void deleteSmsTask(Long id) {
// 校验存在
validateSmsTaskExists(id);
// 删除
smsTaskMapper.deleteById(id);
}
private void validateSmsTaskExists(Long id) {
if (smsTaskMapper.selectById(id) == null) {
throw exception(SMS_TASK_NOT_EXISTS);
}
}
@Override
public SmsTaskDO getSmsTask(Long id) {
return smsTaskMapper.selectById(id);
}
@Override
public PageResult<SmsTaskDO> getSmsTaskPage(SmsTaskPageReqVO pageReqVO) {
return smsTaskMapper.selectPage(pageReqVO);
}
@Resource
private SmsSendApi smsSendApi;
/**
* @param orderStatus
* @param orderId
* @param source
* @param onSaleProductId
* @param refundStatus
* @param callStatus
* @param sentToPhone
*/
public void sendSMS(Long orderStatus, Long orderId, String source, Long onSaleProductId,
String refundStatus, Long callStatus, String sentToPhone, OrdersDO ordersDO) {
try {
List<SmsTaskDO> smsTaskDOList = smsTaskMapper
.selectList(new LambdaQueryWrapperX<SmsTaskDO>()
.eq(SmsTaskDO::getActive, true));
if (CollectionUtil.isEmpty(smsTaskDOList)) {
return;
}
for (SmsTaskDO smsTaskDO : smsTaskDOList) {
if (smsTaskDO.getOrderStatus() != null &&
!smsTaskDO.getOrderStatus().equals(orderStatus)) {
continue;
}
if (smsTaskDO.getOrderSourceList() != null &&
!smsTaskDO.getOrderSourceList().contains(source)) {
continue;
}
if (smsTaskDO.getOrderOnSaleProductList() != null &&
!smsTaskDO.getOrderOnSaleProductList().contains(onSaleProductId.toString())) {
continue;
}
if (smsTaskDO.getRefundStatus() != null &&
!smsTaskDO.getRefundStatus().contains(refundStatus)) {
continue;
}
if (smsTaskDO.getCallStatus() != null &&
!smsTaskDO.getCallStatus().equals(callStatus.intValue())) {
continue;
}
// logisticsInformation
Map<String, Object> param = new HashMap<>();
param.put("phone", ordersDO.getPlanMobile());
param.put("logisticsInfo", ordersDO.getTrackingCompany() + ordersDO.getTrackingNumber());
param.put("imgUrl", getImageUrl(ordersDO));
smsSendApi.sendSingleSmsWithChannel(
sentToPhone,
smsTaskDO.getName(),
orderId,
smsTaskDO.getSmsTemplateCode(),
param,
smsTaskDO.getSmsChannelId()
);
}
} catch (Exception e) {
log.error(e.getMessage());
}
}
private String getImageUrl(OrdersDO ordersDO) {
String orderCreateResponse = ordersDO.getOrderCreateResponse();
if (StringUtils.isEmpty(orderCreateResponse)) {
return "";
}
JSONObject jsonObject = JSON.parseObject(orderCreateResponse);
if (jsonObject == null) {
return "";
}
if (jsonObject.containsKey("shortUrl")) {
return jsonObject.getString("shortUrl");
}
return "";
}
}

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.iocoder.yudao.module.haoka.dal.mysql.smstask.SmsTaskMapper">
<!--
一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
文档可见https://www.iocoder.cn/MyBatis/x-plugins/
-->
</mapper>

View File

@ -0,0 +1,166 @@
package cn.iocoder.yudao.module.haoka.service.smstask;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.mock.mockito.MockBean;
import jakarta.annotation.Resource;
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
import cn.iocoder.yudao.module.haoka.controller.admin.smstask.vo.*;
import cn.iocoder.yudao.module.haoka.dal.dataobject.smstask.SmsTaskDO;
import cn.iocoder.yudao.module.haoka.dal.mysql.smstask.SmsTaskMapper;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Import;
import java.util.*;
import java.time.LocalDateTime;
import static cn.hutool.core.util.RandomUtil.*;
import static cn.iocoder.yudao.module.haoka.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*;
import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
/**
* {@link SmsTaskServiceImpl} 的单元测试类
*
* @author 超级管理员
*/
@Import(SmsTaskServiceImpl.class)
public class SmsTaskServiceImplTest extends BaseDbUnitTest {
@Resource
private SmsTaskServiceImpl smsTaskService;
@Resource
private SmsTaskMapper smsTaskMapper;
@Test
public void testCreateSmsTask_success() {
// 准备参数
SmsTaskSaveReqVO createReqVO = randomPojo(SmsTaskSaveReqVO.class).setId(null);
// 调用
Long smsTaskId = smsTaskService.createSmsTask(createReqVO);
// 断言
assertNotNull(smsTaskId);
// 校验记录的属性是否正确
SmsTaskDO smsTask = smsTaskMapper.selectById(smsTaskId);
assertPojoEquals(createReqVO, smsTask, "id");
}
@Test
public void testUpdateSmsTask_success() {
// mock 数据
SmsTaskDO dbSmsTask = randomPojo(SmsTaskDO.class);
smsTaskMapper.insert(dbSmsTask);// @Sql: 先插入出一条存在的数据
// 准备参数
SmsTaskSaveReqVO updateReqVO = randomPojo(SmsTaskSaveReqVO.class, o -> {
o.setId(dbSmsTask.getId()); // 设置更新的 ID
});
// 调用
smsTaskService.updateSmsTask(updateReqVO);
// 校验是否更新正确
SmsTaskDO smsTask = smsTaskMapper.selectById(updateReqVO.getId()); // 获取最新的
assertPojoEquals(updateReqVO, smsTask);
}
@Test
public void testUpdateSmsTask_notExists() {
// 准备参数
SmsTaskSaveReqVO updateReqVO = randomPojo(SmsTaskSaveReqVO.class);
// 调用, 并断言异常
assertServiceException(() -> smsTaskService.updateSmsTask(updateReqVO), SMS_TASK_NOT_EXISTS);
}
@Test
public void testDeleteSmsTask_success() {
// mock 数据
SmsTaskDO dbSmsTask = randomPojo(SmsTaskDO.class);
smsTaskMapper.insert(dbSmsTask);// @Sql: 先插入出一条存在的数据
// 准备参数
Long id = dbSmsTask.getId();
// 调用
smsTaskService.deleteSmsTask(id);
// 校验数据不存在了
assertNull(smsTaskMapper.selectById(id));
}
@Test
public void testDeleteSmsTask_notExists() {
// 准备参数
Long id = randomLongId();
// 调用, 并断言异常
assertServiceException(() -> smsTaskService.deleteSmsTask(id), SMS_TASK_NOT_EXISTS);
}
@Test
@Disabled // TODO 请修改 null 为需要的值然后删除 @Disabled 注解
public void testGetSmsTaskPage() {
// mock 数据
SmsTaskDO dbSmsTask = randomPojo(SmsTaskDO.class, o -> { // 等会查询到
o.setName(null);
o.setOrderStatus(null);
o.setOrderSourceList(null);
o.setOrderOnSaleProductList(null);
o.setCallStatus(null);
o.setSendTime(null);
o.setSmsChannelId(null);
o.setSmsType(null);
o.setSmsTemplateId(null);
o.setTestPhone(null);
});
smsTaskMapper.insert(dbSmsTask);
// 测试 name 不匹配
smsTaskMapper.insert(cloneIgnoreId(dbSmsTask, o -> o.setName(null)));
// 测试 orderStatus 不匹配
smsTaskMapper.insert(cloneIgnoreId(dbSmsTask, o -> o.setOrderStatus(null)));
// 测试 orderSourceList 不匹配
smsTaskMapper.insert(cloneIgnoreId(dbSmsTask, o -> o.setOrderSourceList(null)));
// 测试 orderOnSaleProductList 不匹配
smsTaskMapper.insert(cloneIgnoreId(dbSmsTask, o -> o.setOrderOnSaleProductList(null)));
// 测试 callStatus 不匹配
smsTaskMapper.insert(cloneIgnoreId(dbSmsTask, o -> o.setCallStatus(null)));
// 测试 sendTime 不匹配
smsTaskMapper.insert(cloneIgnoreId(dbSmsTask, o -> o.setSendTime(null)));
// 测试 smsChannelId 不匹配
smsTaskMapper.insert(cloneIgnoreId(dbSmsTask, o -> o.setSmsChannelId(null)));
// 测试 smsType 不匹配
smsTaskMapper.insert(cloneIgnoreId(dbSmsTask, o -> o.setSmsType(null)));
// 测试 smsTemplateId 不匹配
smsTaskMapper.insert(cloneIgnoreId(dbSmsTask, o -> o.setSmsTemplateId(null)));
// 测试 testPhone 不匹配
smsTaskMapper.insert(cloneIgnoreId(dbSmsTask, o -> o.setTestPhone(null)));
// 准备参数
SmsTaskPageReqVO reqVO = new SmsTaskPageReqVO();
reqVO.setName(null);
reqVO.setOrderStatus(null);
reqVO.setOrderSourceList(null);
reqVO.setOrderOnSaleProductList(null);
reqVO.setCallStatus(null);
reqVO.setSendTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
reqVO.setSmsChannelId(null);
reqVO.setSmsType(null);
reqVO.setSmsTemplateId(null);
reqVO.setTestPhone(null);
// 调用
PageResult<SmsTaskDO> pageResult = smsTaskService.getSmsTaskPage(reqVO);
// 断言
assertEquals(1, pageResult.getTotal());
assertEquals(1, pageResult.getList().size());
assertPojoEquals(dbSmsTask, pageResult.getList().get(0));
}
}

View File

@ -4,6 +4,8 @@ import cn.iocoder.yudao.module.system.api.sms.dto.send.SmsSendSingleToUserReqDTO
import jakarta.validation.Valid;
import java.util.Map;
/**
* 短信发送 API 接口
*
@ -31,4 +33,6 @@ public interface SmsSendApi {
*/
Long sendSingleSmsToMember(@Valid SmsSendSingleToUserReqDTO reqDTO);
Long sendSingleSmsWithChannel(String mobile, String taskName, Long orderId,
String templateCode, Map<String, Object> templateParams, Long channelId);
}

View File

@ -7,6 +7,8 @@ import org.springframework.validation.annotation.Validated;
import jakarta.annotation.Resource;
import java.util.Map;
/**
* 短信发送 API 接口
*
@ -31,4 +33,9 @@ public class SmsSendApiImpl implements SmsSendApi {
reqDTO.getTemplateCode(), reqDTO.getTemplateParams());
}
public Long sendSingleSmsWithChannel(String mobile, String taskName, Long orderId,
String templateCode, Map<String, Object> templateParams, Long channelId) {
return smsSendService.sendSingleSmsWithChannel(mobile, taskName, orderId,
templateCode, templateParams, channelId);
}
}

View File

@ -40,7 +40,7 @@ public interface SmsSendService {
Long sendSingleSmsToMember(String mobile, Long userId,
String templateCode, Map<String, Object> templateParams);
Long sendSingleSmsWithChannel(String mobile, Long userId, Integer userType, String taskName, Long orderId,
Long sendSingleSmsWithChannel(String mobile, String taskName, Long orderId,
String templateCode, Map<String, Object> templateParams, Long channelId);
/**

View File

@ -78,7 +78,7 @@ public class SmsSendServiceImpl implements SmsSendService {
}
@Override
public Long sendSingleSmsWithChannel(String mobile, Long userId, Integer userType,String taskName,Long orderId,
public Long sendSingleSmsWithChannel(String mobile, String taskName,Long orderId,
String templateCode, Map<String, Object> templateParams, Long channelId) {
// 校验短信模板是否合法
SmsTemplateDO template = validateSmsTemplate(templateCode);
@ -94,7 +94,7 @@ public class SmsSendServiceImpl implements SmsSendService {
Boolean isSend = CommonStatusEnum.ENABLE.getStatus().equals(template.getStatus())
&& CommonStatusEnum.ENABLE.getStatus().equals(smsChannel.getStatus());
String content = smsTemplateService.formatSmsTemplateContent(template.getContent(), templateParams);
Long sendLogId = smsLogService.createSmsLog(mobile, userId, userType, isSend, template, content, templateParams,taskName,orderId);
Long sendLogId = smsLogService.createSmsLog(mobile, 1L, 1, isSend, template, content, templateParams,taskName,orderId);
// 发送 MQ 消息异步执行发送短信
if (isSend) {

View File

@ -0,0 +1,55 @@
-- 菜单 SQL
INSERT INTO system_menu(
name, permission, type, sort, parent_id,
path, icon, component, status, component_name
)
VALUES (
'短信任务管理', '', 2, 0, 2912,
'sms-task', '', 'haoka/smstask/index', 0, 'SmsTask'
);
-- 按钮父菜单ID
-- 暂时只支持 MySQL。如果你是 Oracle、PostgreSQL、SQLServer 的话,需要手动修改 @parentId 的部分的代码
SELECT @parentId := LAST_INSERT_ID();
-- 按钮 SQL
INSERT INTO system_menu(
name, permission, type, sort, parent_id,
path, icon, component, status
)
VALUES (
'短信任务查询', 'haoka:sms-task:query', 3, 1, @parentId,
'', '', '', 0
);
INSERT INTO system_menu(
name, permission, type, sort, parent_id,
path, icon, component, status
)
VALUES (
'短信任务创建', 'haoka:sms-task:create', 3, 2, @parentId,
'', '', '', 0
);
INSERT INTO system_menu(
name, permission, type, sort, parent_id,
path, icon, component, status
)
VALUES (
'短信任务更新', 'haoka:sms-task:update', 3, 3, @parentId,
'', '', '', 0
);
INSERT INTO system_menu(
name, permission, type, sort, parent_id,
path, icon, component, status
)
VALUES (
'短信任务删除', 'haoka:sms-task:delete', 3, 4, @parentId,
'', '', '', 0
);
INSERT INTO system_menu(
name, permission, type, sort, parent_id,
path, icon, component, status
)
VALUES (
'短信任务导出', 'haoka:sms-task:export', 3, 5, @parentId,
'', '', '', 0
);

View File

@ -0,0 +1,9 @@
alter table haoka_sms_task
ADD COLUMN `active`
bit(1) NOT NULL DEFAULT b'1' COMMENT '是否启用';

View File

@ -0,0 +1,7 @@
alter table haoka_sms_task
ADD COLUMN `refund_status`
varchar(2048) COMMENT '退款状态';

View File

@ -0,0 +1,2 @@
ALTER TABLE `haoka_sms_task`
CHANGE COLUMN `sms_template_id` `sms_template_code` varchar(2048) NOT NULL COMMENT '短信内容' AFTER `sms_type`;