Compare commits

...

3 Commits

Author SHA1 Message Date
OlgunR
ba570687b2 Update Workflow-Integration description in Index.cshtml
Revised the description for the "Workflow-Integration" feature
in the `Index.cshtml` file. The previous text, "Durchlauf
definierter Verarbeitungsschritte mit Status-Tracking"
(Execution of defined processing steps with status tracking),
was replaced with "Hier werden Workflow-Schritte durchlaufen
und der Ergebnisbericht erstellt." (Here, workflow steps are
executed, and the result report is generated).
2026-06-02 17:09:11 +02:00
OlgunR
84a4c182e2 Modernize UI with DevExpress icons and improved layout
Updated `Index.cshtml`:
- Added icons and a more descriptive project title.
- Introduced a new introductory paragraph explaining the app's purpose.
- Replaced the old alert section with a detailed workflow explanation.
- Added cards for invoice upload and summary navigation.
- Included a technology stack section with badges for key tools.

Updated `Details.cshtml`:
- Replaced text-based icons with DevExpress icons for titles, buttons, and attachments.
- Improved attachment handling with `<i>` tags and consistent icon usage.
- Updated "No attachments" message to include an icon.

These changes enhance the UI's visual consistency, usability, and professionalism.
2026-06-02 16:56:50 +02:00
OlgunR
a55e53521f Refactor: Remove sample data and add invoice processing
Removed `SampleDataController`, `SampleData`, and `SampleOrder`
classes, along with the `DevExtreme` DataGrid in `Index.cshtml`,
to eliminate reliance on mock data and sample orders.

Updated `Index.cshtml` to introduce a welcome message and
informational section about ZUGFeRD/Factur-X invoice processing,
highlighting features like PDF/A upload, XML extraction, and
result PDF creation. Added navigation links for invoice-related
actions.

Updated `DXApp.TemplateKitProject.csproj` to include a new
`<ItemGroup>` for the `Controllers` folder, preparing the
project structure for future development.
2026-06-02 16:21:18 +02:00
6 changed files with 98 additions and 443 deletions

View File

@@ -1,24 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using DevExtreme.AspNet.Data;
using DevExtreme.AspNet.Mvc;
using DXApp.TemplateKitProject.Models;
using Microsoft.AspNetCore.Mvc;
namespace DXApp.TemplateKitProject.Controllers
{
[Route("api/[controller]")]
public class SampleDataController : Controller
{
[HttpGet]
public object Get(DataSourceLoadOptions loadOptions)
{
return DataSourceLoader.Load(SampleData.Orders, loadOptions);
}
}
}

View File

@@ -27,4 +27,8 @@
<PackageReference Include="Microsoft.Web.LibraryManager.Build" Version="3.0.71" />
</ItemGroup>
<ItemGroup>
<Folder Include="Controllers\" />
</ItemGroup>
</Project>

View File

@@ -1,364 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DXApp.TemplateKitProject.Models
{
internal static class SampleData
{
public static List<SampleOrder> Orders = new List<SampleOrder>() {
new SampleOrder {
OrderID = 10248,
OrderDate = new DateTime(1996, 7, 4),
ShipCountry = "France",
ShipCity = "Reims",
CustomerName = "Paul Henriot"
},
new SampleOrder {
OrderID = 10249,
OrderDate = new DateTime(1996, 7, 5),
ShipCountry = "Germany",
ShipCity = "Münster",
CustomerName = "Karin Josephs"
},
new SampleOrder {
OrderID = 10250,
OrderDate = new DateTime(1996, 7, 8),
ShipCountry = "Brazil",
ShipCity = "Rio de Janeiro",
CustomerName = "Mario Pontes"
},
new SampleOrder {
OrderID = 10251,
OrderDate = new DateTime(1996, 7, 8),
ShipCountry = "France",
ShipCity = "Lyon",
CustomerName = "Mary Saveley"
},
new SampleOrder {
OrderID = 10252,
OrderDate = new DateTime(1996, 7, 9),
ShipCountry = "Belgium",
ShipCity = "Charleroi",
CustomerName = "Pascale Cartrain"
},
new SampleOrder {
OrderID = 10253,
OrderDate = new DateTime(1996, 7, 10),
ShipCountry = "Brazil",
ShipCity = "Rio de Janeiro",
CustomerName = "Mario Pontes"
},
new SampleOrder {
OrderID = 10254,
OrderDate = new DateTime(1996, 7, 11),
ShipCountry = "Switzerland",
ShipCity = "Bern",
CustomerName = "Yang Wang"
},
new SampleOrder {
OrderID = 10255,
OrderDate = new DateTime(1996, 7, 12),
ShipCountry = "Switzerland",
ShipCity = "Genève",
CustomerName = "Michael Holz"
},
new SampleOrder {
OrderID = 10256,
OrderDate = new DateTime(1996, 7, 15),
ShipCountry = "Brazil",
ShipCity = "Resende",
CustomerName = "Paula Parente"
},
new SampleOrder {
OrderID = 10257,
OrderDate = new DateTime(1996, 7, 16),
ShipCountry = "Venezuela",
ShipCity = "San Cristóbal",
CustomerName = "Carlos Hernández"
},
new SampleOrder {
OrderID = 10258,
OrderDate = new DateTime(1996, 7, 17),
ShipCountry = "Austria",
ShipCity = "Graz",
CustomerName = "Roland Mendel"
},
new SampleOrder {
OrderID = 10259,
OrderDate = new DateTime(1996, 7, 18),
ShipCountry = "Mexico",
ShipCity = "México D.F.",
CustomerName = "Francisco Chang"
},
new SampleOrder {
OrderID = 10260,
OrderDate = new DateTime(1996, 7, 19),
ShipCountry = "Germany",
ShipCity = "Köln",
CustomerName = "Henriette Pfalzheim"
},
new SampleOrder {
OrderID = 10261,
OrderDate = new DateTime(1996, 7, 19),
ShipCountry = "Brazil",
ShipCity = "Rio de Janeiro",
CustomerName = "Bernardo Batista"
},
new SampleOrder {
OrderID = 10262,
OrderDate = new DateTime(1996, 7, 22),
ShipCountry = "USA",
ShipCity = "Albuquerque",
CustomerName = "Paula Wilson"
},
new SampleOrder {
OrderID = 10263,
OrderDate = new DateTime(1996, 7, 23),
ShipCountry = "Austria",
ShipCity = "Graz",
CustomerName = "Roland Mendel"
},
new SampleOrder {
OrderID = 10264,
OrderDate = new DateTime(1996, 7, 24),
ShipCountry = "Sweden",
ShipCity = "Bräcke",
CustomerName = "Maria Larsson"
},
new SampleOrder {
OrderID = 10265,
OrderDate = new DateTime(1996, 7, 25),
ShipCountry = "France",
ShipCity = "Strasbourg",
CustomerName = "Frédérique Citeaux"
},
new SampleOrder {
OrderID = 10266,
OrderDate = new DateTime(1996, 7, 26),
ShipCountry = "Finland",
ShipCity = "Oulu",
CustomerName = "Pirkko Koskitalo"
},
new SampleOrder {
OrderID = 10267,
OrderDate = new DateTime(1996, 7, 29),
ShipCountry = "Germany",
ShipCity = "München",
CustomerName = "Peter Franken"
},
new SampleOrder {
OrderID = 10268,
OrderDate = new DateTime(1996, 7, 30),
ShipCountry = "Venezuela",
ShipCity = "Caracas",
CustomerName = "Manuel Pereira"
},
new SampleOrder {
OrderID = 10269,
OrderDate = new DateTime(1996, 7, 31),
ShipCountry = "USA",
ShipCity = "Seattle",
CustomerName = "Karl Jablonski"
},
new SampleOrder {
OrderID = 10270,
OrderDate = new DateTime(1996, 8, 1),
ShipCountry = "Finland",
ShipCity = "Oulu",
CustomerName = "Pirkko Koskitalo"
},
new SampleOrder {
OrderID = 10271,
OrderDate = new DateTime(1996, 8, 1),
ShipCountry = "USA",
ShipCity = "Lander",
CustomerName = "Art Braunschweiger"
},
new SampleOrder {
OrderID = 10272,
OrderDate = new DateTime(1996, 8, 2),
ShipCountry = "USA",
ShipCity = "Albuquerque",
CustomerName = "Paula Wilson"
},
new SampleOrder {
OrderID = 10273,
OrderDate = new DateTime(1996, 8, 5),
ShipCountry = "Germany",
ShipCity = "Cunewalde",
CustomerName = "Horst Kloss"
},
new SampleOrder {
OrderID = 10274,
OrderDate = new DateTime(1996, 8, 6),
ShipCountry = "France",
ShipCity = "Reims",
CustomerName = "Paul Henriot"
},
new SampleOrder {
OrderID = 10275,
OrderDate = new DateTime(1996, 8, 7),
ShipCountry = "Italy",
ShipCity = "Bergamo",
CustomerName = "Giovanni Rovelli"
},
new SampleOrder {
OrderID = 10276,
OrderDate = new DateTime(1996, 8, 8),
ShipCountry = "Mexico",
ShipCity = "México D.F.",
CustomerName = "Miguel Angel Paolino"
},
new SampleOrder {
OrderID = 10277,
OrderDate = new DateTime(1996, 8, 9),
ShipCountry = "Germany",
ShipCity = "Leipzig",
CustomerName = "Alexander Feuer"
},
new SampleOrder {
OrderID = 10278,
OrderDate = new DateTime(1996, 8, 12),
ShipCountry = "Sweden",
ShipCity = "Luleå",
CustomerName = "Christina Berglund"
},
new SampleOrder {
OrderID = 10279,
OrderDate = new DateTime(1996, 8, 13),
ShipCountry = "Germany",
ShipCity = "Frankfurt a.M.",
CustomerName = "Renate Messner"
},
new SampleOrder {
OrderID = 10280,
OrderDate = new DateTime(1996, 8, 14),
ShipCountry = "Sweden",
ShipCity = "Luleå",
CustomerName = "Christina Berglund"
},
new SampleOrder {
OrderID = 10281,
OrderDate = new DateTime(1996, 8, 14),
ShipCountry = "Spain",
ShipCity = "Madrid",
CustomerName = "Alejandra Camino"
},
new SampleOrder {
OrderID = 10282,
OrderDate = new DateTime(1996, 8, 15),
ShipCountry = "Spain",
ShipCity = "Madrid",
CustomerName = "Alejandra Camino"
},
new SampleOrder {
OrderID = 10283,
OrderDate = new DateTime(1996, 8, 16),
ShipCountry = "Venezuela",
ShipCity = "Barquisimeto",
CustomerName = "Carlos González"
},
new SampleOrder {
OrderID = 10284,
OrderDate = new DateTime(1996, 8, 19),
ShipCountry = "Germany",
ShipCity = "Frankfurt a.M.",
CustomerName = "Renate Messner"
},
new SampleOrder {
OrderID = 10285,
OrderDate = new DateTime(1996, 8, 20),
ShipCountry = "Germany",
ShipCity = "Cunewalde",
CustomerName = "Horst Kloss"
},
new SampleOrder {
OrderID = 10286,
OrderDate = new DateTime(1996, 8, 21),
ShipCountry = "Germany",
ShipCity = "Cunewalde",
CustomerName = "Horst Kloss"
},
new SampleOrder {
OrderID = 10287,
OrderDate = new DateTime(1996, 8, 22),
ShipCountry = "Brazil",
ShipCity = "Rio de Janeiro",
CustomerName = "Janete Limeira"
},
new SampleOrder {
OrderID = 10288,
OrderDate = new DateTime(1996, 8, 23),
ShipCountry = "Italy",
ShipCity = "Reggio Emilia",
CustomerName = "Maurizio Moroni"
},
new SampleOrder {
OrderID = 10289,
OrderDate = new DateTime(1996, 8, 26),
ShipCountry = "UK",
ShipCity = "London",
CustomerName = "Victoria Ashworth"
},
new SampleOrder {
OrderID = 10290,
OrderDate = new DateTime(1996, 8, 27),
ShipCountry = "Brazil",
ShipCity = "Sao Paulo",
CustomerName = "Pedro Afonso"
},
new SampleOrder {
OrderID = 10291,
OrderDate = new DateTime(1996, 8, 27),
ShipCountry = "Brazil",
ShipCity = "Rio de Janeiro",
CustomerName = "Bernardo Batista"
},
new SampleOrder {
OrderID = 10292,
OrderDate = new DateTime(1996, 8, 28),
ShipCountry = "Brazil",
ShipCity = "Sao Paulo",
CustomerName = "Anabela Domingues"
},
new SampleOrder {
OrderID = 10293,
OrderDate = new DateTime(1996, 8, 29),
ShipCountry = "Mexico",
ShipCity = "México D.F.",
CustomerName = "Miguel Angel Paolino"
},
new SampleOrder {
OrderID = 10294,
OrderDate = new DateTime(1996, 8, 30),
ShipCountry = "USA",
ShipCity = "Albuquerque",
CustomerName = "Paula Wilson"
},
new SampleOrder {
OrderID = 10295,
OrderDate = new DateTime(1996, 9, 2),
ShipCountry = "France",
ShipCity = "Reims",
CustomerName = "Paul Henriot"
},
new SampleOrder {
OrderID = 10296,
OrderDate = new DateTime(1996, 9, 3),
ShipCountry = "Venezuela",
ShipCity = "Barquisimeto",
CustomerName = "Carlos González"
},
new SampleOrder {
OrderID = 10297,
OrderDate = new DateTime(1996, 9, 4),
ShipCountry = "France",
ShipCity = "Strasbourg",
CustomerName = "Frédérique Citeaux"
}
};
}
}

View File

@@ -1,18 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DXApp.TemplateKitProject.Models
{
public class SampleOrder
{
public int OrderID { get; set; }
public DateTime OrderDate { get; set; }
public string CustomerID { get; set; }
public string CustomerName { get; set; }
public string ShipCountry { get; set; }
public string ShipCity { get; set; }
}
}

View File

@@ -1,28 +1,85 @@
@page
@using DXApp.TemplateKitProject.Models
@model DXApp.TemplateKitProject.Pages.IndexModel
@{
ViewData["Title"] = "Home";
}
<h2 class="content-block">Home</h2>
<div class="content-block">
<h2><i class="dx-icon-product"></i> DevExpress TemplateKit Evaluierungsprojekt</h2>
<p class="lead text-muted">Validierung von DevExpress als Ablösung für GdPicture im Rahmen der E-Rechnungsverarbeitung</p>
@(Html.DevExtreme().DataGrid<SampleOrder>()
.ElementAttr(new { @class = "dx-card wide-card" })
.DataSource(d => d.Mvc().Controller("SampleData").LoadAction("Get").Key("OrderID"))
.ShowBorders(false)
.FilterRow(f => f.Visible(true))
.FocusedRowEnabled(true)
.FocusedRowIndex(0)
.ColumnAutoWidth(true)
.ColumnHidingEnabled(true)
.Columns(columns => {
columns.AddFor(m => m.OrderID);
columns.AddFor(m => m.OrderDate);
columns.AddFor(m => m.CustomerName);
columns.AddFor(m => m.ShipCountry);
columns.AddFor(m => m.ShipCity);
})
.Paging(p => p.PageSize(10))
.Pager(p => p
.ShowPageSizeSelector(true)
.AllowedPageSizes(new[] { 5, 10, 20 })
.ShowInfo(true)
)
)
<div class="alert alert-primary mt-4">
<h4><i class="dx-icon-todo"></i> Projektziel: ZUGFeRD/Factur-X Rechnungsverarbeitung</h4>
<p>Diese Anwendung demonstriert die vollständige Verarbeitungskette für elektronische Rechnungen:</p>
<ol class="mt-3">
<li class="mb-2">
<strong>Upload & Validierung</strong>
<br/>
<small class="text-muted">E-Rechnungen im PDF/A-Format hochladen und auf Konformität prüfen</small>
</li>
<li class="mb-2">
<strong>Extraktion</strong>
<br/>
<small class="text-muted">Automatische Erkennung und Extraktion eingebetteter Anhänge (ZUGFeRD-XML, Bilder, Dokumente)</small>
</li>
<li class="mb-2">
<strong>Datenverarbeitung</strong>
<br/>
<small class="text-muted">Parsing der Rechnungsdaten aus dem ZUGFeRD-XML und persistente Speicherung in der Datenbank</small>
</li>
<li class="mb-2">
<strong>Workflow-Integration</strong>
<br/>
<small class="text-muted">Hier werden Workflow-Schritte durchlaufen und der Ergebnisbericht erstellt.</small>
</li>
<li class="mb-2">
<strong>Ausgabe-Generierung</strong>
<br/>
<small class="text-muted">Erstellung einer Result-PDF mit Verarbeitungsstempel und angehängtem Ergebnisbericht</small>
</li>
<li class="mb-2">
<strong>Visualisierung</strong>
<br/>
<small class="text-muted">Interaktive Anzeige aller Anhänge (XML mit Syntax-Highlighting, PDF-Viewer, Bilder)</small>
</li>
</ol>
</div>
<div class="row mt-4">
<div class="col-md-6">
<div class="card">
<div class="card-body">
<h5 class="card-title"><i class="dx-icon-upload"></i> Rechnungen hochladen</h5>
<p class="card-text">Laden Sie ZUGFeRD-konforme E-Rechnungen hoch und starten Sie die automatische Verarbeitung.</p>
<a href="/Invoices/Upload" class="btn btn-primary">
<i class="dx-icon-upload"></i> Zum Upload
</a>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card">
<div class="card-body">
<h5 class="card-title"><i class="dx-icon-chart"></i> Rechnungsübersicht</h5>
<p class="card-text">Zeigen Sie alle importierten Rechnungen an und greifen Sie auf Details und Anhänge zu.</p>
<a href="/Invoices" class="btn btn-secondary">
<i class="dx-icon-doc"></i> Zur Übersicht
</a>
</div>
</div>
</div>
</div>
<div class="alert alert-light mt-4">
<h6 class="mb-2"><i class="dx-icon-preferences"></i> Technologie-Stack</h6>
<div class="d-flex flex-wrap gap-2">
<span class="badge bg-secondary">ASP.NET Core 8.0</span>
<span class="badge bg-secondary">DevExpress v25.2</span>
<span class="badge bg-secondary">Entity Framework Core</span>
<span class="badge bg-secondary">PDF.js</span>
<span class="badge bg-secondary">CodeMirror</span>
<span class="badge bg-secondary">SQL Server</span>
</div>
</div>
</div>

View File

@@ -11,14 +11,14 @@
}
}
<h2>📄 Rechnungsdetails</h2>
<a href="/Invoices" class="btn btn-secondary mb-3"> Zurück zur Liste</a>
<h2><i class="dx-icon-doc"></i> Rechnungsdetails</h2>
<a href="/Invoices" class="btn btn-secondary mb-3"><i class="dx-icon-back"></i> Zurück zur Liste</a>
@if (!string.IsNullOrEmpty(Model.Invoice?.ResultFilePath))
{
<button class="btn btn-primary mb-3 ms-2"
onclick="openPdfViewer(@Model.Invoice.Id)">
📄 Ergebnis anzeigen
<i class="dx-icon-pdffile"></i> Ergebnis anzeigen
</button>
}
@@ -60,26 +60,26 @@ else
@* Anhänge-Sektion *@
@if (Model.Invoice.Attachments.Any())
{
<h4 class="mt-4">📎 Anhänge (@Model.Invoice.Attachments.Count)</h4>
<h4 class="mt-4"><i class="dx-icon-attach"></i> Anhänge (@Model.Invoice.Attachments.Count)</h4>
<div class="list-group">
@foreach (var attachment in Model.Invoice.Attachments)
{
var icon = attachment.IsZugferdXml ? "📋" : "📄";
var icon = "dx-icon-file";
var extension = System.IO.Path.GetExtension(attachment.OriginalFileName).ToLowerInvariant();
icon = extension switch
{
".xml" => "📋",
".pdf" => "📄",
".jpg" or ".jpeg" or ".png" or ".gif" => "🖼️",
".txt" => "📝",
_ => "📎"
".xml" => "dx-icon-exportxlsx",
".pdf" => "dx-icon-pdffile",
".jpg" or ".jpeg" or ".png" or ".gif" => "dx-icon-image",
".txt" => "dx-icon-txtfile",
_ => "dx-icon-file"
};
<a href="javascript:void(0);"
class="list-group-item list-group-item-action d-flex justify-content-between align-items-center"
onclick="openAttachmentViewer('@attachment.OriginalFileName', '@Uri.EscapeDataString(attachment.SavedFilePath)', '@extension')">
<div>
<span class="me-2">@icon</span>
<i class="@icon me-2"></i>
<strong>@attachment.OriginalFileName</strong>
@if (attachment.IsZugferdXml)
{
@@ -98,7 +98,7 @@ else
}
else
{
<h4 class="mt-4">📎 Anhänge</h4>
<h4 class="mt-4"><i class="dx-icon-attach"></i> Anhänge</h4>
<div class="alert alert-info">Keine Anhänge extrahiert.</div>
}