feat: implement set-based invoice payment calculations and enhance email logging configuration
Playwright Tests / test (push) Canceled after 0s

This commit is contained in:
Stefan
2026-09-16 22:31:27 +02:00
parent 944a5bb442
commit 86f6a60860
8 changed files with 268 additions and 12 deletions
+30 -4
View File
@@ -74,8 +74,8 @@ public class ProcessWebComService : IComService
FuchsTelemetry.EmailsFailed.Add(1, new KeyValuePair<string, object?>("reason", "invalid-email"));
act?.SetStatus(ActivityStatusCode.Error, "invalid-email");
// Every attempt is audit-logged, including this early rejection (previously it returned unlogged).
await WriteAuditLogAsync(reference, "", "", default, false,
[$"Invalid recipient email address: '{email}'"]);
await WriteAuditLogAsync(reference, "", BuildAuditConfig(subject, email, name, cc, attachments?.Keys),
default, false, [$"Invalid recipient email address: '{email}'"]);
return false;
}
@@ -86,7 +86,8 @@ public class ProcessWebComService : IComService
_logger.LogInformation(
"[ComService DISABLED] Would send email ref={Reference} subject='{Subject}' to={Email}",
reference, subject, email);
await WriteAuditLogAsync(reference, "", "", default, false, ["Service disabled – email not sent"]);
await WriteAuditLogAsync(reference, "", BuildAuditConfig(subject, email, name, cc, attachments?.Keys),
default, false, ["Service disabled – email not sent"]);
FuchsTelemetry.EmailsFailed.Add(1, new KeyValuePair<string, object?>("reason", "disabled"));
return false;
}
@@ -153,7 +154,8 @@ public class ProcessWebComService : IComService
_logger.LogInformation("SendEmailAsync ref={Reference} success={Success} in {Ms} ms",
reference, success, sw.ElapsedMilliseconds);
await WriteAuditLogAsync(reference, messageId, "", success ? DateTime.UtcNow : default, success, errors);
await WriteAuditLogAsync(reference, messageId, BuildAuditConfig(subject, email, name, cc, attachments?.Keys),
success ? DateTime.UtcNow : default, success, errors);
return success;
}
@@ -308,6 +310,30 @@ public class ProcessWebComService : IComService
}
}
/// <summary>
/// Serialises the audit <c>config</c> stored in <c>fds__emaillog.config</c>: who the mail went
/// to, its subject and the attachment <em>names</em> — never the body or attachment bytes.
/// The shape (<c>subject</c>/<c>from</c>/<c>to[]</c>/<c>cc[]</c>/<c>bcc[]</c>/<c>attachments[]</c>,
/// addresses as <c>"Name" &lt;email&gt;</c>) is the one the legacy mailer wrote and that
/// <c>[dbo].[fds_wgd_lastEmails]</c> reads back with <c>OPENJSON</c>; an empty string here
/// made that dashboard widget fail for every row the new service logged.
/// Pure so the contract can be unit-tested without a database.
/// </summary>
internal static string BuildAuditConfig(string subject, string email, string? name, string? cc,
IEnumerable<string>? attachmentNames) =>
JsonConvert.SerializeObject(new
{
subject = subject ?? "",
from = "",
to = new[] { FormatAddress(email, name) },
cc = string.IsNullOrWhiteSpace(cc) ? Array.Empty<string>() : new[] { cc.Trim() },
bcc = Array.Empty<string>(),
attachments = (attachmentNames ?? []).ToArray()
});
private static string FormatAddress(string email, string? name) =>
string.IsNullOrWhiteSpace(name) ? (email ?? "") : $"\"{name.Trim()}\" <{email}>";
/// <summary>
/// Builds the parameter list for <c>[dbo].[fds__logEmail]</c>. <c>fds__emaillog</c> declares
/// <c>config</c> and <c>DateSent</c> as NOT NULL, so neither may be sent as NULL: