FineServiceImpl.java

package org.darkroomlibrary.service.impl;

import org.darkroomlibrary.mapper.BorrowRecordMapper;
import org.darkroomlibrary.web.response.ApiResponse;
import org.darkroomlibrary.service.FineService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import jakarta.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;

/**
 * 罚款服务实现
 */
@Slf4j
@Service
public class FineServiceImpl implements FineService {

    @Value("${borrow.fine-per-day:0.5}")
    private double finePerDay;

    @Value("${borrow.fine-max:100}")
    private double fineMax;

    @Resource
    private BorrowRecordMapper borrowRecordMapper;

    @Override
    public BigDecimal calculateFine(LocalDateTime dueDate, LocalDateTime returnTime) {
        if (dueDate == null || returnTime == null) {
            return BigDecimal.ZERO;
        }
        if (!returnTime.isAfter(dueDate)) {
            return BigDecimal.ZERO;
        }
        long overdueDays = Duration.between(dueDate, returnTime).toDays();
        if (overdueDays <= 0) {
            return BigDecimal.ZERO;
        }
        BigDecimal fine = BigDecimal.valueOf(finePerDay).multiply(BigDecimal.valueOf(overdueDays))
                .setScale(2, RoundingMode.HALF_UP);
        BigDecimal max = BigDecimal.valueOf(fineMax);
        return fine.compareTo(max) > 0 ? max : fine;
    }

    @Override
    public ApiResponse<List<Map<String, Object>>> overdueUsers() {
        // 数据库端聚合:按用户分组统计逾期数量和总逾期天数
        List<Map<String, Object>> stats = borrowRecordMapper.overdueUserStats();
        // 补充计算罚款总额(逾期天数 × 每日罚金)
        for (Map<String, Object> row : stats) {
            Object daysObj = row.get("totalOverdueDays");
            long days = daysObj instanceof Number ? ((Number) daysObj).longValue() : 0;
            BigDecimal totalFine = BigDecimal.valueOf(finePerDay)
                    .multiply(BigDecimal.valueOf(days))
                    .setScale(2, RoundingMode.HALF_UP);
            row.put("totalFine", totalFine);
        }
        return ApiResponse.success(stats);
    }

}