Refactor code structure for improved readability and maintainability
Playwright Tests / test (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled
This commit is contained in:
@@ -240,11 +240,22 @@ public partial class IntranetController
|
||||
}
|
||||
|
||||
// ── Form helpers ─────────────────────────────────────────────────────────
|
||||
// Reads from the posted form when available, falling back to the query string. This
|
||||
// supports endpoints in _allowedGet (e.g. req/idoc, rem/idoc) that are invoked via a
|
||||
// plain GET (window.open with '?id=...'), where Request.Form has no Content-Type and
|
||||
// would otherwise throw InvalidOperationException.
|
||||
protected bool HasForm(params string[] keys) =>
|
||||
keys.All(k => Request.Form.ContainsKey(k) && !string.IsNullOrWhiteSpace(Request.Form[k]));
|
||||
keys.All(k => !string.IsNullOrWhiteSpace(FormValue(k)));
|
||||
|
||||
protected string Form(string key, string fallback = "") =>
|
||||
Request.Form.TryGetValue(key, out var v) ? v.ToString() : fallback;
|
||||
FormValue(key) ?? fallback;
|
||||
|
||||
private string? FormValue(string key) =>
|
||||
RequestValueHelper.Resolve(
|
||||
Request.HasFormContentType,
|
||||
Request.HasFormContentType ? Request.Form : Microsoft.AspNetCore.Http.FormCollection.Empty,
|
||||
Request.Query,
|
||||
key);
|
||||
|
||||
private static (DateTime? From, DateTime? To) BankingDateRange(System.Data.DataTable tbl)
|
||||
{
|
||||
|
||||
@@ -87,7 +87,13 @@ public partial class IntranetController
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "HandleInvoiceGet failed for id={InvoiceId} user={User}", Form("id"), UserAccountID);
|
||||
string invoiceId = Form("id");
|
||||
_logger.LogError(ex, "HandleInvoiceGet failed for id={InvoiceId} user={User}", invoiceId, UserAccountID);
|
||||
// This handler has its own catch (returns 500) and so never reaches the Do safety net;
|
||||
// notify the user here so a failed invoice load is not silently swallowed.
|
||||
await _events.InvoiceIssueAsync(
|
||||
"Die Rechnung konnte aufgrund eines Fehlers nicht geladen werden.",
|
||||
UserAccountID, invoiceId);
|
||||
return StatusCode(500);
|
||||
}
|
||||
}
|
||||
@@ -388,8 +394,22 @@ public partial class IntranetController
|
||||
sqldset.Tables("itm").Columns.Contains("order") ? "order" : ""))
|
||||
{
|
||||
var d = sitm.toObjectDictionary();
|
||||
double net = Convert.ToDouble(d.no("value_total", 0));
|
||||
double vat = Convert.ToDouble(d.no("vat", 0));
|
||||
double net = Convert.ToDouble(d.no("value_total", 0));
|
||||
double vat = Convert.ToDouble(d.no("vat", 0));
|
||||
double value = Convert.ToDouble(d.no("value", 0));
|
||||
string quantityStr = d.nz("Quantity");
|
||||
// quantityhours/UnitString reconstruct the hour-based quantity editor's raw
|
||||
// fields (e.g. "5 Std" -> quantityhours=5, UnitString="Std") from the persisted
|
||||
// "Quantity" string, mirroring the legacy fds__invoice_data ndic mapping — without
|
||||
// this, re-editing a reloaded hour-based item showed an empty quantity field.
|
||||
object quantityHours = "";
|
||||
if (value != 0 && !string.IsNullOrEmpty(quantityStr))
|
||||
{
|
||||
long qh = (long)(net / value);
|
||||
if (quantityStr.StartsWith(qh.ToString(CultureInfo.InvariantCulture) + " ", StringComparison.Ordinal))
|
||||
quantityHours = qh;
|
||||
}
|
||||
string unitString = !string.IsNullOrEmpty(quantityStr) ? quantityStr.RightFromFirst(" ") : "";
|
||||
itm.Add(new Dictionary<string, object?>
|
||||
{
|
||||
["Id"] = d["Id"],
|
||||
@@ -399,8 +419,11 @@ public partial class IntranetController
|
||||
["svcnet_val"] = d.no("value_service", 0),
|
||||
["net"] = d.no("value", 0),
|
||||
["quantity"] = d["Quantity"],
|
||||
["quantityhours"] = quantityHours,
|
||||
["UnitString"] = unitString,
|
||||
["Type"] = d["Type"],
|
||||
["Note"] = null,
|
||||
["NameOrNumber"] = "",
|
||||
["htmltext"] = d["Text"],
|
||||
["position"] = d["Position"],
|
||||
["SortOrder"] = d["SortOrder"]
|
||||
|
||||
@@ -22,7 +22,9 @@ public partial class IntranetController
|
||||
{
|
||||
case "get":
|
||||
{
|
||||
if (!HasForm("id")) return BadRequest400();
|
||||
if (!HasForm("id")) { _logger.LogWarning("Reminder get: missing form field 'id', user={User}", UserAccountID); return BadRequest400(); }
|
||||
_logger.LogDebug("Reminder get: preparing reminder for invoice {InvId} type={Type} level={Level} user={User}",
|
||||
Form("id"), Form("type"), Form("level"), UserAccountID);
|
||||
var pl = StdParamlist(
|
||||
SQL_VarChar("@InvId", Form("id")),
|
||||
SQL_VarChar("@type", Form("type")),
|
||||
@@ -32,17 +34,21 @@ public partial class IntranetController
|
||||
_intranet.Intranet__SQLConnectionString, pl,
|
||||
tablenames: new[] { "rem" },
|
||||
Security: DbSec, options: SqlOpt(fn, id, code));
|
||||
if (!string.IsNullOrEmpty(dset.Exception))
|
||||
_logger.LogError("Reminder get: SQL error for invoice {InvId}: {SqlError}, user={User}", Form("id"), dset.Exception, UserAccountID);
|
||||
return await JSONAsync(new { rm = dset.Table("rem").FirstRow.toObjectDictionary() });
|
||||
}
|
||||
|
||||
case "prep":
|
||||
{
|
||||
if (!HasForm("remc")) return BadRequest400();
|
||||
if (!HasForm("remc")) { _logger.LogWarning("Reminder prep: missing form field 'remc', user={User}", UserAccountID); return BadRequest400(); }
|
||||
_logger.LogInformation("Reminder prep: creating draft reminder, user={User}", UserAccountID);
|
||||
var ctd = JsonConvert.DeserializeObject(Form("remc"))!;
|
||||
var fdRem = await _reminders.RegisterReminderAsync(
|
||||
new FdsReminderData(ctd), change: false, remId: "", UserAccountID, DbSec);
|
||||
if (!string.IsNullOrEmpty(fdRem.Id))
|
||||
{
|
||||
_logger.LogInformation("Reminder prep: draft reminder {RemId} created, user={User}", fdRem.Id, UserAccountID);
|
||||
await _events.ReminderDraftCreatedAsync(fdRem, UserAccountID);
|
||||
var imgcol = await _pdf.DocToImageCollectionAsync(_reminders.GenerateReminderPdf(fdRem, fdRem.IsDraft));
|
||||
return await JSONAsync(new { id = fdRem.Id, img = imgcol.ImgB64Array, total = imgcol.TotalPages });
|
||||
@@ -54,7 +60,8 @@ public partial class IntranetController
|
||||
|
||||
case "srs":
|
||||
{
|
||||
if (!HasForm("id")) return BadRequest400();
|
||||
if (!HasForm("id")) { _logger.LogWarning("Reminder srs: missing form field 'id', user={User}", UserAccountID); return BadRequest400(); }
|
||||
_logger.LogInformation("Reminder srs: marking reminder {RemId} as sent, user={User}", Form("id"), UserAccountID);
|
||||
var pl = StdParamlist(SQL_VarChar("@Id", Form("id")), SQL_Bit("@auto", false));
|
||||
var dt2 = await getSQLDataSet_async(
|
||||
"EXECUTE [dbo].[fds__setReminderSent] @Id, @auto, @authuser;",
|
||||
@@ -63,17 +70,25 @@ public partial class IntranetController
|
||||
if (string.IsNullOrEmpty(dt2.Exception))
|
||||
await _events.ReminderMarkedSentAsync(Form("id"), Form("id"), UserAccountID);
|
||||
else
|
||||
{
|
||||
_logger.LogError("Reminder srs: SQL error marking reminder {RemId} sent: {SqlError}, user={User}", Form("id"), dt2.Exception, UserAccountID);
|
||||
await _events.ReminderIssueAsync(
|
||||
$"Mahnung {Form("id")} konnte nicht als versandt markiert werden.",
|
||||
UserAccountID, Form("id"));
|
||||
}
|
||||
return string.IsNullOrEmpty(dt2.Exception) ? await JSONAsync(new { ok = true }) : StatusCode(500);
|
||||
}
|
||||
|
||||
case "rdoc":
|
||||
{
|
||||
if (!HasForm("id")) return BadRequest400();
|
||||
if (!HasForm("id")) { _logger.LogWarning("Reminder rdoc: missing form field 'id', user={User}", UserAccountID); return BadRequest400(); }
|
||||
_logger.LogDebug("Reminder rdoc: fetching stored reminder document {RemId} typ={Typ} user={User}", Form("id"), Form("typ"), UserAccountID);
|
||||
var (file, fc) = await _reminders.GetStoredFileAsync(Form("id"), UserAccountID, DbSec);
|
||||
if (file == null || fc == null) return StatusCode(404, new { error = "Dokument wurde nicht gefunden" });
|
||||
if (file == null || fc == null)
|
||||
{
|
||||
_logger.LogWarning("Reminder rdoc: document not found for reminder {RemId} user={User}", Form("id"), UserAccountID);
|
||||
return StatusCode(404, new { error = "Dokument wurde nicht gefunden" });
|
||||
}
|
||||
return Form("typ") != "img"
|
||||
? await FileContentResultAsync(fc, file.MimeType(), file.Name)
|
||||
: await JSONAsync(new { id = Form("id"), img = await BuildPdfImageArray(fc) });
|
||||
@@ -84,13 +99,16 @@ public partial class IntranetController
|
||||
|
||||
case "lrem":
|
||||
{
|
||||
if (!HasForm("id")) return BadRequest400();
|
||||
if (!HasForm("id")) { _logger.LogWarning("Reminder lrem: missing form field 'id', user={User}", UserAccountID); return BadRequest400(); }
|
||||
_logger.LogDebug("Reminder lrem: listing reminders for invoice {InvId} user={User}", Form("id"), UserAccountID);
|
||||
var dset = await getSQLDataSet_async(
|
||||
"EXECUTE [dbo].[fds__lookupReminders] @InvId, @authuser;",
|
||||
_intranet.Intranet__SQLConnectionString,
|
||||
StdParamlist(SQL_VarChar("@InvId", Form("id"))),
|
||||
tablenames: new[] { "ov", "rem" },
|
||||
Security: DbSec, options: SqlOpt(fn, id, code));
|
||||
if (!string.IsNullOrEmpty(dset.Exception))
|
||||
_logger.LogError("Reminder lrem: SQL error for invoice {InvId}: {SqlError}, user={User}", Form("id"), dset.Exception, UserAccountID);
|
||||
return await JSONAsync(new
|
||||
{
|
||||
ov = dset.Table("ov").FirstRow.toStringDictionary(),
|
||||
@@ -98,18 +116,23 @@ public partial class IntranetController
|
||||
});
|
||||
}
|
||||
|
||||
default: return await JSONAsync(new { ok = true });
|
||||
default:
|
||||
_logger.LogWarning("Do_Process_Reminder: unhandled action id={Id}, user={User}", id, UserAccountID);
|
||||
return await JSONAsync(new { ok = true });
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<IActionResult> HandleReminderConf(string fn, string id, string code)
|
||||
{
|
||||
if (!HasForm("id")) return BadRequest400();
|
||||
if (!HasForm("id")) { _logger.LogWarning("HandleReminderConf: missing form field 'id', user={User}", UserAccountID); return BadRequest400(); }
|
||||
_logger.LogInformation("HandleReminderConf: finalizing reminder {RemId} user={User}", Form("id"), UserAccountID);
|
||||
var dt = await getSQLDatatable_async(
|
||||
"EXECUTE [dbo].[fds__setReminderFinal] @Id, @authuser;",
|
||||
_intranet.Intranet__SQLConnectionString,
|
||||
StdParamlist(SQL_VarChar("@Id", Form("id"))),
|
||||
Security: DbSec, options: SqlOpt(fn, id, code));
|
||||
if (!string.IsNullOrEmpty(dt.Exception))
|
||||
_logger.LogError("HandleReminderConf: SQL error finalizing reminder {RemId}: {SqlError}, user={User}", Form("id"), dt.Exception, UserAccountID);
|
||||
var frdic = dt.FirstRow.toObjectDictionary();
|
||||
if (frdic.TryGetValue("IsFinal", out var isFinal) && isFinal is true)
|
||||
{
|
||||
@@ -167,9 +190,10 @@ public partial class IntranetController
|
||||
|
||||
private async Task<IActionResult> HandleReminderIdoc(string fn, string id, string code)
|
||||
{
|
||||
if (!HasForm("id") || string.IsNullOrEmpty(Form("id"))) return StatusCode(404);
|
||||
if (!HasForm("id") || string.IsNullOrEmpty(Form("id"))) { _logger.LogWarning("HandleReminderIdoc: missing/empty form field 'id', user={User}", UserAccountID); return StatusCode(404); }
|
||||
_logger.LogDebug("HandleReminderIdoc: reminderId={RemId} typ={Typ} create={Create} user={User}", Form("id"), Form("typ"), Form("create", "0"), UserAccountID);
|
||||
var fdRem = await _reminders.LoadReminderAsync(Form("id"), UserAccountID, DbSec);
|
||||
if (string.IsNullOrEmpty(fdRem.Id)) return StatusCode(404, new { error = "Erinnerung wurde nicht gefunden" });
|
||||
if (string.IsNullOrEmpty(fdRem.Id)) { _logger.LogWarning("HandleReminderIdoc: reminder not found id={RemId} user={User}", Form("id"), UserAccountID); return StatusCode(404, new { error = "Erinnerung wurde nicht gefunden" }); }
|
||||
string filename = fdRem.ReminderRegistration!.nz("DocumentName").ne($"Zahlungserinnerung_{fdRem.Id}.pdf");
|
||||
if (Form("typ") != "img")
|
||||
{
|
||||
@@ -184,7 +208,8 @@ public partial class IntranetController
|
||||
|
||||
private async Task<IActionResult> HandleReminderResend(string fn, string id, string code)
|
||||
{
|
||||
if (!HasForm("id") || string.IsNullOrEmpty(Form("id"))) return StatusCode(404);
|
||||
if (!HasForm("id") || string.IsNullOrEmpty(Form("id"))) { _logger.LogWarning("HandleReminderResend: missing/empty form field 'id', user={User}", UserAccountID); return StatusCode(404); }
|
||||
_logger.LogInformation("HandleReminderResend: resending reminder {RemId} user={User}", Form("id"), UserAccountID);
|
||||
var pl = StdParamlist(SQL_VarChar("@Id", Form("id")), new SqlParameter("@includefile", true));
|
||||
var dset = await getSQLDataSet_async(
|
||||
"EXECUTE [dbo].[fds__getReminder] @Id, @includefile, @authuser;",
|
||||
|
||||
@@ -27,13 +27,16 @@ public partial class IntranetController
|
||||
|
||||
case "rthd":
|
||||
{
|
||||
if (!HasForm("id")) return BadRequest400();
|
||||
if (!HasForm("id")) { _logger.LogWarning("Requests rthd: missing form field 'id', user={User}", UserAccountID); return BadRequest400(); }
|
||||
_logger.LogInformation("Requests rthd: toggling hidden state for request {ReqId}, user={User}", Form("id"), UserAccountID);
|
||||
var sqldt = await getSQLDatatable_async(
|
||||
"EXECUTE [dbo].[fds__toggleRequestHidden] @Id, @authuser;",
|
||||
_intranet.Intranet__SQLConnectionString,
|
||||
StdParamlist(SQL_BigInt("@Id", Form("id"))),
|
||||
Security: DbSec, options: SqlOpt(fn, id, code));
|
||||
if (sqldt.Count == 0) return StatusCode(404, new { error = "not found" });
|
||||
if (!string.IsNullOrEmpty(sqldt.Exception))
|
||||
_logger.LogError("Requests rthd: SQL error for request {ReqId}: {SqlError}, user={User}", Form("id"), sqldt.Exception, UserAccountID);
|
||||
if (sqldt.Count == 0) { _logger.LogWarning("Requests rthd: request {ReqId} not found, user={User}", Form("id"), UserAccountID); return StatusCode(404, new { error = "not found" }); }
|
||||
var dic = sqldt.FirstRow.toObjectDictionary();
|
||||
return await JSONAsync(new { id = dic["EntityId"], visible = dic.no("hidden", false) is not true });
|
||||
}
|
||||
@@ -45,12 +48,17 @@ public partial class IntranetController
|
||||
|
||||
case "save":
|
||||
{
|
||||
if (!HasForm("invc")) return BadRequest400();
|
||||
if (!HasForm("invc")) { _logger.LogWarning("Requests save: missing form field 'invc', user={User}", UserAccountID); return BadRequest400(); }
|
||||
bool saveChange = !string.IsNullOrEmpty(Form("id"));
|
||||
_logger.LogInformation("Requests save: saving invoice draft change={Change} invId={InvId} user={User}", saveChange, Form("id"), UserAccountID);
|
||||
var fdInv = await _invoices.RegisterInvoiceAsync(
|
||||
new FdsInvoiceData(JsonConvert.DeserializeObject(Form("invc"))!),
|
||||
change: !string.IsNullOrEmpty(Form("id")), invId: Form("id"), UserAccountID, DbSec);
|
||||
change: saveChange, invId: Form("id"), UserAccountID, DbSec);
|
||||
if (!string.IsNullOrEmpty(fdInv.Id))
|
||||
await _events.InvoiceDraftRegisteredAsync(fdInv, !string.IsNullOrEmpty(Form("id")), UserAccountID);
|
||||
{
|
||||
_logger.LogInformation("Requests save: invoice draft {InvId} saved, user={User}", fdInv.Id, UserAccountID);
|
||||
await _events.InvoiceDraftRegisteredAsync(fdInv, saveChange, UserAccountID);
|
||||
}
|
||||
return !string.IsNullOrEmpty(fdInv.Id)
|
||||
? await JSONAsync(new { id = fdInv.Id })
|
||||
: await InvoiceIssueResult("Die Rechnung konnte aufgrund eines Fehlers nicht gespeichert werden.");
|
||||
@@ -58,12 +66,14 @@ public partial class IntranetController
|
||||
|
||||
case "sprep":
|
||||
{
|
||||
if (!HasForm("invc")) return BadRequest400();
|
||||
if (!HasForm("invc")) { _logger.LogWarning("Requests sprep: missing form field 'invc', user={User}", UserAccountID); return BadRequest400(); }
|
||||
_logger.LogInformation("Requests sprep: preparing new invoice draft, user={User}", UserAccountID);
|
||||
var fdInv = await _invoices.RegisterInvoiceAsync(
|
||||
new FdsInvoiceData(JsonConvert.DeserializeObject(Form("invc"))!),
|
||||
change: false, invId: "", UserAccountID, DbSec);
|
||||
if (!string.IsNullOrEmpty(fdInv.Id))
|
||||
{
|
||||
_logger.LogInformation("Requests sprep: invoice draft {InvId} created, user={User}", fdInv.Id, UserAccountID);
|
||||
await _events.InvoiceDraftRegisteredAsync(fdInv, changed: false, userAccountId: UserAccountID);
|
||||
var imgcol = await _pdf.DocToImageCollectionAsync(_invoices.GenerateInvoicePdf(fdInv, fdInv.IsDraft));
|
||||
return await JSONAsync(new { id = fdInv.Id, img = imgcol.ImgB64Array, total = imgcol.TotalPages });
|
||||
@@ -73,12 +83,14 @@ public partial class IntranetController
|
||||
|
||||
case "sedit":
|
||||
{
|
||||
if (!HasForm("id", "invc")) return BadRequest400();
|
||||
if (!HasForm("id", "invc")) { _logger.LogWarning("Requests sedit: missing form field 'id'/'invc', user={User}", UserAccountID); return BadRequest400(); }
|
||||
_logger.LogInformation("Requests sedit: updating invoice draft {InvId}, user={User}", Form("id"), UserAccountID);
|
||||
var fdInv = await _invoices.RegisterInvoiceAsync(
|
||||
new FdsInvoiceData(JsonConvert.DeserializeObject(Form("invc"))!),
|
||||
change: true, invId: Form("id"), UserAccountID, DbSec);
|
||||
if (!string.IsNullOrEmpty(fdInv.Id))
|
||||
{
|
||||
_logger.LogInformation("Requests sedit: invoice draft {InvId} updated, user={User}", fdInv.Id, UserAccountID);
|
||||
await _events.InvoiceDraftRegisteredAsync(fdInv, changed: true, userAccountId: UserAccountID);
|
||||
var imgcol = await _pdf.DocToImageCollectionAsync(_invoices.GenerateInvoicePdf(fdInv, fdInv.IsDraft));
|
||||
return await JSONAsync(new { id = fdInv.Id, img = imgcol.ImgB64Array, total = imgcol.TotalPages });
|
||||
@@ -87,25 +99,36 @@ public partial class IntranetController
|
||||
}
|
||||
|
||||
case "sdel":
|
||||
if (!HasForm("id")) return BadRequest400();
|
||||
await setSQLValue_async("EXECUTE [dbo].[fds__remInvoice] @Id, @authuser;",
|
||||
{
|
||||
if (!HasForm("id")) { _logger.LogWarning("Requests sdel: missing form field 'id', user={User}", UserAccountID); return BadRequest400(); }
|
||||
_logger.LogInformation("Requests sdel: deleting invoice draft {InvId}, user={User}", Form("id"), UserAccountID);
|
||||
var ok = await setSQLValue_async("EXECUTE [dbo].[fds__remInvoice] @Id, @authuser;",
|
||||
_intranet.Intranet__SQLConnectionString,
|
||||
StdParamlist(SQL_VarChar("@Id", Form("id"))),
|
||||
Security: DbSec, options: SqlOpt(fn, id, code));
|
||||
if (!ok)
|
||||
{
|
||||
_logger.LogError("Requests sdel: SQL failed deleting invoice draft {InvId}, user={User}", Form("id"), UserAccountID);
|
||||
return await InvoiceIssueResult("Die Rechnung konnte aufgrund eines Fehlers nicht gelöscht werden.", Form("id"));
|
||||
}
|
||||
return await JSONAsync(new { ok = true });
|
||||
}
|
||||
|
||||
case "sconf": return await HandleRequestSconf(fn, id, code);
|
||||
case "idoc": return await HandleRequestIdoc(fn, id, code);
|
||||
case "resend": return await HandleRequestResend(fn, id, code);
|
||||
|
||||
default: return await JSONAsync(new { ok = true });
|
||||
default:
|
||||
_logger.LogWarning("Do_Process_Requests: unhandled action id={Id}, user={User}", id, UserAccountID);
|
||||
return await JSONAsync(new { ok = true });
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<IActionResult> HandleRequestList(string fn, string id, string code)
|
||||
{
|
||||
if (!HasForm("mode")) return BadRequest400();
|
||||
if (!HasForm("mode")) { _logger.LogWarning("HandleRequestList: missing form field 'mode', user={User}", UserAccountID); return BadRequest400(); }
|
||||
string mode = Form("mode").ToLower();
|
||||
_logger.LogDebug("HandleRequestList mode={Mode} tgt={Tgt} user={User}", mode, Form("tgt"), UserAccountID);
|
||||
if (mode == "s" && Form("tgt").Contains(':'))
|
||||
{
|
||||
var pl = StdParamlist(
|
||||
@@ -126,7 +149,10 @@ public partial class IntranetController
|
||||
}
|
||||
if (!DateTime.TryParseExact(Form("tgt"), "yy-MM-dd",
|
||||
CultureInfo.InvariantCulture, DateTimeStyles.AllowWhiteSpaces, out var tgtdate))
|
||||
{
|
||||
_logger.LogWarning("HandleRequestList: invalid date format tgt='{Tgt}' user={User}", Form("tgt"), UserAccountID);
|
||||
return BadRequest400();
|
||||
}
|
||||
{
|
||||
var pl = StdParamlist(
|
||||
SQL_Date("@tgtdate", tgtdate),
|
||||
@@ -204,7 +230,8 @@ public partial class IntranetController
|
||||
|
||||
private async Task<IActionResult> HandleRequestGet(string fn, string id, string code)
|
||||
{
|
||||
if (!HasForm("id")) return BadRequest400();
|
||||
if (!HasForm("id")) { _logger.LogWarning("HandleRequestGet: missing form field 'id', user={User}", UserAccountID); return BadRequest400(); }
|
||||
_logger.LogDebug("HandleRequestGet requestId={ReqId} mode={Mode} user={User}", Form("id"), Form("mode"), UserAccountID);
|
||||
string modeVal = Form("mode").ne("ov");
|
||||
string[] tn = modeVal switch
|
||||
{
|
||||
@@ -231,7 +258,8 @@ public partial class IntranetController
|
||||
|
||||
private async Task<IActionResult> HandleRequestIget(string fn, string id, string code)
|
||||
{
|
||||
if (!HasForm("id", "typ")) return BadRequest400();
|
||||
if (!HasForm("id", "typ")) { _logger.LogWarning("HandleRequestIget: missing form field 'id'/'typ', user={User}", UserAccountID); return BadRequest400(); }
|
||||
_logger.LogDebug("HandleRequestIget requestId={ReqId} typ={Typ} mode={Mode} user={User}", Form("id"), Form("typ"), Form("mode"), UserAccountID);
|
||||
var pl = StdParamlist(
|
||||
SQL_BigInt("@servicerequestid", Form("id")),
|
||||
SQL_VarChar("@mode", Form("mode").ne("ov")),
|
||||
@@ -273,12 +301,15 @@ public partial class IntranetController
|
||||
|
||||
private async Task<IActionResult> HandleRequestSconf(string fn, string id, string code)
|
||||
{
|
||||
if (!HasForm("id")) return BadRequest400();
|
||||
if (!HasForm("id")) { _logger.LogWarning("HandleRequestSconf: missing form field 'id', user={User}", UserAccountID); return BadRequest400(); }
|
||||
_logger.LogInformation("HandleRequestSconf: finalizing invoice {InvId} user={User}", Form("id"), UserAccountID);
|
||||
var dt = await getSQLDatatable_async(
|
||||
"EXECUTE [dbo].[fds__setInvoiceFinal] @Id, @authuser;",
|
||||
_intranet.Intranet__SQLConnectionString,
|
||||
StdParamlist(SQL_VarChar("@Id", Form("id"))),
|
||||
Security: DbSec, options: SqlOpt(fn, id, code));
|
||||
if (!string.IsNullOrEmpty(dt.Exception))
|
||||
_logger.LogError("HandleRequestSconf: SQL error finalizing invoice {InvId}: {SqlError}, user={User}", Form("id"), dt.Exception, UserAccountID);
|
||||
var frdic = dt.FirstRow.toObjectDictionary();
|
||||
if (frdic.TryGetValue("IsFinal", out var isFinal) && isFinal is true)
|
||||
{
|
||||
@@ -331,16 +362,19 @@ public partial class IntranetController
|
||||
$"Die Rechnungs-PDF {frdic.nz("DocumentName").ne($"Rechnung_{invId}.pdf")} konnte nicht erstellt werden.",
|
||||
UserAccountID, invId);
|
||||
}
|
||||
return await JSONAsync(new { ok = true });
|
||||
// hasFile tells the frontend whether the PDF was actually stored, so it only opens the
|
||||
// idoc preview popup when there is something to show (never on a failed render/store).
|
||||
return await JSONAsync(new { ok = true, hasFile = filebyte.Length > 0 });
|
||||
}
|
||||
return await InvoiceIssueResult("Die Rechnung konnte aufgrund eines Fehlers nicht erstellt werden.");
|
||||
}
|
||||
|
||||
private async Task<IActionResult> HandleRequestIdoc(string fn, string id, string code)
|
||||
{
|
||||
if (!HasForm("id") || string.IsNullOrEmpty(Form("id"))) return StatusCode(404);
|
||||
if (!HasForm("id") || string.IsNullOrEmpty(Form("id"))) { _logger.LogWarning("HandleRequestIdoc: missing/empty form field 'id', user={User}", UserAccountID); return StatusCode(404); }
|
||||
_logger.LogDebug("HandleRequestIdoc: invoiceId={InvId} typ={Typ} create={Create} user={User}", Form("id"), Form("typ"), Form("create", "0"), UserAccountID);
|
||||
var fdInv = await _invoices.LoadInvoiceAsync(Form("id"), UserAccountID, DbSec);
|
||||
if (string.IsNullOrEmpty(fdInv.Id)) return StatusCode(404, new { error = "Rechnung wurde nicht gefunden" });
|
||||
if (string.IsNullOrEmpty(fdInv.Id)) { _logger.LogWarning("HandleRequestIdoc: invoice not found id={InvId} user={User}", Form("id"), UserAccountID); return StatusCode(404, new { error = "Rechnung wurde nicht gefunden" }); }
|
||||
string filename = fdInv.InvoiceRegistration!.nz("DocumentName").ne($"Rechnung_{fdInv.Id}.pdf");
|
||||
if (Form("typ") != "img")
|
||||
{
|
||||
@@ -357,7 +391,8 @@ public partial class IntranetController
|
||||
|
||||
private async Task<IActionResult> HandleRequestResend(string fn, string id, string code)
|
||||
{
|
||||
if (!HasForm("id") || string.IsNullOrEmpty(Form("id"))) return StatusCode(404);
|
||||
if (!HasForm("id") || string.IsNullOrEmpty(Form("id"))) { _logger.LogWarning("HandleRequestResend: missing/empty form field 'id', user={User}", UserAccountID); return StatusCode(404); }
|
||||
_logger.LogInformation("HandleRequestResend: resending invoice {InvId} user={User}", Form("id"), UserAccountID);
|
||||
var dtset = await getSQLDataSet_async(
|
||||
"EXECUTE [dbo].[fds__getInvoice] @Id, @authuser;",
|
||||
_intranet.Intranet__SQLConnectionString,
|
||||
|
||||
@@ -174,6 +174,19 @@ public partial class IntranetController : Microsoft.AspNetCore.Mvc.Controller
|
||||
{
|
||||
_logger.LogError(ex, "Unhandled exception in Do fn={Fn} id={Id} code={Code} user={User}",
|
||||
fn, id, code, UserAccountID);
|
||||
// Standing rule: an exception that interrupts a user-initiated action must reach the
|
||||
// user as a notification, not only the log. This is the catch-all safety net for any
|
||||
// Do_Process_* action that throws without first publishing its own (more specific)
|
||||
// issue event. Pre-auth flows (login/logout, unauthenticated GETs) are skipped — there
|
||||
// is no user session to notify and the HTTP status already conveys the failure.
|
||||
if (UserIdent.IsAuthenticated)
|
||||
{
|
||||
await _events.UserIssueAsync(
|
||||
"Aktion fehlgeschlagen",
|
||||
"Die Aktion konnte aufgrund eines unerwarteten Fehlers nicht abgeschlossen werden. Bitte versuchen Sie es erneut.",
|
||||
UserAccountID,
|
||||
new Dictionary<string, object?> { ["fn"] = fn });
|
||||
}
|
||||
return ServerError();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Fuchs.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// Resolves a request value from the posted form, falling back to the query string.
|
||||
/// Extracted as pure/testable logic: endpoints in <c>_allowedGet</c> (e.g. req/idoc, rem/idoc)
|
||||
/// are invoked via a plain GET (window.open with '?id=...'), where <see cref="HttpRequest.Form"/>
|
||||
/// has no Content-Type and throws <see cref="InvalidOperationException"/> if read directly.
|
||||
/// </summary>
|
||||
internal static class RequestValueHelper
|
||||
{
|
||||
internal static string? Resolve(bool hasFormContentType, IFormCollection form, IQueryCollection query, string key)
|
||||
{
|
||||
if (hasFormContentType && form.TryGetValue(key, out var formValue))
|
||||
return formValue.ToString();
|
||||
if (query.TryGetValue(key, out var queryValue))
|
||||
return queryValue.ToString();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user