You've already forked FrameTour-BE
订单支付
This commit is contained in:
@@ -56,6 +56,8 @@ import com.ycwl.basic.utils.SnowFlakeUtil;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.annotation.Scope;
|
||||||
|
import org.springframework.context.annotation.ScopedProxyMode;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
@@ -76,10 +78,14 @@ import java.util.stream.Collectors;
|
|||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
|
@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
|
||||||
public class OrderServiceImpl implements OrderService {
|
public class OrderServiceImpl implements OrderService {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private OrderMapper orderMapper;
|
private OrderMapper orderMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private OrderServiceImpl self;
|
||||||
@Autowired
|
@Autowired
|
||||||
private SourceMapper sourceMapper;
|
private SourceMapper sourceMapper;
|
||||||
@Autowired
|
@Autowired
|
||||||
@@ -493,110 +499,154 @@ public class OrderServiceImpl implements OrderService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
|
||||||
public ApiResponse<Map<String, Object>> createOrder(Long userId, CreateOrderReqVO createOrderReqVO) throws Exception {
|
public ApiResponse<Map<String, Object>> createOrder(Long userId, CreateOrderReqVO createOrderReqVO) throws Exception {
|
||||||
IsBuyRespVO isBuy = orderBiz.isBuy(userId, createOrderReqVO.getScenicId(), createOrderReqVO.getGoodsType(), createOrderReqVO.getGoodsId());
|
// 防重复提交检查:基于用户ID、景区ID、商品类型、商品ID生成唯一键
|
||||||
if (isBuy.isBuy()) {
|
String orderKey = String.format("createOrder:%d:%d:%d:%d",
|
||||||
return ApiResponse.fail("您已购买此内容,无需重复购买!");
|
userId, createOrderReqVO.getScenicId(),
|
||||||
}
|
createOrderReqVO.getGoodsType(), createOrderReqVO.getGoodsId());
|
||||||
// 看看有没有之前购买的订单
|
|
||||||
OrderEntity order = orderMapper.getUserOrderItem(userId, createOrderReqVO.getScenicId(), 0, null, createOrderReqVO.getGoodsType(), createOrderReqVO.getGoodsId());
|
|
||||||
boolean haveOldOrder = order != null;
|
|
||||||
if (order != null) {
|
|
||||||
if (order.getStatus() != OrderStateEnum.PAID.getState() && order.getStatus() != OrderStateEnum.UNPAID.getState()) {
|
|
||||||
haveOldOrder = false;
|
|
||||||
}
|
|
||||||
if (!DateUtil.isSameDay(order.getCreateAt(), new Date())) {
|
|
||||||
haveOldOrder = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!haveOldOrder) {
|
|
||||||
order = new OrderEntity();
|
|
||||||
order.setId(SnowFlakeUtil.getLongId());
|
|
||||||
order.setMemberId(userId);
|
|
||||||
MemberRespVO member = memberMapper.getById(userId);
|
|
||||||
order.setOpenId(member.getOpenId());
|
|
||||||
order.setScenicId(createOrderReqVO.getScenicId());
|
|
||||||
|
|
||||||
PriceObj priceObj = orderBiz.queryPrice(order.getScenicId(), createOrderReqVO.getGoodsType(), createOrderReqVO.getGoodsId());
|
// 使用synchronized确保同一用户对同一商品的订单创建操作串行化
|
||||||
order.setSlashPrice(priceObj.getSlashPrice());
|
synchronized (orderKey.intern()) {
|
||||||
order.setPrice(priceObj.getPrice());
|
IsBuyRespVO isBuy = orderBiz.isBuy(userId, createOrderReqVO.getScenicId(), createOrderReqVO.getGoodsType(), createOrderReqVO.getGoodsId());
|
||||||
// 判断是否是本人数据
|
if (isBuy.isBuy()) {
|
||||||
FaceEntity goodsFace = faceRepository.getFace(priceObj.getFaceId());
|
return ApiResponse.fail("您已购买此内容,无需重复购买!");
|
||||||
if (goodsFace != null && !goodsFace.getMemberId().equals(userId)) {
|
|
||||||
return ApiResponse.fail("您无权购买此内容!");
|
|
||||||
}
|
}
|
||||||
// promo code
|
// 看看有没有之前购买的订单
|
||||||
order.setPayPrice(priceObj.getPrice());
|
OrderEntity order = orderMapper.getUserOrderItem(userId, createOrderReqVO.getScenicId(), 0, null, createOrderReqVO.getGoodsType(), createOrderReqVO.getGoodsId());
|
||||||
order.setFaceId(priceObj.getFaceId());
|
boolean haveOldOrder = false;
|
||||||
if (order.getPayPrice().equals(BigDecimal.ZERO)) {
|
if (order != null) {
|
||||||
order.setStatus(OrderStateEnum.PAID.getState());
|
// 如果订单已支付,直接返回错误,不允许重复购买
|
||||||
order.setPayAt(new Date());
|
if (order.getStatus() == OrderStateEnum.PAID.getState()) {
|
||||||
} else {
|
return ApiResponse.fail("您已购买此内容,无需重复购买!");
|
||||||
order.setStatus(OrderStateEnum.UNPAID.getState());
|
}
|
||||||
|
// 只有未支付的订单才允许复用
|
||||||
|
if (order.getStatus() == OrderStateEnum.UNPAID.getState()
|
||||||
|
&& DateUtil.isSameDay(order.getCreateAt(), new Date())) {
|
||||||
|
haveOldOrder = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
if (!haveOldOrder) {
|
||||||
// coupon
|
order = new OrderEntity();
|
||||||
CouponRecordQueryResp couponRecord = null;
|
order.setId(SnowFlakeUtil.getLongId());
|
||||||
switch (createOrderReqVO.getGoodsType()) {
|
order.setMemberId(userId);
|
||||||
case 0: // vlog
|
MemberRespVO member = memberMapper.getById(userId);
|
||||||
VideoEntity video = videoRepository.getVideo(createOrderReqVO.getGoodsId());
|
order.setOpenId(member.getOpenId());
|
||||||
TaskEntity taskById = videoTaskRepository.getTaskById(video.getTaskId());
|
order.setScenicId(createOrderReqVO.getScenicId());
|
||||||
if (taskById != null) {
|
|
||||||
couponRecord = couponBiz.queryUserCouponRecord(order.getScenicId(), userId, order.getFaceId(), taskById.getTemplateId().toString());
|
PriceObj priceObj = orderBiz.queryPrice(order.getScenicId(), createOrderReqVO.getGoodsType(), createOrderReqVO.getGoodsId());
|
||||||
|
order.setSlashPrice(priceObj.getSlashPrice());
|
||||||
|
order.setPrice(priceObj.getPrice());
|
||||||
|
// 判断是否是本人数据
|
||||||
|
FaceEntity goodsFace = faceRepository.getFace(priceObj.getFaceId());
|
||||||
|
if (goodsFace != null && !goodsFace.getMemberId().equals(userId)) {
|
||||||
|
return ApiResponse.fail("您无权购买此内容!");
|
||||||
}
|
}
|
||||||
break;
|
// promo code
|
||||||
case 1:
|
order.setPayPrice(priceObj.getPrice());
|
||||||
case 2:
|
order.setFaceId(priceObj.getFaceId());
|
||||||
couponRecord = couponBiz.queryUserCouponRecord(order.getScenicId(), userId, order.getFaceId(), String.valueOf(createOrderReqVO.getGoodsType()));
|
if (order.getPayPrice().equals(BigDecimal.ZERO)) {
|
||||||
break;
|
order.setStatus(OrderStateEnum.PAID.getState());
|
||||||
}
|
order.setPayAt(new Date());
|
||||||
order.setCouponPrice(BigDecimal.ZERO);
|
} else {
|
||||||
order.setCouponRecordId(null);
|
order.setStatus(OrderStateEnum.UNPAID.getState());
|
||||||
order.setCouponId(null);
|
}
|
||||||
if (couponRecord != null) {
|
}
|
||||||
if (couponRecord.isUsable()) {
|
|
||||||
log.info("优惠券可用,优惠券记录ID:{},优惠券ID:{}", couponRecord.getId(), couponRecord.getCouponId());
|
// 只有新订单才计算优惠券,避免重复处理
|
||||||
order.setCouponId(couponRecord.getCouponId());
|
if (!haveOldOrder) {
|
||||||
order.setCouponRecordId(couponRecord.getId());
|
// coupon
|
||||||
order.setCouponPrice(couponRecord.getCoupon().calculateDiscountPrice(order.getPrice()));
|
CouponRecordQueryResp couponRecord = null;
|
||||||
order.setPayPrice(order.getPayPrice().subtract(order.getCouponPrice()));
|
switch (createOrderReqVO.getGoodsType()) {
|
||||||
if (order.getPayPrice().compareTo(BigDecimal.ZERO) < NumberConstant.ZERO) {
|
case 0: // vlog
|
||||||
// 至少需要支付0.01
|
VideoEntity video = videoRepository.getVideo(createOrderReqVO.getGoodsId());
|
||||||
order.setPayPrice(BigDecimal.valueOf(0.01));
|
TaskEntity taskById = videoTaskRepository.getTaskById(video.getTaskId());
|
||||||
|
if (taskById != null) {
|
||||||
|
couponRecord = couponBiz.queryUserCouponRecord(order.getScenicId(), userId, order.getFaceId(), taskById.getTemplateId().toString());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
couponRecord = couponBiz.queryUserCouponRecord(order.getScenicId(), userId, order.getFaceId(), String.valueOf(createOrderReqVO.getGoodsType()));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
log.info("优惠券不可用,优惠券记录ID:{},优惠券ID:{}", couponRecord.getId(), couponRecord.getCouponId());
|
|
||||||
order.setCouponId(null);
|
|
||||||
order.setCouponRecordId(null);
|
|
||||||
order.setCouponPrice(BigDecimal.ZERO);
|
order.setCouponPrice(BigDecimal.ZERO);
|
||||||
|
order.setCouponRecordId(null);
|
||||||
|
order.setCouponId(null);
|
||||||
|
if (couponRecord != null) {
|
||||||
|
if (couponRecord.isUsable()) {
|
||||||
|
log.info("优惠券可用,优惠券记录ID:{},优惠券ID:{}", couponRecord.getId(), couponRecord.getCouponId());
|
||||||
|
order.setCouponId(couponRecord.getCouponId());
|
||||||
|
order.setCouponRecordId(couponRecord.getId());
|
||||||
|
order.setCouponPrice(couponRecord.getCoupon().calculateDiscountPrice(order.getPrice()));
|
||||||
|
order.setPayPrice(order.getPayPrice().subtract(order.getCouponPrice()));
|
||||||
|
if (order.getPayPrice().compareTo(BigDecimal.ZERO) < NumberConstant.ZERO) {
|
||||||
|
// 至少需要支付0.01
|
||||||
|
order.setPayPrice(BigDecimal.valueOf(0.01));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.info("优惠券不可用,优惠券记录ID:{},优惠券ID:{}", couponRecord.getId(), couponRecord.getCouponId());
|
||||||
|
order.setCouponId(null);
|
||||||
|
order.setCouponRecordId(null);
|
||||||
|
order.setCouponPrice(BigDecimal.ZERO);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
List<OrderItemEntity> orderItems = new ArrayList<>();
|
||||||
List<OrderItemEntity> orderItems = new ArrayList<>();
|
OrderItemEntity orderItem = new OrderItemEntity();
|
||||||
OrderItemEntity orderItem = new OrderItemEntity();
|
orderItem.setGoodsId(createOrderReqVO.getGoodsId());
|
||||||
orderItem.setGoodsId(createOrderReqVO.getGoodsId());
|
orderItem.setGoodsType(createOrderReqVO.getGoodsType());
|
||||||
orderItem.setGoodsType(createOrderReqVO.getGoodsType());
|
orderItem.setOrderId(order.getId());
|
||||||
orderItem.setOrderId(order.getId());
|
orderItems.add(orderItem);
|
||||||
orderItems.add(orderItem);
|
// 在事务中保存订单数据
|
||||||
|
try {
|
||||||
|
self.saveOrderInTransaction(order, orderItems, haveOldOrder);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("保存订单失败", e);
|
||||||
|
return ApiResponse.fail("订单创建失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断是否需要支付(事务外处理)
|
||||||
|
if (order.getPayPrice().compareTo(BigDecimal.ZERO) <= 0) {
|
||||||
|
// 只有新创建的订单才需要执行支付完成逻辑
|
||||||
|
if (!haveOldOrder) {
|
||||||
|
try {
|
||||||
|
orderBiz.paidOrder(order.getId());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("处理免费订单失败", e);
|
||||||
|
return ApiResponse.fail("订单处理失败");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
HashMap<String, Object> data = new HashMap<>();
|
||||||
|
data.put("needPay", false);
|
||||||
|
return ApiResponse.success(data);
|
||||||
|
} else {
|
||||||
|
// 发起支付(事务外调用外部服务)
|
||||||
|
try {
|
||||||
|
Map<String, Object> wxPayRespVO = initiatePayment(order, orderItems);
|
||||||
|
return ApiResponse.success(wxPayRespVO);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("发起支付失败", e);
|
||||||
|
return ApiResponse.fail("支付发起失败,请重试");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // synchronized 块结束
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在事务中保存订单数据
|
||||||
|
*/
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
protected void saveOrderInTransaction(OrderEntity order, List<OrderItemEntity> orderItems, boolean haveOldOrder) {
|
||||||
if (!haveOldOrder) {
|
if (!haveOldOrder) {
|
||||||
orderMapper.add(order);
|
orderMapper.add(order);
|
||||||
int addOrderItems = orderMapper.addOrderItems(orderItems);
|
int addOrderItems = orderMapper.addOrderItems(orderItems);
|
||||||
if (addOrderItems == NumberConstant.ZERO) {
|
if (addOrderItems == NumberConstant.ZERO) {
|
||||||
log.error("订单明细添加失败");
|
throw new RuntimeException("订单明细添加失败");
|
||||||
return ApiResponse.fail("订单添加失败");
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// 对于旧订单,只更新价格相关字段,不重复处理业务逻辑
|
||||||
orderMapper.updateOrderPrice(order);
|
orderMapper.updateOrderPrice(order);
|
||||||
}
|
}
|
||||||
if (order.getPayPrice().compareTo(BigDecimal.ZERO) <= 0) {
|
|
||||||
orderBiz.paidOrder(order.getId());
|
|
||||||
HashMap<String, Object> data = new HashMap<>();
|
|
||||||
data.put("needPay", false);
|
|
||||||
return ApiResponse.success(data);
|
|
||||||
} else {
|
|
||||||
Map<String, Object> wxPayRespVO = initiatePayment(order, orderItems);
|
|
||||||
return ApiResponse.success(wxPayRespVO);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
Reference in New Issue
Block a user