| | |
| | | private static final String TALENT_CODE = "TALENT_CODE"; |
| | | private static final String ORDER_CODE = "ORDER_CODE"; |
| | | private static final String FREE_STAY_CODE = "FREE_STAY_CODE"; |
| | | /** 观影权益(票包兑换码):后台批量生成、绑影城、用户领取后出示二维码,店员扫码核销。 */ |
| | | private static final String TICKET_PACKAGE_CODE = "TICKET_PACKAGE_CODE"; |
| | | |
| | | /** |
| | | * 6 位数字核销码:顾客屏幕上的数字码,相机不好用或屏幕反光时手输兜底。 |
| | |
| | | Map<String, Object> freeStayCode = findFreeStayCode(token, principal); |
| | | if (freeStayCode != null) { |
| | | return createFreeStayAttempt(principal, freeStayCode); |
| | | } |
| | | Map<String, Object> ticketPackageCode = findTicketPackageCode(token, principal); |
| | | if (ticketPackageCode != null) { |
| | | return createTicketPackageAttempt(token, ticketPackageCode); |
| | | } |
| | | throw new BusinessException(ErrorCode.CONFLICT, "二维码已失效、不可核销或不属于当前商户"); |
| | | } |
| | |
| | | return result; |
| | | } |
| | | |
| | | /** |
| | | * 观影权益兑换码:票包后台批量生成、绑到影城、用户在小程序领取后出示二维码。 |
| | | * |
| | | * <p>只认「属于当前商户 + 已发放未核销 + 未过期」的码;核销本身走 |
| | | * {@code POST /api/merchant/benefit-verifications/verify}(与后台同一套记录), |
| | | * 这里只做扫码后的资格确认,让店员先看清是谁的券再确认。 |
| | | */ |
| | | private Map<String, Object> findTicketPackageCode(String token, MerchantPrincipal principal) { |
| | | List<Map<String, Object>> claims = rows(""" |
| | | select cl.id claim_id, cl.exchange_code, cl.talent_name, cl.talent_mobile, cl.card_level, |
| | | cl.valid_end, cl.status claim_status, p.package_name, m.merchant_name |
| | | from ticket_package_claim cl |
| | | join ticket_package p on p.id = cl.package_id and p.deleted = 0 |
| | | left join merchant m on m.id = cl.merchant_id and m.deleted = 0 |
| | | where cl.exchange_code = ? and cl.deleted = 0 and cl.merchant_id = ? |
| | | limit 1 |
| | | """, token, principal.merchantId()); |
| | | if (claims.isEmpty()) return null; |
| | | Map<String, Object> claim = claims.get(0); |
| | | if (!"ISSUED".equalsIgnoreCase(value(claim.get("claimStatus"), "").trim())) { |
| | | throw new BusinessException(ErrorCode.CONFLICT, "该观影权益已核销或已失效"); |
| | | } |
| | | if (expiredDate(claim.get("validEnd"))) { |
| | | throw new BusinessException(ErrorCode.CONFLICT, "该观影权益已过期"); |
| | | } |
| | | return claim; |
| | | } |
| | | |
| | | private Map<String, Object> createTicketPackageAttempt(String exchangeCode, Map<String, Object> claim) { |
| | | // 这类码没有 attempt 表可用(它只服务动态码/订单码/免费入住券),核销记录由 |
| | | // benefit_verify_record 落库,因此这里用「TP+领取记录ID」当核销流水号。 |
| | | Map<String, Object> result = scanResult("TP" + number(claim.get("claimId")), TICKET_PACKAGE_CODE, |
| | | "观影权益有效,请确认后核销", |
| | | claim.get("talentName"), claim.get("talentMobile"), claim.get("cardLevel"), null, null, 0L); |
| | | result.put("verifyCode", exchangeCode); |
| | | result.put("packageName", value(claim.get("packageName"), "")); |
| | | result.put("merchantName", value(claim.get("merchantName"), "")); |
| | | result.put("validEnd", claim.get("validEnd") == null ? "" : String.valueOf(claim.get("validEnd"))); |
| | | return result; |
| | | } |
| | | |
| | | private String freeStayBenefitText(Map<String, Object> code, MerchantPrincipal principal) { |
| | | try { |
| | | List<Map<String, Object>> benefits = rows(""" |