8.8 解耦HTTP和RPC
This commit is contained in:
parent
33d803dd44
commit
72027eefa6
@ -6,7 +6,7 @@ services:
|
||||
container_name: group-buy-market-front
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- '18093:80'
|
||||
- '18091:80'
|
||||
volumes:
|
||||
- ./nginx/html:/usr/share/nginx/html
|
||||
- ./nginx/conf/nginx.conf:/etc/nginx/nginx.conf:ro
|
||||
|
@ -4,6 +4,7 @@ import edu.whut.api.IMarketTradeService;
|
||||
import edu.whut.api.dto.LockMarketPayOrderRequestDTO;
|
||||
import edu.whut.api.dto.LockMarketPayOrderResponseDTO;
|
||||
import edu.whut.api.response.Response;
|
||||
import edu.whut.trigger.http.MarketTradeController;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.junit.Test;
|
||||
@ -22,14 +23,14 @@ import javax.annotation.Resource;
|
||||
public class MarketTradeControllerTest {
|
||||
|
||||
@Resource
|
||||
private IMarketTradeService marketTradeService;
|
||||
private MarketTradeController marketTradeService;
|
||||
|
||||
@Test
|
||||
public void test_lockMarketPayOrder_mq() throws InterruptedException {
|
||||
LockMarketPayOrderRequestDTO lockMarketPayOrderRequestDTO = new LockMarketPayOrderRequestDTO();
|
||||
lockMarketPayOrderRequestDTO.setUserId("zy04");
|
||||
lockMarketPayOrderRequestDTO.setUserId("smile03");
|
||||
lockMarketPayOrderRequestDTO.setTeamId(null);
|
||||
lockMarketPayOrderRequestDTO.setActivityId(100124L);
|
||||
lockMarketPayOrderRequestDTO.setActivityId(100123L);
|
||||
lockMarketPayOrderRequestDTO.setGoodsId("9890001");
|
||||
lockMarketPayOrderRequestDTO.setSource("s01");
|
||||
lockMarketPayOrderRequestDTO.setChannel("c01");
|
||||
|
@ -26,7 +26,7 @@ public class TradeLockRuleFilterFactory {
|
||||
private static final String teamStockKey = "group_buy_market_team_stock_key_";
|
||||
|
||||
/**
|
||||
* 组装责任链
|
||||
* 组装责任链 先活动有效性校验=》用户参与活动次数校验=》抢占库存校验
|
||||
* 通过 Spring @Bean 暴露:外部只需注入 BusinessLinkedList 即可调用 apply
|
||||
*/
|
||||
@Bean("tradeRuleFilter")
|
||||
|
@ -0,0 +1,313 @@
|
||||
package edu.whut.trigger.basic;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import edu.whut.api.IMarketTradeService;
|
||||
import edu.whut.api.dto.*;
|
||||
import edu.whut.api.response.Response;
|
||||
import edu.whut.domain.activity.model.entity.MarketProductEntity;
|
||||
import edu.whut.domain.activity.model.entity.TrialBalanceEntity;
|
||||
import edu.whut.domain.activity.model.valobj.GroupBuyActivityDiscountVO;
|
||||
import edu.whut.domain.activity.service.IIndexGroupBuyMarketService;
|
||||
import edu.whut.domain.trade.model.entity.*;
|
||||
import edu.whut.domain.trade.model.valobj.GroupBuyProgressVO;
|
||||
import edu.whut.domain.trade.model.valobj.NotifyConfigVO;
|
||||
import edu.whut.domain.trade.model.valobj.NotifyTypeEnumVO;
|
||||
import edu.whut.domain.trade.model.valobj.TradeOrderStatusEnumVO;
|
||||
import edu.whut.domain.trade.service.ITradeLockOrderService;
|
||||
import edu.whut.domain.trade.service.ITradeRefundOrderService;
|
||||
import edu.whut.domain.trade.service.ITradeSettlementOrderService;
|
||||
import edu.whut.types.enums.ResponseCode;
|
||||
import edu.whut.types.exception.AppException;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import java.util.Objects;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class MarketTradeService implements IMarketTradeService {
|
||||
//价格试算
|
||||
private final IIndexGroupBuyMarketService indexGroupBuyMarketService;
|
||||
//拼团锁单
|
||||
private final ITradeLockOrderService tradeOrderService;
|
||||
//拼团结算
|
||||
private final ITradeSettlementOrderService tradeSettlementOrderService;
|
||||
//退单
|
||||
private final ITradeRefundOrderService tradeRefundOrderService;
|
||||
|
||||
/**
|
||||
* 锁定营销预支付订单(拼团 / 普通优惠)
|
||||
*/
|
||||
@Override
|
||||
public Response<LockMarketPayOrderResponseDTO> lockMarketPayOrder(@RequestBody LockMarketPayOrderRequestDTO lockMarketPayOrderRequestDTO) {
|
||||
try {
|
||||
/* ---------- 1. 基础参数提取与校验 ---------- */
|
||||
String userId = lockMarketPayOrderRequestDTO.getUserId();
|
||||
String source = lockMarketPayOrderRequestDTO.getSource();
|
||||
String channel = lockMarketPayOrderRequestDTO.getChannel();
|
||||
String goodsId = lockMarketPayOrderRequestDTO.getGoodsId();
|
||||
Long activityId = lockMarketPayOrderRequestDTO.getActivityId();
|
||||
String outTradeNo = lockMarketPayOrderRequestDTO.getOutTradeNo();
|
||||
String teamId = lockMarketPayOrderRequestDTO.getTeamId(); //可为空,对应参与拼团or创建拼团
|
||||
LockMarketPayOrderRequestDTO.NotifyConfigVO notifyConfigVO = lockMarketPayOrderRequestDTO.getNotifyConfigVO();
|
||||
|
||||
log.info("营销锁单开始执行:拼团交易锁单入参 userId={} req={}", userId, JSON.toJSONString(lockMarketPayOrderRequestDTO));
|
||||
|
||||
// 空值校验(任何一个关键字段为空则直接返回错误)
|
||||
boolean httpWithoutUrl =
|
||||
"HTTP".equals(notifyConfigVO.getNotifyType())
|
||||
&& StringUtils.isBlank(notifyConfigVO.getNotifyUrl());
|
||||
|
||||
if (StringUtils.isAnyBlank(userId, source, channel, goodsId)
|
||||
|| activityId == null
|
||||
|| httpWithoutUrl) {
|
||||
return Response.<LockMarketPayOrderResponseDTO>builder()
|
||||
.code(ResponseCode.ILLEGAL_PARAMETER.getCode())
|
||||
.info(ResponseCode.ILLEGAL_PARAMETER.getInfo())
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
/* ---------- 2. 查询是否已存在未支付锁单 ---------- */
|
||||
MarketPayOrderEntity marketPayOrderEntity =
|
||||
tradeOrderService.queryNoPayMarketPayOrderByOutTradeNo(userId, outTradeNo);
|
||||
if (marketPayOrderEntity != null && TradeOrderStatusEnumVO.CREATE.equals(marketPayOrderEntity.getTradeOrderStatusEnumVO())) {
|
||||
// 若已锁单未支付,直接返回原锁单信息(幂等)
|
||||
return buildSuccessResp(marketPayOrderEntity);
|
||||
}
|
||||
|
||||
/* ---------- 3. 拼团目标人数校验 可能前端显示可参与,实际点击之后人数已满 ---------- */
|
||||
//(teamId 不为空表示 参与拼团 )
|
||||
if (StringUtils.isNotBlank(teamId)) {
|
||||
// 查询当前拼团的 目标数量 已完成下单数量 锁单数量
|
||||
GroupBuyProgressVO progress = tradeOrderService.queryGroupBuyProgress(teamId);
|
||||
// 如果目标人数已满,则拒绝本次锁单 目前逻辑是结算完成LockCount也不会减。
|
||||
if (progress != null && Objects.equals(progress.getTargetCount(), progress.getLockCount())) {
|
||||
log.info("交易锁单拦截-拼单目标已达成 userId={} teamId={} target={} lock={}",
|
||||
userId, teamId, progress.getTargetCount(), progress.getLockCount());
|
||||
return Response.<LockMarketPayOrderResponseDTO>builder()
|
||||
.code(ResponseCode.E0006.getCode())
|
||||
.info(ResponseCode.E0006.getInfo())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------- 4. 调用营销服务进行优惠试算 ---------- */
|
||||
TrialBalanceEntity trialBalance = indexGroupBuyMarketService.indexMarketTrial(
|
||||
MarketProductEntity.builder()
|
||||
.userId(userId)
|
||||
.source(source)
|
||||
.channel(channel)
|
||||
.goodsId(goodsId)
|
||||
.activityId(activityId)
|
||||
.build());
|
||||
|
||||
// 人群限定,非目前人群不允许参与活动
|
||||
if (!trialBalance.getIsVisible() || !trialBalance.getIsEnable()){
|
||||
return Response.<LockMarketPayOrderResponseDTO>builder()
|
||||
.code(ResponseCode.E0007.getCode())
|
||||
.info(ResponseCode.E0007.getInfo())
|
||||
.build();
|
||||
}
|
||||
|
||||
//获取拼团活动配置信息
|
||||
GroupBuyActivityDiscountVO discountVO = trialBalance.getGroupBuyActivityDiscountVO();
|
||||
|
||||
/* ---------- 5. 组装领域对象后调用真正的锁单 ---------- */
|
||||
marketPayOrderEntity = tradeOrderService.lockMarketPayOrder(
|
||||
UserEntity.builder().userId(userId).build(),
|
||||
PayActivityEntity.builder()
|
||||
.teamId(teamId)
|
||||
.activityId(activityId)
|
||||
.activityName(discountVO.getActivityName())
|
||||
.startTime(discountVO.getStartTime())
|
||||
.endTime(discountVO.getEndTime())
|
||||
.validTime(discountVO.getValidTime())
|
||||
.targetCount(discountVO.getTarget())
|
||||
.build(),
|
||||
PayDiscountEntity.builder()
|
||||
.source(source)
|
||||
.channel(channel)
|
||||
.goodsId(goodsId)
|
||||
.goodsName(trialBalance.getGoodsName())
|
||||
.originalPrice(trialBalance.getOriginalPrice())
|
||||
.deductionPrice(trialBalance.getDeductionPrice())
|
||||
.payPrice(trialBalance.getPayPrice())
|
||||
.outTradeNo(outTradeNo)
|
||||
.notifyConfigVO(
|
||||
// 构建回调通知对象
|
||||
NotifyConfigVO.builder()
|
||||
.notifyType(NotifyTypeEnumVO.valueOf(notifyConfigVO.getNotifyType()))
|
||||
.notifyMQ(notifyConfigVO.getNotifyMQ())
|
||||
.notifyUrl(notifyConfigVO.getNotifyUrl())
|
||||
.build())
|
||||
.build());
|
||||
|
||||
log.info("交易锁单成功 userId={} order={}", userId, JSON.toJSONString(marketPayOrderEntity));
|
||||
|
||||
/* ---------- 6. 构建成功返回 ---------- */
|
||||
return buildSuccessResp(marketPayOrderEntity);
|
||||
} catch (AppException e) {
|
||||
// 可预期的业务异常(如活动已过期、优惠额度不足等)
|
||||
log.error("拼团交易锁单业务异常 userId={} req={}", lockMarketPayOrderRequestDTO.getUserId(),
|
||||
JSON.toJSONString(lockMarketPayOrderRequestDTO), e);
|
||||
return Response.<LockMarketPayOrderResponseDTO>builder()
|
||||
.code(e.getCode())
|
||||
.info(e.getInfo())
|
||||
.build();
|
||||
} catch (Exception e) {
|
||||
// 系统异常(NPE、RPC 调用失败等)
|
||||
log.error("拼团交易锁单未知错误 userId={} req={}", lockMarketPayOrderRequestDTO.getUserId(),
|
||||
JSON.toJSONString(lockMarketPayOrderRequestDTO), e);
|
||||
return Response.<LockMarketPayOrderResponseDTO>builder()
|
||||
.code(ResponseCode.UN_ERROR.getCode())
|
||||
.info(ResponseCode.UN_ERROR.getInfo())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 拼团交易结算
|
||||
* @param requestDTO 结算商品信息
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Response<SettlementMarketPayOrderResponseDTO> settlementMarketPayOrder(
|
||||
@RequestBody SettlementMarketPayOrderRequestDTO requestDTO) {
|
||||
log.info("营销交易组队结算开始: requestDTO={}", JSON.toJSONString(requestDTO));
|
||||
|
||||
// —— 1. 参数校验 ——
|
||||
if (StringUtils.isAnyBlank(requestDTO.getUserId(), requestDTO.getSource(), requestDTO.getChannel(), requestDTO.getOutTradeNo())
|
||||
|| requestDTO.getOutTradeTime() == null) {
|
||||
return Response.<SettlementMarketPayOrderResponseDTO>builder()
|
||||
.code(ResponseCode.ILLEGAL_PARAMETER.getCode())
|
||||
.info(ResponseCode.ILLEGAL_PARAMETER.getInfo())
|
||||
.build();
|
||||
}
|
||||
|
||||
try {
|
||||
// —— 2. 调用结算服务 ——
|
||||
TradePaySuccessEntity successEntity = new TradePaySuccessEntity();
|
||||
BeanUtils.copyProperties(requestDTO, successEntity);
|
||||
|
||||
//开始结算
|
||||
TradePaySettlementEntity settlement = tradeSettlementOrderService.settlementMarketPayOrder(successEntity);
|
||||
|
||||
// —— 3. 构造返回 DTO ——
|
||||
SettlementMarketPayOrderResponseDTO responseDTO = new SettlementMarketPayOrderResponseDTO();
|
||||
BeanUtils.copyProperties(settlement, responseDTO);
|
||||
|
||||
Response<SettlementMarketPayOrderResponseDTO> resp =
|
||||
Response.<SettlementMarketPayOrderResponseDTO>builder()
|
||||
.code(ResponseCode.SUCCESS.getCode())
|
||||
.info(ResponseCode.SUCCESS.getInfo())
|
||||
.data(responseDTO)
|
||||
.build();
|
||||
|
||||
log.info("营销交易组队结算完成: userId={} outTradeNo={} response={}",
|
||||
requestDTO.getUserId(),
|
||||
requestDTO.getOutTradeNo(),
|
||||
JSON.toJSONString(resp));
|
||||
|
||||
return resp;
|
||||
|
||||
} catch (AppException e) {
|
||||
log.error("营销交易组队结算业务异常: userId={} requestDTO={}",
|
||||
requestDTO.getUserId(),
|
||||
JSON.toJSONString(requestDTO), e);
|
||||
return Response.<SettlementMarketPayOrderResponseDTO>builder()
|
||||
.code(e.getCode())
|
||||
.info(e.getInfo())
|
||||
.build();
|
||||
} catch (Exception e) {
|
||||
log.error("营销交易组队结算失败: userId={} requestDTO={}",
|
||||
requestDTO.getUserId(),
|
||||
JSON.toJSONString(requestDTO), e);
|
||||
return Response.<SettlementMarketPayOrderResponseDTO>builder()
|
||||
.code(ResponseCode.UN_ERROR.getCode())
|
||||
.info(ResponseCode.UN_ERROR.getInfo())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 构建成功响应体,避免重复写样板代码
|
||||
*/
|
||||
private Response<LockMarketPayOrderResponseDTO> buildSuccessResp(MarketPayOrderEntity entity) {
|
||||
return Response.<LockMarketPayOrderResponseDTO>builder()
|
||||
.code(ResponseCode.SUCCESS.getCode())
|
||||
.info(ResponseCode.SUCCESS.getInfo())
|
||||
.data(LockMarketPayOrderResponseDTO.builder()
|
||||
.orderId(entity.getOrderId())
|
||||
.originalPrice(entity.getOriginalPrice())
|
||||
.deductionPrice(entity.getDeductionPrice())
|
||||
.payPrice(entity.getPayPrice())
|
||||
.teamId(entity.getTeamId())
|
||||
.tradeOrderStatus(entity.getTradeOrderStatusEnumVO().getCode())
|
||||
.build())
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户退单接口
|
||||
* @param requestDTO 退单请求信息
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Response<RefundMarketPayOrderResponseDTO> refundMarketPayOrder(@RequestBody RefundMarketPayOrderRequestDTO requestDTO) {
|
||||
try {
|
||||
log.info("营销拼团退单开始:{} outTradeNo:{}", requestDTO.getUserId(), requestDTO.getOutTradeNo());
|
||||
|
||||
if (StringUtils.isBlank(requestDTO.getUserId()) || StringUtils.isBlank(requestDTO.getOutTradeNo()) || StringUtils.isBlank(requestDTO.getSource()) || StringUtils.isBlank(requestDTO.getChannel())) {
|
||||
return Response.<RefundMarketPayOrderResponseDTO>builder()
|
||||
.code(ResponseCode.ILLEGAL_PARAMETER.getCode())
|
||||
.info(ResponseCode.ILLEGAL_PARAMETER.getInfo())
|
||||
.build();
|
||||
}
|
||||
|
||||
// 1. 退单服务
|
||||
TradeRefundBehaviorEntity tradeRefundBehaviorEntity = tradeRefundOrderService.refundOrder(TradeRefundCommandEntity.builder()
|
||||
.userId(requestDTO.getUserId())
|
||||
.outTradeNo(requestDTO.getOutTradeNo())
|
||||
.source(requestDTO.getSource())
|
||||
.channel(requestDTO.getChannel())
|
||||
.build());
|
||||
|
||||
RefundMarketPayOrderResponseDTO responseDTO = RefundMarketPayOrderResponseDTO.builder()
|
||||
.userId(tradeRefundBehaviorEntity.getUserId())
|
||||
.orderId(tradeRefundBehaviorEntity.getOrderId())
|
||||
.teamId(tradeRefundBehaviorEntity.getTeamId())
|
||||
.code(tradeRefundBehaviorEntity.getTradeRefundBehaviorEnum().getCode())
|
||||
.info(tradeRefundBehaviorEntity.getTradeRefundBehaviorEnum().getInfo())
|
||||
.build();
|
||||
|
||||
// 返回结果
|
||||
Response<RefundMarketPayOrderResponseDTO> response = Response.<RefundMarketPayOrderResponseDTO>builder()
|
||||
.code(ResponseCode.SUCCESS.getCode())
|
||||
.info(ResponseCode.SUCCESS.getInfo())
|
||||
.data(responseDTO)
|
||||
.build();
|
||||
|
||||
log.info("营销拼团退单完成:{} outTradeNo:{} response:{}", requestDTO.getUserId(), requestDTO.getOutTradeNo(), JSON.toJSONString(response));
|
||||
|
||||
return response;
|
||||
} catch (AppException e) {
|
||||
log.error("营销拼团退单异常:{} RefundMarketPayOrderRequestDTO:{}", requestDTO.getUserId(), JSON.toJSONString(requestDTO), e);
|
||||
return Response.<RefundMarketPayOrderResponseDTO>builder()
|
||||
.code(e.getCode())
|
||||
.info(e.getInfo())
|
||||
.build();
|
||||
} catch (Exception e) {
|
||||
log.error("营销拼团退单失败:{} RefundMarketPayOrderRequestDTO:{}", requestDTO.getUserId(), JSON.toJSONString(requestDTO), e);
|
||||
return Response.<RefundMarketPayOrderResponseDTO>builder()
|
||||
.code(ResponseCode.UN_ERROR.getCode())
|
||||
.info(ResponseCode.UN_ERROR.getInfo())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
}
|
@ -16,6 +16,7 @@ import edu.whut.domain.trade.model.valobj.TradeOrderStatusEnumVO;
|
||||
import edu.whut.domain.trade.service.ITradeLockOrderService;
|
||||
import edu.whut.domain.trade.service.ITradeRefundOrderService;
|
||||
import edu.whut.domain.trade.service.ITradeSettlementOrderService;
|
||||
import edu.whut.trigger.basic.MarketTradeService;
|
||||
import edu.whut.types.enums.ResponseCode;
|
||||
import edu.whut.types.exception.AppException;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@ -43,147 +44,16 @@ import java.util.Objects;
|
||||
@CrossOrigin("*")
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/api/v1/gbm/trade")
|
||||
public class MarketTradeController implements IMarketTradeService {
|
||||
public class MarketTradeController {
|
||||
|
||||
//价格试算
|
||||
private final IIndexGroupBuyMarketService indexGroupBuyMarketService;
|
||||
//拼团锁单
|
||||
private final ITradeLockOrderService tradeOrderService;
|
||||
//拼团结算
|
||||
private final ITradeSettlementOrderService tradeSettlementOrderService;
|
||||
//退单
|
||||
private final ITradeRefundOrderService tradeRefundOrderService;
|
||||
private final MarketTradeService marketTradeService;
|
||||
|
||||
/**
|
||||
* 锁定营销预支付订单(拼团 / 普通优惠)
|
||||
*/
|
||||
@PostMapping("/lock_market_pay_order")
|
||||
@Override
|
||||
public Response<LockMarketPayOrderResponseDTO> lockMarketPayOrder(@RequestBody LockMarketPayOrderRequestDTO lockMarketPayOrderRequestDTO) {
|
||||
try {
|
||||
/* ---------- 1. 基础参数提取与校验 ---------- */
|
||||
String userId = lockMarketPayOrderRequestDTO.getUserId();
|
||||
String source = lockMarketPayOrderRequestDTO.getSource();
|
||||
String channel = lockMarketPayOrderRequestDTO.getChannel();
|
||||
String goodsId = lockMarketPayOrderRequestDTO.getGoodsId();
|
||||
Long activityId = lockMarketPayOrderRequestDTO.getActivityId();
|
||||
String outTradeNo = lockMarketPayOrderRequestDTO.getOutTradeNo();
|
||||
String teamId = lockMarketPayOrderRequestDTO.getTeamId(); //可为空,对应参与拼团or创建拼团
|
||||
LockMarketPayOrderRequestDTO.NotifyConfigVO notifyConfigVO = lockMarketPayOrderRequestDTO.getNotifyConfigVO();
|
||||
|
||||
log.info("营销锁单开始执行:拼团交易锁单入参 userId={} req={}", userId, JSON.toJSONString(lockMarketPayOrderRequestDTO));
|
||||
|
||||
// 空值校验(任何一个关键字段为空则直接返回错误)
|
||||
boolean httpWithoutUrl =
|
||||
"HTTP".equals(notifyConfigVO.getNotifyType())
|
||||
&& StringUtils.isBlank(notifyConfigVO.getNotifyUrl());
|
||||
|
||||
if (StringUtils.isAnyBlank(userId, source, channel, goodsId)
|
||||
|| activityId == null
|
||||
|| httpWithoutUrl) {
|
||||
return Response.<LockMarketPayOrderResponseDTO>builder()
|
||||
.code(ResponseCode.ILLEGAL_PARAMETER.getCode())
|
||||
.info(ResponseCode.ILLEGAL_PARAMETER.getInfo())
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
/* ---------- 2. 查询是否已存在未支付锁单 ---------- */
|
||||
MarketPayOrderEntity marketPayOrderEntity =
|
||||
tradeOrderService.queryNoPayMarketPayOrderByOutTradeNo(userId, outTradeNo);
|
||||
if (marketPayOrderEntity != null && TradeOrderStatusEnumVO.CREATE.equals(marketPayOrderEntity.getTradeOrderStatusEnumVO())) {
|
||||
// 若已锁单未支付,直接返回原锁单信息(幂等)
|
||||
return buildSuccessResp(marketPayOrderEntity);
|
||||
}
|
||||
|
||||
/* ---------- 3. 拼团目标人数校验 可能前端显示可参与,实际点击之后人数已满 ---------- */
|
||||
//(teamId 不为空表示 参与拼团 )
|
||||
if (StringUtils.isNotBlank(teamId)) {
|
||||
// 查询当前拼团的 目标数量 已完成下单数量 锁单数量
|
||||
GroupBuyProgressVO progress = tradeOrderService.queryGroupBuyProgress(teamId);
|
||||
// 如果目标人数已满,则拒绝本次锁单 目前逻辑是结算完成LockCount也不会减。
|
||||
if (progress != null && Objects.equals(progress.getTargetCount(), progress.getLockCount())) {
|
||||
log.info("交易锁单拦截-拼单目标已达成 userId={} teamId={} target={} lock={}",
|
||||
userId, teamId, progress.getTargetCount(), progress.getLockCount());
|
||||
return Response.<LockMarketPayOrderResponseDTO>builder()
|
||||
.code(ResponseCode.E0006.getCode())
|
||||
.info(ResponseCode.E0006.getInfo())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------- 4. 调用营销服务进行优惠试算 ---------- */
|
||||
TrialBalanceEntity trialBalance = indexGroupBuyMarketService.indexMarketTrial(
|
||||
MarketProductEntity.builder()
|
||||
.userId(userId)
|
||||
.source(source)
|
||||
.channel(channel)
|
||||
.goodsId(goodsId)
|
||||
.activityId(activityId)
|
||||
.build());
|
||||
|
||||
// 人群限定,非目前人群不允许参与活动
|
||||
if (!trialBalance.getIsVisible() || !trialBalance.getIsEnable()){
|
||||
return Response.<LockMarketPayOrderResponseDTO>builder()
|
||||
.code(ResponseCode.E0007.getCode())
|
||||
.info(ResponseCode.E0007.getInfo())
|
||||
.build();
|
||||
}
|
||||
|
||||
//获取拼团活动配置信息
|
||||
GroupBuyActivityDiscountVO discountVO = trialBalance.getGroupBuyActivityDiscountVO();
|
||||
|
||||
/* ---------- 5. 组装领域对象后调用真正的锁单 ---------- */
|
||||
marketPayOrderEntity = tradeOrderService.lockMarketPayOrder(
|
||||
UserEntity.builder().userId(userId).build(),
|
||||
PayActivityEntity.builder()
|
||||
.teamId(teamId)
|
||||
.activityId(activityId)
|
||||
.activityName(discountVO.getActivityName())
|
||||
.startTime(discountVO.getStartTime())
|
||||
.endTime(discountVO.getEndTime())
|
||||
.validTime(discountVO.getValidTime())
|
||||
.targetCount(discountVO.getTarget())
|
||||
.build(),
|
||||
PayDiscountEntity.builder()
|
||||
.source(source)
|
||||
.channel(channel)
|
||||
.goodsId(goodsId)
|
||||
.goodsName(trialBalance.getGoodsName())
|
||||
.originalPrice(trialBalance.getOriginalPrice())
|
||||
.deductionPrice(trialBalance.getDeductionPrice())
|
||||
.payPrice(trialBalance.getPayPrice())
|
||||
.outTradeNo(outTradeNo)
|
||||
.notifyConfigVO(
|
||||
// 构建回调通知对象
|
||||
NotifyConfigVO.builder()
|
||||
.notifyType(NotifyTypeEnumVO.valueOf(notifyConfigVO.getNotifyType()))
|
||||
.notifyMQ(notifyConfigVO.getNotifyMQ())
|
||||
.notifyUrl(notifyConfigVO.getNotifyUrl())
|
||||
.build())
|
||||
.build());
|
||||
|
||||
log.info("交易锁单成功 userId={} order={}", userId, JSON.toJSONString(marketPayOrderEntity));
|
||||
|
||||
/* ---------- 6. 构建成功返回 ---------- */
|
||||
return buildSuccessResp(marketPayOrderEntity);
|
||||
} catch (AppException e) {
|
||||
// 可预期的业务异常(如活动已过期、优惠额度不足等)
|
||||
log.error("拼团交易锁单业务异常 userId={} req={}", lockMarketPayOrderRequestDTO.getUserId(),
|
||||
JSON.toJSONString(lockMarketPayOrderRequestDTO), e);
|
||||
return Response.<LockMarketPayOrderResponseDTO>builder()
|
||||
.code(e.getCode())
|
||||
.info(e.getInfo())
|
||||
.build();
|
||||
} catch (Exception e) {
|
||||
// 系统异常(NPE、RPC 调用失败等)
|
||||
log.error("拼团交易锁单未知错误 userId={} req={}", lockMarketPayOrderRequestDTO.getUserId(),
|
||||
JSON.toJSONString(lockMarketPayOrderRequestDTO), e);
|
||||
return Response.<LockMarketPayOrderResponseDTO>builder()
|
||||
.code(ResponseCode.UN_ERROR.getCode())
|
||||
.info(ResponseCode.UN_ERROR.getInfo())
|
||||
.build();
|
||||
}
|
||||
return marketTradeService.lockMarketPayOrder(lockMarketPayOrderRequestDTO);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -192,140 +62,18 @@ public class MarketTradeController implements IMarketTradeService {
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/settlement_market_pay_order")
|
||||
@Override
|
||||
public Response<SettlementMarketPayOrderResponseDTO> settlementMarketPayOrder(
|
||||
@RequestBody SettlementMarketPayOrderRequestDTO requestDTO) {
|
||||
log.info("营销交易组队结算开始: requestDTO={}", JSON.toJSONString(requestDTO));
|
||||
|
||||
// —— 1. 参数校验 ——
|
||||
if (StringUtils.isAnyBlank(requestDTO.getUserId(), requestDTO.getSource(), requestDTO.getChannel(), requestDTO.getOutTradeNo())
|
||||
|| requestDTO.getOutTradeTime() == null) {
|
||||
return Response.<SettlementMarketPayOrderResponseDTO>builder()
|
||||
.code(ResponseCode.ILLEGAL_PARAMETER.getCode())
|
||||
.info(ResponseCode.ILLEGAL_PARAMETER.getInfo())
|
||||
.build();
|
||||
public Response<SettlementMarketPayOrderResponseDTO> settlementMarketPayOrder(@RequestBody SettlementMarketPayOrderRequestDTO requestDTO) {
|
||||
return marketTradeService.settlementMarketPayOrder(requestDTO);
|
||||
}
|
||||
|
||||
try {
|
||||
// —— 2. 调用结算服务 ——
|
||||
TradePaySuccessEntity successEntity = new TradePaySuccessEntity();
|
||||
BeanUtils.copyProperties(requestDTO, successEntity);
|
||||
|
||||
//开始结算
|
||||
TradePaySettlementEntity settlement = tradeSettlementOrderService.settlementMarketPayOrder(successEntity);
|
||||
|
||||
// —— 3. 构造返回 DTO ——
|
||||
SettlementMarketPayOrderResponseDTO responseDTO = new SettlementMarketPayOrderResponseDTO();
|
||||
BeanUtils.copyProperties(settlement, responseDTO);
|
||||
|
||||
Response<SettlementMarketPayOrderResponseDTO> resp =
|
||||
Response.<SettlementMarketPayOrderResponseDTO>builder()
|
||||
.code(ResponseCode.SUCCESS.getCode())
|
||||
.info(ResponseCode.SUCCESS.getInfo())
|
||||
.data(responseDTO)
|
||||
.build();
|
||||
|
||||
log.info("营销交易组队结算完成: userId={} outTradeNo={} response={}",
|
||||
requestDTO.getUserId(),
|
||||
requestDTO.getOutTradeNo(),
|
||||
JSON.toJSONString(resp));
|
||||
|
||||
return resp;
|
||||
|
||||
} catch (AppException e) {
|
||||
log.error("营销交易组队结算业务异常: userId={} requestDTO={}",
|
||||
requestDTO.getUserId(),
|
||||
JSON.toJSONString(requestDTO), e);
|
||||
return Response.<SettlementMarketPayOrderResponseDTO>builder()
|
||||
.code(e.getCode())
|
||||
.info(e.getInfo())
|
||||
.build();
|
||||
} catch (Exception e) {
|
||||
log.error("营销交易组队结算失败: userId={} requestDTO={}",
|
||||
requestDTO.getUserId(),
|
||||
JSON.toJSONString(requestDTO), e);
|
||||
return Response.<SettlementMarketPayOrderResponseDTO>builder()
|
||||
.code(ResponseCode.UN_ERROR.getCode())
|
||||
.info(ResponseCode.UN_ERROR.getInfo())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 构建成功响应体,避免重复写样板代码
|
||||
*/
|
||||
private Response<LockMarketPayOrderResponseDTO> buildSuccessResp(MarketPayOrderEntity entity) {
|
||||
return Response.<LockMarketPayOrderResponseDTO>builder()
|
||||
.code(ResponseCode.SUCCESS.getCode())
|
||||
.info(ResponseCode.SUCCESS.getInfo())
|
||||
.data(LockMarketPayOrderResponseDTO.builder()
|
||||
.orderId(entity.getOrderId())
|
||||
.originalPrice(entity.getOriginalPrice())
|
||||
.deductionPrice(entity.getDeductionPrice())
|
||||
.payPrice(entity.getPayPrice())
|
||||
.teamId(entity.getTeamId())
|
||||
.tradeOrderStatus(entity.getTradeOrderStatusEnumVO().getCode())
|
||||
.build())
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户退单接口
|
||||
* @param requestDTO 退单请求信息
|
||||
* @return
|
||||
*/
|
||||
@RequestMapping(value = "refund_market_pay_order", method = RequestMethod.POST)
|
||||
@Override
|
||||
@PostMapping("/refund_market_pay_order")
|
||||
public Response<RefundMarketPayOrderResponseDTO> refundMarketPayOrder(@RequestBody RefundMarketPayOrderRequestDTO requestDTO) {
|
||||
try {
|
||||
log.info("营销拼团退单开始:{} outTradeNo:{}", requestDTO.getUserId(), requestDTO.getOutTradeNo());
|
||||
|
||||
if (StringUtils.isBlank(requestDTO.getUserId()) || StringUtils.isBlank(requestDTO.getOutTradeNo()) || StringUtils.isBlank(requestDTO.getSource()) || StringUtils.isBlank(requestDTO.getChannel())) {
|
||||
return Response.<RefundMarketPayOrderResponseDTO>builder()
|
||||
.code(ResponseCode.ILLEGAL_PARAMETER.getCode())
|
||||
.info(ResponseCode.ILLEGAL_PARAMETER.getInfo())
|
||||
.build();
|
||||
}
|
||||
|
||||
// 1. 退单服务
|
||||
TradeRefundBehaviorEntity tradeRefundBehaviorEntity = tradeRefundOrderService.refundOrder(TradeRefundCommandEntity.builder()
|
||||
.userId(requestDTO.getUserId())
|
||||
.outTradeNo(requestDTO.getOutTradeNo())
|
||||
.source(requestDTO.getSource())
|
||||
.channel(requestDTO.getChannel())
|
||||
.build());
|
||||
|
||||
RefundMarketPayOrderResponseDTO responseDTO = RefundMarketPayOrderResponseDTO.builder()
|
||||
.userId(tradeRefundBehaviorEntity.getUserId())
|
||||
.orderId(tradeRefundBehaviorEntity.getOrderId())
|
||||
.teamId(tradeRefundBehaviorEntity.getTeamId())
|
||||
.code(tradeRefundBehaviorEntity.getTradeRefundBehaviorEnum().getCode())
|
||||
.info(tradeRefundBehaviorEntity.getTradeRefundBehaviorEnum().getInfo())
|
||||
.build();
|
||||
|
||||
// 返回结果
|
||||
Response<RefundMarketPayOrderResponseDTO> response = Response.<RefundMarketPayOrderResponseDTO>builder()
|
||||
.code(ResponseCode.SUCCESS.getCode())
|
||||
.info(ResponseCode.SUCCESS.getInfo())
|
||||
.data(responseDTO)
|
||||
.build();
|
||||
|
||||
log.info("营销拼团退单完成:{} outTradeNo:{} response:{}", requestDTO.getUserId(), requestDTO.getOutTradeNo(), JSON.toJSONString(response));
|
||||
|
||||
return response;
|
||||
} catch (AppException e) {
|
||||
log.error("营销拼团退单异常:{} RefundMarketPayOrderRequestDTO:{}", requestDTO.getUserId(), JSON.toJSONString(requestDTO), e);
|
||||
return Response.<RefundMarketPayOrderResponseDTO>builder()
|
||||
.code(e.getCode())
|
||||
.info(e.getInfo())
|
||||
.build();
|
||||
} catch (Exception e) {
|
||||
log.error("营销拼团退单失败:{} RefundMarketPayOrderRequestDTO:{}", requestDTO.getUserId(), JSON.toJSONString(requestDTO), e);
|
||||
return Response.<RefundMarketPayOrderResponseDTO>builder()
|
||||
.code(ResponseCode.UN_ERROR.getCode())
|
||||
.info(ResponseCode.UN_ERROR.getInfo())
|
||||
.build();
|
||||
}
|
||||
return marketTradeService.refundMarketPayOrder(requestDTO);
|
||||
}
|
||||
}
|
||||
|
@ -3,31 +3,29 @@ package edu.whut.trigger.rpc;
|
||||
import edu.whut.api.IMarketTradeService;
|
||||
import edu.whut.api.dto.*;
|
||||
import edu.whut.api.response.Response;
|
||||
import edu.whut.trigger.http.MarketTradeController;
|
||||
import edu.whut.trigger.basic.MarketTradeService;
|
||||
import org.apache.dubbo.config.annotation.DubboService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
|
||||
@DubboService(version = "1.0.0") // 关键注解
|
||||
@RequiredArgsConstructor
|
||||
public class MarketTradeDubboService implements IMarketTradeService {
|
||||
public class MarketTradeDubboService {
|
||||
|
||||
private final MarketTradeController delegate; // 复用现有业务
|
||||
private final MarketTradeService marketTradeService; // 复用现有业务
|
||||
|
||||
@Override
|
||||
public Response<LockMarketPayOrderResponseDTO> lockMarketPayOrder(
|
||||
LockMarketPayOrderRequestDTO dto) {
|
||||
return delegate.lockMarketPayOrder(dto); // 直接委托原 Controller 逻辑
|
||||
return marketTradeService.lockMarketPayOrder(dto); // 直接委托原 Controller 逻辑
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response<SettlementMarketPayOrderResponseDTO> settlementMarketPayOrder(
|
||||
SettlementMarketPayOrderRequestDTO dto) {
|
||||
return delegate.settlementMarketPayOrder(dto);
|
||||
return marketTradeService.settlementMarketPayOrder(dto);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response<RefundMarketPayOrderResponseDTO> refundMarketPayOrder(
|
||||
RefundMarketPayOrderRequestDTO dto) {
|
||||
return delegate.refundMarketPayOrder(dto);
|
||||
return marketTradeService.refundMarketPayOrder(dto);
|
||||
}
|
||||
}
|
||||
|
@ -7,46 +7,46 @@ import lombok.EqualsAndHashCode;
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class AppException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 5317680961212299217L;
|
||||
|
||||
/** 异常码 */
|
||||
private String code;
|
||||
|
||||
/** 异常信息 */
|
||||
private String info;
|
||||
private final String code;
|
||||
private final String info;
|
||||
|
||||
public AppException(String code) {
|
||||
super(code); // 至少给个非空 message
|
||||
this.code = code;
|
||||
this.info = null;
|
||||
}
|
||||
|
||||
public AppException(ResponseCode responseCode) {
|
||||
this.code = responseCode.getCode();
|
||||
this.info = responseCode.getInfo();
|
||||
public AppException(ResponseCode rc) {
|
||||
super(rc.getInfo()); // 关键:作为 Throwable 的 message
|
||||
this.code = rc.getCode();
|
||||
this.info = rc.getInfo();
|
||||
}
|
||||
|
||||
public AppException(String code, Throwable cause) {
|
||||
super(code, cause); // 用父类带 cause 的构造器
|
||||
this.code = code;
|
||||
super.initCause(cause);
|
||||
this.info = null;
|
||||
}
|
||||
|
||||
public AppException(String code, String message) {
|
||||
super(message);
|
||||
this.code = code;
|
||||
this.info = message;
|
||||
}
|
||||
|
||||
public AppException(String code, String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
this.code = code;
|
||||
this.info = message;
|
||||
super.initCause(cause);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "edu.whut.types.exception.AppException{" +
|
||||
"code='" + code + '\'' +
|
||||
", info='" + info + '\'' +
|
||||
'}';
|
||||
@Override public String getMessage() {
|
||||
return (info != null) ? info : super.getMessage();
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
return "AppException{code='" + code + "', info='" + info + "'}";
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user