Zum Hauptinhalt springen

Import (Import-Jobs)

Zweck

Die /import-Route ist die Detail-Sicht laufender und vergangener Import-Jobs (DataImportJob). Pro Job werden Datei-Verweis, Ziel-Modell (targetModel, z. B. Customer, Product), Modus (upsert, insert, ...), Mapping (Spalten-Zuordnung), Match-Keys (eindeutige Identifikation pro Datensatz) und Optionen gepflegt. Der Status (pending, running, completed, failed) wird mit progress-Daten zu totalRows, processedRows, createdRows, updatedRows angezeigt.

/import/history zeigt vergangene Jobs.

Voraussetzungen

- Berechtigung `view:DataImportJob` und `create:DataImportJob`. - Datei-Upload-Berechtigung (`create:Document`). - Geeignete Quell-Datei (CSV, Excel, JSON).

Berechtigungen (CASL)

ActionSubjectWirkungKeycloak-Rolle
viewFE_Import, DataImportJobListe/Detail aufrufbar
createDataImportJobNeuen Import startenAPP_SPEAMCORE_CREATE_DATA_IMPORT_JOB
cancelDataImportJobLaufenden Import abbrechenAPP_SPEAMCORE_CANCEL_DATA_IMPORT_JOB

Schritt-für-Schritt-Anleitung

Neuen Import anlegen

  1. Import (/import) → + Neu.
  2. Quell-Datei hochladen — wird als Document gespeichert.
  3. targetModel wählen (z. B. Customer, Product, SalesDocument).
  4. mode wählen — insert (nur neue), update (nur bestehende), upsert (beide).
  5. Mapping pflegen — Spalten der Quell-Datei auf Felder des Ziel-Modells abbilden. Auto-Match-Vorschläge werden angeboten.
  6. Match-Keys wählen — z. B. email, customerNumber — Felder, die einen Datensatz eindeutig identifizieren.
  7. Optionen einstellen (z. B. skipErrors, dryRun).
  8. Vor dem Start: optional POST /api/import/preview für einen vollständigen Trockenlauf — analysiert alle Zeilen, klassifiziert sie als CREATE / UPDATE / ERROR, läuft Fuzzy-Name-Search gegen bestehende Stammdaten (Employee, Branch, PaymentTarget) mit Similarity-Score. Ergebnis fliesst in das Pre-Import-Mapping-Modal des FE — User kann Override-Zuordnungen setzen, die beim eigentlichen Import berücksichtigt werden.
  9. Start klicken — POST /api/data-import-jobs/:id/start. Bei dryRun=true im Upload-Payload läuft der Job durch alle Schritte, schreibt aber nichts in die DB; End-Status ist dry_run_completed.

Fortschritt verfolgen

Detail-Sicht zeigt einen Progress-Block mit processedRows / totalRows, sowie Counts für createdRows und updatedRows. Bei Fehlern: Drill-Down in die Fehler-Liste pro Zeile.

Abbrechen

Bei laufendem Job (status = running) ist der Button Abbrechen sichtbar — POST /api/data-import-jobs/:id/cancel.

Listenansicht — import

Felder und Eingaben

FeldnamePflichtDatentypWirkung beim AusfuellenVoraussetzung
targetModeljaStringModellname (z. B. Customer, Product).
modejaENUM (insert, update, upsert)Steuert, ob neu, geändert oder beides.
fileNamejaStringOriginal-Datei-Name.
documentIdneinUUID (Document)Verweis auf hochgeladene Quell-Datei.view:Document.
mappingjaJSONMapping Quell-Spalte → Ziel-Feld.
matchKeysneinArrayEindeutigkeits-Kriterien.
optionsneinJSONKonfiguration (skipErrors, dryRun, ...).

Job-Progress (read-only)

FeldnameDatentypBedeutung
job.statusENUM (pending, running, completed, failed, dry_run_completed)Lebenszyklus. dry_run_completed zeigt einen Trockenlauf an — alle Validierungen + Fuzzy-Matches durchgelaufen, aber keine DB-Writes.
job.progress.totalRowsIntegerAnzahl Zeilen in Quelldatei.
job.progress.processedRowsIntegerBearbeitete Zeilen.
job.progress.createdRowsIntegerAnzahl neu angelegter Datensaetze.
job.progress.updatedRowsIntegerAnzahl aktualisierter Datensaetze.

Mapping-Wizard — erweiterte Optionen (Juni 2026)

Der Mapping-Schritt des Import-Wizards (/import, /api/import/*) hat vier zusätzliche Werkzeuge bekommen, die die reine Spalte→Feld-Zuordnung ergänzen. Alle werden im Mapping-Schritt konfiguriert, in Vorschau und Validierung berücksichtigt und lassen sich als Vorlage (Template) speichern und mandantenübergreifend wiederverwenden.

Einheiten zuordnen (Unit-Mapping)

Über das Modal „Einheiten zuordnen" werden die Rohwerte einer Einheiten-Spalte (z. B. Stk, Pkg) auf SpeamCore-Units gemappt:

  1. SpeamCore scannt die eindeutigen Werte der Spalte (POST /api/import/column-values).
  2. Eine Heuristik schlägt Treffer vor — zuerst über deutsche Alias-Listen (z. B. stk → Stück/piece), dann über Abkürzung/Name/Code, zuletzt partiell.
  3. Pro Wert lässt sich die Ziel-Einheit frei wählen; ein „KI-Vorschlag"-Button nutzt ein Sprachmodell als Fallback (POST /api/import/suggest-units).
  4. Gespeichert wird als unitMappings (value, unitLabel, unitId). unitLabel ist ein mandantenübergreifend stabiles Label, damit Vorlagen auch in anderen Mandanten greifen.
Seit der zentralen Einheiten-Tabelle (eRechnung) ist `Unit` **nicht** mehr auto-anlegbar. Einheiten können nur noch **ausgewählt** werden; ein nicht zugeordneter Wert bleibt leer, statt eine „Junk-Einheit" zu erzeugen. Andere Referenzen (Hersteller, Lieferant, Produkttyp, Warengruppe, Kunde) bleiben bei `autoCreateReferences` weiterhin auto-anlegbar.

Felder kombinieren (Combine Fields)

Eine Template-Engine führt mehrere Quellspalten (plus Literaltext/HTML) zu einem Zielfeld zusammen. Im „Kombinieren"-Modal wird ein Template mit {Spaltenname}-Tokens gepflegt (farblich hervorgehoben, mit Live-Zeilen-Vorschau):

  • Beispiel Zielfeld description, Template `{Bezeichnung2}<br/>{Bezeichnung3}` — verbindet zwei Spalten mit Zeilenumbruch. Echte Zeilenumbrüche im Template werden zu <br/>.
  • FK-Auflösung: Auch Referenzfelder funktionieren — Ziel manufacturerId mit Template `{manufName}` löst den Namen auf die ID auf.
  • Ein kombiniertes Zielfeld kann selbst als Match-Key dienen.
  • Spalten, die nur in Combine-Templates vorkommen, werden nicht zusätzlich als Produkt-Attribut angelegt.

Gespeichert als combineRules (target, template). Die Vorschau (/api/import/preview) wendet die Regeln an, damit Match-Keys korrekt aufgelöst werden.

Lieferant zuordnen (Supplier-Config)

Beim Produkt-Import verknüpft die Box „Lieferant zuordnen" den Import mit einem Lieferanten und legt/aktualisiert pro Produkt einen ProductSupplier (siehe Produkt — Lieferanten und das Konzept Produkt-Lieferanten-Preise). Lieferanten-spezifische Spalten werden über __supplier__:-Mapping-Targets zugeordnet:

TargetBedeutung
__supplier__:articleNoArtikelnummer beim Lieferanten
__supplier__:priceEinkaufspreis (EK)
__supplier__:salePriceVerkaufspreis (VK)
__supplier__:discountRabatt je Produkt
__supplier__:discountablerabattfähig (Ja/Nein) je Zeile
__supplier__:deliveryTimeDays / :stock / :minimumOrderQuantity / :packagingUnitLieferzeit, Bestand, Mindestmenge, Verpackungseinheit

Konfiguriert wird über supplierConfig: discountType (percentage/fixed/none), discountableTrueValue (Spezialwert der Rabattfähig-Spalte, z. B. „Ja"), salePriceFallbackMarkupPercent (VK-Aufschlag, falls VK ≤ EK oder fehlt), supplierDiscount und mainSupplier (Hauptlieferant). DATANORM-Dateien füllen Lieferant + Artikelnummer/Preis automatisch vor. Die Rabatt-Fallback-Kette ist Produkt → Warengruppe → Lieferant.

Sind Lieferanten-Spalten gemappt, aber kein Lieferant zugeordnet, bricht die Validierung mit einem Hinweis ab.

Warengruppen-Typ & Hierarchie (ProductGroup)

Ist productGroupId gemappt, stehen zwei Optionen bereit:

  • productGroupType (internal / external, Default external) — Typ neu angelegter Warengruppen.
  • productGroupHierarchy + productGroupHierarchySeparator (Default >) — interpretiert einen Spaltenwert als Pfad: `Brandschutz > Melder > Rauchmelder` legt verschachtelte Warengruppen an und hängt das Produkt an das Blatt.

Neue Mapping-Optionen (Übersicht)

OptionDatentypWirkungVoraussetzung
unitMappingsObjekt[] (value, unitLabel, unitId)Einheiten-Rohwerte → UnitEinheiten-Spalte gemappt
combineRulesObjekt[] (target, template)mehrere Spalten → ein Zielfeld
supplierConfigObjektLieferanten-Zuordnung + Rabatt/VK-LogikProdukt-Import, __supplier__:-Targets
productGroupTypeinternal / externalTyp neuer WarengruppenproductGroupId gemappt
productGroupHierarchyBooleanPfad-Interpretation der Warengruppen-SpalteproductGroupId gemappt
productGroupHierarchySeparatorString (max 5)Pfad-Trennzeichen (Default >)productGroupHierarchy = true
autoCreateReferencesBooleanfehlende FK-Referenzen automatisch anlegen (außer Unit)
autoMapUnmappedAsAttributesBooleannicht gemappte Spalten als Produkt-AttributeProdukt-Import

Endpoints des Mapping-Wizards (Auswahl)

MethodeEndpointZweckCASL
POST/api/import/column-valueseindeutige Werte einer Spalte (Unit-Modal)create Import
POST/api/import/suggest-unitsKI-Vorschlag für Einheiten-Zuordnungcreate Import
POST/api/import/preview-referencesVorschau der FK-Auflösung/-Anlageview Import
POST/api/import/previewZeilen-Vorschau (wendet combineRules an)view Import
POST/api/import/executeImport ausführen (alle Optionen im Body)create Import

ARGE 10.0 — Hersteller-Produktdaten importieren (Juni 2026)

Neben CSV/Excel/GAEB/DATANORM versteht der Import jetzt das ARGE-10.0-/DQR-10.0-Format — die Hersteller-Stammdaten-Pakete von building-masterdata.com (ARGE Neue Medien e. V.). Ein Hersteller-Paket ist ein ZIP mit mehreren relationalen CSVs (Kopfdaten, Artikel, Gruppen, Langtexte …), die über die Werksartikelnummer verknüpft werden — entpackt schnell mehrere hundert MB.

Format-Eigenschaften (DQR 10.0): UTF-8, Trennzeichen ;, Anführungszeichen ", Dezimaltrenner ,, Datumsformat DDMMYYYY. In der ersten Ausbaustufe werden die wichtigsten Felder aus der Artikel-Stammdatei auf Produkt + Attribute gemappt.

Wegen der Dateigröße verarbeitet ein **Hintergrund-Worker** (`import-wizard-worker`, Sperrdauer bis 10 Minuten pro Job) das ARGE-Paket entkoppelt vom Upload. Der Import-Wizard zeigt dabei eine **Live-Vorschau** und behandelt Fehler je Datensatz, ohne den ganzen Lauf abzubrechen; bereits vorhandene Datensätze werden in der Vorschau entsprechend gekennzeichnet.

Wiederverwendbare Konzepte

Verknuepfungen zu anderen Modulen

  • Datentransfer — Universal-Page, über die Imports gestartet werden.
  • Document-Center — speichert die Quell-Datei.
  • Produkt-Import (/product-import) — spezialisierte Import-Variante (siehe Kontext-Notiz unten). Keine eigene Doku-Seite (Stand: noch nicht migriert).
**Hinweis: Produkt-Import als Sonderfall.** Es existiert eine eigene Route `/product-import` mit `/product-import/status` für den Produkt-Datenimport — dort wird ein vereinfachter Workflow speziell für das Modell `Product` angeboten. Die generische Import-Pipeline auf `/import` ist breiter angelegt und unterstützt alle Modelle.

API/Schnittstellen

MethodeEndpointZweckCASL
GET/api/data-import-jobsListeview DataImportJob
GET/api/data-import-jobs/:idDetailview DataImportJob
POST/api/data-import-jobsAnlegencreate DataImportJob
POST/api/data-import-jobs/:id/startStartcreate DataImportJob
POST/api/data-import-jobs/:id/cancelAbbrechencancel DataImportJob
GET/api/data-import-jobs/historyHistorieview DataImportJob

CSV-Bulk-Import (Mai 2026)

Parallel zur oben beschriebenen DataImportJob-Pipeline gibt es seit Mai 2026 eine eigene CSV-Bulk-Import-Route-Familie (/imports/*, Modell CsvImportJob), die per Worker + Queue arbeitet und 13 Ziel-Modelle über pro-Entity-Konfigurationen unterstützt.

MethodeEndpointZweckCASL
POST/imports/uploadCSV hochladen + Job queuen (CSV als String, Default-Trennzeichen ;)create:ImportJob
POST/imports/previewVorschau-/Trockenlauf ohne DB-Writeview:ImportJob
GET/importsJob-Liste (paginiert)view:ImportJob
GET/imports/:idJob-Detailview:ImportJob
PATCH/imports/:idJob abbrechen (status=cancelled)update:ImportJob

Unterstützte Ziel-Modelle: Customer, Location, Employee, Branch, Supplier, Workorder, SalesDocument, SalesDocumentItem, EmployeeTimeTracking, EmployeeTimeTrackingType, PurchaseDocument, PurchaseDocumentItem, PaymentTarget.

Identität: Spalte _externalId ist der stabile Schlüssel. Dokument-Modelle (SalesDocument, PurchaseDocument, EmployeeTimeTracking) matchen ausschließlich über _externalId; Stammdaten zusätzlich über Business-Key (Name etc.).

Fuzzy-Matching (nur Employee, Branch, PaymentTarget): wort-basiert mit Zahlen-Präfix-Strip; Score = passende Wörter ÷ Gesamtwörter; ≥ 0,5 → Vorschlag, ≥ 0,8 → Auto-Promote.

DryRun: dryRun-Flag im Upload-Body, ephemer (nicht im Modell persistiert). Preview-Response enthält summary (willCreate/willUpdate/willSkip/willError), matches[], unmatchedRows[] mit possibleMatches, allEntities[].

Post-Import-Hook refreshAddressSnapshot: frischt nach dem Import die denormalisierten Parent-Adressfelder bei SalesDocument, PurchaseDocument, Workorder auf (Import läuft mit hooks:false aus Performance-Gründen, daher manueller Refresh).

Versionshinweise

  • 2026-06-30: DATANORM-Import großer Bestände verbessert — disk-basierte Zwischenspeicherung der Artikel-/Preis-Maps (konstanter Speicherbedarf statt Abbruch bei sehr großen Katalogen wie GC) und wiederaufnehmbare Verarbeitung nach Unterbrechung; Fix: Mehr-Monats-Archive (Format DATANORM-25.001) werden jetzt korrekt nach Datum sortiert (vorher gleiche Sortierung → falsche Reihenfolge). Verifiziert an datanormMetadataDiskStore.ts, datanormParser.ts.
  • 2026-06-24: ARGE-10.0-/DQR-10.0-Import (Hersteller-Stammdaten-Pakete von building-masterdata.com, Multi-CSV-ZIP via Werksartikelnummer) dokumentiert; großvolumige Importe laufen über den import-wizard-worker mit Live-Vorschau und datensatzweisem Error-Handling. Verifiziert an argeParser.ts (DQR-10.0-Format), import.service.ts (parseArgeSample, ARGE_*), import-wizard-worker.ts.
  • 2026-06-22: Mapping-Wizard erweitert — Einheiten-Zuordnung (unitMappings, Heuristik + KI-Vorschlag, Unit nicht mehr auto-anlegbar), Felder kombinieren (combineRules, FK-Auflösung), Lieferant-Zuordnung (supplierConfig, __supplier__:-Targets, DATANORM-Vorbefüllung) und Warengruppen-Typ/-Hierarchie (productGroupType, productGroupHierarchy). Neue Endpoints column-values, suggest-units, preview-references. Verifiziert an import.validate.ts, import.router.ts, import.service.ts (AUTO_CREATABLE_MODELS, SUPPLIER_MAPPING_PREFIX), MappingStep.tsx. Bad-Merge-Regressionen (u. a. Unit-Auto-Create) im selben Drop bereinigt.
  • 2026-05-29: CSV-Bulk-Import-Pipeline ergänzt (13 Entity-Configs, /imports/*-API, Fuzzy-Matching, Address-Snapshot-Hook).
  • 2026-04-30: Initiale Veroeffentlichung.