feat(akquise): Papierkorb fuer geloeschte Eintraege
Loeschen in der Akquise war ein echtes DELETE: der Eintrag stand danach in keiner Liste, auch nicht im Archiv, und war nicht zurueckholbar. Jetzt setzt es `deleted_at`/`deleted_by`, die Zeile bleibt 90 Tage stehen. Der Papierkorb ist die eine Ausnahme von der Regel, dass diese Tabelle keinen Zustand fuehrt: Loeschen von Hand ist eine Entscheidung, kein Ablauf. Was dort liegt, blenden alle anderen Abfragen ueber NOT_DELETED aus - Eingang, Archiv, Menuezahlen und Dashboard. Der Aufraeumlauf ueber `found_at` laesst geloeschte Zeilen ausdruecklich liegen, sonst waere ein alter Fund im Papierkorb sofort weg; der Papierkorb raeumt ab `deleted_at`. Zwei Rueckwege, deshalb zwei Routen. `/reopen` (bisher `/restore`) holt aus dem Archiv in den Eingang und setzt das Funddatum auf heute. `/restore` holt aus dem Papierkorb zurueck und laesst das Funddatum in Ruhe - der Eintrag soll dort auftauchen, wo er hingehoert, also im Archiv, wenn er alt ist. Die Meldung nennt das Ziel. Dazu `DELETE /:id/permanent` und `POST /trash/empty`. Im Papierkorb wird nicht gepflegt: Bearbeiten und Uebernehmen antworten 409. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
f319b8207b
commit
6e66bd39d7
+18
-2
@@ -2,6 +2,7 @@ export type ViewState =
|
||||
| 'Dashboard'
|
||||
| 'Akquise'
|
||||
| 'Archiv'
|
||||
| 'Akquise-Papierkorb'
|
||||
| 'Opportunities'
|
||||
| 'Opportunity-Papierkorb'
|
||||
| 'Interviews'
|
||||
@@ -52,8 +53,13 @@ export const MAIL_VIEWS: ViewState[] = ['Mails', 'Papierkorb'];
|
||||
/**
|
||||
* Akquise. "Akquise" ist der Eingang der letzten 14 Tage, "Archiv" alles
|
||||
* Aeltere. Beides ist dieselbe Liste, nur nach dem Funddatum geteilt.
|
||||
*
|
||||
* Der Papierkorb kommt aus einer anderen Ecke: dort liegt, was jemand von Hand
|
||||
* geloescht hat. Der Wert heisst "Akquise-Papierkorb", weil Mails und
|
||||
* Opportunities schon einen Papierkorb haben und der Ansichtsname eindeutig sein
|
||||
* muss; angezeigt wird er als "Papierkorb" (siehe VIEW_TITLES).
|
||||
*/
|
||||
export const ACQUISITION_VIEWS: ViewState[] = ['Akquise', 'Archiv'];
|
||||
export const ACQUISITION_VIEWS: ViewState[] = ['Akquise', 'Archiv', 'Akquise-Papierkorb'];
|
||||
|
||||
/**
|
||||
* Opportunities mit ihrem Papierkorb. Der Wert heisst "Opportunity-Papierkorb",
|
||||
@@ -69,6 +75,7 @@ export const OPPORTUNITY_VIEWS: ViewState[] = ['Opportunities', 'Opportunity-Pap
|
||||
*/
|
||||
export const VIEW_TITLES: Partial<Record<ViewState, string>> = {
|
||||
'Opportunity-Papierkorb': 'Papierkorb',
|
||||
'Akquise-Papierkorb': 'Papierkorb',
|
||||
};
|
||||
|
||||
export const viewTitle = (view: ViewState): string => VIEW_TITLES[view] ?? view;
|
||||
@@ -379,6 +386,13 @@ export interface Acquisition {
|
||||
opportunity_gone?: boolean;
|
||||
created_by: number | null;
|
||||
created_by_name?: string | null;
|
||||
/**
|
||||
* Gesetzt = im Papierkorb (UTC). Ein solcher Eintrag steht in keiner der
|
||||
* beiden Listen und in keiner Auswertung - nur im Papierkorb.
|
||||
*/
|
||||
deleted_at?: string | null;
|
||||
deleted_by?: number | null;
|
||||
deleted_by_name?: string | null;
|
||||
created_at?: string;
|
||||
updated_at?: string;
|
||||
}
|
||||
@@ -387,7 +401,9 @@ export interface Acquisition {
|
||||
export interface AcquisitionList {
|
||||
archive_after_days: number;
|
||||
delete_after_days: number;
|
||||
counts: { eingang: number; archiv: number };
|
||||
/** So lange liegt ein von Hand geloeschter Eintrag im Papierkorb. */
|
||||
trash_delete_after_days: number;
|
||||
counts: { eingang: number; archiv: number; papierkorb: number };
|
||||
/** Inhalte der Dropdowns; kommen mit, damit die Eingabe sie sofort hat. */
|
||||
options: AcquisitionOptions;
|
||||
/** Schon benutzte Anbieter, der zuletzt verwendete zuerst - "Anbieter" ist Freitext. */
|
||||
|
||||
Reference in New Issue
Block a user