feat: add statistics in json format
refactor: move methods to their proper classes
This commit is contained in:
parent
7742a8d62a
commit
8f104c786e
@ -14,8 +14,8 @@ public class ReportController : ControllerBase
|
||||
_reportService = reportService;
|
||||
}
|
||||
|
||||
[HttpGet("ticket")]
|
||||
public async Task<IActionResult> GetTicket(int ticketGroupId)
|
||||
[HttpGet("pdf/ticket")]
|
||||
public async Task<IActionResult> GetTicketPdf(int ticketGroupId)
|
||||
{
|
||||
var result = await _reportService.GetTicket(ticketGroupId);
|
||||
|
||||
@ -24,21 +24,45 @@ public class ReportController : ControllerBase
|
||||
return BadRequest(result.actionResult);
|
||||
}
|
||||
|
||||
return File(result.ticketPdf, "application/pdf",
|
||||
$"ticket.pdf");
|
||||
return File(result.ticketPdf, "application/pdf", $"ticket.pdf");
|
||||
}
|
||||
|
||||
[HttpGet("report")]
|
||||
public async Task<IActionResult> GetCompanyReport(int companyId, DateTime fromDate, DateTime toDate)
|
||||
[HttpGet("pdf/company")]
|
||||
public async Task<IActionResult> GetCompanyReportPdf(int companyId, DateTime fromDate, DateTime toDate)
|
||||
{
|
||||
var result = await _reportService.GetCompanyReport(companyId, fromDate, toDate);
|
||||
var result = await _reportService.GetCompanyReportPdf(companyId, fromDate, toDate);
|
||||
|
||||
if (!result.isSucceed)
|
||||
{
|
||||
return BadRequest(result.actionResult);
|
||||
}
|
||||
|
||||
return File(result.reportPdf, "application/pdf",
|
||||
$"report.pdf");
|
||||
return File(result.reportPdf, "application/pdf", $"report.pdf");
|
||||
}
|
||||
|
||||
[HttpGet("raw/company")]
|
||||
public async Task<IActionResult> GetCompanyReportRaw(int companyId, DateTime fromDate, DateTime toDate)
|
||||
{
|
||||
var result = await _reportService.GetCompanyReportRaw(companyId, fromDate, toDate);
|
||||
|
||||
if (!result.isSucceed)
|
||||
{
|
||||
return BadRequest(result.actionResult);
|
||||
}
|
||||
|
||||
return Ok(result.statistics);
|
||||
}
|
||||
|
||||
[HttpGet("raw/admin")]
|
||||
public async Task<IActionResult> GetAdminReportRaw(DateTime fromDate, DateTime toDate)
|
||||
{
|
||||
var result = await _reportService.GetAdminReportRaw(fromDate, toDate);
|
||||
|
||||
if (!result.isSucceed)
|
||||
{
|
||||
return BadRequest(result.actionResult);
|
||||
}
|
||||
|
||||
return Ok(result.statistics);
|
||||
}
|
||||
}
|
||||
|
@ -16,4 +16,134 @@ public class Company
|
||||
|
||||
public virtual IList<Vehicle> Vehicles { get; set; } = null!;
|
||||
public virtual IList<CompanyDriver> CompanyDrivers { get; set; } = null!;
|
||||
|
||||
public int GetTotalEnrollmentCount()
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
foreach (var vehicle in Vehicles)
|
||||
{
|
||||
foreach (var enrollment in vehicle.VehicleEnrollments)
|
||||
{
|
||||
result += vehicle.GetEnrollmentCount(enrollment.RouteId);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public int GetTotalCanceledEnrollmentCount()
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
foreach (var vehicle in Vehicles)
|
||||
{
|
||||
foreach (var enrollment in vehicle.VehicleEnrollments)
|
||||
{
|
||||
result += vehicle.GetCanceledEnrollmentCount(enrollment.RouteId);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public int GetTotalSoldTicketCount()
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
foreach (var vehicle in Vehicles)
|
||||
{
|
||||
foreach (var enrollment in vehicle.VehicleEnrollments)
|
||||
{
|
||||
result += vehicle.GetSoldTicketCount(enrollment.RouteId);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public int GetTotalReturnedTicketCount()
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
foreach (var vehicle in Vehicles)
|
||||
{
|
||||
foreach (var enrollment in vehicle.VehicleEnrollments)
|
||||
{
|
||||
result += vehicle.GetReturnedTicketCount(enrollment.RouteId);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public int GetTotalIndirectTicketCount()
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
foreach (var vehicle in Vehicles)
|
||||
{
|
||||
foreach (var enrollment in vehicle.VehicleEnrollments)
|
||||
{
|
||||
result += vehicle.GetIndirectTicketCount(enrollment.RouteId);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public int GetTotalReturnedIndirectTicketCount()
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
foreach (var vehicle in Vehicles)
|
||||
{
|
||||
foreach (var enrollment in vehicle.VehicleEnrollments)
|
||||
{
|
||||
result += vehicle.GetReturnedIndirectTicketCount(enrollment.RouteId);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public double GetTotalRevenue()
|
||||
{
|
||||
double result = 0;
|
||||
|
||||
foreach (var vehicle in Vehicles)
|
||||
{
|
||||
foreach (var enrollment in vehicle.VehicleEnrollments)
|
||||
{
|
||||
result += vehicle.GetTotalRevenue(enrollment.RouteId);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public double GetTotalAverageRating()
|
||||
{
|
||||
double result = 0;
|
||||
int enrollmentCount = 0;
|
||||
|
||||
foreach (var vehicle in Vehicles)
|
||||
{
|
||||
foreach (var enrollment in vehicle.VehicleEnrollments)
|
||||
{
|
||||
if (enrollment.Reviews.Count == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
result += vehicle.GetAverageRating(enrollment.RouteId);
|
||||
enrollmentCount++;
|
||||
}
|
||||
}
|
||||
|
||||
result /= enrollmentCount;
|
||||
result = !Double.IsNaN(result) ? Math.Round(result, 3) : 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
@ -11,4 +11,83 @@ public class Route
|
||||
|
||||
public virtual IList<RouteAddress> RouteAddresses { get; set; } = null!;
|
||||
public virtual IList<VehicleEnrollment> VehicleEnrollments { get; set; } = null!;
|
||||
|
||||
public int GetEnrollmentCount()
|
||||
{
|
||||
return VehicleEnrollments.Count(ve => !ve.IsCanceled);
|
||||
}
|
||||
|
||||
public int GetCanceledEnrollmentCount()
|
||||
{
|
||||
return VehicleEnrollments.Count(ve => ve.IsCanceled);
|
||||
}
|
||||
|
||||
public int GetSoldTicketCount()
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
foreach (var enrollment in VehicleEnrollments)
|
||||
{
|
||||
result += enrollment.Tickets.Count(t => !t.IsReturned);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public int GetIndirectTicketCount()
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
int departureAddressId = RouteAddresses.First().AddressId;
|
||||
int arrivalAddressId = RouteAddresses.Last().AddressId;
|
||||
|
||||
foreach (var enrollment in VehicleEnrollments)
|
||||
{
|
||||
result += enrollment.Tickets.Count(t => !t.IsReturned &&
|
||||
t.FirstRouteAddressId != departureAddressId ||
|
||||
t.LastRouteAddressId != arrivalAddressId);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public double GetTotalRevenue()
|
||||
{
|
||||
double result = 0;
|
||||
|
||||
foreach (var enrollment in VehicleEnrollments)
|
||||
{
|
||||
foreach (var ticket in enrollment.Tickets)
|
||||
{
|
||||
result += ticket.GetCost();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public double GetAverageRating()
|
||||
{
|
||||
double result = 0;
|
||||
int reviewCount = 0;
|
||||
|
||||
foreach (var enrollment in VehicleEnrollments)
|
||||
{
|
||||
if (enrollment.Reviews.Count == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var review in enrollment.Reviews)
|
||||
{
|
||||
result += review.Rating;
|
||||
reviewCount += enrollment.Reviews.Count;
|
||||
}
|
||||
}
|
||||
|
||||
result /= reviewCount;
|
||||
result = !Double.IsNaN(result) ? Math.Round(result, 3) : 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -21,4 +21,88 @@ public class Ticket
|
||||
public int LastRouteAddressId { get; set; }
|
||||
public bool IsReturned { get; set; } = false;
|
||||
public bool IsMissed { get; set; } = false;
|
||||
|
||||
public double GetCost()
|
||||
{
|
||||
double cost = 0;
|
||||
|
||||
var routeAddresses = VehicleEnrollment.Route.RouteAddresses
|
||||
.OrderBy(ra => ra.Order)
|
||||
.SkipWhile(ra => ra.AddressId != FirstRouteAddressId)
|
||||
.TakeWhile(ra => ra.AddressId != LastRouteAddressId)
|
||||
.ToArray();
|
||||
|
||||
foreach (var routeAddress in routeAddresses)
|
||||
{
|
||||
var details = routeAddress.RouteAddressDetails
|
||||
.First(rad => rad.RouteAddressId == routeAddress.Id);
|
||||
|
||||
cost += details.CostToNextCity;
|
||||
}
|
||||
|
||||
return cost;
|
||||
}
|
||||
|
||||
public DateTime GetDepartureTime()
|
||||
{
|
||||
var departureDateTimeUtc = VehicleEnrollment.DepartureDateTimeUtc;
|
||||
|
||||
var routeAddresses = VehicleEnrollment.Route.RouteAddresses
|
||||
.OrderBy(ra => ra.Order).ToArray();
|
||||
|
||||
foreach (var routeAddress in routeAddresses)
|
||||
{
|
||||
var details = routeAddress.RouteAddressDetails
|
||||
.First(rad => rad.RouteAddressId == routeAddress.Id);
|
||||
|
||||
if (routeAddress.AddressId == FirstRouteAddressId)
|
||||
{
|
||||
departureDateTimeUtc += details.WaitTimeSpan;
|
||||
break;
|
||||
}
|
||||
|
||||
departureDateTimeUtc += details.TimeSpanToNextCity;
|
||||
departureDateTimeUtc += details.WaitTimeSpan;
|
||||
}
|
||||
|
||||
return departureDateTimeUtc;
|
||||
}
|
||||
|
||||
public DateTime GetArrivalTime()
|
||||
{
|
||||
var arrivalDateTimeUtc = VehicleEnrollment.DepartureDateTimeUtc;
|
||||
|
||||
var routeAddresses = VehicleEnrollment.Route.RouteAddresses
|
||||
.OrderBy(ra => ra.Order).ToArray();
|
||||
|
||||
foreach (var routeAddress in routeAddresses)
|
||||
{
|
||||
var details = routeAddress.RouteAddressDetails
|
||||
.First(rad => rad.RouteAddressId == routeAddress.Id);
|
||||
|
||||
if (routeAddress.AddressId == LastRouteAddressId)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
arrivalDateTimeUtc += details.TimeSpanToNextCity;
|
||||
arrivalDateTimeUtc += details.WaitTimeSpan;
|
||||
}
|
||||
|
||||
return arrivalDateTimeUtc;
|
||||
}
|
||||
|
||||
public Address GetDepartureAddress()
|
||||
{
|
||||
return VehicleEnrollment.Route.RouteAddresses
|
||||
.First(ra => ra.AddressId == FirstRouteAddressId)
|
||||
.Address;
|
||||
}
|
||||
|
||||
public Address GetArrivalAddress()
|
||||
{
|
||||
return VehicleEnrollment.Route.RouteAddresses
|
||||
.First(ra => ra.AddressId == LastRouteAddressId)
|
||||
.Address;
|
||||
}
|
||||
}
|
@ -11,4 +11,16 @@ public class TicketGroup
|
||||
public User User { get; set; } = null!;
|
||||
|
||||
public virtual IList<Ticket> Tickets { get; set; }
|
||||
|
||||
public double GetCost()
|
||||
{
|
||||
double cost = 0;
|
||||
|
||||
foreach (var ticket in Tickets)
|
||||
{
|
||||
cost += ticket.GetCost();
|
||||
}
|
||||
|
||||
return cost;
|
||||
}
|
||||
}
|
@ -25,4 +25,108 @@ public class Vehicle
|
||||
public bool HasBelts { get; set; }
|
||||
|
||||
public IList<VehicleEnrollment> VehicleEnrollments { get; set; } = null!;
|
||||
|
||||
public int GetEnrollmentCount(int routeId)
|
||||
{
|
||||
return VehicleEnrollments.Count(ve => !ve.IsCanceled && ve.RouteId == routeId);
|
||||
}
|
||||
|
||||
public int GetCanceledEnrollmentCount(int routeId)
|
||||
{
|
||||
return VehicleEnrollments.Count(ve => ve.IsCanceled && ve.RouteId == routeId);
|
||||
}
|
||||
|
||||
public int GetSoldTicketCount(int routeId)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
foreach (var enrollment in VehicleEnrollments.Where(ve => ve.RouteId == routeId))
|
||||
{
|
||||
result += enrollment.Tickets.Count(t => !t.IsReturned);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public int GetReturnedTicketCount(int routeId)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
foreach (var enrollment in VehicleEnrollments.Where(ve => ve.RouteId == routeId))
|
||||
{
|
||||
result += enrollment.Tickets.Count(t => t.IsReturned);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public int GetIndirectTicketCount(int routeId)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
foreach (var enrollment in VehicleEnrollments.Where(ve => ve.RouteId == routeId))
|
||||
{
|
||||
var departureRouteAddressId = enrollment.Route.RouteAddresses.First().AddressId;
|
||||
var arrivalRouteAddressId = enrollment.Route.RouteAddresses.Last().AddressId;
|
||||
|
||||
result += enrollment.Tickets.Count(t => !t.IsReturned &&
|
||||
t.FirstRouteAddressId != departureRouteAddressId ||
|
||||
t.LastRouteAddressId != arrivalRouteAddressId);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public int GetReturnedIndirectTicketCount(int routeId)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
foreach (var enrollment in VehicleEnrollments.Where(ve => ve.RouteId == routeId))
|
||||
{
|
||||
var departureRouteAddressId = enrollment.Route.RouteAddresses.First().AddressId;
|
||||
var arrivalRouteAddressId = enrollment.Route.RouteAddresses.Last().AddressId;
|
||||
|
||||
result += enrollment.Tickets.Count(t => t.IsReturned &&
|
||||
(t.FirstRouteAddressId != departureRouteAddressId ||
|
||||
t.LastRouteAddressId != arrivalRouteAddressId));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public double GetTotalRevenue(int routeId)
|
||||
{
|
||||
double result = 0;
|
||||
|
||||
foreach (var enrollment in VehicleEnrollments.Where(ve => ve.RouteId == routeId))
|
||||
{
|
||||
foreach (var ticket in enrollment.Tickets)
|
||||
{
|
||||
result += ticket.GetCost();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public double GetAverageRating(int routeId)
|
||||
{
|
||||
double result = 0;
|
||||
int reviewCount = 0;
|
||||
|
||||
foreach (var enrollment in VehicleEnrollments.Where(ve => ve.RouteId == routeId))
|
||||
{
|
||||
reviewCount += enrollment.Reviews.Count;
|
||||
|
||||
foreach (var review in enrollment.Reviews)
|
||||
{
|
||||
result += review.Rating;
|
||||
}
|
||||
}
|
||||
|
||||
result /= reviewCount;
|
||||
result = !Double.IsNaN(result) ? Math.Round(result, 3) : 0;
|
||||
|
||||
return Math.Round(result, 3);
|
||||
}
|
||||
}
|
@ -20,7 +20,7 @@ public class EmailSenderService : IEmailSenderService
|
||||
|
||||
_smtpCredentials = smtpCredentials.Value;
|
||||
_smtpClient = new SmtpClient();
|
||||
_smtpClient.SslProtocols = SslProtocols.Ssl3 | SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12 | SslProtocols.Tls13;
|
||||
_smtpClient.SslProtocols = SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12 | SslProtocols.Tls13;
|
||||
}
|
||||
|
||||
public async Task<(bool succeeded, string message)> SendMail(string toEmail, string subject, string message)
|
||||
@ -34,10 +34,11 @@ public class EmailSenderService : IEmailSenderService
|
||||
mailMessage.Subject = $"{applicationName}. {subject}";
|
||||
mailMessage.Body = new TextPart(MimeKit.Text.TextFormat.Text) { Text = message};
|
||||
|
||||
await _smtpClient.ConnectAsync(_smtpCredentials.Host, _smtpCredentials.Port, false);
|
||||
await _smtpClient.ConnectAsync(_smtpCredentials.Host, _smtpCredentials.Port, SecureSocketOptions.StartTls);
|
||||
await _smtpClient.AuthenticateAsync(Encoding.ASCII, _smtpCredentials.User, _smtpCredentials.Password);
|
||||
await _smtpClient.SendAsync(mailMessage);
|
||||
await _smtpClient.DisconnectAsync(true);
|
||||
_smtpClient.Dispose();
|
||||
|
||||
return (true, "Letter has been sent successfully");
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using SharedModels.Responses;
|
||||
|
||||
namespace Server.Services;
|
||||
|
||||
@ -8,5 +9,11 @@ public interface IReportService
|
||||
GetTicket(int ticketGroupId);
|
||||
|
||||
Task<(bool isSucceed, IActionResult? actionResult, Stream reportPdf)>
|
||||
GetCompanyReport(int companyId, DateTime fromDate, DateTime toDate);
|
||||
GetCompanyReportPdf(int companyId, DateTime fromDate, DateTime toDate);
|
||||
|
||||
Task<(bool isSucceed, IActionResult? actionResult, StatisticsResponse statistics)>
|
||||
GetCompanyReportRaw(int companyId, DateTime fromDate, DateTime toDate);
|
||||
|
||||
Task<(bool isSucceed, IActionResult? actionResult, StatisticsResponse statistics)>
|
||||
GetAdminReportRaw(DateTime fromDate, DateTime toDate);
|
||||
}
|
@ -8,6 +8,7 @@ using PdfSharpCore.Drawing;
|
||||
using PdfSharpCore.Pdf;
|
||||
using Server.Data;
|
||||
using Server.Models;
|
||||
using SharedModels.Responses;
|
||||
using Route = Server.Models.Route;
|
||||
|
||||
namespace Server.Services;
|
||||
@ -223,15 +224,8 @@ public class ReportService : IReportService
|
||||
for (var i = 0; i < ticketGroup.Tickets.Count; i++)
|
||||
{
|
||||
var ticket = ticketGroup.Tickets[i];
|
||||
|
||||
var vehicle = ticket.VehicleEnrollment.Vehicle;
|
||||
|
||||
var departureDateTimeUtc = GetDepartureTime(ticket);
|
||||
var arrivalDateTimeUtc = GetArrivalTime(ticket);
|
||||
|
||||
var departureAddress = GetDepartureAddress(ticket);
|
||||
var arrivalAddress = GetArrivalAddress(ticket);
|
||||
|
||||
row = table.AddRow();
|
||||
table.AddRow();
|
||||
row.Shading.Color = isFilled ? Color.FromRgbColor(25, Colors.Black) : Colors.White;
|
||||
@ -251,12 +245,12 @@ public class ReportService : IReportService
|
||||
|
||||
row.Cells[2].MergeRight = 1;
|
||||
row.Cells[2].MergeDown = 1;
|
||||
row.Cells[2].AddParagraph($"{departureDateTimeUtc:dd.MM.yyyy HH:mm}");
|
||||
row.Cells[2].AddParagraph($"{ticket.GetDepartureTime():dd.MM.yyyy HH:mm}");
|
||||
|
||||
row.Cells[4].MergeRight = 3;
|
||||
row.Cells[4].MergeDown = 1;
|
||||
row.Cells[4].Format.Font.Size = 8;
|
||||
row.Cells[4].AddParagraph($"{departureAddress.GetFullName()}");
|
||||
row.Cells[4].AddParagraph($"{ticket.GetDepartureAddress().GetFullName()}");
|
||||
|
||||
row.Cells[8].MergeRight = 1;
|
||||
row.Cells[8].MergeDown = 1;
|
||||
@ -285,12 +279,12 @@ public class ReportService : IReportService
|
||||
|
||||
row.Cells[2].MergeRight = 1;
|
||||
row.Cells[2].MergeDown = 1;
|
||||
row.Cells[2].AddParagraph($"{arrivalDateTimeUtc:dd.MM.yyyy HH:mm}");
|
||||
row.Cells[2].AddParagraph($"{ticket.GetArrivalTime():dd.MM.yyyy HH:mm}");
|
||||
|
||||
row.Cells[4].MergeRight = 3;
|
||||
row.Cells[4].MergeDown = 1;
|
||||
row.Cells[4].Format.Font.Size = 8;
|
||||
row.Cells[4].AddParagraph($"{arrivalAddress.GetFullName()}");
|
||||
row.Cells[4].AddParagraph($"{ticket.GetArrivalAddress().GetFullName()}");
|
||||
|
||||
row.Cells[8].MergeRight = 1;
|
||||
row.Cells[8].MergeDown = 1;
|
||||
@ -302,8 +296,8 @@ public class ReportService : IReportService
|
||||
|
||||
if (!ticketGroup.Tickets.Last().Equals(ticket))
|
||||
{
|
||||
var nextDepartureTimeUtc = GetDepartureTime(ticketGroup.Tickets[i + 1]);
|
||||
var freeTime = nextDepartureTimeUtc - arrivalDateTimeUtc;
|
||||
var nextDepartureTime = ticketGroup.Tickets[i + 1].GetDepartureTime();
|
||||
var freeTime = nextDepartureTime - ticket.GetArrivalTime();
|
||||
|
||||
row = table.AddRow();
|
||||
table.AddRow();
|
||||
@ -316,7 +310,7 @@ public class ReportService : IReportService
|
||||
|
||||
row.Cells[3].MergeRight = 5;
|
||||
row.Cells[3].MergeDown = 1;
|
||||
row.Cells[3].AddParagraph($"{arrivalDateTimeUtc:dd.MM.yyyy HH:mm} – {nextDepartureTimeUtc:dd.MM.yyyy HH:mm}");
|
||||
row.Cells[3].AddParagraph($"{ticket.GetArrivalTime():dd.MM.yyyy HH:mm} – {nextDepartureTime:dd.MM.yyyy HH:mm}");
|
||||
|
||||
row.Cells[9].MergeRight = 2;
|
||||
row.Cells[9].MergeDown = 1;
|
||||
@ -336,10 +330,6 @@ public class ReportService : IReportService
|
||||
|
||||
foreach (var ticket in ticketGroup.Tickets)
|
||||
{
|
||||
var departureAddress = GetDepartureAddress(ticket);
|
||||
var arrivalAddress = GetArrivalAddress(ticket);
|
||||
var cost = GetTicketCost(ticket);
|
||||
|
||||
row = table.AddRow();
|
||||
table.AddRow();
|
||||
row.Shading.Color = isFilled ? Color.FromRgbColor(25, Colors.Black) : Colors.White;
|
||||
@ -351,7 +341,7 @@ public class ReportService : IReportService
|
||||
row.Cells[1].MergeRight = 3;
|
||||
row.Cells[1].MergeDown = 1;
|
||||
row.Cells[1].Format.Font.Size = 8;
|
||||
row.Cells[1].AddParagraph($"{departureAddress.GetFullName()}");
|
||||
row.Cells[1].AddParagraph($"{ticket.GetDepartureAddress().GetFullName()}");
|
||||
|
||||
row.Cells[5].MergeDown = 1;
|
||||
row.Cells[5].AddParagraph("Куди");
|
||||
@ -359,17 +349,15 @@ public class ReportService : IReportService
|
||||
row.Cells[6].MergeRight = 3;
|
||||
row.Cells[6].MergeDown = 1;
|
||||
row.Cells[6].Format.Font.Size = 8;
|
||||
row.Cells[6].AddParagraph($"{arrivalAddress.GetFullName()}");
|
||||
row.Cells[6].AddParagraph($"{ticket.GetArrivalAddress().GetFullName()}");
|
||||
|
||||
row.Cells[10].MergeDown = 1;
|
||||
row.Cells[10].AddParagraph("Ціна");
|
||||
|
||||
row.Cells[11].MergeDown = 1;
|
||||
row.Cells[11].AddParagraph($"{cost}");
|
||||
row.Cells[11].AddParagraph($"{ticket.GetCost()}");
|
||||
}
|
||||
|
||||
var totalCost = GetTicketGroupCost(ticketGroup);
|
||||
|
||||
row = table.AddRow();
|
||||
row.Shading.Color = isFilled ? Color.FromRgbColor(25, Colors.Black) : Colors.White;
|
||||
isFilled = !isFilled;
|
||||
@ -380,113 +368,12 @@ public class ReportService : IReportService
|
||||
|
||||
row.Cells[10].Borders.Right.Color = Colors.Transparent;
|
||||
|
||||
row.Cells[11].AddParagraph($"{totalCost}");
|
||||
}
|
||||
|
||||
DateTime GetDepartureTime(Ticket ticket)
|
||||
{
|
||||
var departureDateTimeUtc = ticket.VehicleEnrollment.DepartureDateTimeUtc;
|
||||
|
||||
var routeAddresses = ticket.VehicleEnrollment.Route.RouteAddresses
|
||||
.OrderBy(ra => ra.Order).ToArray();
|
||||
|
||||
foreach (var routeAddress in routeAddresses)
|
||||
{
|
||||
var details = routeAddress.RouteAddressDetails
|
||||
.First(rad => rad.RouteAddressId == routeAddress.Id);
|
||||
|
||||
if (routeAddress.AddressId == ticket.FirstRouteAddressId)
|
||||
{
|
||||
departureDateTimeUtc += details.WaitTimeSpan;
|
||||
break;
|
||||
}
|
||||
|
||||
departureDateTimeUtc += details.TimeSpanToNextCity;
|
||||
departureDateTimeUtc += details.WaitTimeSpan;
|
||||
}
|
||||
|
||||
return departureDateTimeUtc;
|
||||
}
|
||||
|
||||
DateTime GetArrivalTime(Ticket ticket)
|
||||
{
|
||||
var arrivalDateTimeUtc = ticket.VehicleEnrollment.DepartureDateTimeUtc;
|
||||
|
||||
var routeAddresses = ticket.VehicleEnrollment.Route.RouteAddresses
|
||||
.OrderBy(ra => ra.Order).ToArray();
|
||||
|
||||
foreach (var routeAddress in routeAddresses)
|
||||
{
|
||||
var details = routeAddress.RouteAddressDetails
|
||||
.First(rad => rad.RouteAddressId == routeAddress.Id);
|
||||
|
||||
if (routeAddress.AddressId == ticket.LastRouteAddressId)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
arrivalDateTimeUtc += details.TimeSpanToNextCity;
|
||||
arrivalDateTimeUtc += details.WaitTimeSpan;
|
||||
}
|
||||
|
||||
return arrivalDateTimeUtc;
|
||||
}
|
||||
|
||||
Address GetDepartureAddress(Ticket ticket)
|
||||
{
|
||||
return ticket.VehicleEnrollment.Route.RouteAddresses
|
||||
.First(ra => ra.AddressId == ticket.FirstRouteAddressId)
|
||||
.Address;
|
||||
}
|
||||
|
||||
Address GetArrivalAddress(Ticket ticket)
|
||||
{
|
||||
return ticket.VehicleEnrollment.Route.RouteAddresses
|
||||
.First(ra => ra.AddressId == ticket.LastRouteAddressId)
|
||||
.Address;
|
||||
}
|
||||
|
||||
double GetTicketCost(Ticket ticket)
|
||||
{
|
||||
double cost = 0;
|
||||
|
||||
var routeAddresses = ticket.VehicleEnrollment.Route.RouteAddresses
|
||||
.OrderBy(ra => ra.Order)
|
||||
.SkipWhile(ra => ra.AddressId != ticket.FirstRouteAddressId)
|
||||
.TakeWhile(ra => ra.AddressId != ticket.LastRouteAddressId)
|
||||
.ToArray();
|
||||
|
||||
foreach (var routeAddress in routeAddresses)
|
||||
{
|
||||
var details = routeAddress.RouteAddressDetails
|
||||
.First(rad => rad.RouteAddressId == routeAddress.Id);
|
||||
|
||||
cost += details.CostToNextCity;
|
||||
}
|
||||
|
||||
return cost;
|
||||
}
|
||||
|
||||
double GetTicketGroupCost(TicketGroup ticketGroup)
|
||||
{
|
||||
double cost = 0;
|
||||
|
||||
foreach (var ticket in ticketGroup.Tickets)
|
||||
{
|
||||
cost += GetTicketCost(ticket);
|
||||
}
|
||||
|
||||
return cost;
|
||||
}
|
||||
|
||||
async Task<bool> DoesTicketGroupExist(int id)
|
||||
{
|
||||
return await _dbContext.TicketGroups.AnyAsync(tg => tg.Id == id);
|
||||
row.Cells[11].AddParagraph($"{ticketGroup.GetCost()}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<(bool isSucceed, IActionResult? actionResult, Stream reportPdf)>
|
||||
GetCompanyReport(int companyId, DateTime fromDate, DateTime toDate)
|
||||
GetCompanyReportPdf(int companyId, DateTime fromDate, DateTime toDate)
|
||||
{
|
||||
if (!await DoesCompanyExist(companyId))
|
||||
{
|
||||
@ -726,22 +613,22 @@ public class ReportService : IReportService
|
||||
row.Shading.Color = Color.FromRgbColor(25, Colors.Black);
|
||||
|
||||
row.Cells[0].MergeRight = 1;
|
||||
row.Cells[0].AddParagraph($"{GetRouteEnrollmentCount(route)}");
|
||||
row.Cells[0].AddParagraph($"{route.GetEnrollmentCount()}");
|
||||
|
||||
row.Cells[2].MergeRight = 1;
|
||||
row.Cells[2].AddParagraph($"{GetRouteCanceledEnrollmentCount(route)}");
|
||||
row.Cells[2].AddParagraph($"{route.GetCanceledEnrollmentCount()}");
|
||||
|
||||
row.Cells[4].MergeRight = 1;
|
||||
row.Cells[4].AddParagraph($"{GetRouteSelledTicketCount(route)}");
|
||||
row.Cells[4].AddParagraph($"{route.GetSoldTicketCount()}");
|
||||
|
||||
row.Cells[6].MergeRight = 1;
|
||||
row.Cells[6].AddParagraph($"{GetRouteIndirectTicketCount(route)}");
|
||||
row.Cells[6].AddParagraph($"{route.GetIndirectTicketCount()}");
|
||||
|
||||
row.Cells[8].MergeRight = 1;
|
||||
row.Cells[8].AddParagraph($"{GetRouteTotalRevenu(route)}");
|
||||
row.Cells[8].AddParagraph($"{route.GetTotalRevenue()}");
|
||||
|
||||
row.Cells[10].MergeRight = 1;
|
||||
var routeAverageRating = GetRouteAvarageRating(route);
|
||||
var routeAverageRating = route.GetAverageRating();
|
||||
row.Cells[10].AddParagraph($"{(routeAverageRating == 0 ? "-" : routeAverageRating)}");
|
||||
|
||||
row = table.AddRow();
|
||||
@ -783,21 +670,23 @@ public class ReportService : IReportService
|
||||
row.Cells[0].MergeRight = 2;
|
||||
row.Cells[0].AddParagraph($"{vehicle.Id}, {vehicle.Type}, {vehicle.Number}");
|
||||
|
||||
var executedEnrollmentCount = GetVehicleEnrollmentCount(vehicle, route.Id);
|
||||
var canceledEnrollmentCount = GetVehicleCanceledEnrollmentCount(vehicle, route.Id);
|
||||
var executedEnrollmentCount = vehicle.GetEnrollmentCount(route.Id);
|
||||
var canceledEnrollmentCount = vehicle.GetCanceledEnrollmentCount(route.Id);
|
||||
row.Cells[3].MergeRight = 1;
|
||||
row.Cells[3].AddParagraph($"{executedEnrollmentCount + canceledEnrollmentCount}, " +
|
||||
$"{executedEnrollmentCount}, {canceledEnrollmentCount}");
|
||||
|
||||
row.Cells[5].MergeRight = 2;
|
||||
row.Cells[5].AddParagraph($"{GetVehicleSelledTicketCount(vehicle, route.Id)}, {GetVehicleReturnedTicketCount(vehicle, route.Id)}; " +
|
||||
$"{GetVehicleIndirectTicketCount(vehicle, route.Id)}, {GetVehicleReturnedIndirectTicketCount(vehicle, route.Id)}");
|
||||
row.Cells[5].AddParagraph($"{vehicle.GetSoldTicketCount(route.Id)}, " +
|
||||
$"{vehicle.GetReturnedTicketCount(route.Id)}; " +
|
||||
$"{vehicle.GetIndirectTicketCount(route.Id)}, " +
|
||||
$"{vehicle.GetReturnedIndirectTicketCount(route.Id)}");
|
||||
|
||||
row.Cells[8].MergeRight = 1;
|
||||
row.Cells[8].AddParagraph($"{GetVehicleTotalRevenue(vehicle, route.Id)}");
|
||||
row.Cells[8].AddParagraph($"{vehicle.GetTotalRevenue(route.Id)}");
|
||||
|
||||
row.Cells[10].MergeRight = 1;
|
||||
var vehicleAverageRating = GetVehicleAverageRating(vehicle, route.Id);
|
||||
var vehicleAverageRating = vehicle.GetAverageRating(route.Id);
|
||||
row.Cells[10].AddParagraph($"{(vehicleAverageRating == 0 ? "-" : vehicleAverageRating)}");
|
||||
}
|
||||
|
||||
@ -812,372 +701,140 @@ public class ReportService : IReportService
|
||||
paragraph.Format.Font.Bold = true;
|
||||
section.AddParagraph();
|
||||
|
||||
var totalEnrollmentCount = GetTotalEnrollmentCount(dbCompany);
|
||||
var totalCanceledEnrollmentCount = GetTotalCanceledEnrollmentCount(dbCompany);
|
||||
var totalSoldTicketCount = GetTotalSoldTickets(dbCompany);
|
||||
var totalReturnedTicketCount = GetTotalReturnedTicketCount(dbCompany);
|
||||
var totalRevenue = GetTotalRevenu(dbCompany);
|
||||
var totalAverageRating = GetTotalAverageRating(dbCompany);
|
||||
|
||||
paragraph = section.AddParagraph(
|
||||
$"У період з {fromDate:dd.MM.yyyy} по {toDate:dd.MM.yyyy} " +
|
||||
$"({(toDate - fromDate).Days} днів) компанією {dbCompany.Name} " +
|
||||
$"було заплановано {(totalEnrollmentCount)} поїздки, " +
|
||||
$"з яких {totalCanceledEnrollmentCount} було скасовано, " +
|
||||
$"продано {totalSoldTicketCount} квитків, " +
|
||||
$"з яких {totalReturnedTicketCount} було повернено. " +
|
||||
$"За цей час було зароблено {totalRevenue} гривень. " +
|
||||
$"Середній рейтинг по всім поїздкам: {totalAverageRating}");
|
||||
$"було заплановано {dbCompany.GetTotalEnrollmentCount()} поїздки, " +
|
||||
$"з яких {dbCompany.GetTotalCanceledEnrollmentCount()} було скасовано, " +
|
||||
$"продано {dbCompany.GetTotalSoldTicketCount()} квитків, " +
|
||||
$"з яких {dbCompany.GetTotalReturnedTicketCount()} було повернено. " +
|
||||
$"За цей час було зароблено {dbCompany.GetTotalRevenue()} гривень. " +
|
||||
$"Середній рейтинг по всім поїздкам: {dbCompany.GetTotalAverageRating()}");
|
||||
paragraph.Format.Alignment = ParagraphAlignment.Justify;
|
||||
paragraph.Format.Font.Size = 14;
|
||||
|
||||
int GetRouteEnrollmentCount(Route route)
|
||||
{
|
||||
return route.VehicleEnrollments.Count(ve => !ve.IsCanceled);
|
||||
}
|
||||
|
||||
int GetVehicleEnrollmentCount(Vehicle vehicle, int routeId)
|
||||
{
|
||||
return vehicle.VehicleEnrollments.Count(ve =>
|
||||
!ve.IsCanceled && ve.RouteId == routeId);
|
||||
}
|
||||
|
||||
int GetTotalEnrollmentCount(Company company)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
foreach (var vehicle in company.Vehicles)
|
||||
{
|
||||
foreach (var enrollment in vehicle.VehicleEnrollments)
|
||||
{
|
||||
result += GetVehicleEnrollmentCount(vehicle, enrollment.RouteId);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int GetRouteCanceledEnrollmentCount(Route route)
|
||||
{
|
||||
return route.VehicleEnrollments.Count(ve => ve.IsCanceled);
|
||||
}
|
||||
|
||||
int GetVehicleCanceledEnrollmentCount(Vehicle vehicle, int routeId)
|
||||
{
|
||||
return vehicle.VehicleEnrollments.Count(ve =>
|
||||
ve.IsCanceled && ve.RouteId == routeId);
|
||||
}
|
||||
|
||||
int GetTotalCanceledEnrollmentCount(Company company)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
foreach (var vehicle in company.Vehicles)
|
||||
{
|
||||
foreach (var enrollment in vehicle.VehicleEnrollments)
|
||||
{
|
||||
result += GetVehicleCanceledEnrollmentCount(vehicle, enrollment.RouteId);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int GetRouteSelledTicketCount(Route route)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
foreach (var enrollment in route.VehicleEnrollments)
|
||||
{
|
||||
result += enrollment.Tickets.Count(t => !t.IsReturned);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int GetVehicleSelledTicketCount(Vehicle vehicle, int routeId)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
foreach (var enrollment in vehicle.VehicleEnrollments
|
||||
.Where(ve => ve.RouteId == routeId))
|
||||
{
|
||||
result += enrollment.Tickets.Count(t => !t.IsReturned);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int GetTotalSoldTickets(Company company)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
foreach (var vehicle in company.Vehicles)
|
||||
{
|
||||
foreach (var enrollment in vehicle.VehicleEnrollments)
|
||||
{
|
||||
result += GetVehicleSelledTicketCount(vehicle, enrollment.RouteId);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int GetVehicleReturnedTicketCount(Vehicle vehicle, int routeId)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
foreach (var enrollment in vehicle.VehicleEnrollments
|
||||
.Where(ve => ve.RouteId == routeId))
|
||||
{
|
||||
result += enrollment.Tickets.Count(t => t.IsReturned);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int GetTotalReturnedTicketCount(Company company)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
foreach (var vehicle in company.Vehicles)
|
||||
{
|
||||
foreach (var enrollment in vehicle.VehicleEnrollments)
|
||||
{
|
||||
result += GetVehicleReturnedTicketCount(vehicle, enrollment.RouteId);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int GetRouteIndirectTicketCount(Route route)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
int departureAddressId = route.RouteAddresses.First().AddressId;
|
||||
int arrivalAddressId = route.RouteAddresses.Last().AddressId;
|
||||
|
||||
foreach (var enrollment in route.VehicleEnrollments)
|
||||
{
|
||||
result += enrollment.Tickets.Count(t => !t.IsReturned &&
|
||||
t.FirstRouteAddressId != departureAddressId ||
|
||||
t.LastRouteAddressId != arrivalAddressId);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int GetVehicleIndirectTicketCount(Vehicle vehicle, int routeId)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
foreach (var enrollment in vehicle.VehicleEnrollments
|
||||
.Where(ve => ve.RouteId == routeId))
|
||||
{
|
||||
var departureRouteAddressId = enrollment.Route.RouteAddresses.First().AddressId;
|
||||
var arrivalRouteAddressId = enrollment.Route.RouteAddresses.Last().AddressId;
|
||||
|
||||
result += enrollment.Tickets.Count(t => !t.IsReturned &&
|
||||
t.FirstRouteAddressId != departureRouteAddressId ||
|
||||
t.LastRouteAddressId != arrivalRouteAddressId);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int GetTotalIndirectTicketCount(Company company)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
foreach (var vehicle in company.Vehicles)
|
||||
{
|
||||
foreach (var enrollment in vehicle.VehicleEnrollments)
|
||||
{
|
||||
result += GetVehicleIndirectTicketCount(vehicle, enrollment.RouteId);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int GetVehicleReturnedIndirectTicketCount(Vehicle vehicle, int routeId)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
foreach (var enrollment in vehicle.VehicleEnrollments
|
||||
.Where(ve => ve.RouteId == routeId))
|
||||
{
|
||||
var departureRouteAddressId = enrollment.Route.RouteAddresses.First().AddressId;
|
||||
var arrivalRouteAddressId = enrollment.Route.RouteAddresses.Last().AddressId;
|
||||
|
||||
result += enrollment.Tickets.Count(t => t.IsReturned &&
|
||||
(t.FirstRouteAddressId != departureRouteAddressId ||
|
||||
t.LastRouteAddressId != arrivalRouteAddressId));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int GetTotalReturnedIndirectTicketCount(Company company)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
foreach (var vehicle in company.Vehicles)
|
||||
{
|
||||
foreach (var enrollment in vehicle.VehicleEnrollments)
|
||||
{
|
||||
result += GetVehicleReturnedIndirectTicketCount(vehicle, enrollment.RouteId);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
double GetRouteTotalRevenu(Route route)
|
||||
{
|
||||
double result = 0;
|
||||
|
||||
foreach (var enrollment in route.VehicleEnrollments)
|
||||
{
|
||||
foreach (var ticket in enrollment.Tickets)
|
||||
{
|
||||
result += GetTicketCost(ticket);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
double GetVehicleTotalRevenue(Vehicle vehicle, int routeId)
|
||||
{
|
||||
double result = 0;
|
||||
|
||||
foreach (var enrollment in vehicle.VehicleEnrollments
|
||||
.Where(ve => ve.RouteId == routeId))
|
||||
{
|
||||
foreach (var ticket in enrollment.Tickets)
|
||||
{
|
||||
result += GetTicketCost(ticket);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
double GetTotalRevenu(Company company)
|
||||
{
|
||||
double result = 0;
|
||||
|
||||
foreach (var vehicle in company.Vehicles)
|
||||
{
|
||||
foreach (var enrollment in vehicle.VehicleEnrollments)
|
||||
{
|
||||
result += GetVehicleTotalRevenue(vehicle, enrollment.RouteId);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
double GetRouteAvarageRating(Route route)
|
||||
{
|
||||
double result = 0;
|
||||
int reviewCount = 0;
|
||||
|
||||
foreach (var enrollment in route.VehicleEnrollments)
|
||||
{
|
||||
if (enrollment.Reviews.Count == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var review in enrollment.Reviews)
|
||||
{
|
||||
result += review.Rating;
|
||||
reviewCount += enrollment.Reviews.Count;
|
||||
}
|
||||
}
|
||||
|
||||
result /= reviewCount;
|
||||
result = !Double.IsNaN(result) ? Math.Round(result, 3) : 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
double GetVehicleAverageRating(Vehicle vehicle, int routeId)
|
||||
{
|
||||
double result = 0;
|
||||
int reviewCount = 0;
|
||||
|
||||
foreach (var enrollment in vehicle.VehicleEnrollments
|
||||
.Where(ve => ve.RouteId == routeId))
|
||||
{
|
||||
reviewCount += enrollment.Reviews.Count;
|
||||
|
||||
foreach (var review in enrollment.Reviews)
|
||||
{
|
||||
result += review.Rating;
|
||||
}
|
||||
}
|
||||
|
||||
result /= reviewCount;
|
||||
result = !Double.IsNaN(result) ? Math.Round(result, 3) : 0;
|
||||
|
||||
return Math.Round(result, 3);
|
||||
}
|
||||
|
||||
double GetTotalAverageRating(Company company)
|
||||
{
|
||||
double result = 0;
|
||||
int enrollmentCount = 0;
|
||||
|
||||
foreach (var vehicle in company.Vehicles)
|
||||
{
|
||||
foreach (var enrollment in vehicle.VehicleEnrollments)
|
||||
{
|
||||
if (enrollment.Reviews.Count == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
result += GetVehicleAverageRating(vehicle, enrollment.RouteId);
|
||||
enrollmentCount++;
|
||||
}
|
||||
}
|
||||
|
||||
result /= enrollmentCount;
|
||||
result = !Double.IsNaN(result) ? Math.Round(result, 3) : 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// TODO: repeated function, yoinked from ticket generation
|
||||
double GetTicketCost(Ticket ticket)
|
||||
{
|
||||
double cost = 0;
|
||||
|
||||
var routeAddresses = ticket.VehicleEnrollment.Route.RouteAddresses
|
||||
.OrderBy(ra => ra.Order)
|
||||
.SkipWhile(ra => ra.AddressId != ticket.FirstRouteAddressId)
|
||||
.TakeWhile(ra => ra.AddressId != ticket.LastRouteAddressId)
|
||||
.ToArray();
|
||||
|
||||
foreach (var routeAddress in routeAddresses)
|
||||
{
|
||||
var details = routeAddress.RouteAddressDetails
|
||||
.First(rad => rad.RouteAddressId == routeAddress.Id);
|
||||
|
||||
cost += details.CostToNextCity;
|
||||
}
|
||||
|
||||
return cost;
|
||||
}
|
||||
}
|
||||
|
||||
async Task<bool> DoesCompanyExist(int id)
|
||||
{
|
||||
return await _dbContext.Companies.AnyAsync(c => c.Id == id);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<(bool isSucceed, IActionResult? actionResult, StatisticsResponse statistics)>
|
||||
GetCompanyReportRaw(int companyId, DateTime fromDate, DateTime toDate)
|
||||
{
|
||||
if (!await DoesCompanyExist(companyId))
|
||||
{
|
||||
return (false, new NotFoundResult(), null!);
|
||||
}
|
||||
|
||||
var dbCompany = await _dbContext.Companies
|
||||
.Include(c => c.Vehicles)
|
||||
.ThenInclude(v => v.VehicleEnrollments)
|
||||
.ThenInclude(ve => ve.Reviews)
|
||||
|
||||
.Include(c => c.Vehicles)
|
||||
.ThenInclude(v => v.VehicleEnrollments)
|
||||
.ThenInclude(ve => ve.Tickets)
|
||||
.ThenInclude(t => t.TicketGroup)
|
||||
|
||||
.Include(c => c.Vehicles)
|
||||
.ThenInclude(v => v.VehicleEnrollments)
|
||||
.ThenInclude(ve => ve.Route)
|
||||
.ThenInclude(r => r.RouteAddresses)
|
||||
.ThenInclude(ra => ra.Address)
|
||||
.ThenInclude(a => a.City)
|
||||
.ThenInclude(c => c.State)
|
||||
.ThenInclude(s => s.Country)
|
||||
|
||||
.Include(c => c.Vehicles)
|
||||
.ThenInclude(v => v.VehicleEnrollments)
|
||||
.ThenInclude(ve => ve.RouteAddressDetails)
|
||||
|
||||
.Select(c => new {
|
||||
Company = c,
|
||||
VehicleEnrollments = c.Vehicles
|
||||
.Select(v => new {
|
||||
Vehicle = v,
|
||||
VehicleEnrollments = v.VehicleEnrollments.Where(ve =>
|
||||
ve.DepartureDateTimeUtc.Date >= fromDate &&
|
||||
ve.DepartureDateTimeUtc <= toDate)
|
||||
})
|
||||
})
|
||||
.Select(o => o.Company)
|
||||
.FirstAsync(c => c.Id == companyId);
|
||||
|
||||
var statistics = new StatisticsResponse
|
||||
{
|
||||
EnrollmentsPlanned = dbCompany.GetTotalEnrollmentCount(),
|
||||
EnrollmentsCanceled = dbCompany.GetTotalCanceledEnrollmentCount(),
|
||||
TicketsSold = dbCompany.GetTotalSoldTicketCount(),
|
||||
TicketsReturned = dbCompany.GetTotalReturnedTicketCount(),
|
||||
MoneyEarned = dbCompany.GetTotalRevenue(),
|
||||
AverageRating = dbCompany.GetTotalAverageRating()
|
||||
};
|
||||
|
||||
return (true, null, statistics);
|
||||
}
|
||||
|
||||
public async Task<(bool isSucceed, IActionResult? actionResult, StatisticsResponse statistics)>
|
||||
GetAdminReportRaw(DateTime fromDate, DateTime toDate)
|
||||
{
|
||||
var dbCompanies = await _dbContext.Companies
|
||||
.Include(c => c.Vehicles)
|
||||
.ThenInclude(v => v.VehicleEnrollments)
|
||||
.ThenInclude(ve => ve.Reviews)
|
||||
|
||||
.Include(c => c.Vehicles)
|
||||
.ThenInclude(v => v.VehicleEnrollments)
|
||||
.ThenInclude(ve => ve.Tickets)
|
||||
.ThenInclude(t => t.TicketGroup)
|
||||
|
||||
.Include(c => c.Vehicles)
|
||||
.ThenInclude(v => v.VehicleEnrollments)
|
||||
.ThenInclude(ve => ve.Route)
|
||||
.ThenInclude(r => r.RouteAddresses)
|
||||
.ThenInclude(ra => ra.Address)
|
||||
.ThenInclude(a => a.City)
|
||||
.ThenInclude(c => c.State)
|
||||
.ThenInclude(s => s.Country)
|
||||
|
||||
.Include(c => c.Vehicles)
|
||||
.ThenInclude(v => v.VehicleEnrollments)
|
||||
.ThenInclude(ve => ve.RouteAddressDetails)
|
||||
|
||||
.Select(c => new
|
||||
{
|
||||
Company = c,
|
||||
VehicleEnrollments = c.Vehicles
|
||||
.Select(v => new
|
||||
{
|
||||
Vehicle = v,
|
||||
VehicleEnrollments = v.VehicleEnrollments.Where(ve =>
|
||||
ve.DepartureDateTimeUtc.Date >= fromDate &&
|
||||
ve.DepartureDateTimeUtc <= toDate)
|
||||
})
|
||||
})
|
||||
.Select(o => o.Company)
|
||||
.ToArrayAsync();
|
||||
|
||||
var statistics = new StatisticsResponse();
|
||||
|
||||
foreach (var company in dbCompanies)
|
||||
{
|
||||
statistics.EnrollmentsPlanned += company.GetTotalEnrollmentCount();
|
||||
statistics.EnrollmentsCanceled += company.GetTotalCanceledEnrollmentCount();
|
||||
statistics.TicketsSold += company.GetTotalSoldTicketCount();
|
||||
statistics.TicketsReturned += company.GetTotalReturnedTicketCount();
|
||||
statistics.MoneyEarned += company.GetTotalRevenue();
|
||||
statistics.AverageRating += company.GetTotalAverageRating();
|
||||
}
|
||||
|
||||
return (true, null, statistics);
|
||||
}
|
||||
|
||||
async Task<bool> DoesCompanyExist(int id)
|
||||
{
|
||||
return await _dbContext.Companies.AnyAsync(c => c.Id == id);
|
||||
}
|
||||
|
||||
async Task<bool> DoesTicketGroupExist(int id)
|
||||
{
|
||||
return await _dbContext.TicketGroups.AnyAsync(tg => tg.Id == id);
|
||||
}
|
||||
}
|
11
SharedModels/Responses/StatisticsResponse.cs
Normal file
11
SharedModels/Responses/StatisticsResponse.cs
Normal file
@ -0,0 +1,11 @@
|
||||
namespace SharedModels.Responses;
|
||||
|
||||
public class StatisticsResponse
|
||||
{
|
||||
public int EnrollmentsPlanned { get; set; }
|
||||
public int EnrollmentsCanceled { get; set; }
|
||||
public int TicketsSold { get; set; }
|
||||
public int TicketsReturned { get; set; }
|
||||
public double MoneyEarned { get; set; }
|
||||
public double AverageRating { get; set; }
|
||||
}
|
Loading…
Reference in New Issue
Block a user