Archived
Project to GitHub
This commit is contained in:
@@ -0,0 +1,159 @@
|
||||
using Bsevita.Library.Api.Data.Generated;
|
||||
using Bsevita.Library.Models.Common;
|
||||
using Bsevita.Library.Models.Loans;
|
||||
using Bsevita.Library.Models.Reports;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Bsevita.Library.Api.Services;
|
||||
|
||||
public sealed class ReportService(LibraryDbContext dbContext, TimeProvider timeProvider)
|
||||
{
|
||||
public async Task<ReportsDto> GetReportsAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var activeLoans = await GetActiveLoansAsync(0, LibraryRules.DefaultPageSize, cancellationToken);
|
||||
var overdueLoans = await GetOverdueAsync(0, LibraryRules.DefaultPageSize, cancellationToken);
|
||||
return new ReportsDto(
|
||||
activeLoans,
|
||||
overdueLoans,
|
||||
await GetActiveStudentsAsync(0, LibraryRules.DefaultPageSize, cancellationToken),
|
||||
await GetStatisticsAsync(cancellationToken));
|
||||
}
|
||||
|
||||
public async Task<IReadOnlyList<LoanDto>> GetActiveLoansAsync(
|
||||
int skip,
|
||||
int take,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var now = timeProvider.GetUtcNow();
|
||||
var query = dbContext.Loans.AsNoTracking()
|
||||
.Where(loan => loan.ReturnedAt == null)
|
||||
.OrderBy(loan => loan.DueAt)
|
||||
.Skip(Math.Max(0, skip))
|
||||
.Take(Math.Clamp(take, 1, LibraryRules.MaxPageSize));
|
||||
var loans = await query
|
||||
.Select(loan => new
|
||||
{
|
||||
loan.LoanId,
|
||||
loan.StudentId,
|
||||
StudentName = loan.Student.FirstName + " " + loan.Student.LastName,
|
||||
loan.Student.CardNumber,
|
||||
loan.BookId,
|
||||
BookTitle = loan.Book.Title,
|
||||
loan.Book.BookNumber,
|
||||
loan.LoanedAt,
|
||||
loan.DueAt,
|
||||
loan.ReturnedAt
|
||||
})
|
||||
.ToListAsync(cancellationToken);
|
||||
return loans.Select(loan => ToLoanDto(
|
||||
loan.LoanId,
|
||||
loan.StudentId,
|
||||
loan.StudentName,
|
||||
loan.CardNumber,
|
||||
loan.BookId,
|
||||
loan.BookTitle,
|
||||
loan.BookNumber,
|
||||
loan.LoanedAt,
|
||||
loan.DueAt,
|
||||
loan.ReturnedAt,
|
||||
now)).ToList();
|
||||
}
|
||||
|
||||
public Task<IReadOnlyList<LoanDto>> GetActiveLoansAsync(CancellationToken cancellationToken) =>
|
||||
GetActiveLoansAsync(0, LibraryRules.DefaultPageSize, cancellationToken);
|
||||
|
||||
public async Task<IReadOnlyList<LoanDto>> GetOverdueAsync(
|
||||
int skip,
|
||||
int take,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var now = timeProvider.GetUtcNow();
|
||||
var query = dbContext.Loans.AsNoTracking()
|
||||
.Where(loan => loan.ReturnedAt == null && loan.DueAt < now)
|
||||
.OrderBy(loan => loan.DueAt)
|
||||
.Skip(Math.Max(0, skip))
|
||||
.Take(Math.Clamp(take, 1, LibraryRules.MaxPageSize));
|
||||
var loans = await query
|
||||
.Select(loan => new
|
||||
{
|
||||
loan.LoanId,
|
||||
loan.StudentId,
|
||||
StudentName = loan.Student.FirstName + " " + loan.Student.LastName,
|
||||
loan.Student.CardNumber,
|
||||
loan.BookId,
|
||||
BookTitle = loan.Book.Title,
|
||||
loan.Book.BookNumber,
|
||||
loan.LoanedAt,
|
||||
loan.DueAt,
|
||||
loan.ReturnedAt
|
||||
})
|
||||
.ToListAsync(cancellationToken);
|
||||
return loans.Select(loan => ToLoanDto(
|
||||
loan.LoanId,
|
||||
loan.StudentId,
|
||||
loan.StudentName,
|
||||
loan.CardNumber,
|
||||
loan.BookId,
|
||||
loan.BookTitle,
|
||||
loan.BookNumber,
|
||||
loan.LoanedAt,
|
||||
loan.DueAt,
|
||||
loan.ReturnedAt,
|
||||
now)).ToList();
|
||||
}
|
||||
|
||||
public Task<IReadOnlyList<LoanDto>> GetOverdueAsync(CancellationToken cancellationToken) =>
|
||||
GetOverdueAsync(0, LibraryRules.DefaultPageSize, cancellationToken);
|
||||
|
||||
public async Task<IReadOnlyList<ActiveStudentDto>> GetActiveStudentsAsync(
|
||||
int skip,
|
||||
int take,
|
||||
CancellationToken cancellationToken) =>
|
||||
await dbContext.Students.AsNoTracking()
|
||||
.Where(student => student.IsActive && student.Loans.Any(loan => loan.ReturnedAt == null))
|
||||
.OrderBy(student => student.LastName)
|
||||
.ThenBy(student => student.FirstName)
|
||||
.Skip(Math.Max(0, skip))
|
||||
.Take(Math.Clamp(take, 1, LibraryRules.MaxPageSize))
|
||||
.Select(student => new ActiveStudentDto(
|
||||
student.StudentId,
|
||||
student.FirstName + " " + student.LastName,
|
||||
student.CardNumber,
|
||||
student.ClassName,
|
||||
student.Loans.Count(loan => loan.ReturnedAt == null)))
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
public Task<IReadOnlyList<ActiveStudentDto>> GetActiveStudentsAsync(CancellationToken cancellationToken) =>
|
||||
GetActiveStudentsAsync(0, LibraryRules.DefaultPageSize, cancellationToken);
|
||||
|
||||
public async Task<LibraryStatisticsDto> GetStatisticsAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var now = timeProvider.GetUtcNow();
|
||||
var totalBooks = await dbContext.Books.CountAsync(book => book.IsActive, cancellationToken);
|
||||
var activeLoans = await dbContext.Loans.CountAsync(loan => loan.ReturnedAt == null, cancellationToken);
|
||||
var availableBooks = await dbContext.Books.CountAsync(
|
||||
book => book.IsActive && !book.Loans.Any(loan => loan.ReturnedAt == null),
|
||||
cancellationToken);
|
||||
var totalStudents = await dbContext.Students.CountAsync(student => student.IsActive, cancellationToken);
|
||||
var overdueLoans = await dbContext.Loans.CountAsync(loan => loan.ReturnedAt == null && loan.DueAt < now, cancellationToken);
|
||||
return new LibraryStatisticsDto(totalBooks, availableBooks, totalStudents, activeLoans, overdueLoans);
|
||||
}
|
||||
|
||||
private static LoanDto ToLoanDto(
|
||||
Guid Id,
|
||||
Guid StudentId,
|
||||
string StudentName,
|
||||
string CardNumber,
|
||||
Guid BookId,
|
||||
string BookTitle,
|
||||
string BookNumber,
|
||||
DateTimeOffset LoanedAt,
|
||||
DateTimeOffset DueAt,
|
||||
DateTimeOffset? ReturnedAt,
|
||||
DateTimeOffset now)
|
||||
{
|
||||
var isOverdue = ReturnedAt is null && DueAt < now;
|
||||
var daysOverdue = isOverdue ? Math.Max(1, (int)Math.Floor((now - DueAt).TotalDays)) : 0;
|
||||
return new LoanDto(Id, StudentId, StudentName, CardNumber, BookId, BookTitle, BookNumber, LoanedAt, DueAt, ReturnedAt, isOverdue, daysOverdue);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user