feat(pricing): 新增打印小票和查询券码批次配置功能

- 新增 AppClaimController 控制器处理移动设备端的领券请求
- 实现 ClaimReq 和 ClaimResp 模型类用于领券请求和响应
- 在 VoucherPrintService 接口中新增打印小票方法
- 在VoucherPrintServiceImpl 中实现打印小票和查询券码批次配置的逻辑
- 更新 PriceVoucherBatchConfigMapper 接口和 XML 文件,添加查询券码批次配置的方法
This commit is contained in:
2025-08-30 11:41:37 +08:00
parent 1ac375e491
commit b1deabc7c1
9 changed files with 337 additions and 13 deletions

View File

@@ -1,11 +1,13 @@
package com.ycwl.basic.pricing.dto.req;
import lombok.AllArgsConstructor;
import lombok.Data;
/**
* 打印小票请求
*/
@Data
@AllArgsConstructor
public class VoucherPrintReq {
private Long faceId;

View File

@@ -14,6 +14,7 @@ public class VoucherPrintResp {
* 流水号
*/
private String code;
private String type;
/**
* 券码

View File

@@ -44,4 +44,11 @@ public interface PriceVoucherBatchConfigMapper extends BaseMapper<PriceVoucherBa
* @return 统计信息
*/
PriceVoucherBatchConfig selectBatchStats(@Param("batchId") Long batchId);
/**
* 根据券码查询对应的券码批次配置
* @param voucherCode 券码
* @return 券码批次配置
*/
PriceVoucherBatchConfig selectByVoucherCode(@Param("voucherCode") String voucherCode);
}

View File

@@ -16,4 +16,6 @@ public interface VoucherPrintService {
VoucherPrintResp printVoucherTicket(VoucherPrintReq request);
VoucherPrintResp queryPrintedVoucher(Long faceId);
VoucherPrintResp printBookingTicket(VoucherPrintReq voucherPrintReq);
}

View File

@@ -7,8 +7,10 @@ import com.ycwl.basic.model.pc.mp.MpConfigEntity;
import com.ycwl.basic.pricing.dto.req.VoucherPrintReq;
import com.ycwl.basic.pricing.dto.resp.VoucherPrintResp;
import com.ycwl.basic.pricing.entity.PriceVoucherCode;
import com.ycwl.basic.pricing.entity.PriceVoucherBatchConfig;
import com.ycwl.basic.pricing.entity.VoucherPrintRecord;
import com.ycwl.basic.pricing.mapper.PriceVoucherCodeMapper;
import com.ycwl.basic.pricing.mapper.PriceVoucherBatchConfigMapper;
import com.ycwl.basic.pricing.mapper.VoucherPrintRecordMapper;
import com.ycwl.basic.pricing.service.VoucherPrintService;
import com.ycwl.basic.printer.ticket.FeiETicketPrinter;
@@ -16,6 +18,7 @@ import com.ycwl.basic.repository.FaceRepository;
import com.ycwl.basic.repository.ScenicRepository;
import com.ycwl.basic.utils.WxMpUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
@@ -41,6 +44,9 @@ public class VoucherPrintServiceImpl implements VoucherPrintService {
@Autowired
private PriceVoucherCodeMapper priceVoucherCodeMapper;
@Autowired
private PriceVoucherBatchConfigMapper priceVoucherBatchConfigMapper;
@Autowired
private FaceRepository faceRepository;
@@ -92,7 +98,6 @@ public class VoucherPrintServiceImpl implements VoucherPrintService {
if (existingRecord != null) {
log.info("找到已存在的打印记录,返回该记录: {}", existingRecord.getId());
existingRecord.setCode(existingRecord.getVoucherCode());
return buildResponse(existingRecord);
}
@@ -119,9 +124,10 @@ public class VoucherPrintServiceImpl implements VoucherPrintService {
printRecord.setDeleted(0);
voucherPrintRecordMapper.insert(printRecord);
VoucherPrintResp voucherPrintResp = buildResponse(printRecord);
try {
printTicket(printRecord);
printTicket(printRecord, voucherPrintResp);
printRecord.setPrintStatus(1);
} catch (Exception e) {
log.error("打印失败");
@@ -129,10 +135,9 @@ public class VoucherPrintServiceImpl implements VoucherPrintService {
}
voucherPrintRecordMapper.updatePrintStatus(printRecord.getId(), 1, null);
log.info("成功创建打印记录: {}, 券码: {}", code, availableVoucher.getCode());
printRecord.setCode(printRecord.getVoucherCode());
return buildResponse(printRecord);
return voucherPrintResp;
} finally {
// 释放锁
@@ -160,10 +165,99 @@ public class VoucherPrintServiceImpl implements VoucherPrintService {
if (existingRecord == null) {
return null;
}
existingRecord.setCode(existingRecord.getVoucherCode());
return buildResponse(existingRecord);
}
@Override
public VoucherPrintResp printBookingTicket(VoucherPrintReq request) {
// 参数验证
if (request.getFaceId() == null) {
throw new BaseException("用户faceId不能为空");
}
if (request.getBrokerId() == null) {
throw new BaseException("经纪人ID不能为空");
}
FaceEntity face = faceRepository.getFace(request.getFaceId());
if (face == null) {
throw new BaseException("请上传人脸");
}
request.setScenicId(face.getScenicId());
Long currentUserId = Long.valueOf(BaseContextHandler.getUserId());
// 验证faceId是否属于当前用户
validateFaceOwnership(request.getFaceId(), currentUserId);
// 使用Redis分布式锁防止重复打印
String lockKey = String.format(PRINT_LOCK_KEY, request.getFaceId(), request.getBrokerId(), request.getScenicId());
String lockValue = UUID.randomUUID().toString();
try {
// 尝试获取锁,超时时间30秒
Boolean lockAcquired = redisTemplate.opsForValue().setIfAbsent(lockKey, lockValue, 30, TimeUnit.SECONDS);
if (Boolean.FALSE.equals(lockAcquired)) {
throw new BaseException("请求处理中,请稍后再试");
}
// 检查是否已存在相同的打印记录
VoucherPrintRecord existingRecord = voucherPrintRecordMapper.selectByFaceBrokerScenic(
request.getFaceId(), request.getScenicId());
if (existingRecord != null) {
log.info("找到已存在的打印记录,返回该记录: {}", existingRecord.getId());
return buildResponse(existingRecord);
}
// 生成流水号
String code = generateCode();
// 创建打印记录
VoucherPrintRecord printRecord = new VoucherPrintRecord();
printRecord.setCode(code);
printRecord.setFaceId(request.getFaceId());
printRecord.setBrokerId(request.getBrokerId());
printRecord.setScenicId(request.getScenicId());
printRecord.setPrintStatus(0); // 待打印
printRecord.setCreateTime(new Date());
printRecord.setUpdateTime(new Date());
printRecord.setDeleted(0);
voucherPrintRecordMapper.insert(printRecord);
VoucherPrintResp voucherPrintResp = buildResponse(printRecord);
try {
printTicket(printRecord, voucherPrintResp);
printRecord.setPrintStatus(1);
} catch (Exception e) {
log.error("打印失败");
printRecord.setPrintStatus(2);
}
voucherPrintRecordMapper.updatePrintStatus(printRecord.getId(), 1, null);
log.info("成功创建打印记录: {}, 流水号: {}", code, printRecord.getCode());
return voucherPrintResp;
} finally {
// 释放锁
if (lockValue.equals(redisTemplate.opsForValue().get(lockKey))) {
redisTemplate.delete(lockKey);
}
}
}
/**
* 根据券码查询voucher_batch_config记录
* @param voucherCode 券码
* @return 券码批次配置
*/
public PriceVoucherBatchConfig getVoucherBatchConfigByCode(String voucherCode) {
if (voucherCode == null || voucherCode.trim().isEmpty()) {
throw new BaseException("券码不能为空");
}
return priceVoucherBatchConfigMapper.selectByVoucherCode(voucherCode);
}
/**
* 验证faceId是否属于当前用户
*/
@@ -204,20 +298,39 @@ public class VoucherPrintServiceImpl implements VoucherPrintService {
private VoucherPrintResp buildResponse(VoucherPrintRecord record) {
VoucherPrintResp response = new VoucherPrintResp();
BeanUtils.copyProperties(record, response);
if (Strings.isNotBlank(record.getVoucherCode())) {
PriceVoucherBatchConfig priceVoucherBatchConfig = priceVoucherBatchConfigMapper.selectByVoucherCode(record.getVoucherCode());
if (priceVoucherBatchConfig != null) {
if (Integer.valueOf(0).equals(priceVoucherBatchConfig.getDiscountType())) {
response.setType("赠品兑换码");
} else {
response.setType("抵扣兑换码");
}
}
response.setCode(record.getVoucherCode());
} else {
response.setType("小票配对码");
}
return response;
}
/**
* 调用打印机接口(待实现)
*/
private void printTicket(VoucherPrintRecord record) throws Exception {
private void printTicket(VoucherPrintRecord record, VoucherPrintResp voucherPrintResp) throws Exception {
FaceEntity face = faceRepository.getFace(record.getFaceId());
MpConfigEntity scenicMpConfig = scenicRepository.getScenicMpConfig(face.getScenicId());
String urlLink = WxMpUtil.generateUrlLink(scenicMpConfig.getAppId(), scenicMpConfig.getAppSecret(), "pages/videoSynthesis/index", "code=" + record.getVoucherCode() + "&scenicId=" + face.getScenicId() + "&faceId=" + face.getId());
urlLink = urlLink + "?cq=T"+record.getVoucherCode();
String urlLink;
if (Strings.isNotBlank(record.getVoucherCode())) {
urlLink = WxMpUtil.generateUrlLink(scenicMpConfig.getAppId(), scenicMpConfig.getAppSecret(), "pages/videoSynthesis/index", "code=" + record.getVoucherCode() + "&scenicId=" + face.getScenicId() + "&faceId=" + face.getId());
urlLink = urlLink + "?cq=T"+record.getVoucherCode();
log.info(" 调用打印机打印小票,记录ID: {}, 券码: {}", record.getId(), record.getVoucherCode());
} else {
urlLink = WxMpUtil.generateUrlLink(scenicMpConfig.getAppId(), scenicMpConfig.getAppSecret(), "pages/videoSynthesis/index", "scenicId=" + face.getScenicId() + "&faceId=" + face.getId());
log.info(" 调用打印机打印小票,记录ID: {}, 配对码: {}", record.getId(), record.getCode());
}
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
SimpleDateFormat sdf2 = new SimpleDateFormat("MM月dd日");
log.info(" 调用打印机打印小票,记录ID: {}, 券码: {}", record.getId(), record.getVoucherCode());
String content;
content = "<BR><B>世界再大</B><BR>";
content += "<B>你永远是这段旅途</B><BR>";
@@ -234,9 +347,10 @@ public class VoucherPrintServiceImpl implements VoucherPrintService {
content += "<CB>游后微信扫码领取</CB>";
content += "<C>精彩指数:★★★★★</C><BR>";
content += "━━━━━━━━━━━━━━━━<BR>";
content += "<CB>"+record.getVoucherCode()+"</CB>";
content += "<C>赠品兑换码</C>";
content += "<CB>"+voucherPrintResp.getCode()+"</CB>";
content += "<C>"+voucherPrintResp.getType()+"</C>";
content += "<C>有效期:"+sdf2.format(new Date())+"</C>";
FeiETicketPrinter.doPrint("550519002", content, 1);
// FeiETicketPrinter.doPrint("550519002", content, 1);
log.info("打印完成->内容:\n{}", content);
}
}