7.2 支付成功后回调功能实现,更新拼团订单状态

This commit is contained in:
zhangsan 2025-07-02 19:49:10 +08:00
parent f8429e9fcd
commit ca9faa403b
29 changed files with 507 additions and 23 deletions

View File

@ -183,7 +183,7 @@ CREATE TABLE `group_buy_order_list` (
`channel` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '来源',
`original_price` decimal(8, 2) NOT NULL COMMENT '原始价格',
`deduction_price` decimal(8, 2) NOT NULL COMMENT '折扣金额',
`status` tinyint(1) NOT NULL DEFAULT 0 COMMENT '状态0初始锁定、1消费完成',
`status` tinyint(1) NOT NULL DEFAULT 0 COMMENT '状态0初始锁定、1消费完成、2用户退单',
`out_trade_no` varchar(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '外部交易单号-确保外部调用唯一幂等',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',

View File

@ -47,4 +47,13 @@
where user_id = #{userId} and activity_id = #{activityId}
</select>
<update id="updateOrderStatus2COMPLETE" parameterType="edu.whut.infrastructure.dao.po.GroupBuyOrderList">
update group_buy_order_list
set status = 1, update_time = now()
where out_trade_no = #{outTradeNo} and user_id = #{userId}
</update>
<select id="queryGroupBuyCompleteOrderOutTradeNoListByTeamId" parameterType="java.lang.String" resultType="java.lang.String">
select out_trade_no from group_buy_order_list where team_id = #{teamId} and status = 1
</select>
</mapper>

View File

@ -37,15 +37,34 @@
]]>
</update>
<update id="updateAddCompleteCount" parameterType="java.lang.String">
<![CDATA[
update group_buy_order
set complete_count = complete_count + 1, update_time= now()
where team_id = #{teamId} and complete_count < target_count
]]>
</update>
<update id="updateSubtractionLockCount" parameterType="java.lang.String">
update group_buy_order
set lock_count = lock_count - 1, update_time= now()
where team_id = #{teamId} and lock_count > 0
</update>
<update id="updateOrderStatus2COMPLETE" parameterType="java.lang.String">
update group_buy_order
set status = 1, update_time= now()
where team_id = #{teamId} and status = 0
</update>
<select id="queryGroupBuyProgress" parameterType="java.lang.String" resultMap="dataMap">
select target_count, complete_count, lock_count from group_buy_order
where team_id = #{teamId}
</select>
<select id="queryGroupBuyTeamByTeamId" parameterType="java.lang.String" resultMap="dataMap">
select team_id, activity_id, target_count, complete_count, lock_count, status
from group_buy_order where team_id = #{teamId}
</select>
</mapper>

View File

@ -0,0 +1,23 @@
<?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="edu.whut.infrastructure.dao.INotifyTaskDao">
<resultMap id="dataMap" type="edu.whut.infrastructure.dao.po.NotifyTask">
<id column="id" property="id"/>
<result column="activity_id" property="activityId"/>
<result column="team_id" property="teamId"/>
<result column="notify_url" property="notifyUrl"/>
<result column="notify_count" property="notifyCount"/>
<result column="notify_status" property="notifyStatus"/>
<result column="parameter_json" property="parameterJson"/>
<result column="create_time" property="createTime"/>
<result column="update_time" property="updateTime"/>
</resultMap>
<insert id="insert" parameterType="edu.whut.infrastructure.dao.po.NotifyTask">
insert into notify_task(activity_id, team_id, notify_url, notify_count, notify_status, parameter_json,
create_time, update_time)
values(#{activityId}, #{teamId}, #{notifyUrl}, #{notifyCount}, #{notifyStatus}, #{parameterJson}, now(),now())
</insert>
</mapper>

View File

@ -8,7 +8,7 @@ import edu.whut.domain.trade.model.entity.MarketPayOrderEntity;
import edu.whut.domain.trade.model.entity.PayActivityEntity;
import edu.whut.domain.trade.model.entity.PayDiscountEntity;
import edu.whut.domain.trade.model.entity.UserEntity;
import edu.whut.domain.trade.service.ITradeOrderService;
import edu.whut.domain.trade.service.ITradeLockOrderService;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -23,13 +23,13 @@ import javax.annotation.Resource;
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class ITradeOrderServiceTest {
public class ITradeLockOrderServiceTest {
@Resource
private IIndexGroupBuyMarketService indexGroupBuyMarketService;
@Resource
private ITradeOrderService tradeOrderService;
private ITradeLockOrderService tradeOrderService;
@Test
public void test_lockMarketPayOrder() throws Exception {

View File

@ -0,0 +1,38 @@
package edu.whut.test.domain.trade;
import com.alibaba.fastjson2.JSON;
import edu.whut.domain.trade.model.entity.TradePaySettlementEntity;
import edu.whut.domain.trade.model.entity.TradePaySuccessEntity;
import edu.whut.domain.trade.service.ITradeSettlementOrderService;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import javax.annotation.Resource;
/**
* 拼团交易结算服务测试
*/
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class TradeSettlementOrderServiceTest {
@Resource
private ITradeSettlementOrderService tradeSettlementOrderService;
@Test
public void test_settlementMarketPayOrder() {
TradePaySuccessEntity tradePaySuccessEntity = new TradePaySuccessEntity();
tradePaySuccessEntity.setSource("s01");
tradePaySuccessEntity.setChannel("c01");
tradePaySuccessEntity.setUserId("zy03");
tradePaySuccessEntity.setOutTradeNo("192426946598");
TradePaySettlementEntity tradePaySettlementEntity = tradeSettlementOrderService.settlementMarketPayOrder(tradePaySuccessEntity);
log.info("请求参数:{}", JSON.toJSONString(tradePaySuccessEntity));
log.info("测试结果:{}", JSON.toJSONString(tradePaySettlementEntity));
}
}

View File

@ -28,7 +28,7 @@ public class MarketTradeControllerTest {
@Test
public void test_lockMarketPayOrder() {
LockMarketPayOrderRequestDTO lockMarketPayOrderRequestDTO = new LockMarketPayOrderRequestDTO();
lockMarketPayOrderRequestDTO.setUserId("smile01");
lockMarketPayOrderRequestDTO.setUserId("zy01");
lockMarketPayOrderRequestDTO.setTeamId(null);
lockMarketPayOrderRequestDTO.setActivityId(100123L);
lockMarketPayOrderRequestDTO.setGoodsId("9890001");
@ -44,8 +44,8 @@ public class MarketTradeControllerTest {
@Test
public void test_lockMarketPayOrder_teamId_not_null() {
LockMarketPayOrderRequestDTO lockMarketPayOrderRequestDTO = new LockMarketPayOrderRequestDTO();
lockMarketPayOrderRequestDTO.setUserId("smile04");
lockMarketPayOrderRequestDTO.setTeamId("80437493");
lockMarketPayOrderRequestDTO.setUserId("zy03");
lockMarketPayOrderRequestDTO.setTeamId("26432069");
lockMarketPayOrderRequestDTO.setActivityId(100123L);
lockMarketPayOrderRequestDTO.setGoodsId("9890001");
lockMarketPayOrderRequestDTO.setSource("s01");

View File

@ -40,6 +40,8 @@ public class TagService implements ITagService {
add("smile01");
add("smile02");
add("smile03");
add("smile04");
add("smile05");
}};
// 4. 把用户写入标签明细表

View File

@ -1,7 +1,9 @@
package edu.whut.domain.trade.adapter.repository;
import edu.whut.domain.trade.model.aggregate.GroupBuyOrderAggregate;
import edu.whut.domain.trade.model.aggregate.GroupBuyTeamSettlementAggregate;
import edu.whut.domain.trade.model.entity.GroupBuyActivityEntity;
import edu.whut.domain.trade.model.entity.GroupBuyTeamEntity;
import edu.whut.domain.trade.model.entity.MarketPayOrderEntity;
import edu.whut.domain.trade.model.valobj.GroupBuyProgressVO;
@ -20,4 +22,9 @@ public interface ITradeRepository {
Integer queryOrderCountByActivityId(Long activityId, String userId);
GroupBuyTeamEntity queryGroupBuyTeamByTeamId(String teamId);
void settlementMarketPayOrder(GroupBuyTeamSettlementAggregate groupBuyTeamSettlementAggregate);
}

View File

@ -0,0 +1,26 @@
package edu.whut.domain.trade.model.aggregate;
import edu.whut.domain.trade.model.entity.GroupBuyTeamEntity;
import edu.whut.domain.trade.model.entity.TradePaySuccessEntity;
import edu.whut.domain.trade.model.entity.UserEntity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 拼团组队结算聚合
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class GroupBuyTeamSettlementAggregate {
/** 用户实体对象 */
private UserEntity userEntity;
/** 拼团组队实体对象 */
private GroupBuyTeamEntity groupBuyTeamEntity;
/** 交易支付订单实体对象 */
private TradePaySuccessEntity tradePaySuccessEntity;
}

View File

@ -0,0 +1,30 @@
package edu.whut.domain.trade.model.entity;
import edu.whut.types.enums.GroupBuyOrderStatusEnumVO;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 拼团组队实体对象
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class GroupBuyTeamEntity {
/** 拼单组队ID */
private String teamId;
/** 活动ID */
private Long activityId;
/** 目标数量 */
private Integer targetCount;
/** 完成数量 */
private Integer completeCount;
/** 锁单数量 */
private Integer lockCount;
/** 状态0-拼单中、1-完成、2-失败) */
private GroupBuyOrderStatusEnumVO status;
}

View File

@ -16,6 +16,8 @@ import java.math.BigDecimal;
@NoArgsConstructor
public class MarketPayOrderEntity {
/** 拼单组队ID */
private String teamId;
/** 预购订单ID */
private String orderId;
/** 折扣金额 */

View File

@ -0,0 +1,30 @@
package edu.whut.domain.trade.model.entity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 交易结算订单实体
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class TradePaySettlementEntity {
/** 渠道 */
private String source;
/** 来源 */
private String channel;
/** 用户ID */
private String userId;
/** 拼单组队ID */
private String teamId;
/** 活动ID */
private Long activityId;
/** 外部交易单号 */
private String outTradeNo;
}

View File

@ -0,0 +1,26 @@
package edu.whut.domain.trade.model.entity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 交易支付订单实体对象
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class TradePaySuccessEntity {
/** 渠道 */
private String source;
/** 来源 */
private String channel;
/** 用户ID */
private String userId;
/** 外部交易单号 */
private String outTradeNo;
}

View File

@ -9,7 +9,7 @@ import edu.whut.domain.trade.model.valobj.GroupBuyProgressVO;
/**
* 交易订单服务接口
*/
public interface ITradeOrderService {
public interface ITradeLockOrderService {
/**
* 查询未被支付消费完成的营销优惠订单

View File

@ -0,0 +1,18 @@
package edu.whut.domain.trade.service;
import edu.whut.domain.trade.model.entity.TradePaySettlementEntity;
import edu.whut.domain.trade.model.entity.TradePaySuccessEntity;
/**
* 拼团交易结算服务接口
*/
public interface ITradeSettlementOrderService {
/**
* 营销结算
* @param tradePaySuccessEntity 交易支付订单实体对象
* @return 交易结算订单实体
*/
TradePaySettlementEntity settlementMarketPayOrder(TradePaySuccessEntity tradePaySuccessEntity);
}

View File

@ -1,10 +1,11 @@
package edu.whut.domain.trade.service;
package edu.whut.domain.trade.service.lock;
import edu.whut.domain.trade.adapter.repository.ITradeRepository;
import edu.whut.domain.trade.model.aggregate.GroupBuyOrderAggregate;
import edu.whut.domain.trade.model.entity.*;
import edu.whut.domain.trade.model.valobj.GroupBuyProgressVO;
import edu.whut.domain.trade.service.factory.TradeRuleFilterFactory;
import edu.whut.domain.trade.service.ITradeLockOrderService;
import edu.whut.domain.trade.service.lock.factory.TradeRuleFilterFactory;
import edu.whut.types.design.framework.link.model2.chain.BusinessLinkedList;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@ -12,12 +13,12 @@ import org.springframework.stereotype.Service;
/**
* 交易订单服务
* 交易锁单服务但未支付
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class TradeOrderService implements ITradeOrderService {
public class TradeLockLockOrderService implements ITradeLockOrderService {
private final ITradeRepository repository;

View File

@ -1,9 +1,9 @@
package edu.whut.domain.trade.service.factory;
package edu.whut.domain.trade.service.lock.factory;
import edu.whut.domain.trade.model.entity.GroupBuyActivityEntity;
import edu.whut.domain.trade.model.entity.TradeRuleCommandEntity;
import edu.whut.domain.trade.model.entity.TradeRuleFilterBackEntity;
import edu.whut.domain.trade.service.filter.ActivityUsabilityRuleFilter;
import edu.whut.domain.trade.service.filter.UserTakeLimitRuleFilter;
import edu.whut.domain.trade.service.lock.filter.ActivityUsabilityRuleFilter;
import edu.whut.domain.trade.service.lock.filter.UserTakeLimitRuleFilter;
import edu.whut.types.design.framework.link.model2.LinkArmory;
import edu.whut.types.design.framework.link.model2.chain.BusinessLinkedList;
import lombok.AllArgsConstructor;

View File

@ -1,9 +1,9 @@
package edu.whut.domain.trade.service.filter;
package edu.whut.domain.trade.service.lock.filter;
import edu.whut.domain.trade.adapter.repository.ITradeRepository;
import edu.whut.domain.trade.model.entity.GroupBuyActivityEntity;
import edu.whut.domain.trade.model.entity.TradeRuleCommandEntity;
import edu.whut.domain.trade.model.entity.TradeRuleFilterBackEntity;
import edu.whut.domain.trade.service.factory.TradeRuleFilterFactory;
import edu.whut.domain.trade.service.lock.factory.TradeRuleFilterFactory;
import edu.whut.types.design.framework.link.model2.handler.ILogicHandler;
import edu.whut.types.enums.ActivityStatusEnumVO;
import edu.whut.types.enums.ResponseCode;
@ -12,7 +12,6 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Date;
/**

View File

@ -1,9 +1,9 @@
package edu.whut.domain.trade.service.filter;
package edu.whut.domain.trade.service.lock.filter;
import edu.whut.domain.trade.adapter.repository.ITradeRepository;
import edu.whut.domain.trade.model.entity.GroupBuyActivityEntity;
import edu.whut.domain.trade.model.entity.TradeRuleCommandEntity;
import edu.whut.domain.trade.model.entity.TradeRuleFilterBackEntity;
import edu.whut.domain.trade.service.factory.TradeRuleFilterFactory;
import edu.whut.domain.trade.service.lock.factory.TradeRuleFilterFactory;
import edu.whut.types.design.framework.link.model2.handler.ILogicHandler;
import edu.whut.types.enums.ResponseCode;
import edu.whut.types.exception.AppException;

View File

@ -0,0 +1,60 @@
package edu.whut.domain.trade.service.settlement;
import edu.whut.domain.trade.adapter.repository.ITradeRepository;
import edu.whut.domain.trade.model.aggregate.GroupBuyTeamSettlementAggregate;
import edu.whut.domain.trade.model.entity.*;
import edu.whut.domain.trade.service.ITradeSettlementOrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* 拼团交易结算服务
*/
@Slf4j
@Service
public class TradeSettlementOrderService implements ITradeSettlementOrderService {
@Resource
private ITradeRepository repository;
/**
* 第三方支付渠道确认用户支付成功之后调用该函数更新拼团订单状态为 已完成并同步拼团人数
* @param tradePaySuccessEntity 交易支付订单实体对象
* @return
*/
@Override
public TradePaySettlementEntity settlementMarketPayOrder(TradePaySuccessEntity tradePaySuccessEntity) {
log.info("拼团交易-支付订单结算:{} outTradeNo:{}", tradePaySuccessEntity.getUserId(), tradePaySuccessEntity.getOutTradeNo());
// 1. 查询拼团信息
MarketPayOrderEntity marketPayOrderEntity = repository.queryMarketPayOrderEntityByOutTradeNo(tradePaySuccessEntity.getUserId(), tradePaySuccessEntity.getOutTradeNo());
if (null == marketPayOrderEntity) {
log.info("不存在的外部交易单号或用户已退单,不需要做支付订单结算:{} outTradeNo:{}", tradePaySuccessEntity.getUserId(), tradePaySuccessEntity.getOutTradeNo());
return null;
}
// 2. 查询组团信息
GroupBuyTeamEntity groupBuyTeamEntity = repository.queryGroupBuyTeamByTeamId(marketPayOrderEntity.getTeamId());
// 3. 构建聚合对象
GroupBuyTeamSettlementAggregate groupBuyTeamSettlementAggregate = GroupBuyTeamSettlementAggregate.builder()
.userEntity(UserEntity.builder().userId(tradePaySuccessEntity.getUserId()).build())
.groupBuyTeamEntity(groupBuyTeamEntity)
.tradePaySuccessEntity(tradePaySuccessEntity)
.build();
// 4. 更新数据库拼团交易结算
repository.settlementMarketPayOrder(groupBuyTeamSettlementAggregate);
// 5. 返回结算信息 - 公司中开发这样的流程时候会根据外部需要进行值的设置
return TradePaySettlementEntity.builder()
.source(tradePaySuccessEntity.getSource())
.channel(tradePaySuccessEntity.getChannel())
.userId(tradePaySuccessEntity.getUserId())
.teamId(marketPayOrderEntity.getTeamId())
.activityId(groupBuyTeamEntity.getActivityId())
.outTradeNo(tradePaySuccessEntity.getOutTradeNo())
.build();
}
}

View File

@ -1,18 +1,23 @@
package edu.whut.infrastructure.adapter.repository;
import com.alibaba.fastjson2.JSON;
import edu.whut.domain.trade.adapter.repository.ITradeRepository;
import edu.whut.domain.trade.model.aggregate.GroupBuyOrderAggregate;
import edu.whut.domain.trade.model.aggregate.GroupBuyTeamSettlementAggregate;
import edu.whut.domain.trade.model.entity.*;
import edu.whut.domain.trade.model.valobj.GroupBuyProgressVO;
import edu.whut.domain.trade.model.valobj.TradeOrderStatusEnumVO;
import edu.whut.infrastructure.dao.IGroupBuyActivityDao;
import edu.whut.infrastructure.dao.IGroupBuyOrderDao;
import edu.whut.infrastructure.dao.IGroupBuyOrderListDao;
import edu.whut.infrastructure.dao.INotifyTaskDao;
import edu.whut.infrastructure.dao.po.GroupBuyActivity;
import edu.whut.infrastructure.dao.po.GroupBuyOrder;
import edu.whut.infrastructure.dao.po.GroupBuyOrderList;
import edu.whut.infrastructure.dao.po.NotifyTask;
import edu.whut.types.common.Constants;
import edu.whut.types.enums.ActivityStatusEnumVO;
import edu.whut.types.enums.GroupBuyOrderStatusEnumVO;
import edu.whut.types.enums.ResponseCode;
import edu.whut.types.exception.AppException;
import lombok.RequiredArgsConstructor;
@ -23,6 +28,9 @@ import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import java.util.HashMap;
import java.util.List;
/**
* 仓储实现负责把领域对象 <-> 数据库 PO 的转换与持久化
@ -39,6 +47,8 @@ public class TradeRepository implements ITradeRepository {
private final IGroupBuyActivityDao groupBuyActivityDao;
private final INotifyTaskDao notifyTaskDao;
/**
* 根据外部交易号 & 用户id 查询未支付的锁单记录用于幂等
*/
@ -54,8 +64,9 @@ public class TradeRepository implements ITradeRepository {
return null;
}
// 只返回上层真正关心的属性
// // 组装领域对象返回只返回上层真正关心的属性
return MarketPayOrderEntity.builder()
.teamId(po.getTeamId())
.orderId(po.getOrderId())
.deductionPrice(po.getDeductionPrice())
.tradeOrderStatusEnumVO(TradeOrderStatusEnumVO.valueOf(po.getStatus()))
@ -113,6 +124,7 @@ public class TradeRepository implements ITradeRepository {
/* ---------- 2. 写入 group_buy_order_list团单明细表 ---------- */
String orderId = RandomStringUtils.randomNumeric(12); // 订单号
//构建拼团明细单
GroupBuyOrderList orderListPo = GroupBuyOrderList.builder()
.userId(user.getUserId())
.teamId(teamId)
@ -162,6 +174,9 @@ public class TradeRepository implements ITradeRepository {
.build();
}
/**
* 根据 activityId 查询拼团活动实体
*/
@Override
public GroupBuyActivityEntity queryGroupBuyActivityEntityByActivityId(Long activityId) {
GroupBuyActivity groupBuyActivity = groupBuyActivityDao.queryGroupBuyActivityByActivityId(activityId);
@ -181,6 +196,9 @@ public class TradeRepository implements ITradeRepository {
.build();
}
/**
* 查询用户在某活动中已下单次数用于限购校验
*/
@Override
public Integer queryOrderCountByActivityId(Long activityId, String userId) {
GroupBuyOrderList groupBuyOrderListReq = new GroupBuyOrderList();
@ -188,4 +206,80 @@ public class TradeRepository implements ITradeRepository {
groupBuyOrderListReq.setUserId(userId);
return groupBuyOrderListDao.queryOrderCountByActivityId(groupBuyOrderListReq);
}
/**
* 查询团队订单主表信息
*/
@Override
public GroupBuyTeamEntity queryGroupBuyTeamByTeamId(String teamId) {
GroupBuyOrder groupBuyOrder = groupBuyOrderDao.queryGroupBuyTeamByTeamId(teamId);
return GroupBuyTeamEntity.builder()
.teamId(groupBuyOrder.getTeamId())
.activityId(groupBuyOrder.getActivityId())
.targetCount(groupBuyOrder.getTargetCount())
.completeCount(groupBuyOrder.getCompleteCount())
.lockCount(groupBuyOrder.getLockCount())
.status(GroupBuyOrderStatusEnumVO.valueOf(groupBuyOrder.getStatus()))
.build();
}
/**
* 拼团支付成功后的结算逻辑
* 步骤
* 更新明细表状态 COMPLETE
* 更新主表 complete_count + 1
* 当达到 targetCount 更新主表状态 COMPLETE 并写入回调任务
* 整体包裹在 500ms 事务内任何一步失败都会回滚
*/
@Transactional(timeout = 500)
@Override
public void settlementMarketPayOrder(GroupBuyTeamSettlementAggregate agg) {
// ========= 1. 聚合拆分 =========
UserEntity user = agg.getUserEntity();
GroupBuyTeamEntity team = agg.getGroupBuyTeamEntity();
TradePaySuccessEntity payOK = agg.getTradePaySuccessEntity();
// ========= 2. 更新拼团订单明细状态 =========
GroupBuyOrderList req = new GroupBuyOrderList();
req.setUserId(user.getUserId());
req.setOutTradeNo(payOK.getOutTradeNo());
//更新订单状态到已完成
int rows = groupBuyOrderListDao.updateOrderStatus2COMPLETE(req);
if (rows != 1) {
throw new AppException(ResponseCode.UPDATE_ZERO);
}
// ========= 3. 更新拼团已完成人数 =========
int addCnt = groupBuyOrderDao.updateAddCompleteCount(team.getTeamId());
if (addCnt != 1) {
throw new AppException(ResponseCode.UPDATE_ZERO);
}
// ========= 4. 达标后收尾状态改为 COMPLETE & 写入回调任务 =========
if (team.getTargetCount() - team.getCompleteCount() == 1) { // 刚好凑齐
int updStat = groupBuyOrderDao.updateOrderStatus2COMPLETE(team.getTeamId());
if (updStat != 1) {
throw new AppException(ResponseCode.UPDATE_ZERO);
}
// 查询已完成外部交易号列表用于业务通知
List<String> outTradeNoList = groupBuyOrderListDao.queryGroupBuyCompleteOrderOutTradeNoListByTeamId(team.getTeamId());
// 构造并写入通知任务异步回调
NotifyTask task = new NotifyTask();
task.setActivityId(team.getActivityId());
task.setTeamId(team.getTeamId());
task.setNotifyUrl("暂无"); // TODO待配置回调地址
task.setNotifyCount(0);
task.setNotifyStatus(0);
task.setParameterJson(JSON.toJSONString(new HashMap<String, Object>() {{
put("teamId", team.getTeamId());
put("outTradeNoList", outTradeNoList);
}}));
notifyTaskDao.insert(task);
}
}
}

View File

@ -31,4 +31,10 @@ public interface IGroupBuyOrderDao {
*/
GroupBuyOrder queryGroupBuyProgress(String teamId);
GroupBuyOrder queryGroupBuyTeamByTeamId(String teamId);
int updateAddCompleteCount(String teamId);
int updateOrderStatus2COMPLETE(String teamId);
}

View File

@ -2,6 +2,8 @@ package edu.whut.infrastructure.dao;
import edu.whut.infrastructure.dao.po.GroupBuyOrderList;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* 用户拼单明细
*/
@ -19,4 +21,9 @@ public interface IGroupBuyOrderListDao {
Integer queryOrderCountByActivityId(GroupBuyOrderList groupBuyOrderListReq);
int updateOrderStatus2COMPLETE(GroupBuyOrderList groupBuyOrderListReq);
List<String> queryGroupBuyCompleteOrderOutTradeNoListByTeamId(String teamId);
}

View File

@ -0,0 +1,13 @@
package edu.whut.infrastructure.dao;
import edu.whut.infrastructure.dao.po.NotifyTask;
import org.apache.ibatis.annotations.Mapper;
/**
* 回调任务
*/
@Mapper
public interface INotifyTaskDao {
void insert(NotifyTask notifyTask);
}

View File

@ -0,0 +1,37 @@
package edu.whut.infrastructure.dao.po;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
/**
* 通知回调任务
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class NotifyTask {
/** 自增ID */
private Long id;
/** 活动ID */
private Long activityId;
/** 拼单组队ID */
private String teamId;
/** 回调接口 */
private String notifyUrl;
/** 回调次数 */
private Integer notifyCount;
/** 回调状态【0初始、1完成、2重试、3失败】 */
private Integer notifyStatus;
/** 参数对象 */
private String parameterJson;
/** 创建时间 */
private Date createTime;
/** 更新时间 */
private Date updateTime;
}

View File

@ -14,7 +14,7 @@ import edu.whut.domain.trade.model.entity.PayActivityEntity;
import edu.whut.domain.trade.model.entity.PayDiscountEntity;
import edu.whut.domain.trade.model.entity.UserEntity;
import edu.whut.domain.trade.model.valobj.GroupBuyProgressVO;
import edu.whut.domain.trade.service.ITradeOrderService;
import edu.whut.domain.trade.service.ITradeLockOrderService;
import edu.whut.types.enums.ResponseCode;
import edu.whut.types.exception.AppException;
import lombok.RequiredArgsConstructor;
@ -47,7 +47,7 @@ public class MarketTradeController implements IMarketTradeService {
private final IIndexGroupBuyMarketService indexGroupBuyMarketService;
private final ITradeOrderService tradeOrderService;
private final ITradeLockOrderService tradeOrderService;
/**
* 锁定营销预支付订单拼团 / 普通优惠

View File

@ -0,0 +1,35 @@
package edu.whut.types.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
/**
* 拼团订单枚举
*/
@Getter
@AllArgsConstructor
@NoArgsConstructor
public enum GroupBuyOrderStatusEnumVO {
PROGRESS(0, "拼单中"),
COMPLETE(1, "完成"),
FAIL(2, "失败"),
;
private Integer code;
private String info;
public static GroupBuyOrderStatusEnumVO valueOf(Integer code) {
switch (code) {
case 0:
return PROGRESS;
case 1:
return COMPLETE;
case 2:
return FAIL;
}
throw new RuntimeException("err code not exist!");
}
}

View File

@ -13,6 +13,8 @@ public enum ResponseCode {
UN_ERROR("0001", "未知失败"),
ILLEGAL_PARAMETER("0002", "非法参数"),
INDEX_EXCEPTION("0003", "唯一索引冲突"),
UPDATE_ZERO("0004", "更新记录为0"),
E0001("E0001", "不存在对应的折扣计算服务"),
E0002("E0002", "无拼团营销配置"),
E0003("E0003", "拼团活动降级拦截"),