Anfragen annehmen und ablehnen — mit laufender Zeit bis zur Übergabe
Annehmen war bisher nur ein Etikett: Man stellte den Status um, und es passierte nichts. Kunde, Projekt, Aufgabenliste, Termin und Zugang musste man danach von Hand in fünf Schritten nachbauen. Der alte Code gab das im Kommentar selbst zu -- schlug der zweite von zwei Aufrufen fehl, stand der Kunde schon in der Datenbank und man durfte es nicht noch einmal versuchen. Jetzt macht das EIN Aufruf, ganz oder gar nicht: Kunde finden oder anlegen, Projekt anlegen, die komplette Aufgabenliste des Pakets einsetzen, Liefertermin berechnen, Einladungslink erzeugen. Der Kunde verfolgt ab diesem Moment alles in seinem Portal. Die Zeit läuft wirklich: - Eigenes Datumsfeld (termin_am) neben dem freien Text. Aus 'Mitte Oktober' kann man keine verbleibenden Tage rechnen. - Werktage statt Kalendertage, inklusive luxemburgischer Feiertage. Die beweglichen werden über die Osterformel berechnet statt gepflegt -- eine Liste ist im übernächsten Jahr lautlos falsch. - Vorschlag je Paket (Onepager 10, Website 20, Shop 30 Werktage), überschreibbar vor dem Bestätigen. - Verbleibende Zeit wird SERVERSEITIG gerechnet. Der Browser kennt die Feiertage nicht; zwei verschiedene Zahlen für denselben Termin wären schlimmer als gar keine. Ablehnen mit Grund und vorbereiteter Absage in fünf Sprachen, Text serverseitig erzeugt und vor dem Abschicken lesbar. Ein laufendes Projekt lässt sich nicht nachträglich als Anfrage ablehnen. Sechs Fehler dabei gefunden: - Ein unbekanntes Paket hätte GAR KEINEN Termin bekommen statt des Ersatzwerts. Zwei Funktionen lasen dieselbe Tabelle, nur eine hatte einen Rückfallwert. Eine fehlende Zahl fällt nirgends auf. - wd_anfragen hat keine Spalte 'firma' -- better-sqlite3 weist undefined ab, die ganze Annahme wäre gescheitert. - Migrationen stehen in einer ausdrücklichen Liste; 0015 fehlte darin. - datumKurz() wurde aufgerufen, gab es aber nicht. Der Fehler wäre erst NACH dem Anlegen aufgetreten. - Der Installations-Hinweis lag fest über dem Annehmen-Knopf und machte ihn auf dem Handy untreffbar. Die Seite reserviert jetzt Platz dafür. - 'richttermin' ist freier Text, lief aber durch einen Datumsformatierer: Der Kunde las 'Invalid Date' an der wichtigsten Stelle seines Projekts. Geprüft: 49 Prüfungen der Terminrechnung gegen nachschlagbare Osterdaten und Wochentage, 70 gegen eine echte Datenbank (darunter: zweiter Klick legt nichts doppelt an, Abbruch mittendrin lässt NICHTS zurück, gesperrter Kunde wird nicht still entsperrt), 42 im Browser auf Computer und Handy, 40 im Portal. Alle bestehenden Prüfungen weiter grün. Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
-- =====================================================================
|
||||
-- Annehmen und Ablehnen einer Anfrage — und eine Zeit, die wirklich läuft
|
||||
--
|
||||
-- WARUM EIN ZWEITES TERMINFELD
|
||||
--
|
||||
-- `wd_projekte.richttermin` gibt es schon, es ist aber freier Text:
|
||||
-- "Mitte Oktober", "KW 42", "sobald die Texte da sind". Das ist für ein
|
||||
-- Gespräch genau richtig und für eine Rechnung völlig unbrauchbar — man
|
||||
-- kann daraus keine verbleibenden Tage ermitteln.
|
||||
--
|
||||
-- Den bestehenden Text nachträglich zu deuten wäre die schlechtere
|
||||
-- Lösung: Aus "Mitte Oktober" ein Datum zu raten heißt, sich bei jedem
|
||||
-- zweiten Projekt um Tage zu vertun — und ausgerechnet ein Liefertermin
|
||||
-- ist nichts, wo man raten sollte. Deshalb ein eigenes, echtes Datum
|
||||
-- daneben. Der Text bleibt, weil er das Menschliche transportiert
|
||||
-- ("wenn deine Texte da sind"), das Datum trägt das Rechnen.
|
||||
--
|
||||
-- Bewusst ein reines Datum (JJJJ-MM-TT) und kein Zeitstempel: Ein
|
||||
-- Liefertermin ist ein Tag, keine Uhrzeit. "Noch 3 Tage" darf nicht
|
||||
-- davon abhängen, ob um 9 oder um 17 Uhr angenommen wurde.
|
||||
-- =====================================================================
|
||||
|
||||
ALTER TABLE wd_projekte ADD COLUMN termin_am TEXT;
|
||||
|
||||
-- Wann die Uhr zu laufen begann. `start_am` gibt es schon, wird aber
|
||||
-- frei gesetzt; dieses Feld hält fest, wann ANGENOMMEN wurde. Beides
|
||||
-- kann auseinanderfallen (angenommen am Freitag, Start am Montag), und
|
||||
-- für "seit wann läuft das" zählt die Annahme.
|
||||
ALTER TABLE wd_projekte ADD COLUMN angenommen_am TEXT;
|
||||
|
||||
-- Wie viele Werktage beim Annehmen vorgesehen waren. Nur zur
|
||||
-- Nachvollziehbarkeit: Verschiebt man den Termin später, sieht man noch,
|
||||
-- was ursprünglich zugesagt war.
|
||||
ALTER TABLE wd_projekte ADD COLUMN termin_werktage INTEGER;
|
||||
|
||||
-- ---------------------------------------------------------------------
|
||||
-- Ablehnung
|
||||
--
|
||||
-- Der Grund steht am Vorgang selbst und nicht nur in einer Notiz: Er
|
||||
-- entscheidet mit, welcher Absagetext erzeugt wird, und man will später
|
||||
-- auswerten können, WORAN Anfragen scheitern (kein Budget? kein
|
||||
-- Zeitfenster?). In Fließtext vergraben ginge das nicht.
|
||||
-- ---------------------------------------------------------------------
|
||||
ALTER TABLE wd_anfragen ADD COLUMN ablehnung_grund TEXT;
|
||||
ALTER TABLE wd_anfragen ADD COLUMN ablehnung_am TEXT;
|
||||
|
||||
-- Ob die Absage tatsächlich verschickt wurde. Getrennt vom Grund, weil
|
||||
-- beides verschiedene Dinge sind: Man kann intern ablehnen, ohne zu
|
||||
-- schreiben — und dann muss man sehen, dass der Mensch noch wartet.
|
||||
ALTER TABLE wd_anfragen ADD COLUMN absage_gesendet_am TEXT;
|
||||
|
||||
-- Zwei Wege führen von einer Anfrage zum Projekt, und beide sollen
|
||||
-- schnell auffindbar sein: vom Projekt zur Anfrage (Spalte anfrage_id,
|
||||
-- gibt es schon) und umgekehrt.
|
||||
CREATE INDEX IF NOT EXISTS idx_wd_projekte_anfrage ON wd_projekte (anfrage_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_wd_projekte_termin ON wd_projekte (termin_am);
|
||||
Reference in New Issue
Block a user