From d7e0eace474143e5bb24f58fd3cbe2cb92d03490 Mon Sep 17 00:00:00 2001
From: KharchenkoVV <vv.harchenko@autodrilling.ru>
Date: Mon, 16 Aug 2021 14:19:43 +0500
Subject: [PATCH] CS2-53: Added WellOperations Controller, Service, Dtos and
 Models

---
 AsbCloudApp/Data/WellOperationCategoryDto.cs  |  11 ++
 AsbCloudApp/Data/WellOperationDto.cs          |  14 ++-
 AsbCloudApp/Services/IWellOperationService.cs |  18 ++-
 AsbCloudDb/Model/AsbCloudDbContext.cs         |  40 +++----
 AsbCloudDb/Model/IAsbCloudDbContext.cs        |   2 +-
 AsbCloudDb/Model/TelemetryAnalysis.cs         |   4 +-
 AsbCloudDb/Model/WellOperation.cs             |   6 +-
 ...onCategory.cs => WellOperationCategory.cs} |   7 +-
 .../Services/TelemetryAnalyticsService.cs     |   8 +-
 .../Services/TelemetryOperationDetector.cs    |   2 +-
 .../TelemetryOperationDetectorService.cs      |   6 +-
 .../Services/WellOperationService.cs          |  91 ++++++++++++--
 .../Controllers/WellOperationController.cs    | 112 +++++++++++++++++-
 13 files changed, 264 insertions(+), 57 deletions(-)
 create mode 100644 AsbCloudApp/Data/WellOperationCategoryDto.cs
 rename AsbCloudDb/Model/{OperationCategory.cs => WellOperationCategory.cs} (72%)

diff --git a/AsbCloudApp/Data/WellOperationCategoryDto.cs b/AsbCloudApp/Data/WellOperationCategoryDto.cs
new file mode 100644
index 00000000..04a8fcd0
--- /dev/null
+++ b/AsbCloudApp/Data/WellOperationCategoryDto.cs
@@ -0,0 +1,11 @@
+namespace AsbCloudApp.Data
+{
+    public class WellOperationCategoryDto
+    {
+        public int Id { get; set; }
+
+        public string Name { get; set; }
+
+        public int Code { get; set; }
+    }
+}
diff --git a/AsbCloudApp/Data/WellOperationDto.cs b/AsbCloudApp/Data/WellOperationDto.cs
index 5428a204..6b8e2d27 100644
--- a/AsbCloudApp/Data/WellOperationDto.cs
+++ b/AsbCloudApp/Data/WellOperationDto.cs
@@ -6,21 +6,25 @@ namespace AsbCloudApp.Data
     {
         public int Id { get; set; }
 
-        public int IdSection { get; set; }
+        public int IdWell { get; set; }
 
-        public int IdCategory { get; set; }
+        public int IdWellSectionType { get; set; }
+
+        public string WellSectionTypeName { get; set; }
+
+        public int IdOperationCategory { get; set; }
 
         public string CategoryName { get; set; }
 
         public string Type { get; set; }
 
-        public string WellDepth { get; set; }
+        public double WellDepth { get; set; }
 
         public DateTime StartDate { get; set; }
 
-        public double Duration { get; set; }
+        public double DurationHours { get; set; }
 
-        public string Data { get; set; }
+        public string Info { get; set; }
 
         public string Comment { get; set; }
     }
diff --git a/AsbCloudApp/Services/IWellOperationService.cs b/AsbCloudApp/Services/IWellOperationService.cs
index fe90fdce..8dca0e31 100644
--- a/AsbCloudApp/Services/IWellOperationService.cs
+++ b/AsbCloudApp/Services/IWellOperationService.cs
@@ -1,4 +1,5 @@
-using System.Threading;
+using System.Collections.Generic;
+using System.Threading;
 using System.Threading.Tasks;
 using AsbCloudApp.Data;
 
@@ -7,7 +8,22 @@ namespace AsbCloudApp.Services
 {
     public interface IWellOperationService
     {
+        IEnumerable<WellOperationCategoryDto> GetTypes();
+
         Task<PaginationContainer<WellOperationDto>> GetAllByWellIdAsync(int idWell,
             int skip = 0, int take = 32, CancellationToken token = default);
+
+        Task<WellOperationDto> GetAsync(int id, CancellationToken token);
+
+        Task<int> InsertAsync(WellOperationDto wellOperationDto,
+            int idWell, CancellationToken token);
+
+        Task<int> InsertRangeAsync(int idWell,
+            IEnumerable<WellOperationDto> wellOperationDtos, CancellationToken token);
+
+        Task<int> UpdateAsync(int idWell, int idSection, WellOperationDto item, 
+            CancellationToken token);
+
+        Task<int> DeleteAsync(IEnumerable<int> ids, CancellationToken token);
     }
 }
diff --git a/AsbCloudDb/Model/AsbCloudDbContext.cs b/AsbCloudDb/Model/AsbCloudDbContext.cs
index 412ac241..8e9934d3 100644
--- a/AsbCloudDb/Model/AsbCloudDbContext.cs
+++ b/AsbCloudDb/Model/AsbCloudDbContext.cs
@@ -27,7 +27,7 @@ namespace AsbCloudDb.Model
         public virtual DbSet<TelemetryEvent> TelemetryEvents { get; set; }
         public virtual DbSet<TelemetryMessage> TelemetryMessages { get; set; }
         public virtual DbSet<TelemetryUser> TelemetryUsers { get; set; }
-        public virtual DbSet<OperationCategory> TelemetryOperations { get; set; }
+        public virtual DbSet<WellOperationCategory> TelemetryOperations { get; set; }
         public virtual DbSet<TelemetryAnalysis> TelemetryAnalysis { get; set; }
         public virtual DbSet<WellSection> WellSections { get; set; }
         public virtual DbSet<WellSectionType> WellSectionTypes { get; set; }
@@ -204,26 +204,26 @@ namespace AsbCloudDb.Model
                 });
             });
 
-            modelBuilder.Entity<OperationCategory>(entity =>
+            modelBuilder.Entity<WellOperationCategory>(entity =>
             {
-                entity.HasData(new List<OperationCategory> {
-                    new OperationCategory {Id = 1, OperationType = 0, Name = "Невозможно определить операцию"},
-                    new OperationCategory {Id = 2, OperationType = 0, Name = "Роторное бурение" },
-                    new OperationCategory {Id = 3, OperationType = 0, Name = "Слайдирование" },
-                    new OperationCategory {Id = 4, OperationType = 0, Name = "Подъем с проработкой" },
-                    new OperationCategory {Id = 5, OperationType = 0, Name = "Спуск с проработкой" },
-                    new OperationCategory {Id = 6, OperationType = 0, Name = "Подъем с промывкой" },
-                    new OperationCategory {Id = 7, OperationType = 0, Name = "Спуск с промывкой" },
-                    new OperationCategory {Id = 8, OperationType = 0, Name = "Спуск в скважину" },
-                    new OperationCategory {Id = 9, OperationType = 0, Name = "Спуск с вращением" },
-                    new OperationCategory {Id = 10, OperationType = 0, Name = "Подъем из скважины" },
-                    new OperationCategory {Id = 11, OperationType = 0, Name = "Подъем с вращением" },
-                    new OperationCategory {Id = 12, OperationType = 0, Name = "Промывка в покое" },
-                    new OperationCategory {Id = 13, OperationType = 0, Name = "Промывка с вращением" },
-                    new OperationCategory {Id = 14, OperationType = 0, Name = "Удержание в клиньях" },
-                    new OperationCategory {Id = 15, OperationType = 0, Name = "Неподвижное состояние" },
-                    new OperationCategory {Id = 16, OperationType = 0, Name = "Вращение без циркуляции" },
-                    new OperationCategory {Id = 17, OperationType = 0, Name = "На поверхности" }
+                entity.HasData(new List<WellOperationCategory> {
+                    new WellOperationCategory {Id = 1, Name = "Невозможно определить операцию", Code = 0},
+                    new WellOperationCategory {Id = 2, Name = "Роторное бурение", Code = 0 },
+                    new WellOperationCategory {Id = 3, Name = "Слайдирование", Code = 0 },
+                    new WellOperationCategory {Id = 4, Name = "Подъем с проработкой", Code = 0 },
+                    new WellOperationCategory {Id = 5, Name = "Спуск с проработкой", Code = 0 },
+                    new WellOperationCategory {Id = 6, Name = "Подъем с промывкой", Code = 0 },
+                    new WellOperationCategory {Id = 7, Name = "Спуск с промывкой", Code = 0 },
+                    new WellOperationCategory {Id = 8, Name = "Спуск в скважину", Code = 0 },
+                    new WellOperationCategory {Id = 9,  Name = "Спуск с вращением", Code = 0 },
+                    new WellOperationCategory {Id = 10, Name = "Подъем из скважины", Code = 0 },
+                    new WellOperationCategory {Id = 11, Name = "Подъем с вращением", Code = 0 },
+                    new WellOperationCategory {Id = 12, Name = "Промывка в покое", Code = 0 },
+                    new WellOperationCategory {Id = 13, Name = "Промывка с вращением", Code = 0 },
+                    new WellOperationCategory {Id = 14, Name = "Удержание в клиньях", Code = 0 },
+                    new WellOperationCategory {Id = 15, Name = "Неподвижное состояние", Code = 0 },
+                    new WellOperationCategory {Id = 16, Name = "Вращение без циркуляции", Code = 0 },
+                    new WellOperationCategory {Id = 17, Name = "На поверхности", Code = 0 }
                 });
             });
 
diff --git a/AsbCloudDb/Model/IAsbCloudDbContext.cs b/AsbCloudDb/Model/IAsbCloudDbContext.cs
index d906e035..0d3b2f45 100644
--- a/AsbCloudDb/Model/IAsbCloudDbContext.cs
+++ b/AsbCloudDb/Model/IAsbCloudDbContext.cs
@@ -22,7 +22,7 @@ namespace AsbCloudDb.Model
         DbSet<FileCategory> FileCategories { get; set; }
         DbSet<Telemetry> Telemetries { get; set; }
         DbSet<TelemetryUser> TelemetryUsers { get; set; }
-        DbSet<OperationCategory> TelemetryOperations { get; set; }
+        DbSet<WellOperationCategory> TelemetryOperations { get; set; }
         DbSet<TelemetryAnalysis> TelemetryAnalysis { get; set; }
         DbSet<Well> Wells { get; set; }
         DbSet<WellSection> WellSections { get; set; }
diff --git a/AsbCloudDb/Model/TelemetryAnalysis.cs b/AsbCloudDb/Model/TelemetryAnalysis.cs
index 30346d6c..d4c509ba 100644
--- a/AsbCloudDb/Model/TelemetryAnalysis.cs
+++ b/AsbCloudDb/Model/TelemetryAnalysis.cs
@@ -28,8 +28,8 @@ namespace AsbCloudDb.Model
 
         [JsonIgnore]
         [ForeignKey(nameof(IdOperation))]
-        [InverseProperty(nameof(Model.OperationCategory.Analysis))]
-        public virtual OperationCategory Operation { get; set; }
+        [InverseProperty(nameof(Model.WellOperationCategory.Analysis))]
+        public virtual WellOperationCategory Operation { get; set; }
 
 
         [Column("unix_date", TypeName = "bigint"), Comment("Unix timestamp для Linq запросов с вычислением дат")]
diff --git a/AsbCloudDb/Model/WellOperation.cs b/AsbCloudDb/Model/WellOperation.cs
index d2ca33ac..1b70704c 100644
--- a/AsbCloudDb/Model/WellOperation.cs
+++ b/AsbCloudDb/Model/WellOperation.cs
@@ -20,7 +20,7 @@ namespace AsbCloudDb.Model
         public int IdWellSectionType { get; set; }
 
         [Column("id_category"), Comment("Id категории операции")]
-        public int IdCategory { get; set; }
+        public int IdOperationCategory { get; set; }
 
         [Column("type"), Comment("План или Факт")]
         public string Type { get; set; }
@@ -49,7 +49,7 @@ namespace AsbCloudDb.Model
         public virtual WellSectionType WellSectionType { get; set; }
 
         [JsonIgnore]
-        [ForeignKey(nameof(IdCategory))]
-        public virtual OperationCategory OperationCategory { get; set; }
+        [ForeignKey(nameof(IdOperationCategory))]
+        public virtual WellOperationCategory OperationCategory { get; set; }
     }
 }
diff --git a/AsbCloudDb/Model/OperationCategory.cs b/AsbCloudDb/Model/WellOperationCategory.cs
similarity index 72%
rename from AsbCloudDb/Model/OperationCategory.cs
rename to AsbCloudDb/Model/WellOperationCategory.cs
index 38516bbe..25434aff 100644
--- a/AsbCloudDb/Model/OperationCategory.cs
+++ b/AsbCloudDb/Model/WellOperationCategory.cs
@@ -6,16 +6,13 @@ using System.ComponentModel.DataAnnotations.Schema;
 namespace AsbCloudDb.Model
 {
     [Table("t_operation"), Comment("Справочник операций на скважине")]
-    public class OperationCategory
+    public class WellOperationCategory
     {
         [Key]
         [Column("id")]
         public int Id { get; set; }
 
-        [Column("type"), Comment("Тип операции (авто/ручной ввод)")]
-        public int OperationType { get; set; }
-
-        [Column("name"), Comment("Название операции")]
+        [Column("name"), Comment("Название категории операции")]
         public string Name { get; set; }
 
         [Column("code"), Comment("Код операции")]
diff --git a/AsbCloudInfrastructure/Services/TelemetryAnalyticsService.cs b/AsbCloudInfrastructure/Services/TelemetryAnalyticsService.cs
index fcb604d3..29a7363f 100644
--- a/AsbCloudInfrastructure/Services/TelemetryAnalyticsService.cs
+++ b/AsbCloudInfrastructure/Services/TelemetryAnalyticsService.cs
@@ -17,9 +17,9 @@ namespace AsbCloudInfrastructure.Services
         private readonly IAsbCloudDbContext db;
         private readonly ITelemetryService telemetryService;
         private readonly ISaubDataCache saubDataCache;
-        private readonly CacheTable<OperationCategory> cacheOperations;
+        private readonly CacheTable<WellOperationCategory> cacheOperations;
         private readonly TelemetryOperationDetectorService operationDetectorService;
-        private readonly IEnumerable<OperationCategory> operations;
+        private readonly IEnumerable<WellOperationCategory> operations;
 
         public TelemetryAnalyticsService(IAsbCloudDbContext db, ITelemetryService telemetryService,
             ISaubDataCache saubDataCache, CacheDb cacheDb)
@@ -27,8 +27,8 @@ namespace AsbCloudInfrastructure.Services
             this.db = db;
             this.telemetryService = telemetryService;
             this.saubDataCache = saubDataCache;
-            cacheOperations = cacheDb.GetCachedTable<OperationCategory>((AsbCloudDbContext)db);
-            operations = cacheOperations.Where(c => true);
+            cacheOperations = cacheDb.GetCachedTable<WellOperationCategory>((AsbCloudDbContext)db);
+            operations = cacheOperations.Where();
             operationDetectorService = new TelemetryOperationDetectorService(operations);
         }
 
diff --git a/AsbCloudInfrastructure/Services/TelemetryOperationDetector.cs b/AsbCloudInfrastructure/Services/TelemetryOperationDetector.cs
index bd99f812..c618b0f1 100644
--- a/AsbCloudInfrastructure/Services/TelemetryOperationDetector.cs
+++ b/AsbCloudInfrastructure/Services/TelemetryOperationDetector.cs
@@ -7,7 +7,7 @@ namespace AsbCloudInfrastructure.Services
     public class TelemetryOperationDetector
     {
         public int Order { get; set; }
-        public OperationCategory Operation { get; set; }
+        public WellOperationCategory Operation { get; set; }
         public Func<TelemetryAnalysisDto, bool> Detect { get; set; }
     }
 }
diff --git a/AsbCloudInfrastructure/Services/TelemetryOperationDetectorService.cs b/AsbCloudInfrastructure/Services/TelemetryOperationDetectorService.cs
index 66c0b4ae..c48d21b7 100644
--- a/AsbCloudInfrastructure/Services/TelemetryOperationDetectorService.cs
+++ b/AsbCloudInfrastructure/Services/TelemetryOperationDetectorService.cs
@@ -9,7 +9,7 @@ namespace AsbCloudInfrastructure.Services
     {
         private readonly IEnumerable<TelemetryOperationDetector> detectors;
 
-        public TelemetryOperationDetectorService(IEnumerable<OperationCategory> operations)
+        public TelemetryOperationDetectorService(IEnumerable<WellOperationCategory> operations)
         {
             detectors = new List<TelemetryOperationDetector>()
             {
@@ -180,8 +180,8 @@ namespace AsbCloudInfrastructure.Services
             };
         }
 
-        public OperationCategory DetectOperation(TelemetryAnalysisDto data) =>
+        public WellOperationCategory DetectOperation(TelemetryAnalysisDto data) =>
             detectors.OrderBy(d => d.Order).First(o => o.Detect(data)).Operation
-                ?? new OperationCategory { Id = 1, Name = "Невозможно определить операцию" };
+                ?? new WellOperationCategory { Id = 1, Name = "Невозможно определить операцию" };
     }
 }
diff --git a/AsbCloudInfrastructure/Services/WellOperationService.cs b/AsbCloudInfrastructure/Services/WellOperationService.cs
index e8bf9227..efe2db83 100644
--- a/AsbCloudInfrastructure/Services/WellOperationService.cs
+++ b/AsbCloudInfrastructure/Services/WellOperationService.cs
@@ -1,4 +1,5 @@
-using System.Linq;
+using System.Collections.Generic;
+using System.Linq;
 using System.Threading;
 using System.Threading.Tasks;
 using Microsoft.EntityFrameworkCore;
@@ -13,21 +14,34 @@ namespace AsbCloudInfrastructure.Services
     public class WellOperationService : IWellOperationService
     {
         private readonly IAsbCloudDbContext context;
-        private readonly DbSet<WellOperation> dbSet;
-        private readonly CacheTable<OperationCategory> cachedOperationTypes;
+        private readonly CacheTable<WellOperationCategory> cachedOperationTypes;
 
         public WellOperationService(IAsbCloudDbContext context, Cache.CacheDb cache)
         {
             this.context = context;
-            dbSet = context.Set<WellOperation>();
-            cachedOperationTypes = cache.GetCachedTable<OperationCategory>((DbContext)context);
+            cachedOperationTypes = cache.GetCachedTable<WellOperationCategory>((DbContext)context);
+        }
+
+        public IEnumerable<WellOperationCategoryDto> GetTypes()
+        {
+            var operationTypes = cachedOperationTypes.Where().Distinct();
+            var result = new List<WellOperationCategoryDto>();
+
+            foreach(var op in operationTypes)
+            {
+                var dto = op.Adapt<WellOperationCategoryDto>();
+                result.Add(dto);
+            }
+
+            return result;
         }
 
         public async Task<PaginationContainer<WellOperationDto>> GetAllByWellIdAsync(int idWell,
             int skip = 0, int take = 32, CancellationToken token = default)
         {
-            var query = dbSet
+            var query = context.WellOperations
                 .Include(s => s.WellSectionType)
+                .Include(s => s.OperationCategory)
                 .Where(s => s.IdWell == idWell)
                 .AsNoTracking();
 
@@ -46,16 +60,77 @@ namespace AsbCloudInfrastructure.Services
 
             query = query.Take(take);
 
-            var entities = await query.Take(take).ToListAsync(token).ConfigureAwait(false);
+            var entities = await query.Take(take)
+                .ToListAsync(token).ConfigureAwait(false);
 
             foreach (var item in entities)
             {
                 var dto = item.Adapt<WellOperationDto>();
-                //dto.SectionType = item.WellSectionType.Caption;
+                dto.WellSectionTypeName = item.WellSectionType.Caption;
+                dto.CategoryName = item.OperationCategory.Name;
                 result.Items.Add(dto);
             }
 
             return result;
         }
+
+        public async Task<WellOperationDto> GetAsync(int id, 
+            CancellationToken token = default)
+        {
+            var entity = await context.WellOperations
+                .Include(s => s.WellSectionType)
+                .Include(s => s.OperationCategory)
+                .FirstOrDefaultAsync(e => e.Id == id, token)
+                .ConfigureAwait(false);
+
+            if (entity is null)
+                return null;
+
+            var dto = entity.Adapt<WellOperationDto>();
+            dto.WellSectionTypeName = entity.WellSectionType.Caption;
+            dto.CategoryName = entity.OperationCategory.Name;
+            return dto;
+        }
+
+        public async Task<int> InsertAsync(WellOperationDto wellOperationDto, 
+            int idWell, CancellationToken token = default)
+        {
+            var entity = wellOperationDto.Adapt<WellOperation>();
+            context.WellOperations.Add(entity);
+            return await context.SaveChangesAsync(token)
+                .ConfigureAwait(false);
+        }
+
+        public async Task<int> InsertRangeAsync(int idWell, 
+            IEnumerable<WellOperationDto> wellOperationDtos, 
+            CancellationToken token = default)
+        {
+            foreach(var operationDto in wellOperationDtos)
+            {
+                var entity = operationDto.Adapt<WellOperation>();
+                context.WellOperations.Add(entity);
+            }
+
+            return await context.SaveChangesAsync(token)
+                .ConfigureAwait(false);
+        }
+
+        public async Task<int> UpdateAsync(int idWell, int idSection, 
+            WellOperationDto item, CancellationToken token = default)
+        {
+            var entity = item.Adapt<WellOperation>();
+            context.WellOperations.Update(entity);
+            return await context.SaveChangesAsync(token)
+                .ConfigureAwait(false);
+        }
+
+        public async Task<int> DeleteAsync(IEnumerable<int> ids,
+            CancellationToken token = default)
+        {
+            var entities = context.WellOperations.Where(e => ids.Contains(e.Id));
+            context.WellOperations.RemoveRange(entities);
+            return await context.SaveChangesAsync(token)
+                .ConfigureAwait(false);
+        }
     }
 }
diff --git a/AsbCloudWebApi/Controllers/WellOperationController.cs b/AsbCloudWebApi/Controllers/WellOperationController.cs
index 6ca3fe4a..05316b88 100644
--- a/AsbCloudWebApi/Controllers/WellOperationController.cs
+++ b/AsbCloudWebApi/Controllers/WellOperationController.cs
@@ -1,4 +1,5 @@
-using System.Threading;
+using System.Collections.Generic;
+using System.Threading;
 using System.Threading.Tasks;
 using AsbCloudApp.Data;
 using AsbCloudApp.Services;
@@ -8,9 +9,9 @@ using Microsoft.AspNetCore.Authorization;
 namespace AsbCloudWebApi.Controllers
 {
     /// <summary>
-    /// Контроллер операций на скважине
+    /// Контроллер вручную внесенных операций на скважине
     /// </summary>
-    [Route("api/wellOperation")]
+    [Route("api/wellOperations")]
     [ApiController]
     [Authorize]
     public class WellOperationController : ControllerBase
@@ -24,8 +25,29 @@ namespace AsbCloudWebApi.Controllers
             this.wellService = wellService;
         }
 
+        /// <summary>
+        /// Возвращает список имен типов операций на скважине
+        /// </summary>
+        /// <returns></returns>
         [HttpGet]
-        [ProducesResponseType(typeof(PaginationContainer<WellSectionDto>), (int)System.Net.HttpStatusCode.OK)]
+        [Route("types")]
+        [ProducesResponseType(typeof(IEnumerable<string>), (int)System.Net.HttpStatusCode.OK)]
+        public IActionResult GetTypesAsync()
+        {
+            var result = operationService.GetTypes();
+            return Ok(result);
+        }
+
+        /// <summary>
+        /// Возвращает весь список операций на скважине
+        /// </summary>
+        /// <param name="idWell">id скважины</param>
+        /// <param name="skip">Для пагинации кол-во записей пропустить</param>
+        /// <param name="take">Для пагинации кол-во записей</param>
+        /// <param name="token">Токен отмены задачи</param>
+        /// <returns>Список операций на скважине</returns>
+        [HttpGet]
+        [ProducesResponseType(typeof(PaginationContainer<WellOperationDto>), (int)System.Net.HttpStatusCode.OK)]
         public async Task<IActionResult> GetAllAsync(int idWell, int skip = 0, int take = 32,
             CancellationToken token = default)
         {
@@ -36,6 +58,88 @@ namespace AsbCloudWebApi.Controllers
             return Ok(result);
         }
 
+        /// <summary>
+        /// Возвращает нужную операцию на скважине
+        /// </summary>
+        /// <param name="idWell">id скважины</param>
+        /// <param name="idOperation">id нужной операции</param>
+        /// <param name="token">Токен отмены задачи</param>
+        /// <returns>Нужную операцию на скважине</returns>
+        [HttpGet]
+        [Route("{idOperation}")]
+        [ProducesResponseType(typeof(WellOperationDto), (int)System.Net.HttpStatusCode.OK)]
+        public async Task<IActionResult> GetAsync(int idWell, int idOperation,
+            CancellationToken token = default)
+        {
+            if (!await CanUserAccessToWellAsync(idWell, token).ConfigureAwait(false))
+                return Forbid();
+
+            var result = await operationService.GetAsync(idOperation, token).ConfigureAwait(false);
+            return Ok(result);
+        }
+
+        /// <summary>
+        /// Добавляет новые операции на скважине
+        /// </summary>
+        /// <param name="idWell">id скважины</param>
+        /// <param name="values">Данные о добавляемых операциях</param>
+        /// <param name="token">Токен отмены задачи</param>
+        /// <returns>Количество добавленых в БД строк</returns>
+        [HttpPost]
+        [ProducesResponseType(typeof(IEnumerable<WellOperationDto>), (int)System.Net.HttpStatusCode.OK)]
+        public async Task<IActionResult> InsertRangeAsync(int idWell, [FromBody] IEnumerable<WellOperationDto> values,
+            CancellationToken token = default)
+        {
+            if (!await CanUserAccessToWellAsync(idWell, token).ConfigureAwait(false))
+                return Forbid();
+
+            var result = await operationService.InsertRangeAsync(idWell, values, token)
+                .ConfigureAwait(false);
+            return Ok(result);
+        }
+
+        /// <summary>
+        /// Обновляет выбранную операцию на скважине
+        /// </summary>
+        /// <param name="idWell">id скважины</param>
+        /// <param name="idOperation">id выбраной операции</param>
+        /// <param name="value">Новые данные для выбраной операции</param>
+        /// <param name="token">Токен отмены задачи</param>
+        /// <returns>Количество обновленных в БД строк</returns>
+        [HttpPut("{idOperation}")]
+        [ProducesResponseType(typeof(WellOperationDto), (int)System.Net.HttpStatusCode.OK)]
+        public async Task<IActionResult> UpdateAsync(int idWell, int idOperation, 
+            [FromBody] WellOperationDto value, CancellationToken token = default)
+        {
+            if (!await CanUserAccessToWellAsync(idWell, token).ConfigureAwait(false))
+                return Forbid();
+
+            var result = await operationService.UpdateAsync(idWell, idOperation, value, token)
+                .ConfigureAwait(false);
+            return Ok(result);
+        }
+
+        /// <summary>
+        /// Удаляет выбраную операцию на скважине
+        /// </summary>
+        /// <param name="idWell">id скважины</param>
+        /// <param name="idOperation">id выбраной операции</param>
+        /// <param name="token">Токен отмены задачи</param>
+        /// <returns>Количество удаленных из БД строк</returns>
+        [HttpDelete("{idOperation}")]
+        [ProducesResponseType(typeof(int), (int)System.Net.HttpStatusCode.OK)]
+        public async Task<IActionResult> DeleteAsync(int idWell, int idOperation, CancellationToken token = default)
+        {
+            if (!await CanUserAccessToWellAsync(idWell,
+                token).ConfigureAwait(false))
+                return Forbid();
+
+            var result = await operationService.DeleteAsync(new int[] { idOperation }, token)
+                .ConfigureAwait(false);
+
+            return Ok(result);
+        }
+
         private async Task<bool> CanUserAccessToWellAsync(int idWell, CancellationToken token = default)
         {
             int? idCompany = User.GetCompanyId();