- PermissionsGuard lehnt Routen ohne @RequirePermissions/@AllowAnyAuthenticated
ab. API-Keys umgehen keine Rechteprüfung mehr, sondern gelten nur auf
Routen mit @AllowApiKey (Paperless-Webhook, externer Upload, checksum,
Agent-Routen des Etikettendrucks).
- Rechte für 24 bisher offene Routen ergänzt, u.a. paperless/documents
(nur Admin), paperless/documents/:id und Kontonummern (Posteingang/
manuell), webhook/status (Admin). routen-rechte.spec.ts prüft alle Routen.
- Etiketten-Agent: printed/error nur für abgeholte, offene Jobs (bedingtes
Update, sonst 409) – ein gedruckter Job kann seine Nummer nicht mehr
freigeben. Feldwerte nur aus den Eingabefeldern der Vorlage ({number}
nicht vorgebbar) und URL-kodiert in GET-/Callback-URLs.
- PUT paperless/inbox/:id ignoriert Freigabe (CF15) und Zahlung (CF16)
ohne die jeweilige Rolle (Funktionstrennung).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
133 lines
4.2 KiB
TypeScript
133 lines
4.2 KiB
TypeScript
import { Injectable, Logger } from '@nestjs/common';
|
|
import { InjectRepository } from '@nestjs/typeorm';
|
|
import { Repository } from 'typeorm';
|
|
import { DocumentType } from '../database/entities/document-type.entity';
|
|
import { PaperlessService } from '../paperless/paperless.service';
|
|
import { FREIGABE_FIELD_ID } from '../paperless/status-felder.util';
|
|
|
|
@Injectable()
|
|
export class FreigabeService {
|
|
private readonly logger = new Logger(FreigabeService.name);
|
|
|
|
constructor(
|
|
@InjectRepository(DocumentType)
|
|
private readonly documentTypeRepo: Repository<DocumentType>,
|
|
private readonly paperlessService: PaperlessService,
|
|
) {}
|
|
|
|
async getFreigabeDocuments(
|
|
page: number,
|
|
pageSize: number,
|
|
nurNichtFreigegeben: boolean,
|
|
) {
|
|
const docTypes = await this.documentTypeRepo.find({
|
|
where: { FreigabeErforderlich: true as any },
|
|
});
|
|
|
|
if (docTypes.length === 0) {
|
|
return { count: 0, results: [] };
|
|
}
|
|
|
|
const docTypeIds = docTypes.map((dt) => dt.DocumentTypeId).join(',');
|
|
|
|
const params: Record<string, any> = {
|
|
page,
|
|
page_size: pageSize,
|
|
document_type__id__in: docTypeIds,
|
|
ordering: '-created',
|
|
truncate_content: true,
|
|
};
|
|
|
|
if (nurNichtFreigegeben) {
|
|
// Filter für Belege, bei denen Custom Field 15 nicht gesetzt ist
|
|
params[`custom_fields__field_id`] = FREIGABE_FIELD_ID;
|
|
params[`custom_fields__value__isnull`] = true;
|
|
}
|
|
|
|
try {
|
|
const result = await this.paperlessService.getDocuments(params);
|
|
return result;
|
|
} catch (err: any) {
|
|
// Fallback: Paperless unterstützt den custom_fields-Filter möglicherweise nicht
|
|
// In diesem Fall alle Belege laden und client-seitig filtern
|
|
this.logger.warn(
|
|
'custom_fields Filter nicht unterstützt, lade alle Belege und filtere lokal',
|
|
);
|
|
const fallbackParams: Record<string, any> = {
|
|
page: 1,
|
|
page_size: 9999,
|
|
document_type__id__in: docTypeIds,
|
|
ordering: '-created',
|
|
truncate_content: true,
|
|
};
|
|
const allDocs = await this.paperlessService.getDocuments(fallbackParams);
|
|
const results: any[] = allDocs.results ?? [];
|
|
|
|
if (nurNichtFreigegeben) {
|
|
const filtered = results.filter((doc: any) => {
|
|
const cf = (doc.custom_fields ?? []).find(
|
|
(f: any) => f.field === FREIGABE_FIELD_ID,
|
|
);
|
|
return (
|
|
!cf ||
|
|
cf.value === null ||
|
|
cf.value === '' ||
|
|
cf.value === undefined
|
|
);
|
|
});
|
|
const start = (page - 1) * pageSize;
|
|
return {
|
|
count: filtered.length,
|
|
results: filtered.slice(start, start + pageSize),
|
|
};
|
|
}
|
|
|
|
const start = (page - 1) * pageSize;
|
|
return {
|
|
count: results.length,
|
|
results: results.slice(start, start + pageSize),
|
|
};
|
|
}
|
|
}
|
|
|
|
async setFreigabe(documentId: number, value: string | null) {
|
|
const doc = await this.paperlessService.getDocument(documentId);
|
|
const customFields: any[] = [...(doc.custom_fields ?? [])];
|
|
|
|
const existing = customFields.find(
|
|
(f: any) => f.field === FREIGABE_FIELD_ID,
|
|
);
|
|
if (existing) {
|
|
existing.value = value;
|
|
} else if (value !== null && value !== '') {
|
|
customFields.push({ field: FREIGABE_FIELD_ID, value });
|
|
}
|
|
|
|
await this.paperlessService.updateDocument(documentId, {
|
|
custom_fields: customFields,
|
|
});
|
|
return { success: true };
|
|
}
|
|
|
|
async getFreigabeOptions(): Promise<{ id: string; label: string }[]> {
|
|
const fields = await this.paperlessService.getCustomFields();
|
|
const field = fields.find((f: any) => f.id === FREIGABE_FIELD_ID);
|
|
if (!field) return [];
|
|
|
|
const rawOptions: any[] = field.extra_data?.select_options ?? [];
|
|
return rawOptions
|
|
.filter((o) => o !== null && o !== undefined && o !== '')
|
|
.map((o) => {
|
|
if (typeof o === 'object') {
|
|
// Paperless kann select_options als Objekte liefern
|
|
return {
|
|
id: String(o.id ?? o.value ?? o.label ?? ''),
|
|
label: String(o.label ?? o.name ?? o.id ?? ''),
|
|
};
|
|
}
|
|
return { id: String(o), label: String(o) };
|
|
})
|
|
.filter((o) => o.id !== '');
|
|
}
|
|
}
|