add ticket group creation
This commit is contained in:
parent
5982fa7285
commit
674130c52a
@ -21,4 +21,35 @@ public static class CustomValidators
|
|||||||
ruleBuilder
|
ruleBuilder
|
||||||
.Matches(@"^\+[0-9]{7,15}$");
|
.Matches(@"^\+[0-9]{7,15}$");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static IRuleBuilderOptions<T, ICollection<TSource>>
|
||||||
|
IsUnique<T, TSource, TResult>(
|
||||||
|
this IRuleBuilder<T, ICollection<TSource>> ruleBuilder,
|
||||||
|
Func<TSource, TResult> selector)
|
||||||
|
{
|
||||||
|
if (selector == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(
|
||||||
|
nameof(selector),
|
||||||
|
"Cannot pass a null selector.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
ruleBuilder
|
||||||
|
.Must(x => x.IsDistinct(selector));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsDistinct<TSource, TResult>(
|
||||||
|
this IEnumerable<TSource> elements, Func<TSource, TResult> selector)
|
||||||
|
{
|
||||||
|
var hashSet = new HashSet<TResult>();
|
||||||
|
foreach (var element in elements.Select(selector))
|
||||||
|
{
|
||||||
|
if (!hashSet.Contains(element))
|
||||||
|
hashSet.Add(element);
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
using cuqmbr.TravelGuide.Domain.Entities;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Common.Interfaces
|
||||||
|
.Persistence.Repositories;
|
||||||
|
|
||||||
|
public interface RouteAddressDetailRepository :
|
||||||
|
BaseRepository<RouteAddressDetail> { }
|
@ -0,0 +1,6 @@
|
|||||||
|
using cuqmbr.TravelGuide.Domain.Entities;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Common.Interfaces
|
||||||
|
.Persistence.Repositories;
|
||||||
|
|
||||||
|
public interface TicketGroupRepository : BaseRepository<TicketGroup> { }
|
@ -0,0 +1,6 @@
|
|||||||
|
using cuqmbr.TravelGuide.Domain.Entities;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Common.Interfaces
|
||||||
|
.Persistence.Repositories;
|
||||||
|
|
||||||
|
public interface TicketRepository : BaseRepository<Ticket> { }
|
@ -30,6 +30,12 @@ public interface UnitOfWork : IDisposable
|
|||||||
|
|
||||||
EmployeeRepository EmployeeRepository { get; }
|
EmployeeRepository EmployeeRepository { get; }
|
||||||
|
|
||||||
|
TicketGroupRepository TicketGroupRepository { get; }
|
||||||
|
|
||||||
|
TicketRepository TicketRepository { get; }
|
||||||
|
|
||||||
|
RouteAddressDetailRepository RouteAddressDetailRepository { get; }
|
||||||
|
|
||||||
int Save();
|
int Save();
|
||||||
|
|
||||||
Task<int> SaveAsync(CancellationToken cancellationToken);
|
Task<int> SaveAsync(CancellationToken cancellationToken);
|
||||||
|
@ -6,7 +6,8 @@
|
|||||||
"LessThanOrEqualTo": "Must be less than or equal to {0}.",
|
"LessThanOrEqualTo": "Must be less than or equal to {0}.",
|
||||||
"MustBeInEnum": "Must be one of the following: {0}.",
|
"MustBeInEnum": "Must be one of the following: {0}.",
|
||||||
"IsEmail": "Must be a valid email address according to RFC 5321.",
|
"IsEmail": "Must be a valid email address according to RFC 5321.",
|
||||||
"IsPhoneNumber": "Must be a valid phone number according to ITU-T E.164 with no separator characters."
|
"IsPhoneNumber": "Must be a valid phone number according to ITU-T E.164 with no separator characters.",
|
||||||
|
"IsUnique": "Elements of the collection must be unique."
|
||||||
},
|
},
|
||||||
"Validation": {
|
"Validation": {
|
||||||
"DistinctOrder": "Must have distinct order values.",
|
"DistinctOrder": "Must have distinct order values.",
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
using cuqmbr.TravelGuide.Domain.Enums;
|
||||||
|
using MediatR;
|
||||||
|
using cuqmbr.TravelGuide.Application.TicketGroups.Models;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.TicketGroups.Commands.AddTicketGroup;
|
||||||
|
|
||||||
|
public record AddTicketGroupCommand : IRequest<TicketGroupDto>
|
||||||
|
{
|
||||||
|
public string PassangerFirstName { get; set; }
|
||||||
|
|
||||||
|
public string PassangerLastName { get; set; }
|
||||||
|
|
||||||
|
public string PassangerPatronymic { get; set; }
|
||||||
|
|
||||||
|
public Sex PassangerSex { get; set; }
|
||||||
|
|
||||||
|
public DateOnly PassangerBirthDate { get; set; }
|
||||||
|
|
||||||
|
public DateTimeOffset PurchaseTime { get; set; }
|
||||||
|
|
||||||
|
public bool Returned { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
public ICollection<TicketModel> Tickets { get; set; }
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
using cuqmbr.TravelGuide.Application.Common.Authorization;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Models;
|
||||||
|
using MediatR.Behaviors.Authorization;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.TicketGroups.Commands.AddTicketGroup;
|
||||||
|
|
||||||
|
public class AddTicketGroupCommandAuthorizer :
|
||||||
|
AbstractRequestAuthorizer<AddTicketGroupCommand>
|
||||||
|
{
|
||||||
|
private readonly SessionUserService _sessionUserService;
|
||||||
|
|
||||||
|
public AddTicketGroupCommandAuthorizer(SessionUserService sessionUserService)
|
||||||
|
{
|
||||||
|
_sessionUserService = sessionUserService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void BuildPolicy(AddTicketGroupCommand request)
|
||||||
|
{
|
||||||
|
UseRequirement(new MustBeAuthenticatedRequirement
|
||||||
|
{
|
||||||
|
IsAuthenticated= _sessionUserService.IsAuthenticated
|
||||||
|
});
|
||||||
|
|
||||||
|
UseRequirement(new MustBeInRolesRequirement
|
||||||
|
{
|
||||||
|
RequiredRoles = [IdentityRole.Administrator],
|
||||||
|
UserRoles = _sessionUserService.Roles
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,449 @@
|
|||||||
|
// Check for todos in this file
|
||||||
|
// Change NotImplementedException to proper ones
|
||||||
|
|
||||||
|
using MediatR;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence;
|
||||||
|
using cuqmbr.TravelGuide.Domain.Entities;
|
||||||
|
using AutoMapper;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Exceptions;
|
||||||
|
using Microsoft.Extensions.Localization;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
|
||||||
|
using cuqmbr.TravelGuide.Domain.Enums;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.TicketGroups.Commands.AddTicketGroup;
|
||||||
|
|
||||||
|
public class AddTicketGroupCommandHandler :
|
||||||
|
IRequestHandler<AddTicketGroupCommand, TicketGroupDto>
|
||||||
|
{
|
||||||
|
private readonly UnitOfWork _unitOfWork;
|
||||||
|
private readonly IMapper _mapper;
|
||||||
|
private readonly IStringLocalizer _localizer;
|
||||||
|
|
||||||
|
private readonly SessionCurrencyService _sessionCurrencyService;
|
||||||
|
private readonly CurrencyConverterService _currencyConverterService;
|
||||||
|
|
||||||
|
public AddTicketGroupCommandHandler(
|
||||||
|
UnitOfWork unitOfWork,
|
||||||
|
IMapper mapper,
|
||||||
|
IStringLocalizer localizer,
|
||||||
|
SessionCurrencyService sessionCurrencyService,
|
||||||
|
CurrencyConverterService currencyConverterService)
|
||||||
|
{
|
||||||
|
_unitOfWork = unitOfWork;
|
||||||
|
_mapper = mapper;
|
||||||
|
_localizer = localizer;
|
||||||
|
_sessionCurrencyService = sessionCurrencyService;
|
||||||
|
_currencyConverterService = currencyConverterService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<TicketGroupDto> Handle(
|
||||||
|
AddTicketGroupCommand request,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
// Check whether provided vehicle enrollments are present in datastore.
|
||||||
|
{
|
||||||
|
var vehicleEnrollmentGuids =
|
||||||
|
request.Tickets.Select(t => t.VehicleEnrollmentGuid);
|
||||||
|
|
||||||
|
var vehicleEnrollments = (await _unitOfWork.VehicleEnrollmentRepository
|
||||||
|
.GetPageAsync(
|
||||||
|
e => vehicleEnrollmentGuids.Contains(e.Guid),
|
||||||
|
1, vehicleEnrollmentGuids.Count(), cancellationToken))
|
||||||
|
.Items;
|
||||||
|
|
||||||
|
|
||||||
|
if (vehicleEnrollmentGuids.Count() > vehicleEnrollments.Count)
|
||||||
|
{
|
||||||
|
throw new NotFoundException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Check whether provided arrival and departure address guids
|
||||||
|
// are used in provided vehicle enrollment and
|
||||||
|
// and are in the correct order.
|
||||||
|
{
|
||||||
|
var vehicleEnrollmentGuids =
|
||||||
|
request.Tickets.Select(t => t.VehicleEnrollmentGuid);
|
||||||
|
|
||||||
|
var vehicleEnrollments = (await _unitOfWork.VehicleEnrollmentRepository
|
||||||
|
.GetPageAsync(
|
||||||
|
e => vehicleEnrollmentGuids.Contains(e.Guid),
|
||||||
|
1, vehicleEnrollmentGuids.Count(), cancellationToken))
|
||||||
|
.Items;
|
||||||
|
|
||||||
|
|
||||||
|
var routeAddressGuids =
|
||||||
|
request.Tickets.Select(t => t.DepartureRouteAddressGuid).Concat(
|
||||||
|
request.Tickets.Select(t => t.ArrivalRouteAddressGuid));
|
||||||
|
|
||||||
|
var routeAddresses = (await _unitOfWork.RouteAddressRepository
|
||||||
|
.GetPageAsync(
|
||||||
|
e =>
|
||||||
|
routeAddressGuids.Contains(e.Guid),
|
||||||
|
1, routeAddressGuids.Count(), cancellationToken))
|
||||||
|
.Items;
|
||||||
|
|
||||||
|
|
||||||
|
foreach (var t in request.Tickets)
|
||||||
|
{
|
||||||
|
var departureRouteAddress = routeAddresses.First(
|
||||||
|
ra => ra.Guid == t.DepartureRouteAddressGuid);
|
||||||
|
var arrivalRouteAddress = routeAddresses.First(
|
||||||
|
ra => ra.Guid == t.ArrivalRouteAddressGuid);
|
||||||
|
|
||||||
|
var ve = vehicleEnrollments.First(
|
||||||
|
e => e.Guid == t.VehicleEnrollmentGuid);
|
||||||
|
|
||||||
|
if (departureRouteAddress.RouteId != ve.RouteId ||
|
||||||
|
arrivalRouteAddress.RouteId != ve.RouteId)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (departureRouteAddress.Order > arrivalRouteAddress.Order)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check availability of free places.
|
||||||
|
{
|
||||||
|
// Get all tickets for vehicle enrollments requested in ticket group.
|
||||||
|
var vehicleEnrollmentGuids =
|
||||||
|
request.Tickets.Select(t => t.VehicleEnrollmentGuid);
|
||||||
|
|
||||||
|
var ticketGroupTickets = (await _unitOfWork.TicketRepository
|
||||||
|
.GetPageAsync(
|
||||||
|
e =>
|
||||||
|
vehicleEnrollmentGuids.Contains(e.VehicleEnrollment.Guid) &&
|
||||||
|
e.TicketGroup.Returned == false,
|
||||||
|
1, int.MaxValue, cancellationToken))
|
||||||
|
.Items;
|
||||||
|
|
||||||
|
|
||||||
|
// Get all vehicle enrollments requested in ticket group
|
||||||
|
// together with vehicles.
|
||||||
|
var vehicleEnrollments = (await _unitOfWork.VehicleEnrollmentRepository
|
||||||
|
.GetPageAsync(
|
||||||
|
e => vehicleEnrollmentGuids.Contains(e.Guid),
|
||||||
|
e => e.Vehicle,
|
||||||
|
1, vehicleEnrollmentGuids.Count(), cancellationToken))
|
||||||
|
.Items;
|
||||||
|
|
||||||
|
|
||||||
|
// Get all route addresses of vehicle enrollments
|
||||||
|
// requested in ticket group.
|
||||||
|
var routeIds = vehicleEnrollments.Select(e => e.RouteId);
|
||||||
|
|
||||||
|
var routeAddresses = (await _unitOfWork.RouteAddressRepository
|
||||||
|
.GetPageAsync(
|
||||||
|
e => routeIds.Contains(e.RouteId),
|
||||||
|
1, int.MaxValue, cancellationToken))
|
||||||
|
.Items;
|
||||||
|
|
||||||
|
// For each ticket in request.
|
||||||
|
foreach (var requestTicket in request.Tickets)
|
||||||
|
{
|
||||||
|
// Get vehicle enrollment of requested ticket.
|
||||||
|
var requestVehicleEnrollment = vehicleEnrollments.First(e =>
|
||||||
|
e.Guid == requestTicket.VehicleEnrollmentGuid);
|
||||||
|
|
||||||
|
// Get bought tickets of vehicle enrollment of requested ticket.
|
||||||
|
var tickets = ticketGroupTickets.Where(t =>
|
||||||
|
t.VehicleEnrollmentId == requestVehicleEnrollment.Id);
|
||||||
|
|
||||||
|
// Get route addresses of vehicle enrollment.
|
||||||
|
var ticketRouteAddresses = routeAddresses
|
||||||
|
.Where(e => e.RouteId == requestVehicleEnrollment.RouteId)
|
||||||
|
.OrderBy(e => e.Order);
|
||||||
|
|
||||||
|
|
||||||
|
// Count available capacity.
|
||||||
|
|
||||||
|
// Get total capacity in requested vehicle.
|
||||||
|
int totalCapacity;
|
||||||
|
var vehicle = vehicleEnrollments.First(e =>
|
||||||
|
e.Guid == requestTicket.VehicleEnrollmentGuid)
|
||||||
|
.Vehicle;
|
||||||
|
if (vehicle.VehicleType.Equals(VehicleType.Bus))
|
||||||
|
{
|
||||||
|
totalCapacity = ((Bus)vehicle).Capacity;
|
||||||
|
}
|
||||||
|
else if (vehicle.VehicleType.Equals(VehicleType.Aircraft))
|
||||||
|
{
|
||||||
|
totalCapacity = ((Aircraft)vehicle).Capacity;
|
||||||
|
}
|
||||||
|
else if (vehicle.VehicleType.Equals(VehicleType.Train))
|
||||||
|
{
|
||||||
|
totalCapacity = ((Train)vehicle).Capacity;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
int takenCapacity = 0;
|
||||||
|
|
||||||
|
// For each bought ticket.
|
||||||
|
foreach (var ticket in tickets)
|
||||||
|
{
|
||||||
|
// Get departure and arrival route address
|
||||||
|
// of requested ticket.
|
||||||
|
var requestDepartureRouteAddress = ticketRouteAddresses
|
||||||
|
.Single(e =>
|
||||||
|
e.Guid == requestTicket.DepartureRouteAddressGuid);
|
||||||
|
var requestArrivalRouteAddress = ticketRouteAddresses
|
||||||
|
.Single(e =>
|
||||||
|
e.Guid == requestTicket.ArrivalRouteAddressGuid);
|
||||||
|
|
||||||
|
// Get departure and arrival route address
|
||||||
|
// of bought ticket.
|
||||||
|
var departureRouteAddress = ticketRouteAddresses
|
||||||
|
.Single(e =>
|
||||||
|
e.Id == ticket.DepartureRouteAddressId);
|
||||||
|
var arrivalRouteAddress = ticketRouteAddresses
|
||||||
|
.Single(e =>
|
||||||
|
e.Id == ticket.ArrivalRouteAddressId);
|
||||||
|
|
||||||
|
|
||||||
|
// Count taken capacity in requested vehicle
|
||||||
|
// accounting for requested ticket
|
||||||
|
// departure and arrival route addresses.
|
||||||
|
// The algorithm is the same as vehicle enrollment
|
||||||
|
// time overlap check.
|
||||||
|
if ((requestDepartureRouteAddress.Order >=
|
||||||
|
departureRouteAddress.Order &&
|
||||||
|
requestDepartureRouteAddress.Order <
|
||||||
|
arrivalRouteAddress.Order) ||
|
||||||
|
(requestArrivalRouteAddress.Order <=
|
||||||
|
arrivalRouteAddress.Order &&
|
||||||
|
requestArrivalRouteAddress.Order >
|
||||||
|
departureRouteAddress.Order) ||
|
||||||
|
(requestDepartureRouteAddress.Order <=
|
||||||
|
departureRouteAddress.Order &&
|
||||||
|
requestArrivalRouteAddress.Order >=
|
||||||
|
arrivalRouteAddress.Order))
|
||||||
|
{
|
||||||
|
takenCapacity++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var availableCapacity = totalCapacity - takenCapacity;
|
||||||
|
|
||||||
|
if (availableCapacity <= 0)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate travel time and cost.
|
||||||
|
|
||||||
|
var ticketsDetails = new List<(short order, DateTimeOffset departureTime,
|
||||||
|
DateTimeOffset arrivalTime, decimal cost, Currency currency)>();
|
||||||
|
|
||||||
|
{
|
||||||
|
var vehicleEnrollmentGuids =
|
||||||
|
request.Tickets.Select(t => t.VehicleEnrollmentGuid);
|
||||||
|
|
||||||
|
var vehicleEnrollments = (await _unitOfWork.VehicleEnrollmentRepository
|
||||||
|
.GetPageAsync(
|
||||||
|
e => vehicleEnrollmentGuids.Contains(e.Guid),
|
||||||
|
1, vehicleEnrollmentGuids.Count(), cancellationToken))
|
||||||
|
.Items;
|
||||||
|
|
||||||
|
|
||||||
|
var routeAddressGuids =
|
||||||
|
request.Tickets.Select(t => t.DepartureRouteAddressGuid).Concat(
|
||||||
|
request.Tickets.Select(t => t.ArrivalRouteAddressGuid));
|
||||||
|
|
||||||
|
var routeAddresses = (await _unitOfWork.RouteAddressRepository
|
||||||
|
.GetPageAsync(
|
||||||
|
e =>
|
||||||
|
routeAddressGuids.Contains(e.Guid),
|
||||||
|
1, routeAddressGuids.Count(), cancellationToken))
|
||||||
|
.Items;
|
||||||
|
|
||||||
|
|
||||||
|
var vehicleEnrollmentIds = vehicleEnrollments.Select(ve => ve.Id);
|
||||||
|
|
||||||
|
var allRouteAddressDetails = (await _unitOfWork
|
||||||
|
.RouteAddressDetailRepository.GetPageAsync(
|
||||||
|
e => vehicleEnrollmentIds.Contains(e.VehicleEnrollmentId),
|
||||||
|
e => e.RouteAddress,
|
||||||
|
1, int.MaxValue, cancellationToken))
|
||||||
|
.Items;
|
||||||
|
|
||||||
|
|
||||||
|
foreach (var t in request.Tickets.OrderBy(t => t.Order))
|
||||||
|
{
|
||||||
|
var ve = vehicleEnrollments.First(
|
||||||
|
e => e.Guid == t.VehicleEnrollmentGuid);
|
||||||
|
|
||||||
|
var departureRouteAddressId = routeAddresses.First(
|
||||||
|
ra => ra.Guid == t.DepartureRouteAddressGuid)
|
||||||
|
.Id;
|
||||||
|
var arrivalRouteAddressId = routeAddresses.First(
|
||||||
|
ra => ra.Guid == t.ArrivalRouteAddressGuid)
|
||||||
|
.Id;
|
||||||
|
|
||||||
|
var verad = allRouteAddressDetails
|
||||||
|
.Where(arad => arad.VehicleEnrollmentId == ve.Id)
|
||||||
|
.OrderBy(rad => rad.RouteAddress.Order)
|
||||||
|
.TakeWhile(rad => rad.Id != arrivalRouteAddressId);
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: This counts departure address stop time which is
|
||||||
|
// not wrong but may be not desired.
|
||||||
|
var timeToDeparture = verad
|
||||||
|
.TakeWhile(rad => rad.Id != departureRouteAddressId)
|
||||||
|
.Aggregate(TimeSpan.Zero, (sum, next) =>
|
||||||
|
sum + next.TimeToNextAddress + next.CurrentAddressStopTime);
|
||||||
|
|
||||||
|
var departureTime = ve.DepartureTime.Add(timeToDeparture);
|
||||||
|
|
||||||
|
|
||||||
|
var timeToArrival = verad.Aggregate(TimeSpan.Zero, (sum, next) =>
|
||||||
|
sum + next.TimeToNextAddress + next.CurrentAddressStopTime);
|
||||||
|
|
||||||
|
var arrivalTime = ve.DepartureTime.Add(timeToArrival);
|
||||||
|
|
||||||
|
|
||||||
|
var costToDeparture = verad
|
||||||
|
.TakeWhile(rad => rad.Id != departureRouteAddressId)
|
||||||
|
.Aggregate((decimal)0, (sum, next) =>
|
||||||
|
sum + next.CostToNextAddress);
|
||||||
|
|
||||||
|
var costToArrival = verad
|
||||||
|
.Aggregate((decimal)0, (sum, next) =>
|
||||||
|
sum + next.CostToNextAddress);
|
||||||
|
|
||||||
|
var cost = costToArrival - costToDeparture;
|
||||||
|
|
||||||
|
|
||||||
|
ticketsDetails.Add(
|
||||||
|
(t.Order, departureTime, arrivalTime, cost, ve.Currency));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check whether there are overlaps in ticket departure/arrival times.
|
||||||
|
{
|
||||||
|
for (int i = 1; i < ticketsDetails.Count; i++)
|
||||||
|
{
|
||||||
|
var previousTd = ticketsDetails[i - 1];
|
||||||
|
var currentTd = ticketsDetails[i];
|
||||||
|
|
||||||
|
if (previousTd.arrivalTime >= currentTd.departureTime)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create entity and insert into a datastore.
|
||||||
|
|
||||||
|
var ticketsCostDetails = new List<(short order,
|
||||||
|
decimal cost, Currency currency)>();
|
||||||
|
|
||||||
|
TimeSpan travelTime;
|
||||||
|
|
||||||
|
{
|
||||||
|
travelTime =
|
||||||
|
ticketsDetails.OrderBy(td => td.order).Last().arrivalTime -
|
||||||
|
ticketsDetails.OrderBy(td => td.order).First().departureTime;
|
||||||
|
|
||||||
|
foreach (var td in ticketsDetails)
|
||||||
|
{
|
||||||
|
var initialCurrency = td.currency;
|
||||||
|
var convertedCurrency =
|
||||||
|
_sessionCurrencyService.Currency != Currency.Default ?
|
||||||
|
_sessionCurrencyService.Currency :
|
||||||
|
initialCurrency;
|
||||||
|
|
||||||
|
var cost = td.cost;
|
||||||
|
|
||||||
|
var convertedCost = await _currencyConverterService
|
||||||
|
.ConvertAsync(cost, initialCurrency,
|
||||||
|
convertedCurrency, cancellationToken);
|
||||||
|
|
||||||
|
ticketsCostDetails.Add((td.order, convertedCost, convertedCurrency));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var vehicleEnrollmentGuids =
|
||||||
|
request.Tickets.Select(t => t.VehicleEnrollmentGuid);
|
||||||
|
|
||||||
|
var vehicleEnrollments = (await _unitOfWork.VehicleEnrollmentRepository
|
||||||
|
.GetPageAsync(
|
||||||
|
e => vehicleEnrollmentGuids.Contains(e.Guid),
|
||||||
|
1, vehicleEnrollmentGuids.Count(), cancellationToken))
|
||||||
|
.Items;
|
||||||
|
|
||||||
|
|
||||||
|
var routeAddressGuids =
|
||||||
|
request.Tickets.Select(t => t.DepartureRouteAddressGuid).Concat(
|
||||||
|
request.Tickets.Select(t => t.ArrivalRouteAddressGuid));
|
||||||
|
|
||||||
|
var routeAddresses = (await _unitOfWork.RouteAddressRepository
|
||||||
|
.GetPageAsync(
|
||||||
|
e => routeAddressGuids.Contains(e.Guid),
|
||||||
|
e => e.Address.City.Region.Country,
|
||||||
|
1, routeAddressGuids.Count(), cancellationToken))
|
||||||
|
.Items;
|
||||||
|
|
||||||
|
|
||||||
|
var entity = new TicketGroup()
|
||||||
|
{
|
||||||
|
PassangerFirstName = request.PassangerFirstName,
|
||||||
|
PassangerLastName = request.PassangerLastName,
|
||||||
|
PassangerPatronymic = request.PassangerPatronymic,
|
||||||
|
PassangerSex = request.PassangerSex,
|
||||||
|
PassangerBirthDate = request.PassangerBirthDate,
|
||||||
|
PurchaseTime = request.PurchaseTime,
|
||||||
|
Returned = request.Returned,
|
||||||
|
TravelTime = travelTime,
|
||||||
|
Tickets = request.Tickets.Select(
|
||||||
|
t =>
|
||||||
|
{
|
||||||
|
var ve = vehicleEnrollments.First(
|
||||||
|
ve => ve.Guid == t.VehicleEnrollmentGuid);
|
||||||
|
|
||||||
|
|
||||||
|
var departureRouteAddress = routeAddresses.First(
|
||||||
|
ra => ra.Guid == t.DepartureRouteAddressGuid);
|
||||||
|
var arrivalRouteAddress = routeAddresses.First(
|
||||||
|
ra => ra.Guid == t.ArrivalRouteAddressGuid);
|
||||||
|
|
||||||
|
|
||||||
|
var costDetail = ticketsCostDetails
|
||||||
|
.SingleOrDefault(td => td.order == t.Order);
|
||||||
|
|
||||||
|
|
||||||
|
return new Ticket()
|
||||||
|
{
|
||||||
|
DepartureRouteAddressId = departureRouteAddress.Id,
|
||||||
|
DepartureRouteAddress = departureRouteAddress,
|
||||||
|
ArrivalRouteAddressId = arrivalRouteAddress.Id,
|
||||||
|
ArrivalRouteAddress = arrivalRouteAddress,
|
||||||
|
Order = t.Order,
|
||||||
|
Cost = costDetail.cost,
|
||||||
|
Currency = costDetail.currency,
|
||||||
|
VehicleEnrollmentId = ve.Id
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.ToArray()
|
||||||
|
};
|
||||||
|
|
||||||
|
entity = await _unitOfWork.TicketGroupRepository.AddOneAsync(
|
||||||
|
entity, cancellationToken);
|
||||||
|
|
||||||
|
await _unitOfWork.SaveAsync(cancellationToken);
|
||||||
|
_unitOfWork.Dispose();
|
||||||
|
|
||||||
|
return _mapper.Map<TicketGroupDto>(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,107 @@
|
|||||||
|
using cuqmbr.TravelGuide.Application.Common.FluentValidation;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
|
||||||
|
using cuqmbr.TravelGuide.Domain.Enums;
|
||||||
|
using FluentValidation;
|
||||||
|
using Microsoft.Extensions.Localization;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.TicketGroups.Commands.AddTicketGroup;
|
||||||
|
|
||||||
|
public class AddTicketGroupCommandValidator : AbstractValidator<AddTicketGroupCommand>
|
||||||
|
{
|
||||||
|
public AddTicketGroupCommandValidator(
|
||||||
|
IStringLocalizer localizer,
|
||||||
|
SessionCultureService cultureService)
|
||||||
|
{
|
||||||
|
RuleFor(tg => tg.PassangerFirstName)
|
||||||
|
.NotEmpty()
|
||||||
|
.WithMessage(localizer["FluentValidation.NotEmpty"])
|
||||||
|
.MaximumLength(32)
|
||||||
|
.WithMessage(
|
||||||
|
String.Format(
|
||||||
|
cultureService.Culture,
|
||||||
|
localizer["FluentValidation.MaximumLength"],
|
||||||
|
32));
|
||||||
|
|
||||||
|
RuleFor(tg => tg.PassangerLastName)
|
||||||
|
.NotEmpty()
|
||||||
|
.WithMessage(localizer["FluentValidation.NotEmpty"])
|
||||||
|
.MaximumLength(32)
|
||||||
|
.WithMessage(
|
||||||
|
String.Format(
|
||||||
|
cultureService.Culture,
|
||||||
|
localizer["FluentValidation.MaximumLength"],
|
||||||
|
32));
|
||||||
|
|
||||||
|
RuleFor(tg => tg.PassangerPatronymic)
|
||||||
|
.NotEmpty()
|
||||||
|
.WithMessage(localizer["FluentValidation.NotEmpty"])
|
||||||
|
.MaximumLength(32)
|
||||||
|
.WithMessage(
|
||||||
|
String.Format(
|
||||||
|
cultureService.Culture,
|
||||||
|
localizer["FluentValidation.MaximumLength"],
|
||||||
|
32));
|
||||||
|
|
||||||
|
RuleFor(tg => tg.PassangerSex)
|
||||||
|
.Must((tg, s) => Sex.Enumerations.ContainsValue(s))
|
||||||
|
.WithMessage(
|
||||||
|
String.Format(
|
||||||
|
localizer["FluentValidation.MustBeInEnum"],
|
||||||
|
String.Join(
|
||||||
|
", ",
|
||||||
|
Sex.Enumerations.Values.Select(e => e.Name))));
|
||||||
|
|
||||||
|
RuleFor(tg => tg.PassangerBirthDate)
|
||||||
|
.GreaterThanOrEqualTo(DateOnly.FromDateTime(DateTime.UtcNow.AddYears(-100)))
|
||||||
|
.WithMessage(
|
||||||
|
String.Format(
|
||||||
|
cultureService.Culture,
|
||||||
|
localizer["FluentValidation.GreaterThanOrEqualTo"],
|
||||||
|
DateOnly.FromDateTime(DateTime.UtcNow.AddYears(-100))));
|
||||||
|
|
||||||
|
RuleFor(tg => tg.PurchaseTime)
|
||||||
|
.GreaterThanOrEqualTo(DateTimeOffset.UtcNow)
|
||||||
|
.WithMessage(
|
||||||
|
String.Format(
|
||||||
|
cultureService.Culture,
|
||||||
|
localizer["FluentValidation.GreaterThanOrEqualTo"],
|
||||||
|
DateTimeOffset.UtcNow));
|
||||||
|
|
||||||
|
RuleFor(tg => tg.Tickets)
|
||||||
|
.IsUnique(t => t.VehicleEnrollmentGuid)
|
||||||
|
.WithMessage(localizer["FluentValidation.IsUnique"]);
|
||||||
|
|
||||||
|
RuleFor(tg => tg.Tickets)
|
||||||
|
.IsUnique(t => t.Order)
|
||||||
|
.WithMessage(localizer["FluentValidation.IsUnique"]);
|
||||||
|
|
||||||
|
RuleForEach(tg => tg.Tickets).ChildRules(t =>
|
||||||
|
{
|
||||||
|
t.RuleFor(t => t.DepartureRouteAddressGuid)
|
||||||
|
.NotEmpty()
|
||||||
|
.WithMessage(localizer["FluentValidation.NotEmpty"]);
|
||||||
|
|
||||||
|
t.RuleFor(t => t.ArrivalRouteAddressGuid)
|
||||||
|
.NotEmpty()
|
||||||
|
.WithMessage(localizer["FluentValidation.NotEmpty"]);
|
||||||
|
|
||||||
|
t.RuleFor(t => t.Order)
|
||||||
|
.GreaterThanOrEqualTo(short.MinValue)
|
||||||
|
.WithMessage(
|
||||||
|
String.Format(
|
||||||
|
cultureService.Culture,
|
||||||
|
localizer["FluentValidation.GreaterThanOrEqualTo"],
|
||||||
|
short.MinValue))
|
||||||
|
.LessThanOrEqualTo(short.MaxValue)
|
||||||
|
.WithMessage(
|
||||||
|
String.Format(
|
||||||
|
cultureService.Culture,
|
||||||
|
localizer["FluentValidation.LessThanOrEqualTo"],
|
||||||
|
short.MaxValue));
|
||||||
|
|
||||||
|
t.RuleFor(t => t.VehicleEnrollmentGuid)
|
||||||
|
.NotEmpty()
|
||||||
|
.WithMessage(localizer["FluentValidation.NotEmpty"]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
13
src/Application/TicketGroups/Models/TicketModel.cs
Normal file
13
src/Application/TicketGroups/Models/TicketModel.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
namespace cuqmbr.TravelGuide.Application.TicketGroups.Models;
|
||||||
|
|
||||||
|
public sealed class TicketModel
|
||||||
|
{
|
||||||
|
public Guid DepartureRouteAddressGuid { get; set; }
|
||||||
|
|
||||||
|
public Guid ArrivalRouteAddressGuid { get; set; }
|
||||||
|
|
||||||
|
public short Order { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
public Guid VehicleEnrollmentGuid { get; set; }
|
||||||
|
}
|
53
src/Application/TicketGroups/TicketAddressDto.cs
Normal file
53
src/Application/TicketGroups/TicketAddressDto.cs
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
using cuqmbr.TravelGuide.Application.Common.Mappings;
|
||||||
|
using cuqmbr.TravelGuide.Domain.Entities;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.TicketGroups;
|
||||||
|
|
||||||
|
public sealed class TicketAddressDto : IMapFrom<Address>
|
||||||
|
{
|
||||||
|
public Guid Uuid { get; set; }
|
||||||
|
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
public double Longitude { get; set; }
|
||||||
|
|
||||||
|
public double Latitude { get; set; }
|
||||||
|
|
||||||
|
public Guid CountryUuid { get; set; }
|
||||||
|
|
||||||
|
public string CountryName { get; set; }
|
||||||
|
|
||||||
|
public Guid RegionUuid { get; set; }
|
||||||
|
|
||||||
|
public string RegionName { get; set; }
|
||||||
|
|
||||||
|
public Guid CityUuid { get; set; }
|
||||||
|
|
||||||
|
public string CityName { get; set; }
|
||||||
|
|
||||||
|
public void Mapping(MappingProfile profile)
|
||||||
|
{
|
||||||
|
profile.CreateMap<Address, TicketAddressDto>()
|
||||||
|
.ForMember(
|
||||||
|
d => d.Uuid,
|
||||||
|
opt => opt.MapFrom(s => s.Guid))
|
||||||
|
.ForMember(
|
||||||
|
d => d.CountryUuid,
|
||||||
|
opt => opt.MapFrom(s => s.City.Region.Country.Guid))
|
||||||
|
.ForMember(
|
||||||
|
d => d.CountryName,
|
||||||
|
opt => opt.MapFrom(s => s.City.Region.Country.Name))
|
||||||
|
.ForMember(
|
||||||
|
d => d.RegionUuid,
|
||||||
|
opt => opt.MapFrom(s => s.City.Region.Guid))
|
||||||
|
.ForMember(
|
||||||
|
d => d.RegionName,
|
||||||
|
opt => opt.MapFrom(s => s.City.Region.Name))
|
||||||
|
.ForMember(
|
||||||
|
d => d.CityUuid,
|
||||||
|
opt => opt.MapFrom(s => s.City.Guid))
|
||||||
|
.ForMember(
|
||||||
|
d => d.CityName,
|
||||||
|
opt => opt.MapFrom(s => s.City.Name));
|
||||||
|
}
|
||||||
|
}
|
50
src/Application/TicketGroups/TicketDto.cs
Normal file
50
src/Application/TicketGroups/TicketDto.cs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
using cuqmbr.TravelGuide.Application.Common.Mappings;
|
||||||
|
using cuqmbr.TravelGuide.Domain.Entities;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.TicketGroups;
|
||||||
|
|
||||||
|
public sealed class TicketDto : IMapFrom<Ticket>
|
||||||
|
{
|
||||||
|
public Guid Uuid { get; set; }
|
||||||
|
|
||||||
|
public Guid DepartureRouteAddressUuid { get; set; }
|
||||||
|
|
||||||
|
public Guid ArrivalRouteAddressUuid { get; set; }
|
||||||
|
|
||||||
|
public TicketAddressDto DepartureAddress { get; set; }
|
||||||
|
|
||||||
|
public TicketAddressDto ArrivalAddress { get; set; }
|
||||||
|
|
||||||
|
public short Order { get; set; }
|
||||||
|
|
||||||
|
public Guid VehicleEnrollmentUuid { get; set; }
|
||||||
|
|
||||||
|
// TODO: Add VehicleEnrollment model
|
||||||
|
|
||||||
|
public string Currency { get; set; }
|
||||||
|
|
||||||
|
public decimal Cost { get; set; }
|
||||||
|
|
||||||
|
public void Mapping(MappingProfile profile)
|
||||||
|
{
|
||||||
|
profile.CreateMap<Ticket, TicketDto>()
|
||||||
|
.ForMember(
|
||||||
|
d => d.Uuid,
|
||||||
|
opt => opt.MapFrom(s => s.Guid))
|
||||||
|
.ForMember(
|
||||||
|
d => d.DepartureRouteAddressUuid,
|
||||||
|
opt => opt.MapFrom(s => s.DepartureRouteAddress.Guid))
|
||||||
|
.ForMember(
|
||||||
|
d => d.ArrivalRouteAddressUuid,
|
||||||
|
opt => opt.MapFrom(s => s.ArrivalRouteAddress.Guid))
|
||||||
|
.ForMember(
|
||||||
|
d => d.DepartureAddress,
|
||||||
|
opt => opt.MapFrom(s => s.DepartureRouteAddress.Address))
|
||||||
|
.ForMember(
|
||||||
|
d => d.ArrivalAddress,
|
||||||
|
opt => opt.MapFrom(s => s.ArrivalRouteAddress.Address))
|
||||||
|
.ForMember(
|
||||||
|
d => d.VehicleEnrollmentUuid,
|
||||||
|
opt => opt.MapFrom(s => s.VehicleEnrollment.Guid));
|
||||||
|
}
|
||||||
|
}
|
45
src/Application/TicketGroups/TicketGroupDto.cs
Normal file
45
src/Application/TicketGroups/TicketGroupDto.cs
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
using cuqmbr.TravelGuide.Application.Common.Mappings;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Mappings.Resolvers;
|
||||||
|
using cuqmbr.TravelGuide.Domain.Entities;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.TicketGroups;
|
||||||
|
|
||||||
|
public sealed class TicketGroupDto : IMapFrom<TicketGroup>
|
||||||
|
{
|
||||||
|
public Guid Uuid { get; set; }
|
||||||
|
|
||||||
|
public string PassangerFirstName { get; set; }
|
||||||
|
|
||||||
|
public string PassangerLastName { get; set; }
|
||||||
|
|
||||||
|
public string PassangerPatronymic { get; set; }
|
||||||
|
|
||||||
|
public string PassangerSex { get; set; }
|
||||||
|
|
||||||
|
public DateOnly PassangerBirthDate { get; set; }
|
||||||
|
|
||||||
|
public DateTimeOffset PurchaseTime { get; set; }
|
||||||
|
|
||||||
|
public bool Returned { get; set; }
|
||||||
|
|
||||||
|
public TimeSpan TravelTime { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
public ICollection<TicketDto> Tickets { get; set; }
|
||||||
|
|
||||||
|
public void Mapping(MappingProfile profile)
|
||||||
|
{
|
||||||
|
profile.CreateMap<TicketGroup, TicketGroupDto>()
|
||||||
|
.ForMember(
|
||||||
|
d => d.Uuid,
|
||||||
|
opt => opt.MapFrom(s => s.Guid))
|
||||||
|
.ForMember(
|
||||||
|
d => d.PassangerSex,
|
||||||
|
opt => opt.MapFrom(s => s.PassangerSex.Name))
|
||||||
|
.ForMember(
|
||||||
|
d => d.PurchaseTime,
|
||||||
|
opt => opt
|
||||||
|
.MapFrom<DateTimeOffsetToLocalResolver, DateTimeOffset>(
|
||||||
|
s => s.PurchaseTime));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
namespace cuqmbr.TravelGuide.Application.TicketGroups.ViewModels;
|
||||||
|
|
||||||
|
public sealed class AddTicketGroupViewModel
|
||||||
|
{
|
||||||
|
public string PassangerFirstName { get; set; }
|
||||||
|
|
||||||
|
public string PassangerLastName { get; set; }
|
||||||
|
|
||||||
|
public string PassangerPatronymic { get; set; }
|
||||||
|
|
||||||
|
public string PassangerSex { get; set; }
|
||||||
|
|
||||||
|
public DateOnly PassangerBirthDate { get; set; }
|
||||||
|
|
||||||
|
public DateTimeOffset PurchaseTime { get; set; }
|
||||||
|
|
||||||
|
public bool Returned { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
public ICollection<TicketViewModel> Tickets { get; set; }
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
namespace cuqmbr.TravelGuide.Application.TicketGroups.ViewModels;
|
||||||
|
|
||||||
|
public sealed class GetTicketGroupsPageFilterViewModel
|
||||||
|
{
|
||||||
|
public string? Sex { get; set; }
|
||||||
|
|
||||||
|
public DateOnly? BirthDateGreaterThanOrEqualTo { get; set; }
|
||||||
|
|
||||||
|
public DateOnly? BirthDateLessThanOrEqualTo { get; set; }
|
||||||
|
|
||||||
|
public Guid? CompanyUuid { get; set; }
|
||||||
|
}
|
13
src/Application/TicketGroups/ViewModels/TicketViewModel.cs
Normal file
13
src/Application/TicketGroups/ViewModels/TicketViewModel.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
namespace cuqmbr.TravelGuide.Application.TicketGroups.ViewModels;
|
||||||
|
|
||||||
|
public sealed class TicketViewModel
|
||||||
|
{
|
||||||
|
public Guid DepartureRouteAddressUuid { get; set; }
|
||||||
|
|
||||||
|
public Guid ArrivalRouteAddressUuid { get; set; }
|
||||||
|
|
||||||
|
public short Order { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
public Guid VehicleEnrollmentUuid { get; set; }
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
namespace cuqmbr.TravelGuide.Application.TicketGroups.ViewModels;
|
||||||
|
|
||||||
|
public sealed class UpdateTicketGroupViewModel
|
||||||
|
{
|
||||||
|
public string PassangerFirstName { get; set; }
|
||||||
|
|
||||||
|
public string PassangerLastName { get; set; }
|
||||||
|
|
||||||
|
public string PassangerPatronymic { get; set; }
|
||||||
|
|
||||||
|
public string PassangerSex { get; set; }
|
||||||
|
|
||||||
|
public DateOnly PassangerBirthDate { get; set; }
|
||||||
|
|
||||||
|
public DateTimeOffset PurchaseTime { get; set; }
|
||||||
|
|
||||||
|
public bool Returned { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
public ICollection<TicketViewModel> Tickets { get; set; }
|
||||||
|
}
|
@ -105,13 +105,13 @@ public class AddVehicleEnrollmentCommandHandler :
|
|||||||
|
|
||||||
// Three cases are included:
|
// Three cases are included:
|
||||||
//
|
//
|
||||||
// ---RD---------SD----------RA--->
|
// ---SD---------RD----------SA--->
|
||||||
// time
|
// time
|
||||||
//
|
//
|
||||||
// ---RD---------SA----------RA--->
|
// ---SD---------RA----------SA--->
|
||||||
// time
|
// time
|
||||||
//
|
//
|
||||||
// ---SD-----RD-------RA-----SA--->
|
// ---RD-----SD-------SA-----RA--->
|
||||||
// time
|
// time
|
||||||
// Where:
|
// Where:
|
||||||
// RD - request enrollment departure time
|
// RD - request enrollment departure time
|
||||||
@ -134,12 +134,12 @@ public class AddVehicleEnrollmentCommandHandler :
|
|||||||
rad.CurrentAddressStopTime);
|
rad.CurrentAddressStopTime);
|
||||||
|
|
||||||
return
|
return
|
||||||
(departureTime >= requestDepartureTime &&
|
(requestDepartureTime >= departureTime &&
|
||||||
departureTime <= requestArrivalTime) ||
|
requestDepartureTime <= arrivalTime) ||
|
||||||
(arrivalTime >= requestDepartureTime &&
|
(requestArrivalTime >= departureTime &&
|
||||||
arrivalTime <= requestArrivalTime) ||
|
requestArrivalTime <= arrivalTime) ||
|
||||||
(departureTime <= requestDepartureTime &&
|
(requestDepartureTime <= departureTime &&
|
||||||
arrivalTime >= requestArrivalTime);
|
requestArrivalTime >= arrivalTime);
|
||||||
})
|
})
|
||||||
.Any();
|
.Any();
|
||||||
|
|
||||||
|
@ -83,13 +83,13 @@ public class UpdateVehicleEnrollmentCommandHandler :
|
|||||||
|
|
||||||
// Three cases are included:
|
// Three cases are included:
|
||||||
//
|
//
|
||||||
// ---RD---------SD----------RA--->
|
// ---SD---------RD----------SA--->
|
||||||
// time
|
// time
|
||||||
//
|
//
|
||||||
// ---RD---------SA----------RA--->
|
// ---SD---------RA----------SA--->
|
||||||
// time
|
// time
|
||||||
//
|
//
|
||||||
// ---SD-----RD-------RA-----SA--->
|
// ---RD-----SD-------SA-----RA--->
|
||||||
// time
|
// time
|
||||||
// Where:
|
// Where:
|
||||||
// RD - request enrollment departure time
|
// RD - request enrollment departure time
|
||||||
@ -112,12 +112,12 @@ public class UpdateVehicleEnrollmentCommandHandler :
|
|||||||
rad.CurrentAddressStopTime);
|
rad.CurrentAddressStopTime);
|
||||||
|
|
||||||
return
|
return
|
||||||
(departureTime >= requestDepartureTime &&
|
(requestDepartureTime >= departureTime &&
|
||||||
departureTime <= requestArrivalTime) ||
|
requestDepartureTime <= arrivalTime) ||
|
||||||
(arrivalTime >= requestDepartureTime &&
|
(requestArrivalTime >= departureTime &&
|
||||||
arrivalTime <= requestArrivalTime) ||
|
requestArrivalTime <= arrivalTime) ||
|
||||||
(departureTime <= requestDepartureTime &&
|
(requestDepartureTime <= departureTime &&
|
||||||
arrivalTime >= requestArrivalTime);
|
requestArrivalTime >= arrivalTime);
|
||||||
})
|
})
|
||||||
.Any();
|
.Any();
|
||||||
|
|
||||||
|
30
src/Domain/Entities/Ticket.cs
Normal file
30
src/Domain/Entities/Ticket.cs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
using cuqmbr.TravelGuide.Domain.Enums;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Domain.Entities;
|
||||||
|
|
||||||
|
public sealed class Ticket : EntityBase
|
||||||
|
{
|
||||||
|
public long DepartureRouteAddressId { get; set; }
|
||||||
|
|
||||||
|
public RouteAddress DepartureRouteAddress { get; set; }
|
||||||
|
|
||||||
|
public long ArrivalRouteAddressId { get; set; }
|
||||||
|
|
||||||
|
public RouteAddress ArrivalRouteAddress { get; set; }
|
||||||
|
|
||||||
|
public short Order { get; set; }
|
||||||
|
|
||||||
|
public Currency Currency { get; set; }
|
||||||
|
|
||||||
|
public decimal Cost { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
public long TicketGroupId { get; set; }
|
||||||
|
|
||||||
|
public TicketGroup TicketGroup { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
public long VehicleEnrollmentId { get; set; }
|
||||||
|
|
||||||
|
public VehicleEnrollment VehicleEnrollment { get; set; }
|
||||||
|
}
|
25
src/Domain/Entities/TicketGroup.cs
Normal file
25
src/Domain/Entities/TicketGroup.cs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
using cuqmbr.TravelGuide.Domain.Enums;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Domain.Entities;
|
||||||
|
|
||||||
|
public sealed class TicketGroup : EntityBase
|
||||||
|
{
|
||||||
|
public string PassangerFirstName { get; set; }
|
||||||
|
|
||||||
|
public string PassangerLastName { get; set; }
|
||||||
|
|
||||||
|
public string PassangerPatronymic { get; set; }
|
||||||
|
|
||||||
|
public Sex PassangerSex { get; set; }
|
||||||
|
|
||||||
|
public DateOnly PassangerBirthDate { get; set; }
|
||||||
|
|
||||||
|
public DateTimeOffset PurchaseTime { get; set; }
|
||||||
|
|
||||||
|
public bool Returned { get; set; }
|
||||||
|
|
||||||
|
public TimeSpan TravelTime { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
public ICollection<Ticket> Tickets { get; set; }
|
||||||
|
}
|
221
src/HttpApi/Controllers/TicketGroupsController.cs
Normal file
221
src/HttpApi/Controllers/TicketGroupsController.cs
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Swashbuckle.AspNetCore.Annotations;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Models;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.ViewModels;
|
||||||
|
using cuqmbr.TravelGuide.Domain.Enums;
|
||||||
|
using cuqmbr.TravelGuide.Application.TicketGroups;
|
||||||
|
using cuqmbr.TravelGuide.Application.TicketGroups.Commands.AddTicketGroup;
|
||||||
|
// using cuqmbr.TravelGuide.Application.TicketGroups.Queries.GetTicketGroupsPage;
|
||||||
|
// using cuqmbr.TravelGuide.Application.TicketGroups.Queries.GetTicketGroup;
|
||||||
|
// using cuqmbr.TravelGuide.Application.TicketGroups.Commands.UpdateTicketGroup;
|
||||||
|
// using cuqmbr.TravelGuide.Application.TicketGroups.Commands.DeleteTicketGroup;
|
||||||
|
using cuqmbr.TravelGuide.Application.TicketGroups.ViewModels;
|
||||||
|
using cuqmbr.TravelGuide.Application.TicketGroups.Models;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.HttpApi.Controllers;
|
||||||
|
|
||||||
|
[Route("ticketGroups")]
|
||||||
|
public class TicketGroupsController : ControllerBase
|
||||||
|
{
|
||||||
|
[HttpPost]
|
||||||
|
[SwaggerOperation("Add a ticketGroup")]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status201Created, "Object successfuly created",
|
||||||
|
typeof(TicketGroupDto))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status400BadRequest, "Object already exists",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status400BadRequest, "Input data validation error",
|
||||||
|
typeof(HttpValidationProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status401Unauthorized, "Unauthorized to perform an action",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status403Forbidden,
|
||||||
|
"Not enough privileges to perform an action",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status404NotFound, "Parent object not found",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status500InternalServerError, "Internal server error",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
public async Task<ActionResult<TicketGroupDto>> Add(
|
||||||
|
[FromBody] AddTicketGroupViewModel viewModel,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return StatusCode(
|
||||||
|
StatusCodes.Status201Created,
|
||||||
|
await Mediator.Send(
|
||||||
|
new AddTicketGroupCommand()
|
||||||
|
{
|
||||||
|
PassangerFirstName = viewModel.PassangerFirstName,
|
||||||
|
PassangerLastName = viewModel.PassangerLastName,
|
||||||
|
PassangerPatronymic = viewModel.PassangerPatronymic,
|
||||||
|
PassangerSex = Sex.FromName(viewModel.PassangerSex),
|
||||||
|
PassangerBirthDate = viewModel.PassangerBirthDate,
|
||||||
|
PurchaseTime = viewModel.PurchaseTime,
|
||||||
|
Returned = viewModel.Returned,
|
||||||
|
Tickets = viewModel.Tickets.Select(e =>
|
||||||
|
new TicketModel()
|
||||||
|
{
|
||||||
|
DepartureRouteAddressGuid =
|
||||||
|
e.DepartureRouteAddressUuid,
|
||||||
|
ArrivalRouteAddressGuid =
|
||||||
|
e.ArrivalRouteAddressUuid,
|
||||||
|
Order = e.Order,
|
||||||
|
VehicleEnrollmentGuid =
|
||||||
|
e.VehicleEnrollmentUuid,
|
||||||
|
})
|
||||||
|
.ToArray()
|
||||||
|
},
|
||||||
|
cancellationToken));
|
||||||
|
}
|
||||||
|
|
||||||
|
// [HttpGet]
|
||||||
|
// [SwaggerOperation("Get a list of all ticketGroups")]
|
||||||
|
// [SwaggerResponse(
|
||||||
|
// StatusCodes.Status200OK, "Request successful",
|
||||||
|
// typeof(PaginatedList<TicketGroupDto>))]
|
||||||
|
// [SwaggerResponse(
|
||||||
|
// StatusCodes.Status400BadRequest, "Input data validation error",
|
||||||
|
// typeof(HttpValidationProblemDetails))]
|
||||||
|
// [SwaggerResponse(
|
||||||
|
// StatusCodes.Status401Unauthorized, "Unauthorized to perform an action",
|
||||||
|
// typeof(ProblemDetails))]
|
||||||
|
// [SwaggerResponse(
|
||||||
|
// StatusCodes.Status403Forbidden,
|
||||||
|
// "Not enough privileges to perform an action",
|
||||||
|
// typeof(ProblemDetails))]
|
||||||
|
// [SwaggerResponse(
|
||||||
|
// StatusCodes.Status500InternalServerError, "Internal server error",
|
||||||
|
// typeof(ProblemDetails))]
|
||||||
|
// public async Task<PaginatedList<TicketGroupDto>> GetPage(
|
||||||
|
// [FromQuery] PageQuery pageQuery, [FromQuery] SearchQuery searchQuery,
|
||||||
|
// [FromQuery] SortQuery sortQuery,
|
||||||
|
// [FromQuery] GetTicketGroupsPageFilterViewModel filterQuery,
|
||||||
|
// CancellationToken cancellationToken)
|
||||||
|
// {
|
||||||
|
// return await Mediator.Send(
|
||||||
|
// new GetTicketGroupsPageQuery()
|
||||||
|
// {
|
||||||
|
// PageNumber = pageQuery.PageNumber,
|
||||||
|
// PageSize = pageQuery.PageSize,
|
||||||
|
// Search = searchQuery.Search,
|
||||||
|
// Sort = sortQuery.Sort,
|
||||||
|
// LongitudeGreaterOrEqualThan =
|
||||||
|
// filterQuery.LongitudeGreaterOrEqualThan,
|
||||||
|
// LongitudeLessOrEqualThan =
|
||||||
|
// filterQuery.LongitudeLessOrEqualThan,
|
||||||
|
// LatitudeGreaterOrEqualThan =
|
||||||
|
// filterQuery.LatitudeGreaterOrEqualThan,
|
||||||
|
// LatitudeLessOrEqualThan =
|
||||||
|
// filterQuery.LatitudeLessOrEqualThan,
|
||||||
|
// VehicleType = VehicleType.FromName(filterQuery.VehicleType),
|
||||||
|
// CountryGuid = filterQuery.CountryUuid,
|
||||||
|
// RegionGuid = filterQuery.RegionUuid,
|
||||||
|
// CityGuid = filterQuery.CityUuid
|
||||||
|
// },
|
||||||
|
// cancellationToken);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// [HttpGet("{uuid:guid}")]
|
||||||
|
// [SwaggerOperation("Get a ticketGroup by uuid")]
|
||||||
|
// [SwaggerResponse(
|
||||||
|
// StatusCodes.Status200OK, "Request successful", typeof(TicketGroupDto))]
|
||||||
|
// [SwaggerResponse(
|
||||||
|
// StatusCodes.Status400BadRequest, "Input data validation error",
|
||||||
|
// typeof(HttpValidationProblemDetails))]
|
||||||
|
// [SwaggerResponse(
|
||||||
|
// StatusCodes.Status401Unauthorized, "Unauthorized to perform an action",
|
||||||
|
// typeof(ProblemDetails))]
|
||||||
|
// [SwaggerResponse(
|
||||||
|
// StatusCodes.Status403Forbidden,
|
||||||
|
// "Not enough privileges to perform an action",
|
||||||
|
// typeof(ProblemDetails))]
|
||||||
|
// [SwaggerResponse(
|
||||||
|
// StatusCodes.Status404NotFound, "Object not found", typeof(TicketGroupDto))]
|
||||||
|
// [SwaggerResponse(
|
||||||
|
// StatusCodes.Status500InternalServerError, "Internal server error",
|
||||||
|
// typeof(ProblemDetails))]
|
||||||
|
// public async Task<TicketGroupDto> Get(
|
||||||
|
// [FromRoute] Guid uuid,
|
||||||
|
// CancellationToken cancellationToken)
|
||||||
|
// {
|
||||||
|
// return await Mediator.Send(new GetTicketGroupQuery() { Guid = uuid },
|
||||||
|
// cancellationToken);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// [HttpPut("{uuid:guid}")]
|
||||||
|
// [SwaggerOperation("Update a ticketGroup")]
|
||||||
|
// [SwaggerResponse(
|
||||||
|
// StatusCodes.Status200OK, "Request successful", typeof(TicketGroupDto))]
|
||||||
|
// [SwaggerResponse(
|
||||||
|
// StatusCodes.Status400BadRequest, "Object already exists",
|
||||||
|
// typeof(ProblemDetails))]
|
||||||
|
// [SwaggerResponse(
|
||||||
|
// StatusCodes.Status400BadRequest, "Input data validation error",
|
||||||
|
// typeof(HttpValidationProblemDetails))]
|
||||||
|
// [SwaggerResponse(
|
||||||
|
// StatusCodes.Status401Unauthorized, "Unauthorized to perform an action",
|
||||||
|
// typeof(ProblemDetails))]
|
||||||
|
// [SwaggerResponse(
|
||||||
|
// StatusCodes.Status403Forbidden,
|
||||||
|
// "Not enough privileges to perform an action",
|
||||||
|
// typeof(ProblemDetails))]
|
||||||
|
// [SwaggerResponse(
|
||||||
|
// StatusCodes.Status404NotFound, "Object not found", typeof(TicketGroupDto))]
|
||||||
|
// [SwaggerResponse(
|
||||||
|
// StatusCodes.Status404NotFound, "Parent object not found",
|
||||||
|
// typeof(ProblemDetails))]
|
||||||
|
// [SwaggerResponse(
|
||||||
|
// StatusCodes.Status500InternalServerError, "Internal server error",
|
||||||
|
// typeof(ProblemDetails))]
|
||||||
|
// public async Task<TicketGroupDto> Update(
|
||||||
|
// [FromRoute] Guid uuid,
|
||||||
|
// [FromBody] UpdateTicketGroupViewModel viewModel,
|
||||||
|
// CancellationToken cancellationToken)
|
||||||
|
// {
|
||||||
|
// return await Mediator.Send(
|
||||||
|
// new UpdateTicketGroupCommand()
|
||||||
|
// {
|
||||||
|
// Guid = uuid,
|
||||||
|
// Name = viewModel.Name,
|
||||||
|
// Longitude = viewModel.Longitude,
|
||||||
|
// Latitude = viewModel.Latitude,
|
||||||
|
// VehicleType = VehicleType.FromName(viewModel.VehicleType),
|
||||||
|
// CityGuid = viewModel.CityUuid
|
||||||
|
// },
|
||||||
|
// cancellationToken);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// [HttpDelete("{uuid:guid}")]
|
||||||
|
// [SwaggerOperation("Delete a ticketGroup")]
|
||||||
|
// [SwaggerResponse(StatusCodes.Status204NoContent, "Request successful")]
|
||||||
|
// [SwaggerResponse(
|
||||||
|
// StatusCodes.Status400BadRequest, "Input data validation error",
|
||||||
|
// typeof(HttpValidationProblemDetails))]
|
||||||
|
// [SwaggerResponse(
|
||||||
|
// StatusCodes.Status401Unauthorized, "Unauthorized to perform an action",
|
||||||
|
// typeof(ProblemDetails))]
|
||||||
|
// [SwaggerResponse(
|
||||||
|
// StatusCodes.Status403Forbidden,
|
||||||
|
// "Not enough privileges to perform an action",
|
||||||
|
// typeof(ProblemDetails))]
|
||||||
|
// [SwaggerResponse(
|
||||||
|
// StatusCodes.Status404NotFound, "Object not found",
|
||||||
|
// typeof(ProblemDetails))]
|
||||||
|
// [SwaggerResponse(
|
||||||
|
// StatusCodes.Status500InternalServerError, "Internal server error",
|
||||||
|
// typeof(ProblemDetails))]
|
||||||
|
// public async Task<IActionResult> Delete(
|
||||||
|
// [FromRoute] Guid uuid,
|
||||||
|
// CancellationToken cancellationToken)
|
||||||
|
// {
|
||||||
|
// await Mediator.Send(
|
||||||
|
// new DeleteTicketGroupCommand() { Guid = uuid },
|
||||||
|
// cancellationToken);
|
||||||
|
// return StatusCode(StatusCodes.Status204NoContent);
|
||||||
|
// }
|
||||||
|
}
|
@ -28,6 +28,10 @@ public sealed class InMemoryUnitOfWork : UnitOfWork
|
|||||||
new InMemoryRouteAddressRepository(_dbContext);
|
new InMemoryRouteAddressRepository(_dbContext);
|
||||||
CompanyRepository = new InMemoryCompanyRepository(_dbContext);
|
CompanyRepository = new InMemoryCompanyRepository(_dbContext);
|
||||||
EmployeeRepository = new InMemoryEmployeeRepository(_dbContext);
|
EmployeeRepository = new InMemoryEmployeeRepository(_dbContext);
|
||||||
|
TicketGroupRepository = new InMemoryTicketGroupRepository(_dbContext);
|
||||||
|
TicketRepository = new InMemoryTicketRepository(_dbContext);
|
||||||
|
RouteAddressDetailRepository =
|
||||||
|
new InMemoryRouteAddressDetailRepository(_dbContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CountryRepository CountryRepository { get; init; }
|
public CountryRepository CountryRepository { get; init; }
|
||||||
@ -56,6 +60,12 @@ public sealed class InMemoryUnitOfWork : UnitOfWork
|
|||||||
|
|
||||||
public EmployeeRepository EmployeeRepository { get; init; }
|
public EmployeeRepository EmployeeRepository { get; init; }
|
||||||
|
|
||||||
|
public TicketGroupRepository TicketGroupRepository { get; init; }
|
||||||
|
|
||||||
|
public TicketRepository TicketRepository { get; init; }
|
||||||
|
|
||||||
|
public RouteAddressDetailRepository RouteAddressDetailRepository { get; init; }
|
||||||
|
|
||||||
public int Save()
|
public int Save()
|
||||||
{
|
{
|
||||||
return _dbContext.SaveChanges();
|
return _dbContext.SaveChanges();
|
||||||
|
@ -0,0 +1,11 @@
|
|||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence.Repositories;
|
||||||
|
using cuqmbr.TravelGuide.Domain.Entities;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Persistence.InMemory.Repositories;
|
||||||
|
|
||||||
|
public sealed class InMemoryRouteAddressDetailRepository :
|
||||||
|
InMemoryBaseRepository<RouteAddressDetail>, RouteAddressDetailRepository
|
||||||
|
{
|
||||||
|
public InMemoryRouteAddressDetailRepository(InMemoryDbContext dbContext)
|
||||||
|
: base(dbContext) { }
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence.Repositories;
|
||||||
|
using cuqmbr.TravelGuide.Domain.Entities;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Persistence.InMemory.Repositories;
|
||||||
|
|
||||||
|
public sealed class InMemoryTicketGroupRepository :
|
||||||
|
InMemoryBaseRepository<TicketGroup>, TicketGroupRepository
|
||||||
|
{
|
||||||
|
public InMemoryTicketGroupRepository(InMemoryDbContext dbContext)
|
||||||
|
: base(dbContext) { }
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence.Repositories;
|
||||||
|
using cuqmbr.TravelGuide.Domain.Entities;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Persistence.InMemory.Repositories;
|
||||||
|
|
||||||
|
public sealed class InMemoryTicketRepository :
|
||||||
|
InMemoryBaseRepository<Ticket>, TicketRepository
|
||||||
|
{
|
||||||
|
public InMemoryTicketRepository(InMemoryDbContext dbContext)
|
||||||
|
: base(dbContext) { }
|
||||||
|
}
|
105
src/Persistence/PostgreSql/Configurations/TicketConfiguration.cs
Normal file
105
src/Persistence/PostgreSql/Configurations/TicketConfiguration.cs
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
using cuqmbr.TravelGuide.Domain.Entities;
|
||||||
|
using cuqmbr.TravelGuide.Domain.Enums;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Persistence.PostgreSql.Configurations;
|
||||||
|
|
||||||
|
public class TicketConfiguration : BaseConfiguration<Ticket>
|
||||||
|
{
|
||||||
|
public override void Configure(EntityTypeBuilder<Ticket> builder)
|
||||||
|
{
|
||||||
|
builder
|
||||||
|
.Property(t => t.Currency)
|
||||||
|
.HasColumnName("currency")
|
||||||
|
.IsRequired(true);
|
||||||
|
|
||||||
|
builder
|
||||||
|
.ToTable(
|
||||||
|
"tickets",
|
||||||
|
ve => ve.HasCheckConstraint(
|
||||||
|
"ck_" +
|
||||||
|
$"{builder.Metadata.GetTableName()}_" +
|
||||||
|
$"{builder.Property(ve => ve.Currency)
|
||||||
|
.Metadata.GetColumnName()}",
|
||||||
|
$"{builder.Property(ve => ve.Currency)
|
||||||
|
.Metadata.GetColumnName()} IN ('{String
|
||||||
|
.Join("', '", Currency.Enumerations
|
||||||
|
.Values.Select(v => v.Name))}')"));
|
||||||
|
|
||||||
|
base.Configure(builder);
|
||||||
|
|
||||||
|
|
||||||
|
builder
|
||||||
|
.Property(t => t.DepartureRouteAddressId)
|
||||||
|
.HasColumnName("departure_route_address_id")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.IsRequired(true);
|
||||||
|
|
||||||
|
builder
|
||||||
|
.Property(t => t.ArrivalRouteAddressId)
|
||||||
|
.HasColumnName("arrival_route_address_id")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.IsRequired(true);
|
||||||
|
|
||||||
|
builder
|
||||||
|
.Property(t => t.Order)
|
||||||
|
.HasColumnName("order")
|
||||||
|
.HasColumnType("smallint")
|
||||||
|
.IsRequired(true);
|
||||||
|
|
||||||
|
builder
|
||||||
|
.Property(t => t.Cost)
|
||||||
|
.HasColumnName("cost")
|
||||||
|
.HasColumnType("numeric(24,12)")
|
||||||
|
.IsRequired(true);
|
||||||
|
|
||||||
|
|
||||||
|
builder
|
||||||
|
.Property(t => t.TicketGroupId)
|
||||||
|
.HasColumnName("ticket_group_id")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.IsRequired(true);
|
||||||
|
|
||||||
|
builder
|
||||||
|
.HasOne(t => t.TicketGroup)
|
||||||
|
.WithMany(tg => tg.Tickets)
|
||||||
|
.HasForeignKey(t => t.TicketGroupId)
|
||||||
|
.HasConstraintName(
|
||||||
|
"fk_" +
|
||||||
|
$"{builder.Metadata.GetTableName()}_" +
|
||||||
|
$"{builder.Property(t => t.TicketGroupId).Metadata.GetColumnName()}")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
builder
|
||||||
|
.HasIndex(t => t.TicketGroupId)
|
||||||
|
.HasDatabaseName(
|
||||||
|
"ix_" +
|
||||||
|
$"{builder.Metadata.GetTableName()}_" +
|
||||||
|
$"{builder.Property(t => t.TicketGroupId).Metadata.GetColumnName()}");
|
||||||
|
|
||||||
|
|
||||||
|
builder
|
||||||
|
.Property(t => t.VehicleEnrollmentId)
|
||||||
|
.HasColumnName("vehicle_enrollment_id")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.IsRequired(true);
|
||||||
|
|
||||||
|
builder
|
||||||
|
.HasOne(t => t.VehicleEnrollment)
|
||||||
|
.WithMany(ve => ve.Tickets)
|
||||||
|
.HasForeignKey(t => t.VehicleEnrollmentId)
|
||||||
|
.HasConstraintName(
|
||||||
|
"fk_" +
|
||||||
|
$"{builder.Metadata.GetTableName()}_" +
|
||||||
|
$"{builder.Property(t => t.VehicleEnrollmentId).Metadata.GetColumnName()}")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
builder
|
||||||
|
.HasIndex(t => t.VehicleEnrollmentId)
|
||||||
|
.HasDatabaseName(
|
||||||
|
"ix_" +
|
||||||
|
$"{builder.Metadata.GetTableName()}_" +
|
||||||
|
$"{builder.Property(t => t.VehicleEnrollmentId).Metadata.GetColumnName()}");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,75 @@
|
|||||||
|
using cuqmbr.TravelGuide.Domain.Entities;
|
||||||
|
using cuqmbr.TravelGuide.Domain.Enums;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Persistence.PostgreSql.Configurations;
|
||||||
|
|
||||||
|
public class TicketGroupConfiguration : BaseConfiguration<TicketGroup>
|
||||||
|
{
|
||||||
|
public override void Configure(EntityTypeBuilder<TicketGroup> builder)
|
||||||
|
{
|
||||||
|
builder
|
||||||
|
.Property(tg => tg.PassangerSex)
|
||||||
|
.HasColumnName("passanger_sex")
|
||||||
|
.IsRequired(true);
|
||||||
|
|
||||||
|
builder
|
||||||
|
.ToTable(
|
||||||
|
"ticket_groups",
|
||||||
|
tg => tg.HasCheckConstraint(
|
||||||
|
"ck_" +
|
||||||
|
$"{builder.Metadata.GetTableName()}_" +
|
||||||
|
$"{builder.Property(tg => tg.PassangerSex)
|
||||||
|
.Metadata.GetColumnName()}",
|
||||||
|
$"{builder.Property(g => g.PassangerSex)
|
||||||
|
.Metadata.GetColumnName()} IN ('{String
|
||||||
|
.Join("', '", Sex.Enumerations
|
||||||
|
.Values.Select(v => v.Name))}')"));
|
||||||
|
|
||||||
|
base.Configure(builder);
|
||||||
|
|
||||||
|
|
||||||
|
builder
|
||||||
|
.Property(a => a.PassangerFirstName)
|
||||||
|
.HasColumnName("passanger_first_name")
|
||||||
|
.HasColumnType("varchar(32)")
|
||||||
|
.IsRequired(true);
|
||||||
|
|
||||||
|
builder
|
||||||
|
.Property(a => a.PassangerLastName)
|
||||||
|
.HasColumnName("passanger_last_name")
|
||||||
|
.HasColumnType("varchar(32)")
|
||||||
|
.IsRequired(true);
|
||||||
|
|
||||||
|
builder
|
||||||
|
.Property(a => a.PassangerPatronymic)
|
||||||
|
.HasColumnName("passanger_patronymic")
|
||||||
|
.HasColumnType("varchar(32)")
|
||||||
|
.IsRequired(true);
|
||||||
|
|
||||||
|
builder
|
||||||
|
.Property(a => a.PassangerBirthDate)
|
||||||
|
.HasColumnName("passanger_birth_date")
|
||||||
|
.HasColumnType("date")
|
||||||
|
.IsRequired(true);
|
||||||
|
|
||||||
|
builder
|
||||||
|
.Property(a => a.PurchaseTime)
|
||||||
|
.HasColumnName("purchase_time")
|
||||||
|
.HasColumnType("timestamptz")
|
||||||
|
.IsRequired(true);
|
||||||
|
|
||||||
|
builder
|
||||||
|
.Property(a => a.Returned)
|
||||||
|
.HasColumnName("returned")
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.IsRequired(true);
|
||||||
|
|
||||||
|
builder
|
||||||
|
.Property(a => a.TravelTime)
|
||||||
|
.HasColumnName("travel_time")
|
||||||
|
.HasColumnType("interval")
|
||||||
|
.IsRequired(true);
|
||||||
|
}
|
||||||
|
}
|
1016
src/Persistence/PostgreSql/Migrations/20250519212941_Add_Ticket_and_TicketGroup.Designer.cs
generated
Normal file
1016
src/Persistence/PostgreSql/Migrations/20250519212941_Add_Ticket_and_TicketGroup.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,140 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Persistence.PostgreSql.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class Add_Ticket_and_TicketGroup : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateSequence(
|
||||||
|
name: "ticket_groups_id_sequence",
|
||||||
|
schema: "application");
|
||||||
|
|
||||||
|
migrationBuilder.CreateSequence(
|
||||||
|
name: "tickets_id_sequence",
|
||||||
|
schema: "application");
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "ticket_groups",
|
||||||
|
schema: "application",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
id = table.Column<long>(type: "bigint", nullable: false, defaultValueSql: "nextval('application.ticket_groups_id_sequence')"),
|
||||||
|
passanger_first_name = table.Column<string>(type: "varchar(32)", nullable: false),
|
||||||
|
passanger_last_name = table.Column<string>(type: "varchar(32)", nullable: false),
|
||||||
|
passanger_patronymic = table.Column<string>(type: "varchar(32)", nullable: false),
|
||||||
|
passanger_sex = table.Column<string>(type: "varchar(32)", nullable: false),
|
||||||
|
passanger_birth_date = table.Column<DateOnly>(type: "date", nullable: false),
|
||||||
|
purchase_time = table.Column<DateTimeOffset>(type: "timestamptz", nullable: false),
|
||||||
|
returned = table.Column<bool>(type: "boolean", nullable: false),
|
||||||
|
travel_time = table.Column<TimeSpan>(type: "interval", nullable: false),
|
||||||
|
uuid = table.Column<Guid>(type: "uuid", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("pk_ticket_groups", x => x.id);
|
||||||
|
table.UniqueConstraint("altk_ticket_groups_uuid", x => x.uuid);
|
||||||
|
table.CheckConstraint("ck_ticket_groups_passanger_sex", "passanger_sex IN ('male', 'female')");
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "tickets",
|
||||||
|
schema: "application",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
id = table.Column<long>(type: "bigint", nullable: false, defaultValueSql: "nextval('application.tickets_id_sequence')"),
|
||||||
|
departure_route_address_id = table.Column<long>(type: "bigint", nullable: false),
|
||||||
|
arrival_route_address_id = table.Column<long>(type: "bigint", nullable: false),
|
||||||
|
order = table.Column<short>(type: "smallint", nullable: false),
|
||||||
|
currency = table.Column<string>(type: "varchar(8)", nullable: false),
|
||||||
|
cost = table.Column<decimal>(type: "numeric(24,12)", nullable: false),
|
||||||
|
ticket_group_id = table.Column<long>(type: "bigint", nullable: false),
|
||||||
|
vehicle_enrollment_id = table.Column<long>(type: "bigint", nullable: false),
|
||||||
|
uuid = table.Column<Guid>(type: "uuid", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("pk_tickets", x => x.id);
|
||||||
|
table.UniqueConstraint("altk_tickets_uuid", x => x.uuid);
|
||||||
|
table.CheckConstraint("ck_tickets_currency", "currency IN ('DEFAULT', 'USD', 'EUR', 'UAH')");
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_tickets_route_addresses_arrival_route_address_id",
|
||||||
|
column: x => x.arrival_route_address_id,
|
||||||
|
principalSchema: "application",
|
||||||
|
principalTable: "route_addresses",
|
||||||
|
principalColumn: "id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_tickets_route_addresses_departure_route_address_id",
|
||||||
|
column: x => x.departure_route_address_id,
|
||||||
|
principalSchema: "application",
|
||||||
|
principalTable: "route_addresses",
|
||||||
|
principalColumn: "id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "fk_tickets_ticket_group_id",
|
||||||
|
column: x => x.ticket_group_id,
|
||||||
|
principalSchema: "application",
|
||||||
|
principalTable: "ticket_groups",
|
||||||
|
principalColumn: "id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "fk_tickets_vehicle_enrollment_id",
|
||||||
|
column: x => x.vehicle_enrollment_id,
|
||||||
|
principalSchema: "application",
|
||||||
|
principalTable: "vehicle_enrollments",
|
||||||
|
principalColumn: "id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_tickets_arrival_route_address_id",
|
||||||
|
schema: "application",
|
||||||
|
table: "tickets",
|
||||||
|
column: "arrival_route_address_id");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_tickets_departure_route_address_id",
|
||||||
|
schema: "application",
|
||||||
|
table: "tickets",
|
||||||
|
column: "departure_route_address_id");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "ix_tickets_ticket_group_id",
|
||||||
|
schema: "application",
|
||||||
|
table: "tickets",
|
||||||
|
column: "ticket_group_id");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "ix_tickets_vehicle_enrollment_id",
|
||||||
|
schema: "application",
|
||||||
|
table: "tickets",
|
||||||
|
column: "vehicle_enrollment_id");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "tickets",
|
||||||
|
schema: "application");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "ticket_groups",
|
||||||
|
schema: "application");
|
||||||
|
|
||||||
|
migrationBuilder.DropSequence(
|
||||||
|
name: "ticket_groups_id_sequence",
|
||||||
|
schema: "application");
|
||||||
|
|
||||||
|
migrationBuilder.DropSequence(
|
||||||
|
name: "tickets_id_sequence",
|
||||||
|
schema: "application");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -43,6 +43,10 @@ namespace Persistence.PostgreSql.Migrations
|
|||||||
|
|
||||||
modelBuilder.HasSequence("routes_id_sequence");
|
modelBuilder.HasSequence("routes_id_sequence");
|
||||||
|
|
||||||
|
modelBuilder.HasSequence("ticket_groups_id_sequence");
|
||||||
|
|
||||||
|
modelBuilder.HasSequence("tickets_id_sequence");
|
||||||
|
|
||||||
modelBuilder.HasSequence("vehicle_enrollments_id_sequence");
|
modelBuilder.HasSequence("vehicle_enrollments_id_sequence");
|
||||||
|
|
||||||
modelBuilder.HasSequence("vehicles_id_sequence");
|
modelBuilder.HasSequence("vehicles_id_sequence");
|
||||||
@ -466,6 +470,133 @@ namespace Persistence.PostgreSql.Migrations
|
|||||||
b.ToTable("route_address_details", "application");
|
b.ToTable("route_address_details", "application");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.Ticket", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasColumnName("id")
|
||||||
|
.HasDefaultValueSql("nextval('application.tickets_id_sequence')");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseSequence(b.Property<long>("Id"), "tickets_id_sequence");
|
||||||
|
|
||||||
|
b.Property<long>("ArrivalRouteAddressId")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasColumnName("arrival_route_address_id");
|
||||||
|
|
||||||
|
b.Property<decimal>("Cost")
|
||||||
|
.HasColumnType("numeric(24,12)")
|
||||||
|
.HasColumnName("cost");
|
||||||
|
|
||||||
|
b.Property<string>("Currency")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("varchar(8)")
|
||||||
|
.HasColumnName("currency");
|
||||||
|
|
||||||
|
b.Property<long>("DepartureRouteAddressId")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasColumnName("departure_route_address_id");
|
||||||
|
|
||||||
|
b.Property<Guid>("Guid")
|
||||||
|
.HasColumnType("uuid")
|
||||||
|
.HasColumnName("uuid");
|
||||||
|
|
||||||
|
b.Property<short>("Order")
|
||||||
|
.HasColumnType("smallint")
|
||||||
|
.HasColumnName("order");
|
||||||
|
|
||||||
|
b.Property<long>("TicketGroupId")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasColumnName("ticket_group_id");
|
||||||
|
|
||||||
|
b.Property<long>("VehicleEnrollmentId")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasColumnName("vehicle_enrollment_id");
|
||||||
|
|
||||||
|
b.HasKey("Id")
|
||||||
|
.HasName("pk_tickets");
|
||||||
|
|
||||||
|
b.HasAlternateKey("Guid")
|
||||||
|
.HasName("altk_tickets_uuid");
|
||||||
|
|
||||||
|
b.HasIndex("ArrivalRouteAddressId");
|
||||||
|
|
||||||
|
b.HasIndex("DepartureRouteAddressId");
|
||||||
|
|
||||||
|
b.HasIndex("TicketGroupId")
|
||||||
|
.HasDatabaseName("ix_tickets_ticket_group_id");
|
||||||
|
|
||||||
|
b.HasIndex("VehicleEnrollmentId")
|
||||||
|
.HasDatabaseName("ix_tickets_vehicle_enrollment_id");
|
||||||
|
|
||||||
|
b.ToTable("tickets", "application", t =>
|
||||||
|
{
|
||||||
|
t.HasCheckConstraint("ck_tickets_currency", "currency IN ('DEFAULT', 'USD', 'EUR', 'UAH')");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.TicketGroup", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasColumnName("id")
|
||||||
|
.HasDefaultValueSql("nextval('application.ticket_groups_id_sequence')");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseSequence(b.Property<long>("Id"), "ticket_groups_id_sequence");
|
||||||
|
|
||||||
|
b.Property<Guid>("Guid")
|
||||||
|
.HasColumnType("uuid")
|
||||||
|
.HasColumnName("uuid");
|
||||||
|
|
||||||
|
b.Property<DateOnly>("PassangerBirthDate")
|
||||||
|
.HasColumnType("date")
|
||||||
|
.HasColumnName("passanger_birth_date");
|
||||||
|
|
||||||
|
b.Property<string>("PassangerFirstName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("varchar(32)")
|
||||||
|
.HasColumnName("passanger_first_name");
|
||||||
|
|
||||||
|
b.Property<string>("PassangerLastName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("varchar(32)")
|
||||||
|
.HasColumnName("passanger_last_name");
|
||||||
|
|
||||||
|
b.Property<string>("PassangerPatronymic")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("varchar(32)")
|
||||||
|
.HasColumnName("passanger_patronymic");
|
||||||
|
|
||||||
|
b.Property<string>("PassangerSex")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("varchar(32)")
|
||||||
|
.HasColumnName("passanger_sex");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("PurchaseTime")
|
||||||
|
.HasColumnType("timestamptz")
|
||||||
|
.HasColumnName("purchase_time");
|
||||||
|
|
||||||
|
b.Property<bool>("Returned")
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasColumnName("returned");
|
||||||
|
|
||||||
|
b.Property<TimeSpan>("TravelTime")
|
||||||
|
.HasColumnType("interval")
|
||||||
|
.HasColumnName("travel_time");
|
||||||
|
|
||||||
|
b.HasKey("Id")
|
||||||
|
.HasName("pk_ticket_groups");
|
||||||
|
|
||||||
|
b.HasAlternateKey("Guid")
|
||||||
|
.HasName("altk_ticket_groups_uuid");
|
||||||
|
|
||||||
|
b.ToTable("ticket_groups", "application", t =>
|
||||||
|
{
|
||||||
|
t.HasCheckConstraint("ck_ticket_groups_passanger_sex", "passanger_sex IN ('male', 'female')");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.Vehicle", b =>
|
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.Vehicle", b =>
|
||||||
{
|
{
|
||||||
b.Property<long>("Id")
|
b.Property<long>("Id")
|
||||||
@ -746,6 +877,43 @@ namespace Persistence.PostgreSql.Migrations
|
|||||||
b.Navigation("VehicleEnrollment");
|
b.Navigation("VehicleEnrollment");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.Ticket", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("cuqmbr.TravelGuide.Domain.Entities.RouteAddress", "ArrivalRouteAddress")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ArrivalRouteAddressId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("cuqmbr.TravelGuide.Domain.Entities.RouteAddress", "DepartureRouteAddress")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("DepartureRouteAddressId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("cuqmbr.TravelGuide.Domain.Entities.TicketGroup", "TicketGroup")
|
||||||
|
.WithMany("Tickets")
|
||||||
|
.HasForeignKey("TicketGroupId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired()
|
||||||
|
.HasConstraintName("fk_tickets_ticket_group_id");
|
||||||
|
|
||||||
|
b.HasOne("cuqmbr.TravelGuide.Domain.Entities.VehicleEnrollment", "VehicleEnrollment")
|
||||||
|
.WithMany("Tickets")
|
||||||
|
.HasForeignKey("VehicleEnrollmentId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired()
|
||||||
|
.HasConstraintName("fk_tickets_vehicle_enrollment_id");
|
||||||
|
|
||||||
|
b.Navigation("ArrivalRouteAddress");
|
||||||
|
|
||||||
|
b.Navigation("DepartureRouteAddress");
|
||||||
|
|
||||||
|
b.Navigation("TicketGroup");
|
||||||
|
|
||||||
|
b.Navigation("VehicleEnrollment");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.Vehicle", b =>
|
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.Vehicle", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("cuqmbr.TravelGuide.Domain.Entities.Company", "Company")
|
b.HasOne("cuqmbr.TravelGuide.Domain.Entities.Company", "Company")
|
||||||
@ -823,6 +991,11 @@ namespace Persistence.PostgreSql.Migrations
|
|||||||
b.Navigation("Details");
|
b.Navigation("Details");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.TicketGroup", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Tickets");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.Vehicle", b =>
|
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.Vehicle", b =>
|
||||||
{
|
{
|
||||||
b.Navigation("Enrollments");
|
b.Navigation("Enrollments");
|
||||||
@ -831,6 +1004,8 @@ namespace Persistence.PostgreSql.Migrations
|
|||||||
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.VehicleEnrollment", b =>
|
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.VehicleEnrollment", b =>
|
||||||
{
|
{
|
||||||
b.Navigation("RouteAddressDetails");
|
b.Navigation("RouteAddressDetails");
|
||||||
|
|
||||||
|
b.Navigation("Tickets");
|
||||||
});
|
});
|
||||||
#pragma warning restore 612, 618
|
#pragma warning restore 612, 618
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,10 @@ public sealed class PostgreSqlUnitOfWork : UnitOfWork
|
|||||||
new PostgreSqlRouteAddressRepository(_dbContext);
|
new PostgreSqlRouteAddressRepository(_dbContext);
|
||||||
CompanyRepository = new PostgreSqlCompanyRepository(_dbContext);
|
CompanyRepository = new PostgreSqlCompanyRepository(_dbContext);
|
||||||
EmployeeRepository = new PostgreSqlEmployeeRepository(_dbContext);
|
EmployeeRepository = new PostgreSqlEmployeeRepository(_dbContext);
|
||||||
|
TicketGroupRepository = new PostgreSqlTicketGroupRepository(_dbContext);
|
||||||
|
TicketRepository = new PostgreSqlTicketRepository(_dbContext);
|
||||||
|
RouteAddressDetailRepository =
|
||||||
|
new PostgreSqlRouteAddressDetailRepository(_dbContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CountryRepository CountryRepository { get; init; }
|
public CountryRepository CountryRepository { get; init; }
|
||||||
@ -56,6 +60,12 @@ public sealed class PostgreSqlUnitOfWork : UnitOfWork
|
|||||||
|
|
||||||
public EmployeeRepository EmployeeRepository { get; init; }
|
public EmployeeRepository EmployeeRepository { get; init; }
|
||||||
|
|
||||||
|
public TicketGroupRepository TicketGroupRepository { get; init; }
|
||||||
|
|
||||||
|
public TicketRepository TicketRepository { get; init; }
|
||||||
|
|
||||||
|
public RouteAddressDetailRepository RouteAddressDetailRepository { get; init; }
|
||||||
|
|
||||||
public int Save()
|
public int Save()
|
||||||
{
|
{
|
||||||
return _dbContext.SaveChanges();
|
return _dbContext.SaveChanges();
|
||||||
|
@ -0,0 +1,11 @@
|
|||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence.Repositories;
|
||||||
|
using cuqmbr.TravelGuide.Domain.Entities;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Persistence.PostgreSql.Repositories;
|
||||||
|
|
||||||
|
public sealed class PostgreSqlRouteAddressDetailRepository :
|
||||||
|
PostgreSqlBaseRepository<RouteAddressDetail>, RouteAddressDetailRepository
|
||||||
|
{
|
||||||
|
public PostgreSqlRouteAddressDetailRepository(PostgreSqlDbContext dbContext)
|
||||||
|
: base(dbContext) { }
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence.Repositories;
|
||||||
|
using cuqmbr.TravelGuide.Domain.Entities;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Persistence.PostgreSql.Repositories;
|
||||||
|
|
||||||
|
public sealed class PostgreSqlTicketGroupRepository :
|
||||||
|
PostgreSqlBaseRepository<TicketGroup>, TicketGroupRepository
|
||||||
|
{
|
||||||
|
public PostgreSqlTicketGroupRepository(PostgreSqlDbContext dbContext)
|
||||||
|
: base(dbContext) { }
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence.Repositories;
|
||||||
|
using cuqmbr.TravelGuide.Domain.Entities;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Persistence.PostgreSql.Repositories;
|
||||||
|
|
||||||
|
public sealed class PostgreSqlTicketRepository :
|
||||||
|
PostgreSqlBaseRepository<Ticket>, TicketRepository
|
||||||
|
{
|
||||||
|
public PostgreSqlTicketRepository(PostgreSqlDbContext dbContext)
|
||||||
|
: base(dbContext) { }
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user