shinnosuke
2026-08-03 98d1455efaa4cd3d5d3213e047ccc0ac187ba05c
talent-card-server/src/main/java/com/talentcard/server/business/admin/MerchantSettlementAdminService.java
@@ -11,11 +11,13 @@
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.talentcard.server.business.merchant.HuifuMerchantWithdrawalService;
@Service
public class MerchantSettlementAdminService {
    private final JdbcTemplate jdbc;
    public MerchantSettlementAdminService(JdbcTemplate jdbc) { this.jdbc = jdbc; }
    private final HuifuMerchantWithdrawalService withdrawalService;
    public MerchantSettlementAdminService(JdbcTemplate jdbc, HuifuMerchantWithdrawalService withdrawalService) { this.jdbc = jdbc; this.withdrawalService = withdrawalService; }
    @Transactional(readOnly = true)
    public PageResult<Map<String, Object>> onboardings(int page, int size) { return page("select a.*, m.merchant_name, s.store_name from merchant_onboarding_application a join merchant m on m.id = a.merchant_id join merchant_store s on s.id = a.store_id", "select count(*) from merchant_onboarding_application", page, size); }
@@ -24,9 +26,14 @@
    @Transactional(readOnly = true)
    public PageResult<Map<String, Object>> withdrawals(int page, int size) { return page("select w.*, c.bank_name, c.card_masked, m.merchant_name, s.store_name from merchant_withdrawal w join merchant_bank_card c on c.id = w.bank_card_id join merchant m on m.id = w.merchant_id join merchant_store s on s.id = w.store_id", "select count(*) from merchant_withdrawal", page, size); }
    @Transactional public Map<String, Object> reviewOnboarding(Long id, String status, String reason) { return update("merchant_onboarding_application", id, status, reason, "onboarding"); }
    @Transactional public Map<String, Object> reviewBankCard(Long id, String status, String reason) { return update("merchant_bank_card", id, status, reason, "bank card"); }
    @Transactional public Map<String, Object> reviewWithdrawal(Long id, String status, String reason) { return update("merchant_withdrawal", id, status, reason, "withdrawal"); }
    @Transactional public Map<String, Object> reviewOnboarding(Long id, String status, String reason, String huifuId) { return reviewOnboardingInternal(id, status, reason, huifuId); }
    @Transactional public Map<String, Object> reviewBankCard(Long id, String status, String reason, String tokenNo) { return reviewBankCardInternal(id, status, reason, tokenNo); }
    public Map<String, Object> reviewWithdrawal(Long id, String status, String reason) { if ("paid".equals(normalizeWithdrawalStatus(status))) return withdrawalService.dispatch(id); return update("merchant_withdrawal", id, "failed", reason, "withdrawal"); }
    private Map<String,Object> reviewOnboardingInternal(Long id,String status,String reason,String huifuId) { String value=reviewStatus(status); if("approved".equals(value) && (huifuId==null || !huifuId.trim().matches("[A-Za-z0-9]{1,32}"))) throw new BusinessException(ErrorCode.BAD_REQUEST,"Huifu merchant ID is required when approving onboarding"); int affected=jdbc.update("update merchant_onboarding_application set status=?, reject_reason=?, provider_huifu_id=?, reviewed_at=now() where id=? and status='pending'",value,reason==null?"":reason.trim(),"approved".equals(value)?huifuId.trim():null,id); if(affected==0)throw new BusinessException(ErrorCode.CONFLICT,"Onboarding is already handled or does not exist");return Map.of("id",id,"status",value); }
    private Map<String,Object> reviewBankCardInternal(Long id,String status,String reason,String tokenNo) { String value=reviewStatus(status); if("approved".equals(value) && (tokenNo==null || !tokenNo.trim().matches("[A-Za-z0-9]{1,32}"))) throw new BusinessException(ErrorCode.BAD_REQUEST,"Huifu withdrawal card token is required when approving a bank card"); int affected=jdbc.update("update merchant_bank_card set status=?, reject_reason=?, provider_token_no=?, reviewed_at=now() where id=? and status='pending'",value,reason==null?"":reason.trim(),"approved".equals(value)?tokenNo.trim():null,id); if(affected==0)throw new BusinessException(ErrorCode.CONFLICT,"Bank card is already handled or does not exist");return Map.of("id",id,"status",value); }
    private String reviewStatus(String status) { String value=status==null?"":status.trim().toLowerCase(); if(!List.of("approved","rejected").contains(value))throw new BusinessException(ErrorCode.BAD_REQUEST,"Invalid review status");return value; }
    private String normalizeWithdrawalStatus(String status) { String value=status==null?"":status.trim().toLowerCase(); if(!List.of("paid","failed").contains(value))throw new BusinessException(ErrorCode.BAD_REQUEST,"Invalid withdrawal status");return value; }
    private PageResult<Map<String, Object>> page(String query, String count, int page, int size) { int current = Math.max(1, page); int limit = Math.min(Math.max(1, size), 100); List<Map<String, Object>> values = rows(query + " order by id desc limit ? offset ?", limit, (current - 1) * limit); Long total = jdbc.queryForObject(count, Long.class); return new PageResult<>(values, current, limit, total == null ? 0 : total); }
    private Map<String, Object> update(String table, Long id, String status, String reason, String label) {