diff --git a/AsbCloudApp/Repositories/IWellOperationRepository.cs b/AsbCloudApp/Repositories/IWellOperationRepository.cs index d1db155e..d6302726 100644 --- a/AsbCloudApp/Repositories/IWellOperationRepository.cs +++ b/AsbCloudApp/Repositories/IWellOperationRepository.cs @@ -114,5 +114,20 @@ namespace AsbCloudApp.Repositories /// /// Task GetDatesRangeAsync(int idWell, int idType, CancellationToken cancellationToken); - } + + /// + /// Валидация данных + /// + /// + /// + bool Validate(IEnumerable wellOperations); + + /// + /// Валидация данных (проверка с базой) + /// + /// + /// + /// + Task ValidateWithDbAsync(IEnumerable wellOperations, CancellationToken cancellationToken); + } } \ No newline at end of file diff --git a/AsbCloudInfrastructure/Repository/WellOperationRepository.cs b/AsbCloudInfrastructure/Repository/WellOperationRepository.cs index fb0a8c12..ba566bca 100644 --- a/AsbCloudInfrastructure/Repository/WellOperationRepository.cs +++ b/AsbCloudInfrastructure/Repository/WellOperationRepository.cs @@ -50,7 +50,7 @@ public class WellOperationRepository : IWellOperationRepository } var result = categories - .OrderBy(o => o.Name) + .OrderBy(o => o.Name) .Adapt>(); return result; @@ -89,14 +89,14 @@ public class WellOperationRepository : IWellOperationRepository } private async Task GetDateLastAssosiatedPlanOperationAsync( - int idWell, - DateTime? lessThenDate, - double timeZoneHours, + int idWell, + DateTime? lessThenDate, + double timeZoneHours, CancellationToken token) { - if (lessThenDate is null) + if (lessThenDate is null) return null; - + var currentDateOffset = lessThenDate.Value.ToUtcDateTimeOffset(timeZoneHours); var timeZoneOffset = TimeSpan.FromHours(timeZoneHours); @@ -187,7 +187,7 @@ public class WellOperationRepository : IWellOperationRepository public async Task GetDatesRangeAsync(int idWell, int idType, CancellationToken cancellationToken) { var timezone = wellService.GetTimezone(idWell); - + var query = db.WellOperations.Where(o => o.IdWell == idWell && o.IdType == idType); if (!await query.AnyAsync(cancellationToken)) @@ -195,7 +195,7 @@ public class WellOperationRepository : IWellOperationRepository var minDate = await query.MinAsync(o => o.DateStart, cancellationToken); var maxDate = await query.MaxAsync(o => o.DateStart, cancellationToken); - + return new DatesRangeDto { From = minDate.ToRemoteDateTime(timezone.Hours), @@ -306,12 +306,13 @@ public class WellOperationRepository : IWellOperationRepository DeltaDepth = g.Sum(o => o.DurationDepth), IdParent = parentRelationDictionary[g.Key].IdParent }); - + while (dtos.All(x => x.IdParent != null)) { dtos = dtos .GroupBy(o => o.IdParent!) - .Select(g => { + .Select(g => + { var idCategory = g.Key ?? int.MinValue; var category = parentRelationDictionary.GetValueOrDefault(idCategory); var newDto = new WellGroupOpertionDto @@ -330,6 +331,58 @@ public class WellOperationRepository : IWellOperationRepository return dtos; } + public async Task ValidateWithDbAsync(IEnumerable wellOperationDtos, CancellationToken token) + { + var firstOperation = wellOperationDtos + .FirstOrDefault(); + if (firstOperation is null) + return false; + + var request = new WellOperationRequest() + { + IdWell = firstOperation.IdWell, + OperationType = firstOperation.IdType, + }; + + var operationWithMaxDateStart = await BuildQuery(request) + .OrderByDescending(o => o.DateStart) + .FirstOrDefaultAsync(token); + + if (operationWithMaxDateStart is null) + return Validate(wellOperationDtos); + + var maxOperationDateStart = operationWithMaxDateStart.DateStart; + foreach (var dto in wellOperationDtos) + { + var currentOperationDateStart = dto.DateStart.ToUniversalTime(); + if (maxOperationDateStart!.AddMonths(3) < currentOperationDateStart) + return false; + + maxOperationDateStart = currentOperationDateStart; + } + return true; + } + + public bool Validate(IEnumerable wellOperationDtos) + { + var firstOperation = wellOperationDtos + .FirstOrDefault(); + if (firstOperation is null) + return false; + + var maxOperationDateStart = firstOperation.DateStart.ToUniversalTime(); + + foreach (var dto in wellOperationDtos) + { + var currentOperationDateStart = dto.DateStart.ToUniversalTime(); + if (maxOperationDateStart.AddMonths(3) < currentOperationDateStart) + return false; + + maxOperationDateStart = currentOperationDateStart; + } + return true; + } + /// public async Task InsertRangeAsync( IEnumerable wellOperationDtos, diff --git a/AsbCloudWebApi/Controllers/WellOperationController.cs b/AsbCloudWebApi/Controllers/WellOperationController.cs index ae0c8b92..fa479f12 100644 --- a/AsbCloudWebApi/Controllers/WellOperationController.cs +++ b/AsbCloudWebApi/Controllers/WellOperationController.cs @@ -1,7 +1,13 @@ using AsbCloudApp.Data; +using AsbCloudApp.Data.WellOperationImport; +using AsbCloudApp.Data.WellOperationImport.Options; +using AsbCloudApp.Exceptions; using AsbCloudApp.Repositories; using AsbCloudApp.Requests; using AsbCloudApp.Services; +using AsbCloudApp.Services.WellOperationImport; +using AsbCloudDb.Model; +using AsbCloudInfrastructure; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; @@ -12,12 +18,6 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; -using AsbCloudApp.Data.WellOperationImport; -using AsbCloudApp.Services.WellOperationImport; -using AsbCloudApp.Data.WellOperationImport.Options; -using AsbCloudApp.Exceptions; -using AsbCloudDb.Model; -using AsbCloudInfrastructure; namespace AsbCloudWebApi.Controllers { @@ -39,8 +39,8 @@ namespace AsbCloudWebApi.Controllers private readonly IWellOperationExcelParser wellOperationGazpromKhantosExcelParser; private readonly IUserRepository userRepository; - public WellOperationController(IWellOperationRepository operationRepository, - IWellService wellService, + public WellOperationController(IWellOperationRepository operationRepository, + IWellService wellService, IWellOperationImportTemplateService wellOperationImportTemplateService, IWellOperationExportService wellOperationExportService, IWellOperationImportService wellOperationImportService, @@ -231,12 +231,15 @@ namespace AsbCloudWebApi.Controllers if (!await CanUserEditWellOperationsAsync(idWell, cancellationToken)) return Forbid(); - + wellOperation.IdWell = idWell; wellOperation.LastUpdateDate = DateTimeOffset.UtcNow; wellOperation.IdUser = User.GetUserId(); wellOperation.IdType = idType; + if (!await operationRepository.ValidateWithDbAsync(new[] { wellOperation }, cancellationToken)) + return this.ValidationBadRequest(nameof(wellOperation), "The date difference between the operations is more than 3 months"); + var result = await operationRepository.InsertRangeAsync(new[] { wellOperation }, cancellationToken); return Ok(result); @@ -278,7 +281,7 @@ namespace AsbCloudWebApi.Controllers await operationRepository.DeleteAsync(existingOperations.Select(o => o.Id), cancellationToken); } - + foreach (var wellOperation in wellOperations) { wellOperation.IdWell = idWell; @@ -287,11 +290,31 @@ namespace AsbCloudWebApi.Controllers wellOperation.IdType = idType; } + + if (!await Validate(wellOperations, deleteBeforeInsert, cancellationToken)) + return this.ValidationBadRequest(nameof(wellOperations), "The date difference between the operations is more than 3 months"); + var result = await operationRepository.InsertRangeAsync(wellOperations, cancellationToken); return Ok(result); } + + /// + /// Валидация данных перед вставкой / обновлением / импортом + /// + /// + /// + /// + /// + private async Task Validate(IEnumerable wellOperations, bool deleteBeforeInsert, CancellationToken cancellationToken) + { + if (deleteBeforeInsert) + return operationRepository.Validate(wellOperations); + else + return await operationRepository.ValidateWithDbAsync(wellOperations, cancellationToken); + } + /// /// Обновляет выбранную операцию на скважине /// @@ -308,7 +331,7 @@ namespace AsbCloudWebApi.Controllers { if (!await CanUserAccessToWellAsync(idWell, token)) return Forbid(); - + if (!await CanUserEditWellOperationsAsync(idWell, token)) return Forbid(); @@ -317,6 +340,9 @@ namespace AsbCloudWebApi.Controllers value.LastUpdateDate = DateTimeOffset.UtcNow; value.IdUser = User.GetUserId(); + if (!await operationRepository.ValidateWithDbAsync(new[] { value }, token)) + return this.ValidationBadRequest(nameof(value), "The date difference between the operations is more than 3 months"); + var result = await operationRepository.UpdateAsync(value, token) .ConfigureAwait(false); return Ok(result); @@ -336,7 +362,7 @@ namespace AsbCloudWebApi.Controllers { if (!await CanUserAccessToWellAsync(idWell, token)) return Forbid(); - + if (!await CanUserEditWellOperationsAsync(idWell, token)) return Forbid(); @@ -373,7 +399,7 @@ namespace AsbCloudWebApi.Controllers deleteBeforeInsert, cancellationToken); } - + /// /// Импорт плановых операций из excel (xlsx) файла. Стандартный заполненный шаблон /// @@ -393,7 +419,7 @@ namespace AsbCloudWebApi.Controllers { IdType = WellOperation.IdOperationTypePlan }; - + return ImportExcelFileAsync(idWell, files, options, (stream, _) => wellOperationDefaultExcelParser.Parse(stream, options), null, @@ -522,7 +548,7 @@ namespace AsbCloudWebApi.Controllers return this.ValidationBadRequest(nameof(files), "Требуется xlsx файл."); using Stream stream = file.OpenReadStream(); - + try { var sheet = parseMethod(stream, options); @@ -541,8 +567,8 @@ namespace AsbCloudWebApi.Controllers //TODO: очень быстрый костыль if (deleteBeforeInsert is not null && options.IdType == WellOperation.IdOperationTypeFact) { - return await InsertRangeAsync(idWell, options.IdType, - deleteBeforeInsert.Value, + return await InsertRangeAsync(idWell, options.IdType, + deleteBeforeInsert.Value, wellOperations, cancellationToken); } @@ -554,21 +580,21 @@ namespace AsbCloudWebApi.Controllers return this.ValidationBadRequest(nameof(files), ex.Message); } } - + private async Task CanUserAccessToWellAsync(int idWell, CancellationToken token) { int? idCompany = User.GetCompanyId(); return idCompany is not null && await wellService.IsCompanyInvolvedInWellAsync((int)idCompany, idWell, token).ConfigureAwait(false); } - + private async Task CanUserEditWellOperationsAsync(int idWell, CancellationToken token) { var idUser = User.GetUserId(); if (!idUser.HasValue) return false; - + var well = await wellService.GetOrDefaultAsync(idWell, token); if (well is null)