Skip to content
This repository has been archived by the owner on Jul 12, 2024. It is now read-only.

Commit

Permalink
feat: revenue year report
Browse files Browse the repository at this point in the history
  • Loading branch information
foxminchan committed Jun 5, 2024
1 parent 6450452 commit 6bcce94
Show file tree
Hide file tree
Showing 8 changed files with 99 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace RookieShop.ApiService.Endpoints.Reports;

public sealed record RevenueYearRequest(int Year);
29 changes: 29 additions & 0 deletions src/RookieShop.ApiService/Endpoints/Reports/RevenueYear.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using MediatR;
using Microsoft.AspNetCore.Http.HttpResults;
using RookieShop.Application.Reports.DTOs;
using RookieShop.Application.Reports.Queries.RevenueYear;
using RookieShop.Infrastructure.Endpoints.Abstractions;
using RookieShop.Infrastructure.RateLimiter;

namespace RookieShop.ApiService.Endpoints.Reports;

public sealed class RevenueYear(ISender sender) : IEndpoint<Ok<List<RevenueYearDto>>, RevenueYearRequest>
{
public void MapEndpoint(IEndpointRouteBuilder app) =>
app.MapGet("/reports/revenue-year", async (int year) => await HandleAsync(new(year)))
.Produces<Ok<List<RevenueYearDto>>>()
.WithTags(nameof(Reports))
.WithName("Revenue Year")
.MapToApiVersion(new(1, 0))
.RequirePerIpRateLimit();

public async Task<Ok<List<RevenueYearDto>>> HandleAsync(RevenueYearRequest request,
CancellationToken cancellationToken = default)
{
RevenueYearQuery query = new(request.Year);

var result = await sender.Send(query, cancellationToken);

return TypedResults.Ok(result.Value.ToList());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,7 @@ protected override async Task DoWork(CancellationToken stoppingToken)

if (product is null) continue;

product.AverageRating = feedback.AverageRating;

product.TotalReviews = feedback.TotalFeedback;
product.UpdateRating(feedback.AverageRating, feedback.TotalFeedback);

dbContext.Products.Update(product);
}
Expand Down
7 changes: 7 additions & 0 deletions src/RookieShop.Application/Reports/DTOs/RevenueYearDto.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace RookieShop.Application.Reports.DTOs;

public sealed class RevenueYearDto
{
public string? Month { get; set; }
public decimal Revenue { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using Ardalis.Result;
using Dapper;
using RookieShop.Application.Reports.DTOs;
using RookieShop.Domain.SharedKernel;
using RookieShop.Persistence;

namespace RookieShop.Application.Reports.Queries.RevenueYear;

public sealed class RevenueYearHandler(IDatabaseFactory factory)
: IQueryHandler<RevenueYearQuery, Result<IEnumerable<RevenueYearDto>>>
{
public async Task<Result<IEnumerable<RevenueYearDto>>> Handle(RevenueYearQuery request,
CancellationToken cancellationToken)
{
const string sql = $"""
WITH monthly_revenue AS (
SELECT
to_char(o.created_date, 'Mon') AS month,
SUM(od.price * od.quantity) AS revenue
FROM orders o
JOIN order_details od ON o.id = od.order_id
WHERE EXTRACT(YEAR FROM o.created_date) = @year
GROUP BY to_char(o.created_date, 'Mon')
)
SELECT
month_names.month AS {nameof(RevenueYearDto.Month)},
COALESCE(monthly_revenue.revenue, 0) AS {nameof(RevenueYearDto.Revenue)}
FROM (
VALUES ('Jan'), ('Feb'), ('Mar'), ('Apr'), ('May'), ('Jun'),
('Jul'), ('Aug'), ('Sep'), ('Oct'), ('Nov'), ('Dec')
) AS month_names(month)
LEFT JOIN monthly_revenue ON month_names.month = monthly_revenue.month
ORDER BY month_names.month;
""";

using var conn = factory.GetOpenConnection();

var result = await conn.QueryAsync<RevenueYearDto>(sql,
new { year = request.Year });

return result.ToList();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
using Ardalis.Result;
using RookieShop.Application.Reports.DTOs;
using RookieShop.Domain.SharedKernel;

namespace RookieShop.Application.Reports.Queries.RevenueYear;

public sealed record RevenueYearQuery(int Year) : IQuery<Result<IEnumerable<RevenueYearDto>>>;
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using FluentValidation;

namespace RookieShop.Application.Reports.Queries.RevenueYear;

public sealed class RevenueYearValidator : AbstractValidator<RevenueYearQuery>
{
public RevenueYearValidator() => RuleFor(x => x.Year).NotEmpty().GreaterThan(2000);
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,5 @@ public sealed class ProductsFilterSpec : Specification<Product>
.ApplyOrdering(orderBy, isDescending);
}

public ProductsFilterSpec() => Query
.Where(product => !product.IsDeleted);
public ProductsFilterSpec() => Query.Where(product => !product.IsDeleted);
}

0 comments on commit 6bcce94

Please sign in to comment.