package com.talentcard.server.business.admin; import com.talentcard.server.business.DatabaseRows; import com.talentcard.server.business.PageResult; import com.talentcard.server.business.payment.PaymentReconciliationService; import com.talentcard.server.common.BusinessException; import com.talentcard.server.common.ErrorCode; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; import java.util.List; import java.util.Map; @Service public class PaymentReconciliationAdminService { private final JdbcTemplate jdbc; private final PaymentReconciliationService reconciliation; public PaymentReconciliationAdminService(JdbcTemplate jdbc, PaymentReconciliationService reconciliation) { this.jdbc = jdbc; this.reconciliation = reconciliation; } public PageResult> issues(String status, int page, int size) { int current = Math.max(1, page), limit = Math.min(Math.max(1, size), 100); String value = status == null || status.isBlank() ? "open" : status.trim().toLowerCase(); if (!List.of("open", "resolved", "ignored", "all").contains(value)) throw new BusinessException(ErrorCode.BAD_REQUEST, "Invalid reconciliation status"); boolean all = "all".equals(value); List> records = DatabaseRows.normalize(jdbc.queryForList("select * from payment_reconciliation_issue" + (all ? "" : " where status = ?") + " order by detected_at desc, id desc limit ? offset ?", all ? new Object[] { limit, (current - 1) * limit } : new Object[] { value, limit, (current - 1) * limit })); Long total = all ? jdbc.queryForObject("select count(*) from payment_reconciliation_issue", Long.class) : jdbc.queryForObject("select count(*) from payment_reconciliation_issue where status = ?", Long.class, value); return new PageResult<>(records, current, limit, total == null ? 0 : total); } public Map close(Long id, String status, String operator) { String target = status == null ? "" : status.trim().toLowerCase(); if (!List.of("resolved", "ignored").contains(target)) throw new BusinessException(ErrorCode.BAD_REQUEST, "Invalid reconciliation resolution"); int affected = jdbc.update("update payment_reconciliation_issue set status = ?, resolved_at = now(), resolved_by = ? where id = ? and status = 'open'", target, operator == null || operator.isBlank() ? "admin" : operator.trim(), id); if (affected == 0) throw new BusinessException(ErrorCode.CONFLICT, "Reconciliation issue is already closed or does not exist"); return Map.of("id", id, "status", target); } public Map run(int pendingAfterMinutes) { return reconciliation.reconcile(Math.max(1, Math.min(pendingAfterMinutes, 1440))); } }