Initial Commit after switching from SVN to git
This commit is contained in:
@@ -0,0 +1,161 @@
|
||||
using System.Globalization;
|
||||
using Fuchs.intranet;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using OCORE.SQL;
|
||||
using static OCORE.commons;
|
||||
using static OCORE.io;
|
||||
using static OCORE.SQL.sql;
|
||||
using static OCORE.web.mvc_helper_async;
|
||||
|
||||
namespace Fuchs.Controllers;
|
||||
|
||||
// Partial class: Banking processing
|
||||
public partial class IntranetController
|
||||
{
|
||||
private async Task<IActionResult> Do_Process_Bankings(string fn, string id, string code)
|
||||
{
|
||||
switch (id.ToLower())
|
||||
{
|
||||
case "auth":
|
||||
return await JSONAsync(new { manage = 1 });
|
||||
|
||||
case "up":
|
||||
foreach (var fle in Request.Form.Files)
|
||||
{
|
||||
using var stream = fle.OpenReadStream();
|
||||
var schemaDt = (await getSQLDatatable_async(
|
||||
"DECLARE @tmp [dbo].[fds__tt__bankingtransactions]; SELECT TOP(0) * FROM @tmp;",
|
||||
_intranet.Intranet__SQLConnectionString,
|
||||
Security: DbSec, options: SqlOpt(fn, id, code))).DataTable;
|
||||
|
||||
var tbl = Banking.ParseToDatatable(stream, schemaDt);
|
||||
var tmptbl = "bs_" + Guid.NewGuid().ToString().Replace("-", "");
|
||||
|
||||
var dtwa = new DatatableWriterAsync(tbl, _intranet.Intranet__SQLConnectionString)
|
||||
{
|
||||
CommandAfter = new SqlCommand(
|
||||
"EXECUTE [dbo].[fds__merge_bankingtransactions] @tblname, @authuser;")
|
||||
};
|
||||
dtwa.CommandAfter.Parameters.AddRange(new[]
|
||||
{
|
||||
new SqlParameter("@tblname", dtwa.DestinationTableName),
|
||||
SQL_VarChar("@authuser", UserAccountID)
|
||||
});
|
||||
dtwa.CommandAfterError = new SqlCommand(
|
||||
$"SELECT * INTO [{tmptbl}] FROM {dtwa.DestinationTableName};");
|
||||
dtwa.OnError += (_, exc, _) =>
|
||||
_intranet.debug_log("IntranetController.bam.up - sql exception",
|
||||
exc, UserAccountID, new { uid = dtwa.InstanceGUID, tmptbl });
|
||||
dtwa.OnCommandAfterError += (_, exc) =>
|
||||
_intranet.debug_log("IntranetController.bam.up - command-after exception",
|
||||
exc, UserAccountID, new { uid = dtwa.InstanceGUID, tmptbl });
|
||||
dtwa.DoSubmit();
|
||||
}
|
||||
return Ok();
|
||||
|
||||
case "qtl":
|
||||
{
|
||||
if (!HasForm("mode")) return BadRequest400();
|
||||
var pl = StdParamlist(SQL_VarChar("@mode", Form("mode")));
|
||||
var dset = await getSQLDataSet_async(
|
||||
"EXECUTE [dbo].[fds__getBankingtransfers_questionable] @mode, @authuser;",
|
||||
_intranet.Intranet__SQLConnectionString, pl,
|
||||
tablenames: new[] { "admin", "transfers" },
|
||||
Security: DbSec, options: SqlOpt(fn, id, code));
|
||||
return await JSONAsync(new
|
||||
{
|
||||
admin = dset.Table("admin").FirstRow.toObjectDictionary(),
|
||||
bs = dset.Tables("transfers").toArrayofObjectDictionaries()
|
||||
});
|
||||
}
|
||||
|
||||
case "btl":
|
||||
{
|
||||
if (!HasForm("mode")) return BadRequest400();
|
||||
string mode = Form("mode").ToLower();
|
||||
if (mode == "s" && Form("tgt").Contains(':'))
|
||||
{
|
||||
var pl = StdParamlist(
|
||||
SQL_VarChar("@mode", Form("mode")),
|
||||
SQL_VarChar("@search", Form("tgt")));
|
||||
var dset = await getSQLDataSet_async(
|
||||
"EXECUTE [dbo].[fds__getBankingtransactions_list2] @mode, @search, @authuser;",
|
||||
_intranet.Intranet__SQLConnectionString, pl,
|
||||
tablenames: new[] { "admin", "bank" },
|
||||
Security: DbSec, options: SqlOpt(fn, id, code));
|
||||
return await JSONAsync(new
|
||||
{
|
||||
admin = dset.Table("admin").FirstRow.toObjectDictionary(),
|
||||
bank = dset.Tables("bank").toArrayofObjectDictionaries()
|
||||
});
|
||||
}
|
||||
if (!DateTime.TryParseExact(Form("tgt"), "yy-MM-dd",
|
||||
CultureInfo.InvariantCulture, DateTimeStyles.AllowWhiteSpaces, out var tgtdate))
|
||||
return BadRequest400();
|
||||
{
|
||||
var pl = StdParamlist(
|
||||
SQL_Date("@tgtdate", tgtdate),
|
||||
SQL_VarChar("@mode", Form("mode").ne("m")),
|
||||
SQL_VarChar("@includes", Form("includes").ne(Form("all") == "true" ? "all" : "")));
|
||||
var dset = await getSQLDataSet_async(
|
||||
"EXECUTE [dbo].[fds__getBankingtransfers_list] @tgtdate, @mode, @authuser;",
|
||||
_intranet.Intranet__SQLConnectionString, pl,
|
||||
tablenames: new[] { "admin", "bank" },
|
||||
Security: DbSec, options: SqlOpt(fn, id, code));
|
||||
return await JSONAsync(new
|
||||
{
|
||||
admin = dset.Table("admin").FirstRow.toObjectDictionary(),
|
||||
bank = dset.Tables("bank").toArrayofObjectDictionaries()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
case "smd":
|
||||
{
|
||||
if (!HasForm("taid")) return BadRequest400();
|
||||
var pl = StdParamlist(SQL_VarChar("@taID", Form("taid"), dbNull_IfEmpty: true));
|
||||
var res = await getSQLValue_async(
|
||||
"EXECUTE [dbo].[fds__setBankingtransaction_done] @taID, @authuser;",
|
||||
_intranet.Intranet__SQLConnectionString, pl,
|
||||
Security: DbSec, options: SqlOpt(fn, id, code));
|
||||
return res.Result is true ? Ok() : StatusCode(500, new { error = "not successful" });
|
||||
}
|
||||
|
||||
case "ati":
|
||||
{
|
||||
if (!HasForm("taid", "iid")) return BadRequest400();
|
||||
var pl = StdParamlist(
|
||||
SQL_VarChar("@taid", Form("taid"), dbNull_IfEmpty: true),
|
||||
SQL_VarChar("@invoice_id", Form("iid"), dbNull_IfEmpty: true));
|
||||
var res = await getSQLValue_async(
|
||||
"EXECUTE [dbo].[fds__setBankingtransaction_assignToIvoice] @taID, @invoice_id, @authuser;",
|
||||
_intranet.Intranet__SQLConnectionString, pl,
|
||||
Security: DbSec, options: SqlOpt(fn, id, code));
|
||||
return res.Result is true ? Ok() : StatusCode(500, new { error = "not successful" });
|
||||
}
|
||||
|
||||
case "vfi":
|
||||
{
|
||||
if (!HasForm("invid")) return BadRequest400();
|
||||
var pl = StdParamlist(SQL_VarChar("@InvoiceId", Form("invid"), dbNull_IfEmpty: true));
|
||||
var res = await getSQLDatatable_async(
|
||||
"SELECT [Id],[InvoiceId],[SendToAddress] FROM [dbo].[fds__invoices]" +
|
||||
" WHERE [InvoiceId] LIKE ('%' + @InvoiceId) AND [InvoiceId] IS NOT NULL AND [DateFinalized] IS NOT NULL;",
|
||||
_intranet.Intranet__SQLConnectionString, pl,
|
||||
Security: DbSec, options: SqlOpt(fn, id, code));
|
||||
return await JSONAsync(res.DataTable.toArrayofObjectDictionaries());
|
||||
}
|
||||
|
||||
default:
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
|
||||
// ── Form helpers ─────────────────────────────────────────────────────────
|
||||
protected bool HasForm(params string[] keys) =>
|
||||
keys.All(k => Request.Form.ContainsKey(k) && !string.IsNullOrWhiteSpace(Request.Form[k]));
|
||||
|
||||
protected string Form(string key, string fallback = "") =>
|
||||
Request.Form.TryGetValue(key, out var v) ? v.ToString() : fallback;
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
using System.Globalization;
|
||||
using System.Web;
|
||||
using Fuchs.intranet;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using MFR_RESTClient.generic;
|
||||
using OCORE.SQL;
|
||||
using static OCORE.commons;
|
||||
using static OCORE.io;
|
||||
using static OCORE.SQL.sql;
|
||||
using static OCORE.web.mvc_helper_async;
|
||||
|
||||
namespace Fuchs.Controllers;
|
||||
|
||||
// Partial class: Invoice processing (dispatch + simple actions)
|
||||
public partial class IntranetController
|
||||
{
|
||||
private async Task<IActionResult> Do_Process_Invoices(string fn, string id, string code)
|
||||
{
|
||||
switch (id.ToLower())
|
||||
{
|
||||
case "auth":
|
||||
return await JSONAsync(new { manage = 1 });
|
||||
|
||||
case "setpyd":
|
||||
if (!HasForm("id")) return BadRequest400();
|
||||
return await setSQLValue_async(
|
||||
"EXECUTE [dbo].[fds__setInvoicePayed] @Id, @authuser;",
|
||||
_intranet.Intranet__SQLConnectionString,
|
||||
StdParamlist(SQL_VarChar("@Id", Form("id"))),
|
||||
Security: DbSec, options: SqlOpt(fn, id, code))
|
||||
? Ok() : StatusCode(500);
|
||||
|
||||
case "setupd":
|
||||
if (!HasForm("id")) return BadRequest400();
|
||||
return await setSQLValue_async(
|
||||
"EXECUTE [dbo].[fds__setInvoiceUNPayed] @Id, @authuser;",
|
||||
_intranet.Intranet__SQLConnectionString,
|
||||
StdParamlist(SQL_VarChar("@Id", Form("id"))),
|
||||
Security: DbSec, options: SqlOpt(fn, id, code))
|
||||
? Ok() : StatusCode(500);
|
||||
|
||||
case "setvat":
|
||||
if (!float.TryParse(Form("val").Replace("%", "").Replace(",", ".").Trim(),
|
||||
NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out float vatVal))
|
||||
return BadRequest400();
|
||||
{
|
||||
var pl = StdParamlist(
|
||||
SQL_BigInt("@id", Form("id")),
|
||||
SQL_VarChar("@entitytype", "report"),
|
||||
new SqlParameter("@vat", vatVal),
|
||||
SQL_VarChar("@userid", UserAccountID));
|
||||
string sqlEx = ""; int? sqlCode = null;
|
||||
setSQLValue("EXECUTE [dbo].[fds__setReportVAT] @id, @entitytype, @vat, @authuser;",
|
||||
_intranet.Intranet_SqlCon(), ref sqlEx, ref sqlCode, pl, Security: DbSec);
|
||||
return string.IsNullOrEmpty(sqlEx) ? Ok() : StatusCode(500, new { error = sqlEx });
|
||||
}
|
||||
|
||||
case "sis":
|
||||
if (!HasForm("id")) return BadRequest400();
|
||||
{
|
||||
var pl = StdParamlist(SQL_VarChar("@Id", Form("id")), SQL_Bit("@auto", false));
|
||||
var dt2 = await getSQLDataSet_async(
|
||||
"EXECUTE [dbo].[fds__setInvoiceSent] @Id, @auto, @authuser;",
|
||||
_intranet.Intranet__SQLConnectionString, pl,
|
||||
Security: DbSec, options: SqlOpt(fn, id, code));
|
||||
return string.IsNullOrEmpty(dt2.Exception) ? Ok() : StatusCode(500);
|
||||
}
|
||||
|
||||
case "pget": return await HandleInvoicePget(fn, id, code);
|
||||
case "get": return await HandleInvoiceGet(fn, id, code);
|
||||
case "icget": return await HandleInvoiceIcGet(fn, id, code);
|
||||
case "storno":
|
||||
case "credit": return await HandleInvoiceStornoCredit(fn, id, code);
|
||||
case "invl": return await HandleInvoiceList(fn, id, code);
|
||||
case "rqi": return await HandleInvoiceRequestItems(fn, id, code);
|
||||
case "pyi": return await HandleInvoicePayments(fn, id, code);
|
||||
case "datev": return await HandleDatev(fn, id, code);
|
||||
case "rdoc": return await HandleReportDoc(fn, id, code, Form("id"));
|
||||
case "rdocn": return await HandleReportDocByName(fn, id, code);
|
||||
case "datevzip": return await HandleDatevZip(fn, id, code);
|
||||
case "getrem": return await HandleGetReminder(fn, id, code);
|
||||
|
||||
case "mfrrel":
|
||||
if (!HasForm("id") || !long.TryParse(Form("id"), out long relId)) return BadRequest400();
|
||||
using (var mfr = new fds.FdsMfrClient())
|
||||
await mfr.Update__entitytable(EntityTypes.Invoice,
|
||||
fds.FdsMfr.UpdateNeed.Reset, new[] { relId });
|
||||
return Ok();
|
||||
|
||||
default: return Ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,323 @@
|
||||
using System.Globalization;
|
||||
using System.Web;
|
||||
using Fuchs.intranet;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using MFR_RESTClient.generic;
|
||||
using OCORE.pdf;
|
||||
using OCORE.SQL;
|
||||
using static OCORE.commons;
|
||||
using static OCORE.io;
|
||||
using static OCORE.SQL.sql;
|
||||
using static OCORE.web.mvc_helper_async;
|
||||
|
||||
namespace Fuchs.Controllers;
|
||||
|
||||
// Partial class: Invoice sub-handlers
|
||||
public partial class IntranetController
|
||||
{
|
||||
private async Task<IActionResult> HandleInvoicePget(string fn, string id, string code)
|
||||
{
|
||||
if (!HasForm("id")) return BadRequest400();
|
||||
if (!long.TryParse(Form("id"), out long tgtid)) return BadRequest400();
|
||||
using (var mfr = new fds.FdsMfrClient())
|
||||
await mfr.Update__entitytable(EntityTypes.Invoice,
|
||||
fds.FdsMfr.UpdateNeed.Reset, new[] { tgtid });
|
||||
|
||||
var dt = await getSQLDatatable_async(
|
||||
"SELECT * FROM [dbo].[fds__getInvoiceTreeIds](@srqid);",
|
||||
_intranet.Intranet__SQLConnectionString,
|
||||
StdParamlist(SQL_BigInt("@srqid", tgtid)),
|
||||
Security: DbSec, options: SqlOpt(fn, id, code));
|
||||
|
||||
if (dt.Count > 0)
|
||||
{
|
||||
var invIds = new List<long>();
|
||||
var srqIds = new List<long>();
|
||||
foreach (System.Data.DataRow rw in dt.DataTable.Rows)
|
||||
{
|
||||
long iid = rw.nint64("Id", -1);
|
||||
switch (rw.nz("type"))
|
||||
{
|
||||
case "invoice": if (iid > 0 && !invIds.Contains(iid)) invIds.Add(iid); break;
|
||||
case "servicerequest": if (iid > 0 && !srqIds.Contains(iid)) srqIds.Add(iid); break;
|
||||
}
|
||||
}
|
||||
using var mfr2 = new fds.FdsMfrClient();
|
||||
foreach (var iid in invIds)
|
||||
await mfr2.Update__entitytable(EntityTypes.Invoice, fds.FdsMfr.UpdateNeed.Reset, new[] { iid });
|
||||
foreach (var iid in srqIds)
|
||||
await mfr2.Update__entitytable(EntityTypes.ServiceRequest, fds.FdsMfr.UpdateNeed.Reset, new[] { iid });
|
||||
}
|
||||
return Ok();
|
||||
}
|
||||
|
||||
private async Task<IActionResult> HandleInvoiceGet(string fn, string id, string code)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!HasForm("id")) return BadRequest400();
|
||||
var sqldset = await getSQLDataSet_async(
|
||||
"EXECUTE [dbo].[fds__getInvoice] @Id, @authuser;",
|
||||
_intranet.Intranet__SQLConnectionString,
|
||||
StdParamlist(SQL_VarChar("@Id", Form("id"))),
|
||||
tablenames: new[] { "admin", "inv", "req", "itm" },
|
||||
Security: DbSec, options: SqlOpt(fn, id, code));
|
||||
|
||||
var ldic = BuildInvoiceRequestList(sqldset);
|
||||
var adminDic = sqldset.Table("admin").FirstRow.toObjectDictionary();
|
||||
var invDic = sqldset.Table("inv").FirstRow.toObjectDictionary();
|
||||
if (invDic.nz("InvoiceOptions", "").Split(',').Contains("§13b"))
|
||||
adminDic["p13b"] = true;
|
||||
return await JSONAsync(new { admin = adminDic, inv = invDic, req = ldic });
|
||||
}
|
||||
catch { return StatusCode(500); }
|
||||
}
|
||||
|
||||
private async Task<IActionResult> HandleInvoiceIcGet(string fn, string id, string code)
|
||||
{
|
||||
if (!HasForm("id")) return BadRequest400();
|
||||
var sqldset = await getSQLDataSet_async(
|
||||
"EXECUTE [dbo].[fds__prepStorno_recreate] @InvId, @authuser;",
|
||||
_intranet.Intranet__SQLConnectionString,
|
||||
StdParamlist(SQL_VarChar("@InvId", Form("id"))),
|
||||
tablenames: new[] { "admin", "requests", "items", "steps", "companies", "locations" },
|
||||
Security: DbSec, options: SqlOpt(fn, id, code));
|
||||
|
||||
var ldic = BuildRequestItemList(sqldset);
|
||||
return await JSONAsync(new
|
||||
{
|
||||
admin = sqldset.Table("admin").FirstRow.toObjectDictionary(),
|
||||
requests = ldic,
|
||||
companies = sqldset.Tables("companies").toArrayofObjectDictionaries(),
|
||||
locations = sqldset.Tables("locations").toArrayofObjectDictionaries()
|
||||
});
|
||||
}
|
||||
|
||||
private async Task<IActionResult> HandleInvoiceStornoCredit(string fn, string id, string code)
|
||||
{
|
||||
if (!HasForm("id", "mode")) return BadRequest400();
|
||||
string sqlcmd = Form("mode") switch
|
||||
{
|
||||
"credit" => "EXECUTE [dbo].[fds__createCredit_simple] @Id, @authuser;",
|
||||
"simple" => "EXECUTE [dbo].[fds__createStorno_simple] @Id, @authuser;",
|
||||
"copy" => "EXECUTE [dbo].[fds__createStorno_copy] @Id, @authuser;",
|
||||
_ => ""
|
||||
};
|
||||
if (string.IsNullOrEmpty(sqlcmd)) return StatusCode(500, new { error = "function not allowed" });
|
||||
var sqldset = await getSQLDataSet_async(sqlcmd,
|
||||
_intranet.Intranet__SQLConnectionString,
|
||||
StdParamlist(SQL_VarChar("@Id", Form("id"))),
|
||||
tablenames: new[] { "admin", "inv", "req", "itm" },
|
||||
Security: DbSec, options: SqlOpt(fn, id, code));
|
||||
return await JSONAsync(new
|
||||
{
|
||||
admin = sqldset.Table("admin").FirstRow.toObjectDictionary(),
|
||||
inv = sqldset.Table("inv").FirstRow.toObjectDictionary(),
|
||||
req = BuildInvoiceRequestList(sqldset)
|
||||
});
|
||||
}
|
||||
|
||||
private async Task<IActionResult> HandleInvoiceList(string fn, string id, string code)
|
||||
{
|
||||
if (!HasForm("mode")) return BadRequest400();
|
||||
string mode = Form("mode").ToLower();
|
||||
if (mode == "s" && Form("tgt").Contains(':'))
|
||||
{
|
||||
var pl = StdParamlist(
|
||||
SQL_Date("@tgtdate", DBNull.Value),
|
||||
SQL_VarChar("@mode", Form("mode").ne("m")),
|
||||
SQL_Bit("@include_drafts", Form("all")),
|
||||
SQL_VarChar("@search", Form("tgt")));
|
||||
var dset = await getSQLDataSet_async(
|
||||
"EXECUTE [dbo].[fds__getInvoices_list2] @tgtdate, @mode, @include_drafts, @search, @authuser;",
|
||||
_intranet.Intranet__SQLConnectionString, pl,
|
||||
tablenames: new[] { "admin", "invoices" },
|
||||
Security: DbSec, options: SqlOpt(fn, id, code));
|
||||
return await JSONAsync(new
|
||||
{
|
||||
admin = dset.Table("admin").FirstRow.toObjectDictionary(),
|
||||
invoices = dset.Tables("invoices").toArrayofObjectDictionaries()
|
||||
});
|
||||
}
|
||||
if (!DateTime.TryParseExact(Form("tgt"), "yy-MM-dd",
|
||||
CultureInfo.InvariantCulture, DateTimeStyles.AllowWhiteSpaces, out var tgtdate))
|
||||
return BadRequest400();
|
||||
{
|
||||
var pl = StdParamlist(
|
||||
SQL_Date("@tgtdate", tgtdate),
|
||||
SQL_VarChar("@mode", Form("mode").ne("m")),
|
||||
SQL_VarChar("@includes", Form("includes").ne(Form("all") == "true" ? "all" : "")));
|
||||
var dset = await getSQLDataSet_async(
|
||||
"EXECUTE [dbo].[fds__getInvoices_list_vario] @tgtdate, @mode, @includes, @authuser;",
|
||||
_intranet.Intranet__SQLConnectionString, pl,
|
||||
tablenames: new[] { "admin", "invoices" },
|
||||
Security: DbSec, options: SqlOpt(fn, id, code));
|
||||
return await JSONAsync(new
|
||||
{
|
||||
admin = dset.Table("admin").FirstRow.toObjectDictionary(),
|
||||
invoices = dset.Tables("invoices").toArrayofObjectDictionaries()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<IActionResult> HandleInvoiceRequestItems(string fn, string id, string code)
|
||||
{
|
||||
if (!HasForm("id")) return BadRequest400();
|
||||
var sqldt = await getSQLDataSet_async(
|
||||
"EXECUTE [dbo].[fds__getInvRequestItems] @invoiceid, @authuser;",
|
||||
_intranet.Intranet__SQLConnectionString,
|
||||
StdParamlist(SQL_VarChar("@invoiceid", Form("id"))),
|
||||
tablenames: new[] { "requests", "items" },
|
||||
Security: DbSec, options: SqlOpt(fn, id, code));
|
||||
var ldic = new List<Dictionary<string, object?>>();
|
||||
foreach (System.Data.DataRow sq in sqldt.Tables("requests").Select("",
|
||||
sqldt.Tables("requests").Columns.Contains("order") ? "order" : ""))
|
||||
{
|
||||
var sdic = sq.toObjectDictionary();
|
||||
sdic["items"] = sqldt.Tables("items")
|
||||
.Select($"[ServiceRequestId] = {sdic["id"]}", sqldt.Tables("items").Columns.Contains("order") ? "order" : "")
|
||||
.Select(r => r.toObjectDictionary()).ToList();
|
||||
ldic.Add(sdic!);
|
||||
}
|
||||
return await JSONAsync(new { requests = ldic });
|
||||
}
|
||||
|
||||
private async Task<IActionResult> HandleInvoicePayments(string fn, string id, string code)
|
||||
{
|
||||
if (!HasForm("id")) return BadRequest400();
|
||||
var sqldt = await getSQLDataSet_async(
|
||||
"EXECUTE [dbo].[fds__getInvPayments] @invoiceid, @authuser;",
|
||||
_intranet.Intranet__SQLConnectionString,
|
||||
StdParamlist(SQL_VarChar("@invoiceid", Form("id"))),
|
||||
tablenames: new[] { "items" },
|
||||
Security: DbSec, options: SqlOpt(fn, id, code));
|
||||
return await JSONAsync(new { payments = sqldt.Tables("items").toArrayofObjectDictionaries() });
|
||||
}
|
||||
|
||||
private async Task<IActionResult> HandleDatev(string fn, string id, string code)
|
||||
{
|
||||
if (!DateTime.TryParseExact(Form("tgt"), "yy-MM-dd",
|
||||
CultureInfo.InvariantCulture, DateTimeStyles.AllowWhiteSpaces, out var tgtdate))
|
||||
return BadRequest400();
|
||||
var dset = await getSQLDataSet_async(
|
||||
"EXECUTE [dbo].[fds__getDatevExports] @tgtdate, @mode, @authuser;",
|
||||
_intranet.Intranet__SQLConnectionString,
|
||||
StdParamlist(SQL_Date("@tgtdate", tgtdate), SQL_VarChar("@mode", Form("mode").ne("m"))),
|
||||
tablenames: new[] { "files", "invoices", "debits" },
|
||||
Security: DbSec, options: SqlOpt(fn, id, code));
|
||||
return await JSONAsync(new
|
||||
{
|
||||
files = dset.Tables("files").toArrayofObjectDictionaries(),
|
||||
invoices = dset.Tables("invoices").toArrayofObjectDictionaries()
|
||||
});
|
||||
}
|
||||
|
||||
private async Task<IActionResult> HandleReportDoc(string fn, string id, string code, string reportid)
|
||||
{
|
||||
byte[]? content = null;
|
||||
var file = _mfr.GetReportDoc(ref content, reportid);
|
||||
if (file == null) return StatusCode(404, new { error = "Dokument wurde nicht gefunden" });
|
||||
return Form("typ") != "img"
|
||||
? await FileContentResultAsync(content!, file.MimeType(), file.Name)
|
||||
: await JSONAsync(new { id = reportid, img = await BuildPdfImageArray(content!) });
|
||||
}
|
||||
|
||||
private async Task<IActionResult> HandleReportDocByName(string fn, string id, string code)
|
||||
{
|
||||
if (!HasForm("name")) return BadRequest400();
|
||||
string nme = Form("name").LeftToFirst("(").Trim();
|
||||
if (string.IsNullOrEmpty(nme)) return StatusCode(404);
|
||||
var so = await getSQLValue_async(
|
||||
"SELECT [dbo].[fds__fn_InvoiceIdByName](@nme);",
|
||||
_intranet.Intranet__SQLConnectionString,
|
||||
StdParamlist(SQL_VarChar("@nme", nme)),
|
||||
Security: DbSec, options: SqlOpt(fn, id, code));
|
||||
string reportid = so.Result?.ToString() ?? "";
|
||||
return string.IsNullOrEmpty(reportid)
|
||||
? StatusCode(404)
|
||||
: await HandleReportDoc(fn, id, code, reportid);
|
||||
}
|
||||
|
||||
private async Task<IActionResult> HandleDatevZip(string fn, string id, string code)
|
||||
{
|
||||
if (!DateTime.TryParseExact(Form("tgt"), "yy-MM-dd",
|
||||
CultureInfo.InvariantCulture, DateTimeStyles.AllowWhiteSpaces, out var tgtdate))
|
||||
return BadRequest400();
|
||||
Stream? ms = new MemoryStream();
|
||||
var file = _mfr.GetDatevZip(ref ms, tgtdate,
|
||||
mode: Form("mode").ne("m"),
|
||||
authUser: UserAccountID,
|
||||
includeFiles: Form("files", "1") != "0");
|
||||
if (file == null) return BadRequest400();
|
||||
ms!.Position = 0;
|
||||
return await FileStreamResultAsync(ms, file.MimeType(), file.Name);
|
||||
}
|
||||
|
||||
private async Task<IActionResult> HandleGetReminder(string fn, string id, string code)
|
||||
{
|
||||
if (!HasForm("id")) return BadRequest400();
|
||||
var pl = StdParamlist(
|
||||
SQL_VarChar("@InvId", Form("id")),
|
||||
SQL_Bit("@include_drafts", Form("drafts")));
|
||||
var sqldt = await getSQLDataSet_async(
|
||||
"EXECUTE [dbo].[fds__getInvoiceReminder] @InvId, @include_drafts, @authuser;",
|
||||
_intranet.Intranet__SQLConnectionString, pl,
|
||||
tablenames: new[] { "reminder" },
|
||||
Security: DbSec, options: SqlOpt(fn, id, code));
|
||||
return await JSONAsync(sqldt.Table("reminder").DataTable.toArrayofObjectDictionaries());
|
||||
}
|
||||
|
||||
// -- Shared builder helpers ------------------------------------------------
|
||||
private static List<Dictionary<string, object?>> BuildInvoiceRequestList(SQLDataSet sqldset)
|
||||
{
|
||||
var ldic = new List<Dictionary<string, object?>>();
|
||||
foreach (System.Data.DataRow rq in sqldset.Tables("req").Select("",
|
||||
sqldset.Tables("req").Columns.Contains("order") ? "order" : ""))
|
||||
{
|
||||
var rdic = rq.toObjectDictionary();
|
||||
var sdic = new Dictionary<string, object?>
|
||||
{
|
||||
["Id"] = rdic["mfr__servicerequest"],
|
||||
["InvRqId"] = rdic["Id"],
|
||||
["text"] = HttpUtility.HtmlDecode(rdic["title"]?.ToString() ?? "")
|
||||
};
|
||||
if (sqldset.Contains("itm"))
|
||||
{
|
||||
var itm = new List<Dictionary<string, object?>>();
|
||||
foreach (System.Data.DataRow sitm in sqldset.Tables("itm").Select(
|
||||
$"[InvRqId] = '{rdic["Id"]}'",
|
||||
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));
|
||||
itm.Add(new Dictionary<string, object?>
|
||||
{
|
||||
["Id"] = d["Id"],
|
||||
["net_val"] = net,
|
||||
["vat_val"] = net * vat * 0.01,
|
||||
["vat"] = vat == 0 ? "" : vat.ToString("0.00", FuchsPdf.DeCulture) + "%",
|
||||
["svcnet_val"] = d.no("value_service", 0),
|
||||
["net"] = d.no("value", 0),
|
||||
["quantity"] = d["Quantity"],
|
||||
["Type"] = d["Type"],
|
||||
["Note"] = null,
|
||||
["htmltext"] = d["Text"],
|
||||
["position"] = d["Position"],
|
||||
["SortOrder"] = d["SortOrder"]
|
||||
});
|
||||
}
|
||||
sdic["items"] = itm;
|
||||
}
|
||||
ldic.Add(sdic);
|
||||
}
|
||||
return ldic;
|
||||
}
|
||||
|
||||
private static async Task<string[]> BuildPdfImageArray(byte[] content)
|
||||
{
|
||||
var imgcol = await FuchsPdf.BytesToImageCollection(content);
|
||||
return imgcol.ImgB64Array;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
using Fuchs.intranet;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using Newtonsoft.Json;
|
||||
using OCORE.pdf;
|
||||
using OCORE.SQL;
|
||||
using static OCORE.commons;
|
||||
using static OCORE.io;
|
||||
using static OCORE.SQL.sql;
|
||||
using static OCORE.web.mvc_helper_async;
|
||||
|
||||
namespace Fuchs.Controllers;
|
||||
|
||||
// Partial class: Reminder processing
|
||||
public partial class IntranetController
|
||||
{
|
||||
private async Task<IActionResult> Do_Process_Reminder(string fn, string id, string code)
|
||||
{
|
||||
switch (id.ToLower())
|
||||
{
|
||||
case "get":
|
||||
{
|
||||
if (!HasForm("id")) return BadRequest400();
|
||||
var pl = StdParamlist(
|
||||
SQL_VarChar("@InvId", Form("id")),
|
||||
SQL_VarChar("@type", Form("type")),
|
||||
SQL_Int("@level", Form("level")));
|
||||
var dset = await getSQLDataSet_async(
|
||||
"EXECUTE [dbo].[fds__prepReminder] @InvId, @authuser, @type, @level;",
|
||||
_intranet.Intranet__SQLConnectionString, pl,
|
||||
tablenames: new[] { "rem" },
|
||||
Security: DbSec, options: SqlOpt(fn, id, code));
|
||||
return await JSONAsync(new { rm = dset.Table("rem").FirstRow.toObjectDictionary() });
|
||||
}
|
||||
|
||||
case "prep":
|
||||
{
|
||||
if (!HasForm("remc")) return BadRequest400();
|
||||
var ctd = JsonConvert.DeserializeObject(Form("remc"))!;
|
||||
var fdRem = new FdsReminderData(ctd);
|
||||
fdRem.RegisterReminder(this, change: false, remId: "");
|
||||
if (!string.IsNullOrEmpty(fdRem.Id))
|
||||
{
|
||||
var imgcol = await FuchsPdf.DocToImageCollection(fdRem.ReminderPDF(this));
|
||||
return await JSONAsync(new { id = fdRem.Id, img = imgcol.ImgB64Array, total = imgcol.TotalPages });
|
||||
}
|
||||
return StatusCode(500, new { error = "Erinnerung wurde nicht registriert" });
|
||||
}
|
||||
|
||||
case "conf": return await HandleReminderConf(fn, id, code);
|
||||
|
||||
case "srs":
|
||||
{
|
||||
if (!HasForm("id")) return BadRequest400();
|
||||
var pl = StdParamlist(SQL_VarChar("@Id", Form("id")), SQL_Bit("@auto", false));
|
||||
var dt2 = await getSQLDataSet_async(
|
||||
"EXECUTE [dbo].[fds__setReminderSent] @Id, @auto, @authuser;",
|
||||
_intranet.Intranet__SQLConnectionString, pl,
|
||||
Security: DbSec, options: SqlOpt(fn, id, code));
|
||||
return string.IsNullOrEmpty(dt2.Exception) ? Ok() : StatusCode(500);
|
||||
}
|
||||
|
||||
case "rdoc":
|
||||
{
|
||||
if (!HasForm("id")) return BadRequest400();
|
||||
byte[]? fc = null;
|
||||
var file = FdsReminderData.GetStoredFile(ref fc, Form("id"), this);
|
||||
if (file == null) 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!) });
|
||||
}
|
||||
|
||||
case "idoc": return await HandleReminderIdoc(fn, id, code);
|
||||
case "resend": return await HandleReminderResend(fn, id, code);
|
||||
|
||||
case "lrem":
|
||||
{
|
||||
if (!HasForm("id")) return BadRequest400();
|
||||
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));
|
||||
return await JSONAsync(new
|
||||
{
|
||||
ov = dset.Table("ov").FirstRow.toStringDictionary(),
|
||||
lst = dset.Tables("rem").toArrayofObjectDictionaries()
|
||||
});
|
||||
}
|
||||
|
||||
default: return Ok();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<IActionResult> HandleReminderConf(string fn, string id, string code)
|
||||
{
|
||||
if (!HasForm("id")) return BadRequest400();
|
||||
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));
|
||||
var frdic = dt.FirstRow.toObjectDictionary();
|
||||
if (frdic.TryGetValue("IsFinal", out var isFinal) && isFinal is true)
|
||||
{
|
||||
string remId = frdic["Id"]?.ToString() ?? "";
|
||||
var fdRem = new FdsReminderData(remId, this);
|
||||
byte[] filebyte = await fdRem.StoreReminderDocumentFile(this);
|
||||
string email = frdic.nz("SendToEmail", "");
|
||||
if (!string.IsNullOrEmpty(email) && filebyte.Length > 0)
|
||||
{
|
||||
var remdoc = new Dictionary<string, byte[]>
|
||||
{ [frdic.nz("DocumentName", "").ne("Zahlungserinnerung.pdf")] = filebyte };
|
||||
if (!string.IsNullOrEmpty(frdic.nz("InvoiceFileName")) &&
|
||||
frdic.no("InvoiceFile", null!) is byte[] invFile)
|
||||
remdoc[frdic.nz("InvoiceFileName")] = invFile;
|
||||
|
||||
bool sent = await FuchsFdsEmail.SendEmail(
|
||||
$"inv_{remId}",
|
||||
$"SanitärFuchs - {frdic.nz("subject").ne(frdic.nz("DocumentName"))}",
|
||||
BuildReminderBody(Convert.ToDouble(frdic.no("amount_open", 0))),
|
||||
email.Trim(), "", remdoc, _intranet);
|
||||
if (sent)
|
||||
{
|
||||
var pls = StdParamlist(SQL_VarChar("@Id", remId), SQL_Bit("@auto", true));
|
||||
await getSQLDatatable_async(
|
||||
"EXECUTE [dbo].[fds__setReminderSent] @Id, @auto, @authuser;",
|
||||
_intranet.Intranet__SQLConnectionString, pls,
|
||||
Security: DbSec, options: SqlOpt(fn, id, code));
|
||||
}
|
||||
}
|
||||
return Ok();
|
||||
}
|
||||
return StatusCode(500, new { error = "Aktion war nicht erfolgreich" });
|
||||
}
|
||||
|
||||
private async Task<IActionResult> HandleReminderIdoc(string fn, string id, string code)
|
||||
{
|
||||
if (!HasForm("id") || string.IsNullOrEmpty(Form("id"))) return StatusCode(404);
|
||||
var fdRem = new FdsReminderData(Form("id"), this);
|
||||
if (string.IsNullOrEmpty(fdRem.Id)) return StatusCode(404, new { error = "Erinnerung wurde nicht gefunden" });
|
||||
string filename = fdRem.ReminderRegistration.nz("DocumentName").ne($"Zahlungserinnerung_{fdRem.Id}.pdf");
|
||||
if (Form("typ") != "img")
|
||||
{
|
||||
byte[] ct = Form("create", "0") != "1"
|
||||
? (await fdRem.GetReminderFile(this)) is { Length: > 0 } f1 ? f1 : await fdRem.StoreReminderDocumentFile(this)
|
||||
: FuchsPdf.DocToPdfBytes(fdRem.ReminderPDF(this));
|
||||
return await FileContentResultAsync(ct, "application/pdf", filename, inline: true);
|
||||
}
|
||||
var imgcol = await FuchsPdf.DocToImageCollection(fdRem.ReminderPDF(this));
|
||||
return await JSONAsync(new { id = fdRem.Id, img = imgcol.ImgB64Array, total = imgcol.TotalPages });
|
||||
}
|
||||
|
||||
private async Task<IActionResult> HandleReminderResend(string fn, string id, string code)
|
||||
{
|
||||
if (!HasForm("id") || string.IsNullOrEmpty(Form("id"))) return StatusCode(404);
|
||||
var pl = StdParamlist(SQL_VarChar("@Id", Form("id")), new SqlParameter("@includefile", true));
|
||||
var dset = await getSQLDataSet_async(
|
||||
"EXECUTE [dbo].[fds__getReminder] @Id, @includefile, @authuser;",
|
||||
_intranet.Intranet__SQLConnectionString, pl,
|
||||
tablenames: new[] { "admin", "inv", "req", "itm" },
|
||||
Security: DbSec, options: SqlOpt(fn, id, code));
|
||||
var frdic = dset.Table("inv").FirstRow.toObjectDictionary();
|
||||
if (frdic.TryGetValue("IsFinal", out var isFinal) && isFinal is true)
|
||||
{
|
||||
string remId = frdic["Id"]?.ToString() ?? "";
|
||||
byte[] filebyte = frdic.no("file", null!) as byte[] ?? Array.Empty<byte>();
|
||||
string email = frdic.nz("SendToEmail", "");
|
||||
if (!string.IsNullOrEmpty(email) && filebyte.Length > 0)
|
||||
{
|
||||
var remdoc = new Dictionary<string, byte[]>
|
||||
{ [frdic.nz("DocumentName", "").ne("Zahlungserinnerung.pdf")] = filebyte };
|
||||
if (!string.IsNullOrEmpty(frdic.nz("InvoiceFileName")) &&
|
||||
frdic.no("InvoiceFile", null!) is byte[] invFile)
|
||||
remdoc[frdic.nz("InvoiceFileName")] = invFile;
|
||||
await FuchsFdsEmail.SendEmail($"rem_{remId}",
|
||||
$"SanitärFuchs - {frdic.nz("subject").ne(frdic.nz("DocumentName"))}",
|
||||
BuildReminderBody(Convert.ToDouble(frdic.no("amount_open", 0))),
|
||||
email.Trim(), "", remdoc, _intranet);
|
||||
}
|
||||
return Ok();
|
||||
}
|
||||
return StatusCode(500, new { error = "Aktion war nicht erfolgreich" });
|
||||
}
|
||||
|
||||
private static string BuildReminderBody(double amountOpen) =>
|
||||
"<p>Sehr geehrte Damen und Herren,<br/>wir vermissen Ihren Zahlungseingang.</p>" +
|
||||
(amountOpen != 0
|
||||
? $"<p>Der offene Betrag beläuft sich auf (inkl. MwSt.): {((float)amountOpen).ToString("0.00 €", FuchsPdf.DeCulture)}</p>"
|
||||
: "<p>Die Erinnerung mit allen Details finden Sie angehängt an diese Email.</p>") +
|
||||
"<p>Bitte überweisen Sie den Rechnungsbetrag innerhalb von einer Woche auf unser Konto:<br/>" +
|
||||
"IBAN: DE76300501100045014800, BIC DUSSSDEDDXXX (Stadtsparkasse Düsseldorf)</p>" +
|
||||
"<p>Wenn Sie mit uns zufrieden waren, empfehlen Sie uns gerne weiter, " +
|
||||
"wenn nicht, dann sagen Sie es uns unter " +
|
||||
"<a href=\"mailto:info@sanitaerfuchs.de\">info@sanitaerfuchs.de</a>.</p>";
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
using Fuchs.intranet;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using OCORE.SQL;
|
||||
using static OCORE.commons;
|
||||
using static OCORE.SQL.sql;
|
||||
using static OCORE.web.mvc_helper_async;
|
||||
|
||||
namespace Fuchs.Controllers;
|
||||
|
||||
// Partial class: Reports processing
|
||||
public partial class IntranetController
|
||||
{
|
||||
private async Task<IActionResult> Do_Process_Reports(string fn, string id, string code)
|
||||
{
|
||||
switch (id.ToLower())
|
||||
{
|
||||
case "auth":
|
||||
return await JSONAsync(new { manage = 1 });
|
||||
|
||||
case "catalog":
|
||||
{
|
||||
var pl = StdParamlist(SQL_VarChar("@report_name", Form("report"), dbNull_IfEmpty: true));
|
||||
var dset = await getSQLDataSet_async(
|
||||
"EXECUTE [dbo].[fds__admin_getReportCatalog] @report_name, @authuser;",
|
||||
_intranet.Intranet__SQLConnectionString, pl,
|
||||
tablenames: new[] { "reports", "params", "categories", "tags" },
|
||||
Security: DbSec, options: SqlOpt(fn, id, code));
|
||||
|
||||
var reps = dset.Tables("reports").toArrayofObjectDictionaries();
|
||||
foreach (var ri in reps)
|
||||
{
|
||||
try
|
||||
{
|
||||
ri["params"] = dset.Tables("params")
|
||||
.toArrayofObjectDictionaries($"[object_id] = {ri["object_id"]} AND [name] <> '@authuser'");
|
||||
}
|
||||
catch { ri["params"] = Array.Empty<Dictionary<string, object>>(); }
|
||||
}
|
||||
return await JSONAsync(new
|
||||
{
|
||||
reports = reps,
|
||||
categories = dset.Tables("categories").toArrayofObjectDictionaries(),
|
||||
tags = dset.Tables("tags").toArrayofObjectDictionaries()
|
||||
});
|
||||
}
|
||||
|
||||
default:
|
||||
return await FuchsReports.ProcessFdsRequest(this, id.ToLower(), code);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,349 @@
|
||||
using System.Globalization;
|
||||
using Fuchs.intranet;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using MFR_RESTClient.generic;
|
||||
using Newtonsoft.Json;
|
||||
using OCORE.pdf;
|
||||
using OCORE.SQL;
|
||||
using static OCORE.commons;
|
||||
using static OCORE.io;
|
||||
using static OCORE.SQL.sql;
|
||||
using static OCORE.web.mvc_helper_async;
|
||||
|
||||
namespace Fuchs.Controllers;
|
||||
|
||||
// Partial class: Service request processing
|
||||
public partial class IntranetController
|
||||
{
|
||||
private async Task<IActionResult> Do_Process_Requests(string fn, string id, string code)
|
||||
{
|
||||
switch (id.ToLower())
|
||||
{
|
||||
case "auth":
|
||||
return await JSONAsync(new { manage = 1 });
|
||||
|
||||
case "rthd":
|
||||
{
|
||||
if (!HasForm("id")) return BadRequest400();
|
||||
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" });
|
||||
var dic = sqldt.FirstRow.toObjectDictionary();
|
||||
return await JSONAsync(new { id = dic["EntityId"], visible = dic.no("hidden", false) is not true });
|
||||
}
|
||||
|
||||
case "reql": return await HandleRequestList(fn, id, code);
|
||||
case "pget": return await HandleRequestPget(fn, id, code);
|
||||
case "get": return await HandleRequestGet(fn, id, code);
|
||||
case "iget": return await HandleRequestIget(fn, id, code);
|
||||
|
||||
case "save":
|
||||
{
|
||||
if (!HasForm("invc")) return BadRequest400();
|
||||
var fdInv = new FdsInvoiceData(JsonConvert.DeserializeObject(Form("invc"))!);
|
||||
fdInv.RegisterInvoice(this, change: !string.IsNullOrEmpty(Form("id")), invId: Form("id"));
|
||||
return !string.IsNullOrEmpty(fdInv.Id)
|
||||
? await JSONAsync(new { id = fdInv.Id })
|
||||
: StatusCode(500, new { error = "Rechnung wurde nicht gespeichert" });
|
||||
}
|
||||
|
||||
case "sprep":
|
||||
{
|
||||
if (!HasForm("invc")) return BadRequest400();
|
||||
var fdInv = new FdsInvoiceData(JsonConvert.DeserializeObject(Form("invc"))!);
|
||||
fdInv.RegisterInvoice(this, change: false, invId: "");
|
||||
if (!string.IsNullOrEmpty(fdInv.Id))
|
||||
{
|
||||
var imgcol = await FuchsPdf.DocToImageCollection(fdInv.InvoicePDF(this));
|
||||
return await JSONAsync(new { id = fdInv.Id, img = imgcol.ImgB64Array, total = imgcol.TotalPages });
|
||||
}
|
||||
return StatusCode(500, new { error = "Rechnung wurde nicht registriert" });
|
||||
}
|
||||
|
||||
case "sedit":
|
||||
{
|
||||
if (!HasForm("id", "invc")) return BadRequest400();
|
||||
var fdInv = new FdsInvoiceData(JsonConvert.DeserializeObject(Form("invc"))!);
|
||||
fdInv.RegisterInvoice(this, change: true, invId: Form("id"));
|
||||
if (!string.IsNullOrEmpty(fdInv.Id))
|
||||
{
|
||||
var imgcol = await FuchsPdf.DocToImageCollection(fdInv.InvoicePDF(this));
|
||||
return await JSONAsync(new { id = fdInv.Id, img = imgcol.ImgB64Array, total = imgcol.TotalPages });
|
||||
}
|
||||
return StatusCode(500, new { error = "Rechnung wurde nicht registriert" });
|
||||
}
|
||||
|
||||
case "sdel":
|
||||
if (!HasForm("id")) return BadRequest400();
|
||||
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));
|
||||
return Ok();
|
||||
|
||||
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 Ok();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<IActionResult> HandleRequestList(string fn, string id, string code)
|
||||
{
|
||||
if (!HasForm("mode")) return BadRequest400();
|
||||
string mode = Form("mode").ToLower();
|
||||
if (mode == "s" && Form("tgt").Contains(':'))
|
||||
{
|
||||
var pl = StdParamlist(
|
||||
SQL_Date("@tgtdate", DBNull.Value),
|
||||
SQL_VarChar("@mode", mode),
|
||||
SQL_Bit("@completed", true),
|
||||
SQL_VarChar("@search", Form("tgt")));
|
||||
var dset = await getSQLDataSet_async(
|
||||
"EXECUTE [dbo].[fds__getRequests_list2] @tgtdate, @mode, @completed, @search, @authuser;",
|
||||
_intranet.Intranet__SQLConnectionString, pl,
|
||||
tablenames: new[] { "admin", "requests", "reports" },
|
||||
Security: DbSec, options: SqlOpt(fn, id, code));
|
||||
return await JSONAsync(new
|
||||
{
|
||||
admin = dset.Table("admin").FirstRow.toObjectDictionary(),
|
||||
requests = AttachReports(dset)
|
||||
});
|
||||
}
|
||||
if (!DateTime.TryParseExact(Form("tgt"), "yy-MM-dd",
|
||||
CultureInfo.InvariantCulture, DateTimeStyles.AllowWhiteSpaces, out var tgtdate))
|
||||
return BadRequest400();
|
||||
{
|
||||
var pl = StdParamlist(
|
||||
SQL_Date("@tgtdate", tgtdate),
|
||||
SQL_VarChar("@mode", mode),
|
||||
SQL_Bit("@completed", true));
|
||||
var dset = await getSQLDataSet_async(
|
||||
"EXECUTE [dbo].[fds__getRequests_list] @tgtdate, @mode, @completed, @authuser;",
|
||||
_intranet.Intranet__SQLConnectionString, pl,
|
||||
tablenames: new[] { "admin", "requests", "reports" },
|
||||
Security: DbSec, options: SqlOpt(fn, id, code));
|
||||
return await JSONAsync(new
|
||||
{
|
||||
admin = dset.Table("admin").FirstRow.toObjectDictionary(),
|
||||
requests = AttachReports(dset)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static List<Dictionary<string, object?>> AttachReports(SQLDataSet dset)
|
||||
{
|
||||
var req = new List<Dictionary<string, object?>>(dset.Tables("requests").toArrayofObjectDictionaries()!);
|
||||
foreach (var r in req)
|
||||
{
|
||||
try { r["reports"] = dset.Tables("reports").toArrayofObjectDictionaries($"[requestID] = {r["Id"]}"); }
|
||||
catch { /* no reports table */ }
|
||||
}
|
||||
return req;
|
||||
}
|
||||
|
||||
private async Task<IActionResult> HandleRequestPget(string fn, string id, string code)
|
||||
{
|
||||
if (!HasForm("id") || !long.TryParse(Form("id"), out long tgtid)) return BadRequest400();
|
||||
var dt = await getSQLDatatable_async(
|
||||
"SELECT * FROM [dbo].[fds__getRequestTreeIds](@srqid);",
|
||||
_intranet.Intranet__SQLConnectionString,
|
||||
StdParamlist(SQL_BigInt("@srqid", tgtid)),
|
||||
Security: DbSec, options: SqlOpt(fn, id, code));
|
||||
|
||||
var ids = new List<long> { tgtid };
|
||||
if (dt.Count > 0)
|
||||
{
|
||||
foreach (System.Data.DataRow rw in dt.DataTable.Rows)
|
||||
{
|
||||
long iid = rw.nint64("Id", -1);
|
||||
if (iid > 0 && !ids.Contains(iid)) ids.Add(iid);
|
||||
}
|
||||
}
|
||||
var schemaDic = new Dictionary<string, fds.FdsMfrClient.DatabaseSchema>
|
||||
{
|
||||
[EntityHelper.EntityName(EntityTypes.ServiceRequest)] =
|
||||
new fds.FdsMfrClient.DatabaseSchema(EntityTypes.ServiceRequest)
|
||||
};
|
||||
using var mfr = new fds.FdsMfrClient();
|
||||
await mfr.Update__entitytable(EntityTypes.ServiceRequest,
|
||||
fds.FdsMfr.UpdateNeed.Reset, ids.ToArray(), schemaDic: schemaDic);
|
||||
return Ok();
|
||||
}
|
||||
|
||||
private async Task<IActionResult> HandleRequestGet(string fn, string id, string code)
|
||||
{
|
||||
if (!HasForm("id")) return BadRequest400();
|
||||
string modeVal = Form("mode").ne("ov");
|
||||
string[] tn = modeVal switch
|
||||
{
|
||||
"r" => new[] { "admin", "requests", "inv" },
|
||||
"ful" => new[] { "admin", "requests", "items", "steps", "companies", "locations", "inv" },
|
||||
_ => new[] { "admin", "requests", "items", "inv" }
|
||||
};
|
||||
var pl = StdParamlist(
|
||||
SQL_BigInt("@servicerequestid", Form("id")),
|
||||
SQL_VarChar("@mode", modeVal));
|
||||
var sqldset = await getSQLDataSet_async(
|
||||
"EXECUTE [dbo].[fds__getRequest_details] @servicerequestid, @mode, @authuser;",
|
||||
_intranet.Intranet__SQLConnectionString, pl,
|
||||
tablenames: tn, Security: DbSec, options: SqlOpt(fn, id, code));
|
||||
return await JSONAsync(new
|
||||
{
|
||||
admin = sqldset.Table("admin").FirstRow.toObjectDictionary(),
|
||||
requests = BuildRequestItemList(sqldset),
|
||||
companies = sqldset.Tables("companies").toArrayofObjectDictionaries(),
|
||||
locations = sqldset.Tables("locations").toArrayofObjectDictionaries(),
|
||||
inv = sqldset.Tables("inv").toArrayofObjectDictionaries()
|
||||
});
|
||||
}
|
||||
|
||||
private async Task<IActionResult> HandleRequestIget(string fn, string id, string code)
|
||||
{
|
||||
if (!HasForm("id", "typ")) return BadRequest400();
|
||||
var pl = StdParamlist(
|
||||
SQL_BigInt("@servicerequestid", Form("id")),
|
||||
SQL_VarChar("@mode", Form("mode").ne("ov")),
|
||||
SQL_Char("@type", Form("typ").Substr(0, 1).ToLower()),
|
||||
SQL_VarChar("sel", Form("sel")));
|
||||
var sqldset = await getSQLDataSet_async(
|
||||
"EXECUTE [dbo].[fds__prepInvoice] @servicerequestid, @mode, @authuser, @type, @sel;",
|
||||
_intranet.Intranet__SQLConnectionString, pl,
|
||||
tablenames: new[] { "admin", "requests", "items", "steps", "companies", "locations" },
|
||||
Security: DbSec, options: SqlOpt(fn, id, code));
|
||||
return await JSONAsync(new
|
||||
{
|
||||
admin = sqldset.Table("admin").FirstRow.toObjectDictionary(),
|
||||
requests = BuildRequestItemList(sqldset),
|
||||
companies = sqldset.Tables("companies").toArrayofObjectDictionaries(),
|
||||
locations = sqldset.Tables("locations").toArrayofObjectDictionaries()
|
||||
});
|
||||
}
|
||||
|
||||
private static List<Dictionary<string, object?>> BuildRequestItemList(SQLDataSet sqldset)
|
||||
{
|
||||
var ldic = new List<Dictionary<string, object?>>();
|
||||
foreach (System.Data.DataRow sq in sqldset.Tables("requests").Select("",
|
||||
sqldset.Tables("requests").Columns.Contains("order") ? "order" : ""))
|
||||
{
|
||||
var sdic = sq.toObjectDictionary();
|
||||
if (sqldset.Contains("items"))
|
||||
sdic["items"] = sqldset.Tables("items")
|
||||
.Select($"[ServiceRequestId] = {sdic["Id"]}", sqldset.Tables("items").Columns.Contains("order") ? "order" : "")
|
||||
.Select(r => r.toObjectDictionary()).ToList();
|
||||
if (sqldset.Contains("steps"))
|
||||
sdic["steps"] = sqldset.Tables("steps")
|
||||
.Select($"[ServiceRequestId] = {sdic["Id"]}", sqldset.Tables("steps").Columns.Contains("order") ? "order" : "")
|
||||
.Select(r => r.toObjectDictionary()).ToList();
|
||||
ldic.Add(sdic!);
|
||||
}
|
||||
return ldic;
|
||||
}
|
||||
|
||||
private async Task<IActionResult> HandleRequestSconf(string fn, string id, string code)
|
||||
{
|
||||
if (!HasForm("id")) return BadRequest400();
|
||||
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));
|
||||
var frdic = dt.FirstRow.toObjectDictionary();
|
||||
if (frdic.TryGetValue("IsFinal", out var isFinal) && isFinal is true)
|
||||
{
|
||||
string invId = frdic["Id"]?.ToString() ?? "";
|
||||
var fdInv = new FdsInvoiceData(invId, this);
|
||||
byte[] filebyte = await fdInv.StoreInvoiceDocumentFile(this);
|
||||
var dtset = await getSQLDataSet_async(
|
||||
"EXECUTE [dbo].[fds__getInvoice] @Id, @authuser;",
|
||||
_intranet.Intranet__SQLConnectionString,
|
||||
StdParamlist(SQL_VarChar("@Id", Form("id"))),
|
||||
tablenames: new[] { "admin", "inv", "req", "itm" },
|
||||
Security: DbSec, options: SqlOpt(fn, id, code));
|
||||
frdic = dtset.Table("inv").FirstRow.toObjectDictionary();
|
||||
string email = frdic.nz("SendToEmail", "");
|
||||
if (!string.IsNullOrEmpty(email) && filebyte.Length > 0)
|
||||
{
|
||||
var inv = new Dictionary<string, byte[]> { [frdic.nz("DocumentName")] = filebyte };
|
||||
double bal = Convert.ToDouble(frdic.no("InvoiceBalance", 0));
|
||||
string terms = fdInv.PaymentTerms.Replace("wd", " Werktagen").Replace("d", " Tagen").Replace("wk", " Wochen").ne("10 Tagen");
|
||||
string body = BuildInvoiceBody(bal, terms);
|
||||
bool sent = await FuchsFdsEmail.SendEmail(
|
||||
$"inv_{invId}", $"Sanit\u00e4rFuchs - {frdic.nz("DocumentName")}",
|
||||
body, email.Trim(), "", inv, _intranet);
|
||||
if (sent)
|
||||
{
|
||||
var pls = StdParamlist(SQL_VarChar("@Id", invId), SQL_Bit("@auto", true));
|
||||
await getSQLDatatable_async("EXECUTE [dbo].[fds__setInvoiceSent] @Id, @auto, @authuser;",
|
||||
_intranet.Intranet__SQLConnectionString, pls,
|
||||
Security: DbSec, options: SqlOpt(fn, id, code));
|
||||
}
|
||||
}
|
||||
return Ok();
|
||||
}
|
||||
return StatusCode(500, new { error = "Aktion war nicht erfolgreich" });
|
||||
}
|
||||
|
||||
private async Task<IActionResult> HandleRequestIdoc(string fn, string id, string code)
|
||||
{
|
||||
if (!HasForm("id") || string.IsNullOrEmpty(Form("id"))) return StatusCode(404);
|
||||
var fdInv = new FdsInvoiceData(Form("id"), this);
|
||||
if (string.IsNullOrEmpty(fdInv.Id)) return StatusCode(404, new { error = "Rechnung wurde nicht gefunden" });
|
||||
string filename = fdInv.InvoiceRegistration.nz("DocumentName").ne($"Rechnung_{fdInv.Id}.pdf");
|
||||
if (Form("typ") != "img")
|
||||
{
|
||||
byte[]? ct = Form("create", "0") != "1"
|
||||
? await fdInv.GetInvoiceFile(this) is { Length: > 0 } f1 ? f1 : await fdInv.StoreInvoiceDocumentFile(this)
|
||||
: FuchsPdf.DocToPdfBytes(fdInv.InvoicePDF(this));
|
||||
return ct != null
|
||||
? await FileContentResultAsync(ct, "application/pdf", filename, inline: true)
|
||||
: StatusCode(500, new { error = "Rechnungs-PDF konnte nicht erstellt werden" });
|
||||
}
|
||||
var imgcol = await FuchsPdf.DocToImageCollection(fdInv.InvoicePDF(this));
|
||||
return await JSONAsync(new { id = fdInv.Id, img = imgcol.ImgB64Array, total = imgcol.TotalPages });
|
||||
}
|
||||
|
||||
private async Task<IActionResult> HandleRequestResend(string fn, string id, string code)
|
||||
{
|
||||
if (!HasForm("id") || string.IsNullOrEmpty(Form("id"))) return StatusCode(404);
|
||||
var dtset = await getSQLDataSet_async(
|
||||
"EXECUTE [dbo].[fds__getInvoice] @Id, @authuser;",
|
||||
_intranet.Intranet__SQLConnectionString,
|
||||
StdParamlist(SQL_VarChar("@Id", Form("id"))),
|
||||
tablenames: new[] { "admin", "inv", "req", "itm" },
|
||||
Security: DbSec);
|
||||
var frdic = dtset.Table("inv").FirstRow.toObjectDictionary();
|
||||
if (frdic.TryGetValue("IsFinal", out var isFinal) && isFinal is true)
|
||||
{
|
||||
string invId = frdic["Id"]?.ToString() ?? "";
|
||||
var fdInv = new FdsInvoiceData(invId, this);
|
||||
byte[] filebyte = FuchsPdf.DocToPdfBytes(fdInv.InvoicePDF(this));
|
||||
string email = frdic.nz("SendToEmail", "");
|
||||
if (!string.IsNullOrEmpty(email) && filebyte.Length > 0)
|
||||
{
|
||||
double bal = Convert.ToDouble(frdic.no("InvoiceBalance", 0));
|
||||
string terms = fdInv.PaymentTerms.Replace("wd", " Werktagen").Replace("d", " Tagen").Replace("wk", " Wochen").ne("10 Tagen");
|
||||
await FuchsFdsEmail.SendEmail(
|
||||
$"inv_{invId}", $"Sanit\u00e4rFuchs - {frdic.nz("DocumentName")}",
|
||||
BuildInvoiceBody(bal, terms), email.Trim(), "",
|
||||
new Dictionary<string, byte[]> { [frdic.nz("DocumentName")] = filebyte },
|
||||
_intranet);
|
||||
}
|
||||
return Ok();
|
||||
}
|
||||
return StatusCode(500, new { error = "Aktion war nicht erfolgreich" });
|
||||
}
|
||||
|
||||
private static string BuildInvoiceBody(double balance, string paymentTerms) =>
|
||||
"<p>Sehr geehrte Damen und Herren,<br/>vielen Dank für Ihren Auftrag, wir haben gern für Sie gearbeitet.</p>" +
|
||||
(balance != 0
|
||||
? $"<p>Unsere Dienstleistung stellen wir wie folgt In Rechnung (inkl. MwSt.): {((float)balance).ToString("0.00 €", FuchsPdf.DeCulture)}</p>"
|
||||
: "<p>Die Abrechnung unserer Dienstleistung finden Sie angehängt an diese Email.</p>") +
|
||||
$"<p>Bitte überweisen Sie den Rechnungsbetrag innerhalb von {paymentTerms} auf unser Konto:<br/>" +
|
||||
"IBAN: DE76300501100045014800, BIC DUSSSDEDDXXX (Stadtsparkasse Düsseldorf)</p>";
|
||||
}
|
||||
@@ -0,0 +1,307 @@
|
||||
using System.Web;
|
||||
using Fuchs.intranet;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using MFR_RESTClient.generic;
|
||||
using Newtonsoft.Json;
|
||||
using OCORE.security;
|
||||
using OCORE.SQL;
|
||||
using static OCORE.commons;
|
||||
using static OCORE.OCORE_dictionaries;
|
||||
using static OCORE.SQL.sql;
|
||||
using static OCORE.web.mvc_helper_async;
|
||||
|
||||
namespace Fuchs.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// Fuchs Intranet MVC Controller.
|
||||
/// Handles all intranet requests: authentication, invoices, reminders, requests, banking, reports.
|
||||
/// </summary>
|
||||
public partial class IntranetController : Microsoft.AspNetCore.Mvc.Controller
|
||||
{
|
||||
internal readonly Fuchs_intranet _intranet;
|
||||
internal readonly fds.IFdsMfr _mfr;
|
||||
private readonly ILogger<IntranetController> _logger;
|
||||
private readonly List<string> _allowedNonAuth = new() { "spwc", "spw" };
|
||||
private readonly List<string> _allowedGet = new()
|
||||
{
|
||||
"inv|datevzip", "inv|rdoc", "inv|rdocn",
|
||||
"req|idoc", "req|resend",
|
||||
"rem|idoc", "rem|resend",
|
||||
"bam|up", "mfr", "mfr_update", "todos"
|
||||
};
|
||||
|
||||
private FuchsUserIdentity? _userIdent;
|
||||
private FuchsUserIdentity UserIdent => _userIdent ??= new FuchsUserIdentity(User);
|
||||
|
||||
public string UserAccountID => UserIdent.UserAccountId;
|
||||
public string AuthAccount => UserIdent.Email;
|
||||
|
||||
public IntranetController(Fuchs_intranet intranet, fds.IFdsMfr mfr, ILogger<IntranetController> logger)
|
||||
{
|
||||
_intranet = intranet;
|
||||
_mfr = mfr;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
// ── Standard param list (pre-populates @authuser) ────────────────────────
|
||||
public List<SqlParameter> StdParamlist(params SqlParameter[] extra)
|
||||
{
|
||||
var list = new List<SqlParameter> { SQL_VarChar("@authuser", UserAccountID) };
|
||||
list.AddRange(extra);
|
||||
return list;
|
||||
}
|
||||
|
||||
public List<SqlParameter> StdParamlist(string key, object value, params SqlParameter[] extra)
|
||||
{
|
||||
var list = StdParamlist(extra);
|
||||
list.Insert(0, SQL_VarChar(key, value?.ToString() ?? ""));
|
||||
return list;
|
||||
}
|
||||
|
||||
public DatabaseSecurity DbSec => _intranet.GetDbSecurity(UserAccountID);
|
||||
|
||||
public FIS_SQLOptions SqlOpt(string fn, string id, string code) =>
|
||||
new(new Dictionary<string, object> { ["fn"] = fn, ["id"] = id, ["code"] = code });
|
||||
|
||||
// ── Action helpers ────────────────────────────────────────────────────────
|
||||
protected IActionResult Unauthorized401() => StatusCode(401);
|
||||
protected IActionResult BadRequest400() => BadRequest();
|
||||
protected IActionResult ServerError(string msg = "") => StatusCode(500, new { error = msg });
|
||||
|
||||
// ── Index (GET /) ─────────────────────────────────────────────────────────
|
||||
[AllowAnonymous]
|
||||
public IActionResult Index(string? fn, string? id, string? code) =>
|
||||
View("intranet");
|
||||
|
||||
// ── Do (POST+GET /do/{fn}/{id}/{code}) ─────────────────────────────────
|
||||
[AllowAnonymous]
|
||||
public async Task<IActionResult> Do(string? fn, string? id, string? code)
|
||||
{
|
||||
fn = (fn ?? "").ToLower();
|
||||
id ??= "";
|
||||
code ??= "";
|
||||
bool isGet = HttpContext.Request.Method.Equals("GET", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
if (!UserIdent.IsAuthenticated && !(new string[] { "login","logout" }).Contains(fn.ToLower()) && !_allowedNonAuth.Contains(fn.ToLower()))
|
||||
{
|
||||
if (!_allowedGet.Contains(fn.ToLower()) && !_allowedGet.Contains($"{fn.ToLower()}|{id.ToLower()}"))
|
||||
_logger.LogInformation($"rejected function on do {fn}");
|
||||
return Unauthorized401();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
IActionResult? result = fn.ToLower() switch
|
||||
{
|
||||
"ping" => Ok(),
|
||||
"wdg" => await FuchsWidgets.IntranetWdg(this, id),
|
||||
"todos" => new PhysicalFileResult(
|
||||
Path.Combine(Directory.GetCurrentDirectory(), "Data", "ProjectToDos.html"),
|
||||
"text/html"),
|
||||
"req" => await Do_Process_Requests(fn, id, code),
|
||||
"inv" => await Do_Process_Invoices(fn, id, code),
|
||||
"rem" => await Do_Process_Reminder(fn, id, code),
|
||||
"rep" => await Do_Process_Reports(fn, id, code),
|
||||
"bam" => await Do_Process_Bankings(fn, id, code),
|
||||
"auth" => await HandleAuth(fn, id, code),
|
||||
"spwc" => await HandleSendPasswordCode(fn, id, code),
|
||||
"spw" => await HandleSendPassword(fn, id, code),
|
||||
"account" => await HandleAccount(fn, id, code),
|
||||
"mfr" => await HandleMfr(fn, id, code),
|
||||
"mfr_update" => await HandleMfrUpdate(fn, id, code),
|
||||
"login" => await HandleLogin(fn, id, code),
|
||||
"logout" => await HandleLogout(),
|
||||
_ => null
|
||||
};
|
||||
return result ?? Ok();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_intranet.debug_log("IntranetController.Do", ex, UserAccountID,
|
||||
data: new { fn, id, code });
|
||||
return ServerError();
|
||||
}
|
||||
}
|
||||
|
||||
// ── Auth helper ───────────────────────────────────────────────────────────
|
||||
private async Task<IActionResult> HandleAuth(string fn, string id, string code)
|
||||
{
|
||||
if (!Request.Form.ContainsKey("module")) return BadRequest400();
|
||||
string module = Request.Form["module"].ToString();
|
||||
if (Request.Form["array"] == "1")
|
||||
{
|
||||
var dt = await getSQLDatatable_async(
|
||||
"SELECT * FROM [dbo].[fis_getModuleAuthList](@module, @authuser);",
|
||||
_intranet.Intranet__SQLConnectionString,
|
||||
StdParamlist(SQL_VarChar("@module", module)),
|
||||
Security: DbSec, options: SqlOpt(fn, id, code));
|
||||
return await JSONAsync(dt.DataTable.ToDictionary(KeyColumn: "module", ValueColumn: "auth"));
|
||||
}
|
||||
else
|
||||
{
|
||||
var val = await getSQLValue_async<int>(
|
||||
"SELECT [dbo].[fis_getModuleAuth](@module, @authuser);",
|
||||
_intranet.Intranet__SQLConnectionString, -1,
|
||||
StdParamlist(SQL_VarChar("@module", module)),
|
||||
Security: DbSec, options: SqlOpt(fn, id, code));
|
||||
return await JSONAsync(new { auth = val.Result });
|
||||
}
|
||||
}
|
||||
|
||||
// ── Login / Logout ────────────────────────────────────────────────────────
|
||||
[AllowAnonymous]
|
||||
private async Task<IActionResult> HandleLogin(string fn, string id, string code)
|
||||
{
|
||||
string email = Request.Form["userinfo"].ToString();
|
||||
string password = Request.Form["userpass"].ToString();
|
||||
var row = await _intranet.AuthenticateAsync(email, password);
|
||||
if (row == null)
|
||||
{
|
||||
_logger.LogWarning("Login failed for '{Email}' from {IP}",
|
||||
email, HttpContext.Connection.RemoteIpAddress);
|
||||
_intranet.debug_log("HandleLogin: failed",
|
||||
data: new { email, ip = HttpContext.Connection.RemoteIpAddress?.ToString() });
|
||||
return Unauthorized401();
|
||||
}
|
||||
|
||||
string userId = row.nz("useraccount_id");
|
||||
string userEmail = row.nz("email");
|
||||
int auth = int.TryParse(row.nz("authorization"), out var a) ? a : 0;
|
||||
|
||||
var identity = FuchsUserIdentity.BuildIdentity(userId, userEmail, auth, Fuchs_intranet.AuthScheme);
|
||||
var principal = new System.Security.Claims.ClaimsPrincipal(identity);
|
||||
await HttpContext.SignInAsync(Fuchs_intranet.AuthScheme, principal);
|
||||
return await JSONAsync(new
|
||||
{
|
||||
login = userEmail,
|
||||
useraccount_id = userId,
|
||||
email = userEmail,
|
||||
authorization = auth,
|
||||
requestedaccount = "",
|
||||
accountrequired = false
|
||||
});
|
||||
}
|
||||
|
||||
private async Task<IActionResult> HandleLogout()
|
||||
{
|
||||
await HttpContext.SignOutAsync(Fuchs_intranet.AuthScheme);
|
||||
return Ok();
|
||||
}
|
||||
|
||||
// ── Password helpers ──────────────────────────────────────────────────────
|
||||
private async Task<IActionResult> HandleSendPasswordCode(string fn, string id, string code)
|
||||
{
|
||||
string? lastname = Request.Form["lastname"];
|
||||
string? email = Request.Form["email"];
|
||||
if (string.IsNullOrEmpty(lastname) || string.IsNullOrEmpty(email)) return BadRequest400();
|
||||
|
||||
var row = await _intranet.GetUserAccountByEmailAsync(email);
|
||||
if (row != null && row.nz("email").Length > 5 &&
|
||||
row.nz("name").ToLower().Trim() == lastname.ToLower().Trim() &&
|
||||
row.nz("mobile").Length > 5 && !Request.Host.Host.ToLower().Contains("localhost"))
|
||||
{
|
||||
OCORE.sms.SMS77.Settings.APIKey = _intranet.Intranet__SMS_API_key;
|
||||
using var sms = new OCORE.sms.SMS77.SMS("ProcessWeb");
|
||||
string totp = OCORE.security.TFA.generateTotp_12h(_intranet.Intranet__TOTPsharedsecret_base);
|
||||
if (long.TryParse(row.nz("mobile").Replace("+", "00").Replace(" ", ""), out long smsNum))
|
||||
sms.SendSMS_sync(smsNum,
|
||||
"Zur Bestätigung des Passwortversands auf sanitarfuchs.de, verwenden Sie bitte folgenden Code:" + totp);
|
||||
}
|
||||
return Ok(); // always OK to prevent enumeration
|
||||
}
|
||||
|
||||
private async Task<IActionResult> HandleSendPassword(string fn, string id, string code)
|
||||
{
|
||||
string? lastname = Request.Form["lastname"];
|
||||
string? email = Request.Form["email"];
|
||||
string? totpCode = Request.Form["code"];
|
||||
if (string.IsNullOrEmpty(lastname) || string.IsNullOrEmpty(email) || string.IsNullOrEmpty(totpCode))
|
||||
return BadRequest400();
|
||||
|
||||
if (OCORE.security.TFA.validateTotp_12h(_intranet.Intranet__TOTPsharedsecret_base, totpCode).isVerifiedInTime)
|
||||
{
|
||||
var row = await _intranet.GetUserAccountByEmailAsync(email, includePassword: true);
|
||||
if (row != null && row.nz("email").Length > 5)
|
||||
{
|
||||
await FuchsFdsEmail.SendEmail("pw_" + row.nz("email"),
|
||||
"sanitaerfuchs.de Intranet Passwort",
|
||||
$"<p>Guten Tag {row.nz("firstname")} {row.nz("name")},<br/>Ihr Passwort: {HttpUtility.HtmlEncode(row.nz("password"))}</p>",
|
||||
row.nz("email"), $"{row.nz("firstname")} {row.nz("name")}", null, _intranet);
|
||||
}
|
||||
}
|
||||
return Ok();
|
||||
}
|
||||
|
||||
private async Task<IActionResult> HandleAccount(string fn, string id, string code)
|
||||
{
|
||||
switch (id.ToLower())
|
||||
{
|
||||
case "sms":
|
||||
var row = await _intranet.GetUserAccountByEmailAsync(UserIdent.Email, includePassword: true);
|
||||
if (row != null && row.nz("mobile").Length > 5 && !Request.Host.Host.Contains("localhost"))
|
||||
{
|
||||
OCORE.sms.SMS77.Settings.APIKey = _intranet.Intranet__SMS_API_key;
|
||||
using var sms2 = new OCORE.sms.SMS77.SMS("ProcessWeb");
|
||||
string totp2 = OCORE.security.TFA.generateTotp_3h(_intranet.Intranet__TOTPsharedsecret_base + "3MDR");
|
||||
if (long.TryParse(row.nz("mobile").Replace("+", "00").Replace(" ", ""), out long mob2))
|
||||
sms2.SendSMS_sync(mob2, "Zur Bestätigung der Passwortänderung auf sanitarfuchs.de: " + totp2);
|
||||
}
|
||||
return Ok();
|
||||
|
||||
case "changepassword":
|
||||
string? npw = Request.Form["npw"];
|
||||
string? npwc = Request.Form["npwc"];
|
||||
string? totpCode = Request.Form["code"];
|
||||
if (string.IsNullOrEmpty(npw) || string.IsNullOrEmpty(npwc) || string.IsNullOrEmpty(totpCode))
|
||||
return BadRequest400();
|
||||
if (!OCORE.security.TFA.validateTotp_3h(_intranet.Intranet__TOTPsharedsecret_base + "3MDR", totpCode).isVerifiedInTime)
|
||||
return StatusCode(409, new { error = "sms" });
|
||||
await setSQLValue_async(
|
||||
"EXECUTE [dbo].[fis_admin_setNewPassword] @useraccount_id, @oldpassword, @newpassword, @enc_key;",
|
||||
_intranet.Intranet__SQLConnectionString,
|
||||
new List<SqlParameter>
|
||||
{
|
||||
SQL_VarChar("@useraccount_id", UserAccountID),
|
||||
SQL_VarChar("@oldpassword", Request.Form["opw"].ToString()),
|
||||
SQL_VarChar("@newpassword", npw)
|
||||
},
|
||||
Security: DbSec, options: SqlOpt(fn, id, code));
|
||||
return Ok();
|
||||
}
|
||||
return Ok();
|
||||
}
|
||||
|
||||
private async Task<IActionResult> HandleMfr(string fn, string id, string code)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(UserAccountID) && UserIdent.Authorization > 3)
|
||||
{
|
||||
string path = id + (!string.IsNullOrEmpty(code) ? "/" + code : HttpUtility.UrlDecode(Request.QueryString.Value ?? ""));
|
||||
using var mfrRead = new fds.FdsMfrClient();
|
||||
var result = await mfrRead.ReadOData(path, throwErrorIfNotOk: false);
|
||||
return Content(JsonConvert.SerializeObject(result), "application/json");
|
||||
}
|
||||
return Ok();
|
||||
}
|
||||
|
||||
private async Task<IActionResult> HandleMfrUpdate(string fn, string id, string code)
|
||||
{
|
||||
var et = EntityHelper.EntityValue(Request.Form["type"].ToString());
|
||||
if (et != EntityTypes.none && string.IsNullOrEmpty(Request.Form["need"]))
|
||||
{
|
||||
using var mfrSingle = new fds.FdsMfrClient();
|
||||
await mfrSingle.Update__entitytable(et, fds.FdsMfr.UpdateNeed.Short);
|
||||
return Ok();
|
||||
}
|
||||
if (et != EntityTypes.none && !string.IsNullOrEmpty(Request.Form["need"]))
|
||||
{
|
||||
var need = fds.FdsMfr.UpdateNeedValue(Request.Form["need"].ToString());
|
||||
using var mfr = new fds.FdsMfrClient();
|
||||
await mfr.Update__entitytable(et, updateNeed: need, debugDetails: false);
|
||||
return Ok();
|
||||
}
|
||||
return BadRequest400();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user