| | |
| | | package com.talentcard.server.business.merchant; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.math.RoundingMode; |
| | | import java.time.LocalDate; |
| | | import java.time.LocalDateTime; |
| | | import java.util.LinkedHashMap; |
| | |
| | | import com.talentcard.server.business.merchant.auth.MerchantPrincipal; |
| | | import com.talentcard.server.common.BusinessException; |
| | | import com.talentcard.server.common.ErrorCode; |
| | | import org.springframework.dao.DataAccessException; |
| | | import org.springframework.jdbc.core.JdbcTemplate; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | |
| | | } |
| | | String verificationId = createAttempt(principal, TALENT_CODE, number(code.get("dynamicCodeId")), null, null, code.get("expiresAt")); |
| | | return scanResult(verificationId, TALENT_CODE, "人才码有效,请录入消费金额并发送待支付订单", code.get("talentName"), |
| | | code.get("talentMobile"), code.get("cardLevel"), null, code.get("expiresAt")); |
| | | code.get("talentMobile"), code.get("cardLevel"), null, code.get("expiresAt"), 0L); |
| | | } |
| | | |
| | | private Map<String, Object> createOrderAttempt(MerchantPrincipal principal, Map<String, Object> code) { |
| | | String verificationId = createAttempt(principal, ORDER_CODE, null, number(code.get("orderVerificationCodeId")), null, code.get("expiresAt")); |
| | | String title = value(code.get("productName"), "订单权益"); |
| | | return scanResult(verificationId, ORDER_CODE, "订单核销码有效,请确认后完成核销:" + title, |
| | | code.get("talentName"), code.get("talentMobile"), code.get("cardLevel"), code.get("orderNo"), code.get("expiresAt")); |
| | | code.get("talentName"), code.get("talentMobile"), code.get("cardLevel"), code.get("orderNo"), code.get("expiresAt"), 0L); |
| | | } |
| | | |
| | | private Map<String, Object> createFreeStayAttempt(MerchantPrincipal principal, Map<String, Object> code) { |
| | | Long remaining = number(code.get("totalCount")) - number(code.get("usedCount")); |
| | | String verificationId = createAttempt(principal, FREE_STAY_CODE, null, null, |
| | | number(code.get("freeStayVerificationCodeId")), code.get("expiresAt")); |
| | | return scanResult(verificationId, FREE_STAY_CODE, "免费入住券有效,剩余 " + remaining + " 次,请确认后核销", |
| | | code.get("talentName"), code.get("talentMobile"), code.get("cardLevel"), null, code.get("expiresAt")); |
| | | Map<String, Object> result = scanResult(verificationId, FREE_STAY_CODE, "免费入住券有效,剩余 " + remaining + " 次,请确认后核销", |
| | | code.get("talentName"), code.get("talentMobile"), code.get("cardLevel"), null, code.get("expiresAt"), |
| | | hotelSubsidyAmountCents()); |
| | | result.put("freeStayTotalCount", number(code.get("totalCount"))); |
| | | result.put("freeStayRemainingCount", Math.max(remaining, 0L)); |
| | | result.put("benefitText", freeStayBenefitText(code, principal)); |
| | | return result; |
| | | } |
| | | |
| | | private String freeStayBenefitText(Map<String, Object> code, MerchantPrincipal principal) { |
| | | try { |
| | | List<Map<String, Object>> benefits = rows(""" |
| | | select benefit_text |
| | | from merchant_card_benefit |
| | | where merchant_id = ? and card_level = ? and status = 1 |
| | | limit 1 |
| | | """, principal.merchantId(), value(code.get("cardLevel"), "")); |
| | | return benefits.isEmpty() ? "" : value(benefits.get(0).get("benefitText"), ""); |
| | | } catch (DataAccessException ignored) { |
| | | // Older installations may not have the optional display table yet. |
| | | return ""; |
| | | } |
| | | } |
| | | |
| | | private String createAttempt(MerchantPrincipal principal, String type, Long dynamicCodeId, Long orderCodeId, Long freeStayCodeId, Object expiresAt) { |
| | |
| | | if (codeUpdated == 0 || voucherUpdated == 0) { |
| | | throw new BusinessException(ErrorCode.CONFLICT, "免费入住券已被使用或已失效"); |
| | | } |
| | | Long subsidyAmount = hotelSubsidyAmountCents(); |
| | | String verifyNo = insertRecord(principal, null, number(code.get("talentId")), number(code.get("cardId")), null, |
| | | "HOTEL_FREE", 0L, 0L, "免费入住券"); |
| | | "HOTEL_FREE", 0L, subsidyAmount, "免费入住券(平台线下补贴)"); |
| | | finishAttempt(attempt, verifyNo); |
| | | return confirmed(verifyNo, code.get("cardLevel")); |
| | | } |
| | |
| | | } |
| | | |
| | | private Map<String, Object> scanResult(String verificationId, String credentialType, String message, |
| | | Object talentName, Object talentMobile, Object cardLevel, Object orderNo, Object expiresAt) { |
| | | Object talentName, Object talentMobile, Object cardLevel, Object orderNo, |
| | | Object expiresAt, Long subsidyAmount) { |
| | | Map<String, Object> result = new LinkedHashMap<>(); |
| | | result.put("verificationId", verificationId); |
| | | result.put("credentialType", credentialType); |
| | |
| | | result.put("customerMobile", maskMobile(value(talentMobile, ""))); |
| | | result.put("cardLevel", cardLevel == null ? "人才卡" : String.valueOf(cardLevel)); |
| | | result.put("orderNo", orderNo == null ? "" : String.valueOf(orderNo)); |
| | | result.put("subsidyAmount", subsidyAmount == null ? 0L : subsidyAmount); |
| | | result.put("expiresAt", expiresAt); |
| | | return result; |
| | | } |
| | | |
| | | private Long hotelSubsidyAmountCents() { |
| | | List<Map<String, Object>> settings = rows(""" |
| | | select setting_value |
| | | from admin_setting |
| | | where setting_key = 'hotelSubsidy' |
| | | limit 1 |
| | | """); |
| | | if (settings.isEmpty()) { |
| | | return 0L; |
| | | } |
| | | String configuredAmount = value(settings.get(0).get("settingValue"), "").trim(); |
| | | if (configuredAmount.isEmpty()) { |
| | | return 0L; |
| | | } |
| | | try { |
| | | BigDecimal yuan = new BigDecimal(configuredAmount).setScale(2, RoundingMode.UNNECESSARY); |
| | | if (yuan.signum() < 0) { |
| | | throw new ArithmeticException("negative subsidy"); |
| | | } |
| | | return yuan.movePointRight(2).longValueExact(); |
| | | } catch (ArithmeticException | NumberFormatException exception) { |
| | | throw new BusinessException(ErrorCode.CONFLICT, "酒店免费入住补贴金额配置不正确,请联系平台管理员"); |
| | | } |
| | | } |
| | | |
| | | private Map<String, Object> confirmed(Object verifyNo, Object cardLevel) { |
| | | Map<String, Object> result = new LinkedHashMap<>(); |
| | | result.put("verified", true); |