|
|
|
@@ -0,0 +1,275 @@
|
|
|
|
|
using Fuchs.intranet;
|
|
|
|
|
using Microsoft.AspNetCore.SignalR;
|
|
|
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
|
using static OCORE.OCORE_dictionaries;
|
|
|
|
|
|
|
|
|
|
namespace Fuchs.Notifications;
|
|
|
|
|
|
|
|
|
|
public sealed class EventService : IEventService
|
|
|
|
|
{
|
|
|
|
|
private readonly IHubContext<NotificationHub> _hub;
|
|
|
|
|
private readonly ILogger<EventService> _logger;
|
|
|
|
|
|
|
|
|
|
public EventService(IHubContext<NotificationHub> hub, ILogger<EventService> logger)
|
|
|
|
|
{
|
|
|
|
|
_hub = hub;
|
|
|
|
|
_logger = logger;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task PublishAsync(DomainEvent domainEvent, CancellationToken cancellationToken = default)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
GuiNotification notification = BuildNotification(domainEvent);
|
|
|
|
|
await _hub.Clients
|
|
|
|
|
.All
|
|
|
|
|
.SendAsync("notification", notification, cancellationToken);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
_logger.LogWarning(ex, "Notification publish failed for {EventType}", domainEvent.Type);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Task InvoiceDraftRegisteredAsync(FdsInvoiceData invoice, bool changed, string userAccountId)
|
|
|
|
|
{
|
|
|
|
|
var type = changed ? DomainEventType.InvoiceDraftUpdated : DomainEventType.InvoiceDraftCreated;
|
|
|
|
|
return PublishAsync(new DomainEvent(type, userAccountId, "Rechnungsentwurf", InvoiceContext(invoice)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Task InvoiceFileCreatedAsync(FdsInvoiceData invoice, string fileName, string userAccountId)
|
|
|
|
|
{
|
|
|
|
|
var ctx = InvoiceContext(invoice);
|
|
|
|
|
ctx["fileName"] = fileName;
|
|
|
|
|
return PublishAsync(new DomainEvent(DomainEventType.InvoiceFileCreated, userAccountId, "Rechnungsdatei", ctx));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Task InvoiceSentToCustomerAsync(FdsInvoiceData invoice, string email, string userAccountId, bool resent = false)
|
|
|
|
|
{
|
|
|
|
|
var ctx = InvoiceContext(invoice);
|
|
|
|
|
ctx["email"] = email;
|
|
|
|
|
return PublishAsync(new DomainEvent(
|
|
|
|
|
resent ? DomainEventType.InvoiceResentToCustomer : DomainEventType.InvoiceSentToCustomer,
|
|
|
|
|
userAccountId,
|
|
|
|
|
"Rechnung versandt",
|
|
|
|
|
ctx));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Task InvoiceMarkedSentAsync(string invoiceId, string invoiceNumber, string userAccountId)
|
|
|
|
|
{
|
|
|
|
|
Dictionary<string, object?> ctx = new()
|
|
|
|
|
{
|
|
|
|
|
["id"] = invoiceId,
|
|
|
|
|
["invoiceNumber"] = string.IsNullOrWhiteSpace(invoiceNumber) ? invoiceId : invoiceNumber
|
|
|
|
|
};
|
|
|
|
|
return PublishAsync(new DomainEvent(DomainEventType.InvoiceMarkedSent, userAccountId, "Rechnung markiert", ctx));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Task InvoiceIssueAsync(string message, string userAccountId, string invoiceId = "")
|
|
|
|
|
=> PublishAsync(new DomainEvent(
|
|
|
|
|
DomainEventType.InvoiceCreationFailed,
|
|
|
|
|
userAccountId,
|
|
|
|
|
"Rechnung",
|
|
|
|
|
new Dictionary<string, object?> { ["id"] = invoiceId, ["message"] = message }));
|
|
|
|
|
|
|
|
|
|
public Task ReminderDraftCreatedAsync(FdsReminderData reminder, string userAccountId)
|
|
|
|
|
=> PublishAsync(new DomainEvent(DomainEventType.ReminderDraftCreated, userAccountId, "Mahnentwurf", ReminderContext(reminder)));
|
|
|
|
|
|
|
|
|
|
public Task ReminderFileCreatedAsync(FdsReminderData reminder, string fileName, string userAccountId)
|
|
|
|
|
{
|
|
|
|
|
var ctx = ReminderContext(reminder);
|
|
|
|
|
ctx["fileName"] = fileName;
|
|
|
|
|
return PublishAsync(new DomainEvent(DomainEventType.ReminderFileCreated, userAccountId, "Mahndatei", ctx));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Task ReminderSentToCustomerAsync(FdsReminderData reminder, string email, string userAccountId, bool resent = false)
|
|
|
|
|
{
|
|
|
|
|
var ctx = ReminderContext(reminder);
|
|
|
|
|
ctx["email"] = email;
|
|
|
|
|
return PublishAsync(new DomainEvent(
|
|
|
|
|
resent ? DomainEventType.ReminderResentToCustomer : DomainEventType.ReminderSentToCustomer,
|
|
|
|
|
userAccountId,
|
|
|
|
|
"Mahnung versandt",
|
|
|
|
|
ctx));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Task ReminderMarkedSentAsync(string reminderId, string reminderTitle, string userAccountId)
|
|
|
|
|
{
|
|
|
|
|
Dictionary<string, object?> ctx = new()
|
|
|
|
|
{
|
|
|
|
|
["id"] = reminderId,
|
|
|
|
|
["title"] = string.IsNullOrWhiteSpace(reminderTitle) ? reminderId : reminderTitle
|
|
|
|
|
};
|
|
|
|
|
return PublishAsync(new DomainEvent(DomainEventType.ReminderMarkedSent, userAccountId, "Mahnung markiert", ctx));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Task ReminderIssueAsync(string message, string userAccountId, string reminderId = "")
|
|
|
|
|
=> PublishAsync(new DomainEvent(
|
|
|
|
|
DomainEventType.ReminderCreationFailed,
|
|
|
|
|
userAccountId,
|
|
|
|
|
"Mahnung",
|
|
|
|
|
new Dictionary<string, object?> { ["id"] = reminderId, ["message"] = message }));
|
|
|
|
|
|
|
|
|
|
public Task BankingTransactionsImportedAsync(DateTime? from, DateTime? to, int rows, string fileName, string userAccountId)
|
|
|
|
|
=> PublishAsync(new DomainEvent(
|
|
|
|
|
DomainEventType.BankingTransactionsImported,
|
|
|
|
|
userAccountId,
|
|
|
|
|
"Banking",
|
|
|
|
|
new Dictionary<string, object?>
|
|
|
|
|
{
|
|
|
|
|
["from"] = from,
|
|
|
|
|
["to"] = to,
|
|
|
|
|
["rows"] = rows,
|
|
|
|
|
["fileName"] = fileName
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
public Task BankingImportIssueAsync(string message, string fileName, string userAccountId)
|
|
|
|
|
=> PublishAsync(new DomainEvent(
|
|
|
|
|
DomainEventType.BankingImportFailed,
|
|
|
|
|
userAccountId,
|
|
|
|
|
"Banking",
|
|
|
|
|
new Dictionary<string, object?> { ["fileName"] = fileName, ["message"] = message }));
|
|
|
|
|
|
|
|
|
|
public Task UserIssueAsync(string title, string message, string userAccountId, IReadOnlyDictionary<string, object?>? context = null)
|
|
|
|
|
{
|
|
|
|
|
Dictionary<string, object?> ctx = context == null
|
|
|
|
|
? new Dictionary<string, object?>()
|
|
|
|
|
: new Dictionary<string, object?>(context);
|
|
|
|
|
ctx["message"] = message;
|
|
|
|
|
return PublishAsync(new DomainEvent(DomainEventType.UserIssue, userAccountId, title, ctx));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static GuiNotification BuildNotification(DomainEvent domainEvent)
|
|
|
|
|
{
|
|
|
|
|
string message = domainEvent.Type switch
|
|
|
|
|
{
|
|
|
|
|
DomainEventType.InvoiceDraftCreated =>
|
|
|
|
|
$"Rechnungsentwurf {Ctx(domainEvent, "invoiceNumber")} wurde erstellt.",
|
|
|
|
|
DomainEventType.InvoiceDraftUpdated =>
|
|
|
|
|
$"Rechnungsentwurf {Ctx(domainEvent, "invoiceNumber")} wurde aktualisiert.",
|
|
|
|
|
DomainEventType.InvoiceFileCreated =>
|
|
|
|
|
$"Rechnungsdatei {Ctx(domainEvent, "fileName")} wurde erstellt.",
|
|
|
|
|
DomainEventType.InvoiceSentToCustomer =>
|
|
|
|
|
$"Rechnung {Ctx(domainEvent, "invoiceNumber")} wurde an den Kunden mit der E-Mail {Ctx(domainEvent, "email")} versandt.",
|
|
|
|
|
DomainEventType.InvoiceResentToCustomer =>
|
|
|
|
|
$"Rechnung {Ctx(domainEvent, "invoiceNumber")} wurde erneut an {Ctx(domainEvent, "email")} versandt.",
|
|
|
|
|
DomainEventType.InvoiceMarkedSent =>
|
|
|
|
|
$"Rechnung {Ctx(domainEvent, "invoiceNumber")} wurde als versandt markiert.",
|
|
|
|
|
DomainEventType.InvoiceCreationFailed =>
|
|
|
|
|
Ctx(domainEvent, "message"),
|
|
|
|
|
DomainEventType.InvoiceFileCreationFailed =>
|
|
|
|
|
Ctx(domainEvent, "message"),
|
|
|
|
|
DomainEventType.InvoiceSendFailed =>
|
|
|
|
|
Ctx(domainEvent, "message"),
|
|
|
|
|
DomainEventType.ReminderDraftCreated =>
|
|
|
|
|
$"Mahnentwurf {Ctx(domainEvent, "title")} wurde erstellt.",
|
|
|
|
|
DomainEventType.ReminderFileCreated =>
|
|
|
|
|
$"Mahndatei {Ctx(domainEvent, "fileName")} wurde erstellt.",
|
|
|
|
|
DomainEventType.ReminderSentToCustomer =>
|
|
|
|
|
$"Mahnung {Ctx(domainEvent, "title")} wurde an den Kunden mit der E-Mail {Ctx(domainEvent, "email")} versandt.",
|
|
|
|
|
DomainEventType.ReminderResentToCustomer =>
|
|
|
|
|
$"Mahnung {Ctx(domainEvent, "title")} wurde erneut an {Ctx(domainEvent, "email")} versandt.",
|
|
|
|
|
DomainEventType.ReminderMarkedSent =>
|
|
|
|
|
$"Mahnung {Ctx(domainEvent, "title")} wurde als versandt markiert.",
|
|
|
|
|
DomainEventType.ReminderCreationFailed =>
|
|
|
|
|
Ctx(domainEvent, "message"),
|
|
|
|
|
DomainEventType.ReminderFileCreationFailed =>
|
|
|
|
|
Ctx(domainEvent, "message"),
|
|
|
|
|
DomainEventType.ReminderSendFailed =>
|
|
|
|
|
Ctx(domainEvent, "message"),
|
|
|
|
|
DomainEventType.BankingTransactionsImported =>
|
|
|
|
|
BankingImportMessage(domainEvent),
|
|
|
|
|
DomainEventType.BankingImportFailed =>
|
|
|
|
|
Ctx(domainEvent, "message"),
|
|
|
|
|
DomainEventType.UserIssue =>
|
|
|
|
|
Ctx(domainEvent, "message"),
|
|
|
|
|
_ => domainEvent.Title
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return new GuiNotification(
|
|
|
|
|
Guid.NewGuid().ToString("N"),
|
|
|
|
|
domainEvent.Type.ToString(),
|
|
|
|
|
domainEvent.Title,
|
|
|
|
|
message,
|
|
|
|
|
IsFailure(domainEvent.Type) ? "error" : "info",
|
|
|
|
|
domainEvent.CreatedAt,
|
|
|
|
|
domainEvent.Context);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static bool IsFailure(DomainEventType type) =>
|
|
|
|
|
type is DomainEventType.InvoiceCreationFailed
|
|
|
|
|
or DomainEventType.InvoiceFileCreationFailed
|
|
|
|
|
or DomainEventType.InvoiceSendFailed
|
|
|
|
|
or DomainEventType.ReminderCreationFailed
|
|
|
|
|
or DomainEventType.ReminderFileCreationFailed
|
|
|
|
|
or DomainEventType.ReminderSendFailed
|
|
|
|
|
or DomainEventType.BankingImportFailed
|
|
|
|
|
or DomainEventType.UserIssue;
|
|
|
|
|
|
|
|
|
|
private static string BankingImportMessage(DomainEvent domainEvent)
|
|
|
|
|
{
|
|
|
|
|
int rows = int.TryParse(Ctx(domainEvent, "rows"), out int r) ? r : 0;
|
|
|
|
|
string movement = rows == 1 ? "Kontobewegung" : "Kontobewegungen";
|
|
|
|
|
string period = BankingPeriod(domainEvent);
|
|
|
|
|
return string.IsNullOrEmpty(period)
|
|
|
|
|
? $"{rows} {movement} wurden importiert."
|
|
|
|
|
: $"{movement} für {period} wurden importiert.";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static string BankingPeriod(DomainEvent domainEvent)
|
|
|
|
|
{
|
|
|
|
|
DateTime? from = DateCtx(domainEvent, "from");
|
|
|
|
|
DateTime? to = DateCtx(domainEvent, "to");
|
|
|
|
|
if (from == null && to == null) return "";
|
|
|
|
|
if (from != null && to != null)
|
|
|
|
|
{
|
|
|
|
|
string fromFmt = from.Value.Year == to.Value.Year
|
|
|
|
|
? from.Value.ToString("d.M.")
|
|
|
|
|
: from.Value.ToString("d.M.yyyy");
|
|
|
|
|
string toFmt = from.Value.Year == to.Value.Year
|
|
|
|
|
? to.Value.ToString("dd.MM.")
|
|
|
|
|
: to.Value.ToString("dd.MM.yyyy");
|
|
|
|
|
return $"{fromFmt} - {toFmt}";
|
|
|
|
|
}
|
|
|
|
|
return (from ?? to)!.Value.ToString("dd.MM.yyyy");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static DateTime? DateCtx(DomainEvent domainEvent, string key)
|
|
|
|
|
{
|
|
|
|
|
if (!domainEvent.Context.TryGetValue(key, out var value) || value == null) return null;
|
|
|
|
|
if (value is DateTime dt) return dt;
|
|
|
|
|
if (value is DateTimeOffset dto) return dto.DateTime;
|
|
|
|
|
return DateTime.TryParse(value.ToString(), out var parsed) ? parsed : null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static Dictionary<string, object?> InvoiceContext(FdsInvoiceData invoice)
|
|
|
|
|
{
|
|
|
|
|
string invoiceNumber = invoice.InvoiceId;
|
|
|
|
|
return new Dictionary<string, object?>
|
|
|
|
|
{
|
|
|
|
|
["id"] = invoice.Id,
|
|
|
|
|
["invoiceNumber"] = string.IsNullOrWhiteSpace(invoiceNumber) ? invoice.Id : invoiceNumber,
|
|
|
|
|
["documentName"] = invoice.InvoiceRegistration?.getString("DocumentName") ?? "",
|
|
|
|
|
["email"] = invoice.InvoiceRegistration?.getString("SendToEmail") ?? "",
|
|
|
|
|
["title"] = invoice.InvoiceTitle
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static Dictionary<string, object?> ReminderContext(FdsReminderData reminder)
|
|
|
|
|
{
|
|
|
|
|
return new Dictionary<string, object?>
|
|
|
|
|
{
|
|
|
|
|
["id"] = reminder.Id,
|
|
|
|
|
["invoiceNumber"] = reminder.InvoiceId,
|
|
|
|
|
["title"] = string.IsNullOrWhiteSpace(reminder.ReminderTitle) ? reminder.Id : reminder.ReminderTitle,
|
|
|
|
|
["documentName"] = reminder.ReminderRegistration?.getString("DocumentName") ?? "",
|
|
|
|
|
["email"] = reminder.InvoiceEmail
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static string Ctx(DomainEvent domainEvent, string key)
|
|
|
|
|
{
|
|
|
|
|
if (!domainEvent.Context.TryGetValue(key, out var value)) return "";
|
|
|
|
|
return value?.ToString() ?? "";
|
|
|
|
|
}
|
|
|
|
|
}
|