## 报单赠送添加校验,订单同步至报单赠送定时任务

This commit is contained in:
zhangheng 2025-10-17 13:17:32 +08:00
parent e33b1e799c
commit 0a5edf9a78
12 changed files with 261 additions and 26 deletions

View File

@ -147,4 +147,6 @@ public interface ISaOrderServiceApi {
*/
List<SingleItemStatDTO> singleItemStat(SingleItemStatParamDTO singleItemStatParamDTO);
R<?> autoPushDeclaration();
}

View File

@ -1,5 +1,6 @@
package com.hzs.activity.base.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.hzs.activity.base.param.ActivityParam;
import com.hzs.activity.base.param.QueryActivityParam;
import com.hzs.activity.base.vo.BaseConfigVo;

View File

@ -21,4 +21,6 @@ public interface AcDeclarationGiftRecordMapper extends BaseMapper<AcDeclarationG
List<AcDeclarationListVO> queryList(AcDeclarationListParam param);
List<AcDeclarationListVO> selectDeclarationList(AcDeclarationListParam param);
AcDeclarationGiftRecord selectLastRecord();
}

View File

@ -20,4 +20,6 @@ public interface IAcDeclarationGiftRecordService extends IService<AcDeclarationG
List<AcDeclarationListVO> selectDeclarationList(AcDeclarationListParam param);
AcDeclarationGiftRecord selectLastRecord();
}

View File

@ -1,6 +1,7 @@
package com.hzs.activity.declaration.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.alibaba.nacos.client.naming.utils.CollectionUtils;
import com.alibaba.nacos.shaded.org.checkerframework.checker.units.qual.A;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.hzs.activity.add.param.AcAddUpgradeConfigParam;
@ -39,10 +40,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
@ -69,6 +67,10 @@ public class AcDeclarationGiftConfigServiceImpl extends ServiceImpl<AcDeclaratio
@Autowired
private IBdProductService iBdProductService;
@Autowired
private IAcBaseConfigService iAcBaseConfigService;
@Autowired
private IAcDeclarationGiftConfigService iAcDeclarationGiftConfigService;
@Override
public AjaxResult getDetail(Integer pkId) {
@ -98,6 +100,10 @@ public class AcDeclarationGiftConfigServiceImpl extends ServiceImpl<AcDeclaratio
log.error("登录用户信息为空");
return "登录用户信息为空";
}
String validated = validateDuplicateConfig(acDeclarationParam.getAcDeclarationConfigParams());
if (validated != null) {
return validated;
}
ActivityParam activityParam = acDeclarationParam.getActivityParam();
activityParam.setPkCountry(loginUser.getDataCountry());
activityParam.setPkCreator(loginUser.getUserId());
@ -112,6 +118,55 @@ public class AcDeclarationGiftConfigServiceImpl extends ServiceImpl<AcDeclaratio
return null;
}
private String validateDuplicateConfig(List<AcDeclarationConfigParam> acDeclarationConfigParams) {
// 获取当前时间还有效的报单赠送活动
List<AcBaseConfig> validBaseConfigs = iAcBaseConfigService.list(
new LambdaQueryWrapper<AcBaseConfig>()
.le(AcBaseConfig::getActStartDate, new Date())
.ge(AcBaseConfig::getActEndDate, new Date())
.eq(AcBaseConfig::getActType, EActType.DECLARATION_GIFT.getValue())
.eq(AcBaseConfig::getDelFlag, 0)
);
if (CollectionUtils.isEmpty(validBaseConfigs)) {
log.info("当前没有有效的报单赠送活动,可以直接添加新配置");
// 可以直接执行新增
return null;
}
// 获取报单赠送详情配置
List<Long> baseIds = validBaseConfigs.stream()
.map(AcBaseConfig::getPkId)
.collect(Collectors.toList());
List<AcDeclarationGiftConfig> existingConfigs = iAcDeclarationGiftConfigService.list(
new LambdaQueryWrapper<AcDeclarationGiftConfig>()
.in(AcDeclarationGiftConfig::getPkBaseId, baseIds)
.eq(AcDeclarationGiftConfig::getDelFlag, 0)
);
// 获取报单赠送报单等级和指定等级组合
Set<String> existingComboSet = existingConfigs.stream()
.map(cfg -> cfg.getRegisterAuthority() + "_" + cfg.getSpecifyLevel())
.collect(Collectors.toSet());
// 当前配置活动数据报单等级和指定等级组合
Set<String> newComboSet = acDeclarationConfigParams.stream()
.filter(Objects::nonNull)
.map(cfg -> cfg.getRegisterAuthority() + "_" + cfg.getSpecifyLevel())
.collect(Collectors.toSet());
// 判断是否有重复值,有重复值不允许添加
Set<String> duplicates = newComboSet.stream()
.filter(existingComboSet::contains)
.collect(Collectors.toSet());
if (!duplicates.isEmpty()) {
return "新增活动配置中存在重复的报单等级+指定等级组合: " + duplicates;
}
return null;
}
@Override
public String updateConfig(AcDeclarationParam acDeclarationParam) {
LoginUser loginUser = acDeclarationParam.getLoginUser();
@ -119,6 +174,10 @@ public class AcDeclarationGiftConfigServiceImpl extends ServiceImpl<AcDeclaratio
log.error("登录用户信息为空");
return "登录用户信息为空";
}
String validated = validateDuplicateConfig(acDeclarationParam.getAcDeclarationConfigParams());
if (validated != null) {
return validated;
}
ActivityParam activityParam = acDeclarationParam.getActivityParam();
activityParam.setPkCountry(loginUser.getDataCountry());
activityParam.setPkCreator(loginUser.getUserId());

View File

@ -88,4 +88,9 @@ public class AcDeclarationGiftRecordServiceImpl extends ServiceImpl<AcDeclaratio
return voList;
}
@Override
public AcDeclarationGiftRecord selectLastRecord() {
return baseMapper.selectLastRecord();
}
}

View File

@ -1,9 +1,11 @@
package com.hzs.activity.declaration.vo;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableField;
import com.hzs.common.core.web.domain.BaseEntity;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
@ -20,6 +22,8 @@ import lombok.experimental.Accessors;
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
@TableName("AC_DECLARATION_GIFT_RECORD")
@KeySequence("AC_DECLARATION_GIFT_RECORD_SEQ")
@Builder
public class AcDeclarationGiftRecord extends BaseEntity {
private static final long serialVersionUID = 1L;
@ -41,24 +45,17 @@ public class AcDeclarationGiftRecord extends BaseEntity {
*/
@TableField("PK_RULE_ID")
private Long pkRuleId;
/**
* 会员ID
* 订单编号
*/
@TableField("PK_MEMBER")
private Long pkMember;
@TableField("ORDER_CODE")
private String orderCode;
/**
* 赠品产品ID
* 同步状态
*/
@TableField("PK_PRODUCT")
private Integer pkProduct;
@TableField("SYNC_STATUS")
private Integer syncStatus;
/**
* 赠品数量
*/
@TableField("QUANTITY")
private Integer quantity;
}

View File

@ -1,16 +1,28 @@
package com.hzs.sale.order.provider;
import cn.hutool.core.bean.BeanUtil;
import com.alibaba.nacos.shaded.org.checkerframework.checker.units.qual.A;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.hzs.activity.base.service.IAcBaseConfigService;
import com.hzs.activity.declaration.service.IAcDeclarationGiftConfigService;
import com.hzs.activity.declaration.service.IAcDeclarationGiftRecordService;
import com.hzs.activity.declaration.vo.AcDeclarationGiftConfig;
import com.hzs.activity.declaration.vo.AcDeclarationGiftRecord;
import com.hzs.common.core.constant.CacheConstants;
import com.hzs.common.core.constant.CountryConstants;
import com.hzs.common.core.constant.msg.SaOrderMsgConstants;
import com.hzs.common.core.domain.R;
import com.hzs.common.core.enums.EOrderStatus;
import com.hzs.common.core.service.RedisService;
import com.hzs.common.core.utils.ComputeUtil;
import com.hzs.common.domain.activity.base.AcBaseConfig;
import com.hzs.common.domain.member.base.CuMember;
import com.hzs.common.domain.member.ext.CuMemberAccountExt;
import com.hzs.common.domain.sale.ext.SaOrderExt;
import com.hzs.common.domain.sale.order.SaOrder;
import com.hzs.common.domain.sale.order.SaOrderItems;
import com.hzs.member.base.IMemberServiceApi;
import com.hzs.member.detail.ICuMemberDetailServiceApi;
import com.hzs.sale.order.ISaOrderServiceApi;
import com.hzs.sale.order.dto.*;
import com.hzs.sale.order.param.*;
@ -19,12 +31,18 @@ import com.hzs.sale.order.vo.MemberFirstOrderVo;
import com.hzs.sale.order.vo.SingleItemStatVo;
import com.hzs.system.sys.dto.ApprovalBusinessResultDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
@ -38,6 +56,14 @@ public class SaOrderServiceProvider implements ISaOrderServiceApi {
private RedisService redisService;
@Autowired
private ISaOrderService iSaOrderService;
@Autowired
private IMemberServiceApi iMemberServiceApi;
@Autowired
private IAcBaseConfigService iAcBaseConfigService;
@Autowired
private IAcDeclarationGiftConfigService iAcDeclarationGiftConfigService;
@Autowired
private IAcDeclarationGiftRecordService iAcDeclarationGiftRecordService;
@Override
public R<List<SaOrderExt>> queryRepeatSaOrderByDay(Date startDate, Date endDate) {
@ -180,4 +206,112 @@ public class SaOrderServiceProvider implements ISaOrderServiceApi {
return singleItemStatVoList.stream().map(a -> BeanUtil.copyProperties(a, SingleItemStatDTO.class)).collect(Collectors.toList());
}
@Override
@Transactional(rollbackFor = Exception.class)
public R<?> autoPushDeclaration() {
// 获取所属国家
Integer pkCountry = CountryConstants.CHINA_COUNTRY;
// 获取 record 表最后一条数据
AcDeclarationGiftRecord lastRecord = iAcDeclarationGiftRecordService.selectLastRecord();
// 默认查 7 天前的数据
int daysAgo = 7;
// 如果上次记录不是昨天表示有漏数据
if (lastRecord != null) {
LocalDate lastDate = lastRecord.getCreationTime().toInstant()
.atZone(ZoneId.systemDefault())
.toLocalDate();
LocalDate today = LocalDate.now();
long diff = ChronoUnit.DAYS.between(lastDate, today);
if (diff > 1) {
// 有漏跑天数就加上差值
daysAgo = (int) (7 + (diff - 1));
log.info("检测到漏跑 {} 天,将查询 {} 天前的订单", diff - 1, daysAgo);
}
}
// 获取目标日期SYSDATE - daysAgo
Date targetDate = java.sql.Date.valueOf(LocalDate.now().minusDays(7));
log.info("处理日期: {}", targetDate);
// 查询订单
List<SaOrder> orderList = iSaOrderService.list(new LambdaQueryWrapper<SaOrder>()
.in(SaOrder::getOrderType, 1, 2, 4, 5)
.apply("TRUNC(PAY_TIME) = TRUNC(SYSDATE - {0})", daysAgo)
.eq(SaOrder::getOrderStatus, 1)
.eq(SaOrder::getDelFlag, 0));
log.info("{}天无有效订单,处理结束",daysAgo);
// 获取所有7天前有效的报单赠送活动
List<AcBaseConfig> acBaseConfigList = iAcBaseConfigService.list(new LambdaQueryWrapper<AcBaseConfig>()
.le(AcBaseConfig::getActStartDate, targetDate)
.ge(AcBaseConfig::getActEndDate, targetDate)
.eq(AcBaseConfig::getActType, 32)
.eq(AcBaseConfig::getDelFlag, 0));
if (acBaseConfigList.isEmpty()) {
log.info("{}天前无有效报单赠送活动,处理结束",daysAgo);
return R.ok();
}
// 报单赠送活动主键集合
List<Long> declarationBaseIds = acBaseConfigList.stream().map(AcBaseConfig::getPkId).collect(Collectors.toList());
// 查询所有报单赠送活动数据
List<AcDeclarationGiftConfig> declarationGiftConfigs = iAcDeclarationGiftConfigService.list(new LambdaQueryWrapper<AcDeclarationGiftConfig>()
.in(AcDeclarationGiftConfig::getPkBaseId, declarationBaseIds)
.eq(AcDeclarationGiftConfig::getDelFlag, 0));
Map<String, AcDeclarationGiftConfig> configMap = declarationGiftConfigs.stream()
.collect(Collectors.toMap(
cfg -> cfg.getRegisterAuthority() + "_" + cfg.getSpecifyLevel(),
Function.identity(),
(a, b) -> b
));
orderList.forEach(order -> {
// 查看是否有重复订单
int count = iAcDeclarationGiftRecordService.count(new LambdaQueryWrapper<AcDeclarationGiftRecord>()
.eq(AcDeclarationGiftRecord::getOrderCode, order.getOrderCode())
.eq(AcDeclarationGiftRecord::getDelFlag, 0));
if (count > 0) {
log.warn("当前订单已同步至报单明细{}",order.getOrderCode());
return;
}
// 查询会员信息
R<CuMember> memberResult = iMemberServiceApi.getMember(order.getPkCreator());
CuMember member = memberResult.getData();
if (member == null) {
log.warn("会员信息不存在, orderId={}", order.getPkId());
return;
}
// 组合 key 匹配活动配置
String key = member.getRegisterAuthority() + "_" + member.getPkSettleGrade();
AcDeclarationGiftConfig matchedConfig = configMap.get(key);
if (matchedConfig == null) {
log.info("未找到匹配的报单赠送配置, 会员id={}, 注册权限={}, 结算等级={}",
member.getPkId(), member.getRegisterAuthority(), member.getPkSettleGrade());
return;
}
AcDeclarationGiftRecord record = AcDeclarationGiftRecord.builder()
.pkRuleId(matchedConfig.getPkId())
.pkBaseId(matchedConfig.getPkBaseId())
.orderCode(order.getOrderCode())
.syncStatus(0)
.build();
record.setCreationTime(new Date());
record.setDelFlag(0);
record.setPkCreator(member.getPkId());
record.setPkCountry(pkCountry);
// 插入数据库
iAcDeclarationGiftRecordService.save(record);
log.info("成功插入报单赠送记录 -> memberId={}, ruleId={}",
member.getPkId(), matchedConfig.getPkId());
});
return R.ok();
}
}

View File

@ -38,17 +38,17 @@
MERGE INTO AC_PICK tgt USING (
SELECT
adgr.PK_ID AS SRC_ID,
adgr.PK_MEMBER,
so.PK_CREATOR AS PK_MEMBER,
32 AS PICK_TYPE,
adgc.PK_ID AS PK_BASE_CONFIG,
adgr.PK_PRODUCT AS PK_DATA_ID,
adgd.PK_PRODUCT AS PK_DATA_ID,
adgd.SPECS_NAME AS SPECS_NAME,
adgd.SPECS_NAME_ID AS SPECS_NAME_ID,
adgr.QUANTITY AS USABLE_QUANTITY,
adgd.QUANTITY AS USABLE_QUANTITY,
bp.COVER AS PICK_COVER,
0 AS IS_FREE_MAIL,
0 AS DEL_FLAG,
adgr.QUANTITY AS BASE_QUANTITY,
adgd.QUANTITY AS BASE_QUANTITY,
adgr.PK_BASE_ID AS PK_BASE_ID,
SYSDATE AS CREATION_TIME,
100000000 AS PK_CREATOR,
@ -57,10 +57,11 @@
AC_DECLARATION_GIFT_RECORD adgr
LEFT JOIN AC_DECLARATION_GIFT_CONFIG adgc ON adgr.PK_RULE_ID = adgc.PK_ID
LEFT JOIN AC_DECLARATION_GIFT_DETAIL adgd ON adgc.PK_ID = adgd.PK_RULE_ID
LEFT JOIN BD_PRODUCT bp ON adgr.PK_PRODUCT = bp.PK_ID
LEFT JOIN BD_PRODUCT bp ON adgd.PK_PRODUCT = bp.PK_ID
LEFT JOIN BD_PRODUCT_EXTEND bpe ON bp.PK_ID = bpe.PK_PRODUCT
LEFT JOIN SA_ORDER so ON adgr.ORDER_CODE = so.ORDER_CODE
WHERE
TRUNC(adgr.CREATION_TIME) = TRUNC(SYSDATE) - 7
adgr.SYNC_STATUS = 0
OR adgr.SYNC_STATUS = 2
) src ON (
tgt.PICK_TYPE = src.PICK_TYPE
@ -116,14 +117,16 @@
UPDATE AC_DECLARATION_GIFT_RECORD
SET SYNC_STATUS = 1
WHERE
(TRUNC(CREATION_TIME) = TRUNC(SYSDATE) - 7 OR SYNC_STATUS = 2);
SYNC_STATUS = 0
OR SYNC_STATUS = 2;
EXCEPTION
WHEN OTHERS THEN
v_error_count := SQL % ROWCOUNT;
UPDATE AC_DECLARATION_GIFT_RECORD
SET SYNC_STATUS = 2
WHERE
(TRUNC(CREATION_TIME) = TRUNC(SYSDATE) - 7 OR SYNC_STATUS = 2);
SYNC_STATUS = 0
OR SYNC_STATUS = 2;
END;
INSERT INTO AC_PICK_LOG (PK_ID, PK_PICK, PK_USER, QUANTITY, PK_COUNTRY) SELECT
AC_PICK_LOG_SEQ.NEXTVAL,

View File

@ -117,5 +117,13 @@
AND adgr.CREATION_TIME &lt;= #{creationEndTime}
</if>
</select>
<select id="selectLastRecord" resultType="com.hzs.activity.declaration.vo.AcDeclarationGiftRecord">
SELECT
*
FROM
(SELECT * FROM AC_DECLARATION_GIFT_RECORD WHERE DEL_FLAG = 0 ORDER BY CREATION_TIME DESC)
WHERE
ROWNUM = 1
</select>
</mapper>

View File

@ -7,6 +7,8 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 活动涉及定时任务
@ -44,7 +46,8 @@ public class ActivityJob {
if (resultR.isSuccess()) {
log.info("报单赠送更新提货列表 执行成功");
} else {
log.error("报单赠送更新提货列表 执行失败");
log.error("报单赠送更新提货列表" +
" 执行失败");
}
log.info("报单赠送更新提货列表 结束执行");
}

View File

@ -1,11 +1,15 @@
package com.hzs.third.job;
import com.hzs.common.core.domain.R;
import com.hzs.sale.order.ISaOrderServiceApi;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Slf4j
@ConditionalOnProperty(name = "xxl-job.start", havingValue = "true")
@ -22,5 +26,20 @@ public class OrderJob {
public void timingCloseOrder() {
iSaOrderServiceApi.closeOrder();
}
/**
* 报单赠送订单推送
*/
@XxlJob("autoPushDeclaration")
public void autoPushDeclaration() {
log.info("推送报单赠送订单 开始执行");
R<?> resultR = iSaOrderServiceApi.autoPushDeclaration();
if (resultR.isSuccess()) {
log.info("推送报单赠送订单 执行成功");
} else {
log.error("推送报单赠送订单 执行失败");
}
log.info("推送报单赠送订单 结束执行");
}
}