forked from ddrilling/AsbCloudServer
Draft WellOperationImportService. incomplete
This commit is contained in:
parent
674fe9586c
commit
2868304546
@ -31,7 +31,7 @@ namespace AsbCloudDb.Model
|
||||
public virtual DbSet<UserRole> UserRoles { get; set; }
|
||||
public virtual DbSet<Well> Wells { get; set; }
|
||||
public virtual DbSet<WellOperation> WellOperations { get; set; }
|
||||
public virtual DbSet<WellOperationCategory> TelemetryOperations { get; set; }
|
||||
public virtual DbSet<WellOperationCategory> WellOperationCategories { get; set; }
|
||||
public virtual DbSet<WellSectionType> WellSectionTypes { get; set; }
|
||||
public virtual DbSet<WellType> WellTypes { get; set; }
|
||||
|
||||
|
@ -23,7 +23,7 @@ namespace AsbCloudDb.Model
|
||||
DbSet<FileCategory> FileCategories { get; set; }
|
||||
DbSet<Telemetry> Telemetries { get; set; }
|
||||
DbSet<TelemetryUser> TelemetryUsers { get; set; }
|
||||
DbSet<WellOperationCategory> TelemetryOperations { get; set; }
|
||||
DbSet<WellOperationCategory> WellOperationCategories { get; set; }
|
||||
DbSet<TelemetryAnalysis> TelemetryAnalysis { get; set; }
|
||||
DbSet<Well> Wells { get; set; }
|
||||
DbSet<WellSectionType> WellSectionTypes { get; set; }
|
||||
|
@ -170,7 +170,7 @@ namespace AsbCloudInfrastructure.Services.Analysis
|
||||
return await (from a in db.TelemetryAnalysis
|
||||
where a.IdTelemetry == telemetryId &&
|
||||
a.UnixDate > unixBegin && a.UnixDate < unixEnd
|
||||
join o in db.TelemetryOperations on a.IdOperation equals o.Id
|
||||
join o in db.WellOperationCategories on a.IdOperation equals o.Id
|
||||
group a by new { a.IdOperation, o.Name } into g
|
||||
select new TelemetryOperationDurationDto
|
||||
{
|
||||
@ -198,7 +198,7 @@ namespace AsbCloudInfrastructure.Services.Analysis
|
||||
// Without dividing these operations duration by given interval
|
||||
var ops = await (from a in db.TelemetryAnalysis
|
||||
where a.IdTelemetry == telemetryId
|
||||
join o in db.TelemetryOperations on a.IdOperation equals o.Id
|
||||
join o in db.WellOperationCategories on a.IdOperation equals o.Id
|
||||
group a by new
|
||||
{
|
||||
Interval = Math.Floor((a.UnixDate - workBeginSeconds + timezoneOffset) / intervalSeconds),
|
||||
|
@ -2,10 +2,9 @@
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using ClosedXML.Excel;
|
||||
using AsbCloudApp.Data;
|
||||
using AsbCloudDb.Model;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services
|
||||
{
|
||||
@ -14,24 +13,188 @@ namespace AsbCloudInfrastructure.Services
|
||||
private const string sheetNamePlan = "План";
|
||||
private const string sheetNameFact = "Факт";
|
||||
|
||||
private static readonly DateTime dateLimitMin = new DateTime(2001,1,1,0,0,0);
|
||||
private static readonly DateTime dateLimitMax = new DateTime(2099,1,1,0,0,0);
|
||||
private static readonly TimeSpan drillingDurationLimitMax = TimeSpan.FromDays(366);
|
||||
|
||||
private readonly IAsbCloudDbContext db;
|
||||
|
||||
private List<WellOperationCategory> categories = null;
|
||||
public List<WellOperationCategory> Categories {
|
||||
get {
|
||||
if (categories is null)
|
||||
categories = db.WellOperationCategories.ToList();
|
||||
return categories;
|
||||
}
|
||||
}
|
||||
|
||||
private List<WellSectionType> sections = null;
|
||||
public List<WellSectionType> Sections
|
||||
{
|
||||
get
|
||||
{
|
||||
if (sections is null)
|
||||
sections = db.WellSectionTypes.ToList();
|
||||
return sections;
|
||||
}
|
||||
}
|
||||
|
||||
public WellOperationImportService(IAsbCloudDbContext db)
|
||||
{
|
||||
this.db = db;
|
||||
}
|
||||
|
||||
public IEnumerable<WellOperationDto> ParseFile(string excelFilePath)
|
||||
{
|
||||
if (!File.Exists(excelFilePath))
|
||||
throw new FileNotFoundException($"Файл {excelFilePath} не найден.");
|
||||
|
||||
return ParseWorkbook(excelFilePath);
|
||||
}
|
||||
|
||||
private IEnumerable<WellOperationDto> ParseWorkbook(string excelFilePath)
|
||||
{
|
||||
using var sourceExcelWorkbook = new XLWorkbook(excelFilePath, XLEventTracking.Disabled);
|
||||
|
||||
var sheetPlan = sourceExcelWorkbook.Worksheets.FirstOrDefault(ws => ws.Name == sheetNamePlan);
|
||||
if (sheetPlan is null)
|
||||
throw new FileFormatException($"Файл {excelFilePath} не не содержит листа {sheetNamePlan}.");
|
||||
|
||||
|
||||
var sheetFact = sourceExcelWorkbook.Worksheets.FirstOrDefault(ws => ws.Name == sheetNameFact);
|
||||
if (sheetFact is null)
|
||||
throw new FileFormatException($"Файл {excelFilePath} не не содержит листа {sheetNameFact}.");
|
||||
|
||||
//sheetPlan.RangeUsed().RangeAddress.LastAddress.ColumnNumber
|
||||
var wellOperations = new List<WellOperationDto>();
|
||||
|
||||
var wellOperationsPlan = ParseSheet(sheetPlan, 0);
|
||||
wellOperations.AddRange(wellOperationsPlan);
|
||||
|
||||
var wellOperationsFact = ParseSheet(sheetFact, 1);
|
||||
wellOperations.AddRange(wellOperationsFact);
|
||||
|
||||
return wellOperations;
|
||||
}
|
||||
|
||||
private IEnumerable<WellOperationDto> ParseSheet(IXLWorksheet sheet, int idType)
|
||||
{
|
||||
const int headerRowsCount = 1;
|
||||
|
||||
if (sheet.RangeUsed().RangeAddress.LastAddress.ColumnNumber < 7)
|
||||
throw new FileFormatException($"Лист {sheet.Name} содержит меньшее количество столбцев.");
|
||||
|
||||
var count = sheet.RowsUsed().Count() - headerRowsCount;
|
||||
|
||||
if (count > 1024)
|
||||
throw new FileFormatException($"Лист {sheet.Name} содержит слишком большое количество операций.");
|
||||
|
||||
if (count <= 0)
|
||||
return new List<WellOperationDto>();
|
||||
|
||||
var operations = new List<WellOperationDto>(count);
|
||||
var parseErrors = new List<string>();
|
||||
DateTime lastOperationDateStart = new DateTime();
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var row = sheet.Row(1 + i + headerRowsCount);
|
||||
try
|
||||
{
|
||||
var operation = ParseRow(row, idType);
|
||||
operations.Add(operation);
|
||||
|
||||
if (lastOperationDateStart > operation.DateStart)
|
||||
parseErrors.Add($"Лист {sheet.Name} строка {row.RowNumber()} дата позднее даты предыдущей операции.");
|
||||
|
||||
lastOperationDateStart = operation.DateStart;
|
||||
}
|
||||
catch(FileFormatException ex)
|
||||
{
|
||||
parseErrors.Add(ex.Message);
|
||||
}
|
||||
};
|
||||
|
||||
// проверка диапазона дат
|
||||
if(operations.Min(o => o.DateStart) - operations.Max(o => o.DateStart) > drillingDurationLimitMax)
|
||||
parseErrors.Add($"Лист {sheet.Name} содержит диапазон дат больше {drillingDurationLimitMax}");
|
||||
|
||||
if (parseErrors.Any())
|
||||
throw new FileFormatException(string.Join("\r\n", parseErrors));
|
||||
|
||||
return operations;
|
||||
}
|
||||
|
||||
private WellOperationDto ParseRow(IXLRow row, int idType)
|
||||
{
|
||||
const int columnSection = 1;
|
||||
const int columnCategory = 2;
|
||||
const int columnCategoryInfo = 3;
|
||||
const int columnDepthStart = 4;
|
||||
const int columnDepthEnd = 5;
|
||||
const int columnDate = 6;
|
||||
const int columnDuration = 7;
|
||||
const int columnComment = 8;
|
||||
|
||||
var vSection = row.Cell(columnSection).Value;
|
||||
var vCategory = row.Cell(columnCategory).Value;
|
||||
var vCategoryInfo = row.Cell(columnCategoryInfo).Value;
|
||||
var vDepthStart = row.Cell(columnDepthStart).Value;
|
||||
var vDepthEnd = row.Cell(columnDepthEnd).Value;
|
||||
var vDate = row.Cell(columnDate).Value;
|
||||
var vDuration = row.Cell(columnDuration).Value;
|
||||
var vComment = row.Cell(columnComment).Value;
|
||||
|
||||
var operation = new WellOperationDto{IdType = idType};
|
||||
|
||||
if (vSection is string sectionName)
|
||||
{
|
||||
var section = Sections.Find(c => c.Caption.ToLower() == sectionName.ToLower());
|
||||
if (section is null)
|
||||
throw new FileFormatException($"Лист {row.Worksheet.Name}. Строка {row.RowNumber()} указана некорректная секция");
|
||||
|
||||
operation.IdWellSectionType = section.Id;
|
||||
operation.WellSectionTypeName = section.Caption;
|
||||
}
|
||||
else
|
||||
throw new FileFormatException($"Лист {row.Worksheet.Name}. Строка {row.RowNumber()} не указана секция");
|
||||
|
||||
if (vCategory is string categoryName)
|
||||
{
|
||||
var category = Categories.Find(c => c.Name.ToLower() == categoryName.ToLower());
|
||||
if(category is null)
|
||||
throw new FileFormatException($"Лист {row.Worksheet.Name}. Строка {row.RowNumber()} указана некорректная операция");
|
||||
|
||||
operation.IdCategory = category.Id;
|
||||
operation.CategoryName = category.Name;
|
||||
}
|
||||
else
|
||||
throw new FileFormatException($"Лист {row.Worksheet.Name}. Строка {row.RowNumber()} не указана операция");
|
||||
|
||||
if (vCategoryInfo is not null)
|
||||
operation.CategoryInfo = vCategoryInfo.ToString();
|
||||
|
||||
if (vDepthStart is double depthStart && depthStart >= 0d && depthStart <= 20_000d)
|
||||
operation.DepthStart = depthStart;
|
||||
else
|
||||
throw new FileFormatException($"Лист {row.Worksheet.Name}. Строка {row.RowNumber()} не указана глубина на начало операции");
|
||||
|
||||
if (vDepthEnd is double depthEnd && depthEnd >= 0d && depthEnd <= 20_000d)
|
||||
operation.DepthEnd = depthEnd;
|
||||
else
|
||||
throw new FileFormatException($"Лист {row.Worksheet.Name}. Строка {row.RowNumber()} не указана глубина при завершении операции");
|
||||
|
||||
if (vDate is DateTime date && date > dateLimitMin && date < dateLimitMax)
|
||||
operation.DateStart = date;
|
||||
else
|
||||
throw new FileFormatException($"Лист {row.Worksheet.Name}. Строка {row.RowNumber()} неправильно указана дата/время начала операции");
|
||||
|
||||
if (vDuration is double duration && duration >= 0d && duration <= 240d)
|
||||
operation.DurationHours = duration;
|
||||
else
|
||||
throw new FileFormatException($"Лист {row.Worksheet.Name}. Строка {row.RowNumber()} не указана длительность операции");
|
||||
|
||||
if (vComment is not null)
|
||||
operation.Comment = vComment.ToString();
|
||||
|
||||
return operation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,23 +1,23 @@
|
||||
{
|
||||
"files": {
|
||||
"main.css": "/static/css/main.01936687.chunk.css",
|
||||
"main.js": "/static/js/main.d2dfd398.chunk.js",
|
||||
"main.js.map": "/static/js/main.d2dfd398.chunk.js.map",
|
||||
"runtime-main.js": "/static/js/runtime-main.7bbed929.js",
|
||||
"runtime-main.js.map": "/static/js/runtime-main.7bbed929.js.map",
|
||||
"static/js/2.766da71c.chunk.js": "/static/js/2.766da71c.chunk.js",
|
||||
"static/js/2.766da71c.chunk.js.map": "/static/js/2.766da71c.chunk.js.map",
|
||||
"static/js/3.58b81d69.chunk.js": "/static/js/3.58b81d69.chunk.js",
|
||||
"static/js/3.58b81d69.chunk.js.map": "/static/js/3.58b81d69.chunk.js.map",
|
||||
"main.css": "/static/css/main.1a531ce4.chunk.css",
|
||||
"main.js": "/static/js/main.d3cf7fb0.chunk.js",
|
||||
"main.js.map": "/static/js/main.d3cf7fb0.chunk.js.map",
|
||||
"runtime-main.js": "/static/js/runtime-main.b402d8a8.js",
|
||||
"runtime-main.js.map": "/static/js/runtime-main.b402d8a8.js.map",
|
||||
"static/js/2.f3289dc7.chunk.js": "/static/js/2.f3289dc7.chunk.js",
|
||||
"static/js/2.f3289dc7.chunk.js.map": "/static/js/2.f3289dc7.chunk.js.map",
|
||||
"static/js/3.a064d157.chunk.js": "/static/js/3.a064d157.chunk.js",
|
||||
"static/js/3.a064d157.chunk.js.map": "/static/js/3.a064d157.chunk.js.map",
|
||||
"index.html": "/index.html",
|
||||
"static/css/main.01936687.chunk.css.map": "/static/css/main.01936687.chunk.css.map",
|
||||
"static/js/2.766da71c.chunk.js.LICENSE.txt": "/static/js/2.766da71c.chunk.js.LICENSE.txt",
|
||||
"static/css/main.1a531ce4.chunk.css.map": "/static/css/main.1a531ce4.chunk.css.map",
|
||||
"static/js/2.f3289dc7.chunk.js.LICENSE.txt": "/static/js/2.f3289dc7.chunk.js.LICENSE.txt",
|
||||
"static/media/pointer.e8df778c.svg": "/static/media/pointer.e8df778c.svg"
|
||||
},
|
||||
"entrypoints": [
|
||||
"static/js/runtime-main.7bbed929.js",
|
||||
"static/js/2.766da71c.chunk.js",
|
||||
"static/css/main.01936687.chunk.css",
|
||||
"static/js/main.d2dfd398.chunk.js"
|
||||
"static/js/runtime-main.b402d8a8.js",
|
||||
"static/js/2.f3289dc7.chunk.js",
|
||||
"static/css/main.1a531ce4.chunk.css",
|
||||
"static/js/main.d3cf7fb0.chunk.js"
|
||||
]
|
||||
}
|
@ -1 +1 @@
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Web site created using create-react-app"/><link rel="manifest" href="/manifest.json"/><title>АСБ Vision</title><link href="/static/css/main.01936687.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(e){function r(r){for(var n,a,i=r[0],c=r[1],l=r[2],s=0,p=[];s<i.length;s++)a=i[s],Object.prototype.hasOwnProperty.call(o,a)&&o[a]&&p.push(o[a][0]),o[a]=0;for(n in c)Object.prototype.hasOwnProperty.call(c,n)&&(e[n]=c[n]);for(f&&f(r);p.length;)p.shift()();return u.push.apply(u,l||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,i=1;i<t.length;i++){var c=t[i];0!==o[c]&&(n=!1)}n&&(u.splice(r--,1),e=a(a.s=t[0]))}return e}var n={},o={1:0},u=[];function a(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,a),t.l=!0,t.exports}a.e=function(e){var r=[],t=o[e];if(0!==t)if(t)r.push(t[2]);else{var n=new Promise((function(r,n){t=o[e]=[r,n]}));r.push(t[2]=n);var u,i=document.createElement("script");i.charset="utf-8",i.timeout=120,a.nc&&i.setAttribute("nonce",a.nc),i.src=function(e){return a.p+"static/js/"+({}[e]||e)+"."+{3:"58b81d69"}[e]+".chunk.js"}(e);var c=new Error;u=function(r){i.onerror=i.onload=null,clearTimeout(l);var t=o[e];if(0!==t){if(t){var n=r&&("load"===r.type?"missing":r.type),u=r&&r.target&&r.target.src;c.message="Loading chunk "+e+" failed.\n("+n+": "+u+")",c.name="ChunkLoadError",c.type=n,c.request=u,t[1](c)}o[e]=void 0}};var l=setTimeout((function(){u({type:"timeout",target:i})}),12e4);i.onerror=i.onload=u,document.head.appendChild(i)}return Promise.all(r)},a.m=e,a.c=n,a.d=function(e,r,t){a.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},a.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},a.t=function(e,r){if(1&r&&(e=a(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(a.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)a.d(t,n,function(r){return e[r]}.bind(null,n));return t},a.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return a.d(r,"a",r),r},a.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},a.p="/",a.oe=function(e){throw console.error(e),e};var i=this.webpackJsonpasb_cloud_front_react=this.webpackJsonpasb_cloud_front_react||[],c=i.push.bind(i);i.push=r,i=i.slice();for(var l=0;l<i.length;l++)r(i[l]);var f=c;t()}([])</script><script src="/static/js/2.766da71c.chunk.js"></script><script src="/static/js/main.d2dfd398.chunk.js"></script></body></html>
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Web site created using create-react-app"/><link rel="manifest" href="/manifest.json"/><title>АСБ Vision</title><link href="/static/css/main.1a531ce4.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(e){function r(r){for(var n,a,i=r[0],c=r[1],l=r[2],s=0,p=[];s<i.length;s++)a=i[s],Object.prototype.hasOwnProperty.call(o,a)&&o[a]&&p.push(o[a][0]),o[a]=0;for(n in c)Object.prototype.hasOwnProperty.call(c,n)&&(e[n]=c[n]);for(f&&f(r);p.length;)p.shift()();return u.push.apply(u,l||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,i=1;i<t.length;i++){var c=t[i];0!==o[c]&&(n=!1)}n&&(u.splice(r--,1),e=a(a.s=t[0]))}return e}var n={},o={1:0},u=[];function a(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,a),t.l=!0,t.exports}a.e=function(e){var r=[],t=o[e];if(0!==t)if(t)r.push(t[2]);else{var n=new Promise((function(r,n){t=o[e]=[r,n]}));r.push(t[2]=n);var u,i=document.createElement("script");i.charset="utf-8",i.timeout=120,a.nc&&i.setAttribute("nonce",a.nc),i.src=function(e){return a.p+"static/js/"+({}[e]||e)+"."+{3:"a064d157"}[e]+".chunk.js"}(e);var c=new Error;u=function(r){i.onerror=i.onload=null,clearTimeout(l);var t=o[e];if(0!==t){if(t){var n=r&&("load"===r.type?"missing":r.type),u=r&&r.target&&r.target.src;c.message="Loading chunk "+e+" failed.\n("+n+": "+u+")",c.name="ChunkLoadError",c.type=n,c.request=u,t[1](c)}o[e]=void 0}};var l=setTimeout((function(){u({type:"timeout",target:i})}),12e4);i.onerror=i.onload=u,document.head.appendChild(i)}return Promise.all(r)},a.m=e,a.c=n,a.d=function(e,r,t){a.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},a.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},a.t=function(e,r){if(1&r&&(e=a(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(a.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)a.d(t,n,function(r){return e[r]}.bind(null,n));return t},a.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return a.d(r,"a",r),r},a.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},a.p="/",a.oe=function(e){throw console.error(e),e};var i=this.webpackJsonpasb_cloud_front_react=this.webpackJsonpasb_cloud_front_react||[],c=i.push.bind(i);i.push=r,i=i.slice();for(var l=0;l<i.length;l++)r(i[l]);var f=c;t()}([])</script><script src="/static/js/2.f3289dc7.chunk.js"></script><script src="/static/js/main.d3cf7fb0.chunk.js"></script></body></html>
|
@ -12,17 +12,15 @@ namespace ConsoleApp1
|
||||
{
|
||||
public static class DebugWellOperationImportService
|
||||
{
|
||||
private static DbContextOptions<AsbCloudDbContext> options = new DbContextOptionsBuilder<AsbCloudDbContext>()
|
||||
.UseNpgsql("Host=localhost;Database=postgres;Username=postgres;Password=q;Persist Security Info=True")
|
||||
.Options;
|
||||
|
||||
public static void Main(/*string[] args*/)
|
||||
{
|
||||
var options = new DbContextOptionsBuilder<AsbCloudDbContext>()
|
||||
.UseNpgsql("Host=localhost;Database=postgres;Username=postgres;Password=q;Persist Security Info=True")
|
||||
.Options;
|
||||
using var db = new AsbCloudDbContext(options);
|
||||
|
||||
var cacheDb = new CacheDb();
|
||||
var wellService = new WellService(db, new TelemetryTracker(), cacheDb);
|
||||
|
||||
var wellOperationImportService = new WellOperationImportService();
|
||||
var wellOperationImportService = new WellOperationImportService(db);
|
||||
|
||||
var ops = wellOperationImportService.ParseFile(@"C:\temp\Миграция.xlsx");
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
{
|
||||
static void Main(/*string[] args*/)
|
||||
{
|
||||
ActionWellOperationsRefactor.Main();
|
||||
DebugWellOperationImportService.Main();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user