feat: CRM-Stufen (Lead/Kunde) + InvoiceNinja-Sync (eine Pflege)

- Zwei Kundenstufen: Lead (potenziell) und fester Kunde; Lead braucht nur
  Unternehmen + E-Mail und erzeugt automatisch ein Akquise-Ticket
- Akquise-Worksheet-Ergebnis (In Kontakt/Zugesagt/Abgesagt) sichtbar in WSIDs;
  "Zugesagt" macht den Lead automatisch zum festen Kunden, "Abgesagt" -> verloren
- Kunde wird nur in Appwrite gepflegt und automatisch als InvoiceNinja-Client
  angelegt/aktualisiert (beim Upgrade bzw. bei Datenpflege)
- Rechnungen nur fuer feste Kunden mit vollstaendigen Daten (Strasse/PLZ/Stadt)
- Kundenliste mit Stufen-Filter, neue Rechnungs-/Adressfelder

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Webklar Deploy
2026-06-17 11:18:28 +00:00
parent 7d764ce6bc
commit a1cb90372f
8 changed files with 296 additions and 80 deletions

View File

@@ -30,6 +30,9 @@ const RESPONSE_LEVELS = [
'n/a'
]
// Akquise-Tickets: Ergebnis des Kundenkontakts (statt technischer Status)
const ACQUISITION_STATUS = ['In Kontakt', 'Zugesagt', 'Abgesagt']
export default function CreateWorksheetModal({ isOpen, onClose, workorder, onCreate }) {
const { user } = useAuth()
const today = new Date().toLocaleDateString('de-DE', {
@@ -55,12 +58,18 @@ export default function CreateWorksheetModal({ isOpen, onClose, workorder, onCre
const [error, setError] = useState('')
const [autoCalculate, setAutoCalculate] = useState(true)
const isAcquisition = workorder?.type === 'Akquise'
const statusOptions = isAcquisition ? ACQUISITION_STATUS : STATUS_OPTIONS
const defaultStatus = isAcquisition
? (ACQUISITION_STATUS.includes(workorder?.status) ? workorder.status : 'In Kontakt')
: (workorder?.status || 'Open')
// Reset form wenn Modal geöffnet wird
useEffect(() => {
if (isOpen && workorder) {
setFormData({
serviceType: 'Remote',
newStatus: workorder.status || 'Open',
newStatus: defaultStatus,
newResponseLevel: workorder.responseLevel || '',
totalTime: 0,
startDate: today,
@@ -189,17 +198,22 @@ export default function CreateWorksheetModal({ isOpen, onClose, workorder, onCre
</div>
<div className="form-group">
<label className="form-label">New Status</label>
<label className="form-label">{isAcquisition ? 'Akquise-Ergebnis' : 'New Status'}</label>
<select
className="form-control"
value={formData.newStatus}
onChange={(e) => handleChange('newStatus', e.target.value)}
required
>
{STATUS_OPTIONS.map(status => (
{statusOptions.map(status => (
<option key={status} value={status}>{status}</option>
))}
</select>
{isAcquisition && (
<small style={{ color: '#a0aec0', fontSize: '12px' }}>
"Zugesagt" macht den Lead automatisch zum festen Kunden.
</small>
)}
</div>
<div className="form-group">