efcf7b180c
Fixes 'error while parsing protocol' HanaException by supporting SSL/TLS encryption, Multi-Tenant Database Container (MDC) database name, and arbitrary additional connection parameters. - HanaServer model: added DatabaseName, UseSsl, ValidateCertificate, AdditionalParams fields + BuildConnectionString() helper - HanaQueryService: accepts HanaServer directly, uses BuildConnectionString() for full parameter support - AppDbContext: added EnsureSchema() method that uses PRAGMA table_info + ALTER TABLE ADD COLUMN to add the new fields to existing SQLite databases without losing data (EnsureCreated does not update schema) - Program.cs: calls EnsureSchema on startup before seeding - Standorte.razor: server dialog now exposes DatabaseName, UseSsl, ValidateCertificate, AdditionalParams with helper texts; test connection uses new signature https://claude.ai/code/session_012heAXNMbbyxqYf2S2HrKLj
162 lines
5.1 KiB
C#
162 lines
5.1 KiB
C#
using Microsoft.EntityFrameworkCore;
|
|
using System.Diagnostics;
|
|
using TrafagSalesExporter.Data;
|
|
using TrafagSalesExporter.Models;
|
|
|
|
namespace TrafagSalesExporter.Services;
|
|
|
|
public class ExportOrchestrationService
|
|
{
|
|
private readonly IDbContextFactory<AppDbContext> _dbFactory;
|
|
private readonly HanaQueryService _hanaService;
|
|
private readonly ExcelExportService _excelService;
|
|
private readonly SharePointUploadService _sharePointService;
|
|
private readonly ILogger<ExportOrchestrationService> _logger;
|
|
|
|
public event Action? OnExportStatusChanged;
|
|
|
|
private readonly Dictionary<int, string> _runningExports = new();
|
|
private readonly object _lock = new();
|
|
|
|
public ExportOrchestrationService(
|
|
IDbContextFactory<AppDbContext> dbFactory,
|
|
HanaQueryService hanaService,
|
|
ExcelExportService excelService,
|
|
SharePointUploadService sharePointService,
|
|
ILogger<ExportOrchestrationService> logger)
|
|
{
|
|
_dbFactory = dbFactory;
|
|
_hanaService = hanaService;
|
|
_excelService = excelService;
|
|
_sharePointService = sharePointService;
|
|
_logger = logger;
|
|
}
|
|
|
|
public bool IsExporting(int siteId)
|
|
{
|
|
lock (_lock)
|
|
{
|
|
return _runningExports.ContainsKey(siteId);
|
|
}
|
|
}
|
|
|
|
public string GetExportStatus(int siteId)
|
|
{
|
|
lock (_lock)
|
|
{
|
|
return _runningExports.TryGetValue(siteId, out var status) ? status : string.Empty;
|
|
}
|
|
}
|
|
|
|
public async Task ExportAllAsync()
|
|
{
|
|
using var db = await _dbFactory.CreateDbContextAsync();
|
|
var sites = await db.Sites.Include(s => s.HanaServer).Where(s => s.IsActive).ToListAsync();
|
|
foreach (var site in sites)
|
|
{
|
|
await ExportSiteAsync(site);
|
|
}
|
|
}
|
|
|
|
public async Task ExportSiteByIdAsync(int siteId)
|
|
{
|
|
using var db = await _dbFactory.CreateDbContextAsync();
|
|
var site = await db.Sites.Include(s => s.HanaServer).FirstOrDefaultAsync(s => s.Id == siteId);
|
|
if (site is null) return;
|
|
await ExportSiteAsync(site);
|
|
}
|
|
|
|
private async Task ExportSiteAsync(Site site)
|
|
{
|
|
if (site.HanaServer is null) return;
|
|
|
|
lock (_lock)
|
|
{
|
|
if (_runningExports.ContainsKey(site.Id)) return;
|
|
_runningExports[site.Id] = "HANA Abfrage...";
|
|
}
|
|
NotifyChanged();
|
|
|
|
var sw = Stopwatch.StartNew();
|
|
var log = new ExportLog
|
|
{
|
|
Timestamp = DateTime.Now,
|
|
SiteId = site.Id,
|
|
Land = site.Land,
|
|
TSC = site.TSC
|
|
};
|
|
|
|
try
|
|
{
|
|
using var db = await _dbFactory.CreateDbContextAsync();
|
|
var settings = await db.ExportSettings.FirstOrDefaultAsync() ?? new ExportSettings();
|
|
var spConfig = await db.SharePointConfigs.FirstOrDefaultAsync();
|
|
|
|
UpdateStatus(site.Id, "HANA Abfrage...");
|
|
var records = await Task.Run(() => _hanaService.GetSalesRecords(
|
|
site.HanaServer, site.Schema, site.TSC, site.Land, settings.DateFilter));
|
|
|
|
UpdateStatus(site.Id, "Excel erstellen...");
|
|
var outputDir = Path.Combine(AppContext.BaseDirectory, "output");
|
|
var filePath = _excelService.CreateExcelFile(outputDir, site.TSC, DateTime.UtcNow.Date, records);
|
|
var fileName = Path.GetFileName(filePath);
|
|
|
|
if (spConfig is not null &&
|
|
!string.IsNullOrWhiteSpace(spConfig.TenantId) &&
|
|
!string.IsNullOrWhiteSpace(spConfig.ClientId) &&
|
|
!string.IsNullOrWhiteSpace(spConfig.ClientSecret))
|
|
{
|
|
UpdateStatus(site.Id, "SharePoint Upload...");
|
|
await _sharePointService.UploadAsync(
|
|
spConfig.TenantId, spConfig.ClientId, spConfig.ClientSecret,
|
|
spConfig.SiteUrl, spConfig.ExportFolder, site.Land, filePath);
|
|
}
|
|
|
|
sw.Stop();
|
|
log.Status = "OK";
|
|
log.RowCount = records.Count;
|
|
log.FileName = fileName;
|
|
log.DurationSeconds = sw.Elapsed.TotalSeconds;
|
|
|
|
_logger.LogInformation("Export OK: {Land} ({TSC}) - {Rows} Zeilen in {Duration:F1}s",
|
|
site.Land, site.TSC, records.Count, sw.Elapsed.TotalSeconds);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
sw.Stop();
|
|
log.Status = "Error";
|
|
log.ErrorMessage = ex.Message;
|
|
log.FileName = string.Empty;
|
|
log.DurationSeconds = sw.Elapsed.TotalSeconds;
|
|
|
|
_logger.LogError(ex, "Export Fehler: {Land} ({TSC})", site.Land, site.TSC);
|
|
}
|
|
finally
|
|
{
|
|
using var db = await _dbFactory.CreateDbContextAsync();
|
|
db.ExportLogs.Add(log);
|
|
await db.SaveChangesAsync();
|
|
|
|
lock (_lock)
|
|
{
|
|
_runningExports.Remove(site.Id);
|
|
}
|
|
NotifyChanged();
|
|
}
|
|
}
|
|
|
|
private void UpdateStatus(int siteId, string status)
|
|
{
|
|
lock (_lock)
|
|
{
|
|
_runningExports[siteId] = status;
|
|
}
|
|
NotifyChanged();
|
|
}
|
|
|
|
private void NotifyChanged()
|
|
{
|
|
OnExportStatusChanged?.Invoke();
|
|
}
|
|
}
|