fix: Berechtigungen der Tagesübersicht, WebDAV-Ausbau, Tests instand gesetzt
Build and Push Multi-Platform Images / build-and-push (push) Successful in 55s

Die tägliche E-Mail-Zusammenfassung zeigte Nutzern Bereiche, für die sie
keine Berechtigung haben. Zwei unabhängige Ursachen:

- Das Backend prüfte weiterhin die Altgruppe PM_Belege. Die Umbenennung
  zu PM_Buchhaltung (ca1d371) war nur im Frontend angekommen, weshalb
  der Digest "Manuell bearbeiten" und "In Agrarmonitor" anbot, während
  die Oberfläche beide Bereiche sperrte.
- Der Cron-Versand wertet die Gruppen aus user_settings aus. Diese Spalte
  wurde nur beim Aufruf der Benutzereinstellungen gefüllt; entzogene
  Berechtigungen erreichten den Digest daher unter Umständen nie.

Behoben durch Angleichen des Gruppen-Mappings und den neuen
UserIdentitySyncService, der E-Mail, Benutzername und Gruppen bei jedem
authentifizierten Request aus dem Token spiegelt – ohne den Request zu
blockieren und ohne DB-Zugriff, solange sich das Token nicht ändert. Die
doppelte Identitätspflege im UserSettingsService entfällt.

WebDAV wird nicht eingesetzt und ist entfernt; Export-Ziele bieten nur
noch FTP. Damit verschwindet das ESM-Paket webdav, an dem zwei
Jest-Suites bereits beim Parsen scheiterten.

Veraltete Tests instand gesetzt: email.controller und settings.controller
mockten weniger Abhängigkeiten, als die Klassen inzwischen haben;
postprocessing.service.spec beschrieb noch das alte Regelmodell mit
Einzelfeldern statt FilterJson und ist gegen die heutige Filter-Engine
neu geschrieben (AND/OR, verschachtelte Gruppen, Fehlerprotokollierung).

Enthält außerdem den Arbeitsstand der E-Rechnungs-Mandantenzuordnung, da
sich beide Änderungen dieselben Dateien teilen (SettingsPage, package.json).

98 Tests in 12 Suites grün, Backend- und Frontend-Build sauber.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
bjoernpoettkerandClaude Opus 5 committed 2026-09-01 00:06:50 +02:00
1 parent 32ba772e4e
commit b7b65c64ae
41 files changed
+2462 -443

No files matched your search

@@ -15,6 +15,7 @@ import {
Kontonummer,
Document,
UserClient,
ClientIdentifier,
Email,
Attachment,
Content,
@@ -47,6 +48,7 @@ export const entities = [
Kontonummer,
Document,
UserClient,
ClientIdentifier,
Email,
Attachment,
Content,
@@ -0,0 +1,33 @@
import { Entity, PrimaryGeneratedColumn, Column, Index } from 'typeorm';
/**
* Kennungsarten, über die ein Mandant in einer E-Rechnung erkannt werden kann.
* Bewusst nur "starke" Kennungen – Name und E-Mail sind zu unscharf, um sie
* dauerhaft festzuschreiben.
*/
export type ClientIdentifierTyp = 'ustid' | 'leitwegid' | 'kaeuferkennung';
export const CLIENT_IDENTIFIER_TYPEN: ClientIdentifierTyp[] = [
'ustid',
'leitwegid',
'kaeuferkennung',
];
/** Zuordnung einer Käufer-Kennung aus dem E-Rechnungs-XML zu einem Mandanten. */
@Entity('ClientIdentifiers')
@Index('IX_ClientIdentifiers_TypWert', ['Typ', 'Wert'], { unique: true })
export class ClientIdentifier {
@PrimaryGeneratedColumn()
Id!: number;
@Index('IX_ClientIdentifiers_ClientId')
@Column({ type: 'int' })
ClientId!: number;
@Column({ type: 'varchar', length: 20 })
Typ!: ClientIdentifierTyp;
/** Normalisiert gespeichert: Großschreibung, ohne Leer- und Trennzeichen. */
@Column({ type: 'varchar', length: 100 })
Wert!: string;
}
@@ -19,4 +19,12 @@ export class DocumentType {
@Column({ type: 'tinyint', width: 1, nullable: true, default: null })
FreigabeErforderlich!: boolean | null;
/**
* Rechnungstyp-Codes (BT-3) einer E-Rechnung, die auf diese Belegart
* abgebildet werden – kommagetrennt, z. B. "380,384" für Rechnung, "381"
* für Gutschrift. Leer = diese Belegart wird nie vorgeschlagen.
*/
@Column({ type: 'varchar', length: 100, nullable: true, default: null })
ERechnungTypeCodes!: string | null;
}
@@ -9,7 +9,7 @@ export class ExportTarget {
Name!: string;
@Column({ type: 'varchar', length: 20 })
Protocol!: string; // 'ftp' | 'webdav'
Protocol!: string; // 'ftp'
@Column({ type: 'varchar', length: 255 })
Host!: string;
@@ -10,6 +10,7 @@ export { Setting } from './setting.entity';
export { Kontonummer } from './kontonummer.entity';
export { Document } from './document.entity';
export { UserClient } from './user-client.entity';
export { ClientIdentifier } from './client-identifier.entity';
export { Email } from './email.entity';
export { Attachment } from './attachment.entity';
export { Content } from './content.entity';
@@ -10,7 +10,7 @@ export class PostprocessingAction {
@Column({ type: 'int' })
ActionType!: number;
// 1 = Export (FTP/WebDAV)
// 1 = Export (FTP)
// 2 = Mail
// 3 = Tag setzen/entfernen
// 4 = Custom Field setzen
@@ -0,0 +1,41 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
/**
* Grundlage für den Mandanten-Vorschlag aus E-Rechnungen:
*
* - `ClientIdentifiers` ordnet Käufer-Kennungen aus dem Rechnungs-XML
* (USt-IdNr., Leitweg-ID, Käufer-Kennung) einem Mandanten zu. Der eindeutige
* Index über (Typ, Wert) verhindert, dass eine Kennung auf mehrere Mandanten
* zeigt.
* - `DocumentTypes.ERechnungTypeCodes` bildet den Rechnungstyp (BT-3) auf eine
* Belegart ab, z. B. "380,384" für Rechnung und "381" für Gutschrift.
*/
export class ERechnungMandantenzuordnung1787000000000 implements MigrationInterface {
name = 'ERechnungMandantenzuordnung1787000000000';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
CREATE TABLE IF NOT EXISTS \`ClientIdentifiers\` (
\`Id\` int NOT NULL AUTO_INCREMENT,
\`ClientId\` int NOT NULL,
\`Typ\` varchar(20) NOT NULL,
\`Wert\` varchar(100) NOT NULL,
PRIMARY KEY (\`Id\`),
UNIQUE INDEX \`IX_ClientIdentifiers_TypWert\` (\`Typ\`, \`Wert\`),
INDEX \`IX_ClientIdentifiers_ClientId\` (\`ClientId\`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
`);
await queryRunner.query(`
ALTER TABLE \`DocumentTypes\`
ADD \`ERechnungTypeCodes\` varchar(100) NULL DEFAULT NULL
`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE \`DocumentTypes\` DROP COLUMN \`ERechnungTypeCodes\``,
);
await queryRunner.query(`DROP TABLE \`ClientIdentifiers\``);
}
}