You've already forked FrameTour-BE
feat(printer): 扩展虚拟订单功能支持实际支付模式
- 修改CreateVirtualOrderRequest添加needActualPayment字段 - 更新SourceController接口方法签名以传递实际支付参数 - 在PrinterServiceImpl中实现两种订单模式:0元立即购买和待支付订单 - 添加价格计算逻辑,支持通过价格计算服务获取真实价格 - 实现微信Native支付集成,为待支付订单生成支付二维码 - 添加Redis临时存储机制,用于支付完成后恢复needEnhance配置 - 更新createVirtualOrder方法重载,支持完整的参数组合 - 添加详细的日志记录以便跟踪订单创建和支付状态变化
This commit is contained in:
@@ -53,8 +53,9 @@ public class SourceController {
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建虚拟用户0元订单
|
||||
* 创建虚拟用户订单
|
||||
* 用于后台直接从source创建订单,不需要真实用户
|
||||
* 支持立即0元购买或创建待支付订单(由needActualPayment控制)
|
||||
*
|
||||
* @param request 请求参数
|
||||
* @return 订单信息
|
||||
@@ -67,7 +68,8 @@ public class SourceController {
|
||||
request.getScenicId(),
|
||||
request.getPrinterId(),
|
||||
request.getNeedEnhance(),
|
||||
request.getPrintImgUrl()
|
||||
request.getPrintImgUrl(),
|
||||
request.getNeedActualPayment()
|
||||
);
|
||||
return ApiResponse.success(result);
|
||||
} catch (Exception e) {
|
||||
|
||||
@@ -31,4 +31,11 @@ public class CreateVirtualOrderRequest {
|
||||
* 打印图片URL(可选,如果提供则使用此URL进行打印)
|
||||
*/
|
||||
private String printImgUrl;
|
||||
|
||||
/**
|
||||
* 是否需要实际支付(可选,默认false)
|
||||
* false/null: 创建0元虚拟订单,立即完成购买
|
||||
* true: 创建待支付订单(计算实际价格),由前端处理支付流程
|
||||
*/
|
||||
private Boolean needActualPayment;
|
||||
}
|
||||
|
||||
@@ -144,6 +144,19 @@ public interface PrinterService {
|
||||
*/
|
||||
Map<String, Object> createVirtualOrder(Long sourceId, Long scenicId, Integer printerId, Boolean needEnhance, String printImgUrl);
|
||||
|
||||
/**
|
||||
* 创建虚拟用户订单(支持实际支付模式)
|
||||
*
|
||||
* @param sourceId source记录ID
|
||||
* @param scenicId 景区ID
|
||||
* @param printerId 打印机ID(可选)
|
||||
* @param needEnhance 是否需要图像增强(可选)
|
||||
* @param printImgUrl 打印图片URL(可选)
|
||||
* @param needActualPayment 是否需要实际支付(true: 创建待支付订单, false/null: 0元立即购买)
|
||||
* @return 订单信息
|
||||
*/
|
||||
Map<String, Object> createVirtualOrder(Long sourceId, Long scenicId, Integer printerId, Boolean needEnhance, String printImgUrl, Boolean needActualPayment);
|
||||
|
||||
/**
|
||||
* 根据accessKey获取打印机详情
|
||||
* @param accessKey 打印机accessKey
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
package com.ycwl.basic.service.printer.impl;
|
||||
|
||||
import com.wechat.pay.java.service.payments.nativepay.NativePayService;
|
||||
import com.wechat.pay.java.service.payments.nativepay.model.Amount;
|
||||
import com.wechat.pay.java.service.payments.nativepay.model.PrepayRequest;
|
||||
import com.wechat.pay.java.service.payments.nativepay.model.PrepayResponse;
|
||||
import com.ycwl.basic.pay.adapter.IPayAdapter;
|
||||
import com.ycwl.basic.pay.adapter.WxMpPayAdapter;
|
||||
import com.ycwl.basic.service.pc.ScenicService;
|
||||
import com.ycwl.basic.biz.OrderBiz;
|
||||
import com.ycwl.basic.constant.NumberConstant;
|
||||
import com.ycwl.basic.enums.OrderStateEnum;
|
||||
@@ -162,6 +169,9 @@ public class PrinterServiceImpl implements PrinterService {
|
||||
@Autowired
|
||||
@Lazy
|
||||
private WatermarkEdgeService watermarkEdgeService;
|
||||
@Autowired
|
||||
@Lazy
|
||||
private ScenicService scenicService;
|
||||
|
||||
@Override
|
||||
public List<PrinterResp> listByScenicId(Long scenicId) {
|
||||
@@ -1126,7 +1136,14 @@ public class PrinterServiceImpl implements PrinterService {
|
||||
|
||||
@Override
|
||||
public void setUserIsBuyItem(Long memberId, Long id, Long orderId) {
|
||||
setUserIsBuyItem(memberId, id, orderId, null);
|
||||
// 尝试从 Redis 读取虚拟订单存储的 needEnhance 配置
|
||||
Boolean needEnhance = null;
|
||||
String enhanceFlag = redisTemplate.opsForValue().get("virtual_order_enhance:" + orderId);
|
||||
if (enhanceFlag != null) {
|
||||
needEnhance = Boolean.parseBoolean(enhanceFlag);
|
||||
redisTemplate.delete("virtual_order_enhance:" + orderId);
|
||||
}
|
||||
setUserIsBuyItem(memberId, id, orderId, needEnhance);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1680,16 +1697,21 @@ public class PrinterServiceImpl implements PrinterService {
|
||||
|
||||
@Override
|
||||
public Map<String, Object> createVirtualOrder(Long sourceId, Long scenicId, Integer printerId) {
|
||||
return createVirtualOrder(sourceId, scenicId, printerId, null, null);
|
||||
return createVirtualOrder(sourceId, scenicId, printerId, null, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> createVirtualOrder(Long sourceId, Long scenicId, Integer printerId, Boolean needEnhance) {
|
||||
return createVirtualOrder(sourceId, scenicId, printerId, needEnhance, null);
|
||||
return createVirtualOrder(sourceId, scenicId, printerId, needEnhance, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> createVirtualOrder(Long sourceId, Long scenicId, Integer printerId, Boolean needEnhance, String printImgUrl) {
|
||||
return createVirtualOrder(sourceId, scenicId, printerId, needEnhance, printImgUrl, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> createVirtualOrder(Long sourceId, Long scenicId, Integer printerId, Boolean needEnhance, String printImgUrl, Boolean needActualPayment) {
|
||||
// 1. 查询source记录
|
||||
SourceEntity source = sourceMapper.getEntity(sourceId);
|
||||
FaceSampleEntity faceSample = faceSampleMapper.getEntity(source.getFaceSampleId());
|
||||
@@ -1752,7 +1774,7 @@ public class PrinterServiceImpl implements PrinterService {
|
||||
throw new BaseException("打印机不属于该景区");
|
||||
}
|
||||
|
||||
// 6. 创建0元订单
|
||||
// 6. 创建订单
|
||||
OrderEntity order = new OrderEntity();
|
||||
Long orderId = SnowFlakeUtil.getLongId();
|
||||
redisTemplate.opsForValue().set("printer_size:" + orderId, printer.getPreferPaper(), 60, TimeUnit.SECONDS);
|
||||
@@ -1776,13 +1798,52 @@ public class PrinterServiceImpl implements PrinterService {
|
||||
return orderItem;
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
// 设置价格为0
|
||||
order.setPrice(BigDecimal.ZERO);
|
||||
order.setSlashPrice(BigDecimal.ZERO);
|
||||
order.setPayPrice(BigDecimal.ZERO);
|
||||
order.setFaceId(faceId);
|
||||
order.setStatus(OrderStateEnum.PAID.getState());
|
||||
order.setPayAt(new Date());
|
||||
boolean actualPayment = Boolean.TRUE.equals(needActualPayment);
|
||||
|
||||
if (actualPayment) {
|
||||
// 需要实际支付:通过价格计算服务获取真实价格
|
||||
PriceCalculationRequest priceRequest = new PriceCalculationRequest();
|
||||
priceRequest.setUserId(virtualMemberId);
|
||||
priceRequest.setScenicId(scenicId);
|
||||
|
||||
List<ProductItem> productItems = new ArrayList<>();
|
||||
ProductItem photoItem = new ProductItem();
|
||||
photoItem.setProductType(ProductType.PHOTO_PRINT);
|
||||
photoItem.setProductId(scenicId.toString());
|
||||
photoItem.setQuantity(1);
|
||||
photoItem.setPurchaseCount(1);
|
||||
photoItem.setScenicId(scenicId.toString());
|
||||
// 通过 source 的 deviceId 设置 attributeKeys
|
||||
SourceEntity priceSource = sourceRepository.getSource(sourceId);
|
||||
if (priceSource != null && priceSource.getDeviceId() != null) {
|
||||
photoItem.setAttributeKeys(List.of(String.valueOf(priceSource.getDeviceId())));
|
||||
}
|
||||
productItems.add(photoItem);
|
||||
|
||||
priceRequest.setProducts(productItems);
|
||||
priceRequest.setAutoUseCoupon(false);
|
||||
priceRequest.setPreviewOnly(false);
|
||||
|
||||
PriceCalculationResult priceResult = priceCalculationService.calculatePrice(priceRequest);
|
||||
|
||||
order.setPrice(priceResult.getFinalAmount());
|
||||
order.setSlashPrice(priceResult.getOriginalAmount());
|
||||
order.setPayPrice(priceResult.getFinalAmount());
|
||||
order.setStatus(OrderStateEnum.UNPAID.getState());
|
||||
log.info("创建待支付虚拟订单: orderId={}, price={}", orderId, priceResult.getFinalAmount());
|
||||
|
||||
// 将 needEnhance 存入 Redis,支付完成后 setUserIsBuyItem 可读取
|
||||
if (needEnhance != null) {
|
||||
redisTemplate.opsForValue().set("virtual_order_enhance:" + orderId, needEnhance.toString(), 24, TimeUnit.HOURS);
|
||||
}
|
||||
} else {
|
||||
// 虚拟0元购买:价格为0,直接标记已支付
|
||||
order.setPrice(BigDecimal.ZERO);
|
||||
order.setSlashPrice(BigDecimal.ZERO);
|
||||
order.setPayPrice(BigDecimal.ZERO);
|
||||
order.setStatus(OrderStateEnum.PAID.getState());
|
||||
order.setPayAt(new Date());
|
||||
}
|
||||
|
||||
// 保存订单
|
||||
orderMapper.add(order);
|
||||
@@ -1792,19 +1853,51 @@ public class PrinterServiceImpl implements PrinterService {
|
||||
throw new BaseException("订单添加失败");
|
||||
}
|
||||
|
||||
log.info("创建0元订单成功: orderId={}, virtualMemberId={}, faceId={}", orderId, virtualMemberId, faceId);
|
||||
log.info("创建虚拟订单成功: orderId={}, virtualMemberId={}, faceId={}, actualPayment={}", orderId, virtualMemberId, faceId, actualPayment);
|
||||
|
||||
// 7. 触发购买后逻辑(调用setUserIsBuyItem)
|
||||
setUserIsBuyItem(virtualMemberId, memberPrintId.longValue(), orderId, needEnhance);
|
||||
log.info("触发购买后逻辑完成: orderId={}", orderId);
|
||||
|
||||
// 8. 返回结果
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("orderId", orderId);
|
||||
result.put("faceId", faceId);
|
||||
result.put("virtualMemberId", virtualMemberId);
|
||||
result.put("memberPrintId", memberPrintId);
|
||||
result.put("needPay", false);
|
||||
|
||||
if (actualPayment) {
|
||||
if (order.getPayPrice().compareTo(BigDecimal.ZERO) <= 0) {
|
||||
// 计算后价格为0,直接走免费逻辑
|
||||
order.setStatus(OrderStateEnum.PAID.getState());
|
||||
order.setPayAt(new Date());
|
||||
orderMapper.updateOrder(order);
|
||||
setUserIsBuyItem(virtualMemberId, memberPrintId.longValue(), orderId, needEnhance);
|
||||
log.info("待支付订单计算后价格为0,直接完成购买: orderId={}", orderId);
|
||||
result.put("needPay", false);
|
||||
} else {
|
||||
// 通过 Native 支付生成二维码
|
||||
IPayAdapter payAdapter = scenicService.getScenicPayAdapter(scenicId);
|
||||
if (payAdapter instanceof WxMpPayAdapter adapter) {
|
||||
NativePayService nativePayService = new NativePayService.Builder().config(adapter.getConfig()).build();
|
||||
PrepayRequest prepayRequest = new PrepayRequest();
|
||||
prepayRequest.setAppid(adapter._config().getAppId());
|
||||
prepayRequest.setMchid(adapter._config().getMerchantId());
|
||||
prepayRequest.setDescription("照片打印");
|
||||
prepayRequest.setOutTradeNo(String.valueOf(orderId));
|
||||
prepayRequest.setNotifyUrl("https://zhentuai.com/api/mobile/wx/pay/v1/" + scenicId + "/payNotify");
|
||||
Amount amount = new Amount();
|
||||
amount.setTotal(order.getPayPrice().multiply(new BigDecimal(100)).intValue());
|
||||
prepayRequest.setAmount(amount);
|
||||
PrepayResponse prepayResponse = nativePayService.prepay(prepayRequest);
|
||||
result.put("payCode", prepayResponse.getCodeUrl());
|
||||
} else {
|
||||
throw new BaseException("该景区不支持 Native 支付");
|
||||
}
|
||||
result.put("needPay", true);
|
||||
result.put("price", order.getPayPrice());
|
||||
}
|
||||
} else {
|
||||
// 立即购买模式:触发购买后逻辑
|
||||
setUserIsBuyItem(virtualMemberId, memberPrintId.longValue(), orderId, needEnhance);
|
||||
log.info("触发购买后逻辑完成: orderId={}", orderId);
|
||||
result.put("needPay", false);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user