| | |
| | | return requested == null || requested.isBlank() ? "merchant" : requested.trim(); |
| | | } |
| | | |
| | | /** |
| | | * 手输 6 位数字核销码之后的确认核销。 |
| | | * |
| | | * <p>为什么不复用 {@code /api/merchant/orders/{orderNo}/verify}:手输那条路的扫码答复刻意不返回 |
| | | * 「这个码属于哪笔订单」(6 位只有 100 万空间,带回去等于给枚举一张映射表),所以客户端拿不到单号。 |
| | | * 这里由服务端从扫码尝试反查订单,再走同一套核销实现——幂等、行锁、资金确认都不重复写第二份。 |
| | | */ |
| | | @Transactional |
| | | public Map<String, Object> confirmNumericVerification(MerchantPrincipal principal, String verificationId, String idempotencyKey) { |
| | | if (idempotencyKey == null || idempotencyKey.isBlank()) { |
| | | throw new BusinessException(ErrorCode.BAD_REQUEST, "缺少幂等键"); |
| | | } |
| | | String attemptId = verificationId == null ? "" : verificationId.trim(); |
| | | if (attemptId.isBlank()) throw new BusinessException(ErrorCode.BAD_REQUEST, "缺少核销凭证编号"); |
| | | List<Map<String, Object>> orders = query(""" |
| | | select o.order_no |
| | | from merchant_verification_attempt a |
| | | join order_dynamic_verification_code c on c.id = a.order_verification_code_id |
| | | join benefit_order o on o.id = c.order_id and o.deleted = 0 |
| | | where a.verification_id = ? and a.credential_type = 'ORDER_CODE' |
| | | and a.merchant_id = ? and a.store_id = ? and a.operator_id = ? |
| | | limit 1 |
| | | """, attemptId, principal.merchantId(), principal.storeId(), principal.operatorId()); |
| | | if (orders.isEmpty()) throw new BusinessException(ErrorCode.NOT_FOUND, "核销凭证不存在或无权操作"); |
| | | return verify(String.valueOf(orders.get(0).get("orderNo")).trim(), principal, |
| | | new VerifyRequest("ORDER_CODE", "", attemptId), idempotencyKey); |
| | | } |
| | | |
| | | /** 扫码尝试:核销成功后要标记完成,并且只有扫码码未过期才能核销。 */ |
| | | private record Attempt(Long id, java.time.LocalDateTime expiresAt) { } |
| | | |