Generalize email system with invoice workflow and Stiftungsgeschichte category
- Rename DestinataerEmailEingang → EmailEingang with category support (destinataer, rechnung, land_pacht, stiftungsgeschichte, allgemein) - Add invoice capture workflow: create Verwaltungskosten from email, link DMS documents as invoice attachments, track payment status - Add Stiftungsgeschichte email category with auto-detection patterns (Ahnenforschung, Genealogie, Chronik, etc.) and DMS integration - Update poll_emails task with category detection and DMS context mapping - Show available history documents in Geschichte editor sidebar - Consolidate DMS views, remove legacy dokument templates - Update all detail/form templates for DMS document linking - Add deploy.sh script and streamline compose.yml Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
33
app/stiftung/migrations/0049_phase3_email_dms_m2m.py
Normal file
33
app/stiftung/migrations/0049_phase3_email_dms_m2m.py
Normal file
@@ -0,0 +1,33 @@
|
||||
# Generated by Django 5.0.6 on 2026-03-12 08:11
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('stiftung', '0048_phase3_dms_dokument_datei'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='destinataeremaileingang',
|
||||
name='dokument_dateien',
|
||||
field=models.ManyToManyField(blank=True, help_text='Automatisch befüllte Anhänge als Django-DMS-Dateien.', related_name='email_eingaenge', to='stiftung.dokumentdatei', verbose_name='DMS-Dokumente (Anhänge)'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='appconfiguration',
|
||||
name='category',
|
||||
field=models.CharField(choices=[('paperless', 'Paperless Integration'), ('email', 'E-Mail / IMAP'), ('general', 'General Settings'), ('corporate', 'Corporate Identity'), ('notifications', 'Notifications'), ('system', 'System Settings')], default='general', max_length=50, verbose_name='Category'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='appconfiguration',
|
||||
name='setting_type',
|
||||
field=models.CharField(choices=[('text', 'Text'), ('password', 'Password'), ('number', 'Number'), ('boolean', 'Boolean'), ('url', 'URL'), ('tag', 'Tag Name'), ('tag_id', 'Tag ID')], default='text', max_length=20, verbose_name='Type'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='destinataeremaileingang',
|
||||
name='paperless_dokument_ids',
|
||||
field=models.JSONField(blank=True, default=list, help_text='Veraltet – wird nach vollständiger Migration entfernt. Neue Anhänge in dokument_dateien.', verbose_name='Paperless Dokument-IDs (Anhänge, veraltet)'),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,132 @@
|
||||
# Phase 4: Generalize EmailEingang + Rechnungsworkflow
|
||||
# - Rename DestinataerEmailEingang → EmailEingang
|
||||
# - Add kategorie, verwaltungskosten FK, land FK, verpachtung FK
|
||||
# - Expand status choices (rechnung_erfasst, zahlung_gebucht)
|
||||
# - Add verwaltungskosten FK to DokumentDatei
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('stiftung', '0049_phase3_email_dms_m2m'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
# 1. Rename model (preserves DB table, updates Django state)
|
||||
migrations.RenameModel(
|
||||
old_name='DestinataerEmailEingang',
|
||||
new_name='EmailEingang',
|
||||
),
|
||||
|
||||
# 2. Add kategorie field to EmailEingang
|
||||
migrations.AddField(
|
||||
model_name='emaileingang',
|
||||
name='kategorie',
|
||||
field=models.CharField(
|
||||
choices=[
|
||||
('destinataer', 'Destinataer'),
|
||||
('rechnung', 'Rechnung'),
|
||||
('land_pacht', 'Grundstueck / Pacht'),
|
||||
('allgemein', 'Allgemein'),
|
||||
],
|
||||
default='allgemein',
|
||||
max_length=20,
|
||||
verbose_name='Kategorie',
|
||||
),
|
||||
),
|
||||
|
||||
# 3. Add verwaltungskosten FK to EmailEingang
|
||||
migrations.AddField(
|
||||
model_name='emaileingang',
|
||||
name='verwaltungskosten',
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name='email_eingaenge',
|
||||
to='stiftung.verwaltungskosten',
|
||||
verbose_name='Verwaltungskosten / Rechnung',
|
||||
),
|
||||
),
|
||||
|
||||
# 4. Add land FK to EmailEingang
|
||||
migrations.AddField(
|
||||
model_name='emaileingang',
|
||||
name='land',
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name='email_eingaenge',
|
||||
to='stiftung.land',
|
||||
verbose_name='Laenderei',
|
||||
),
|
||||
),
|
||||
|
||||
# 5. Add verpachtung FK to EmailEingang
|
||||
migrations.AddField(
|
||||
model_name='emaileingang',
|
||||
name='verpachtung',
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name='email_eingaenge',
|
||||
to='stiftung.landverpachtung',
|
||||
verbose_name='Verpachtung',
|
||||
),
|
||||
),
|
||||
|
||||
# 6. Update status choices on EmailEingang
|
||||
migrations.AlterField(
|
||||
model_name='emaileingang',
|
||||
name='status',
|
||||
field=models.CharField(
|
||||
choices=[
|
||||
('neu', 'Neu / Unbearbeitet'),
|
||||
('zugewiesen', 'Destinataer zugewiesen'),
|
||||
('verarbeitet', 'Verarbeitet'),
|
||||
('rechnung_erfasst', 'Rechnung erfasst'),
|
||||
('zahlung_gebucht', 'Zahlung gebucht'),
|
||||
('unbekannt', 'Unbekannter Absender'),
|
||||
('fehler', 'Fehler bei Verarbeitung'),
|
||||
],
|
||||
default='neu',
|
||||
max_length=20,
|
||||
verbose_name='Status',
|
||||
),
|
||||
),
|
||||
|
||||
# 7. Update Meta on EmailEingang
|
||||
migrations.AlterModelOptions(
|
||||
name='emaileingang',
|
||||
options={
|
||||
'ordering': ['-eingangsdatum'],
|
||||
'verbose_name': 'E-Mail-Eingang',
|
||||
'verbose_name_plural': 'E-Mail-Eingaenge',
|
||||
},
|
||||
),
|
||||
|
||||
# 8. Set kategorie='destinataer' for existing emails that have a destinataer FK
|
||||
migrations.RunSQL(
|
||||
sql="UPDATE stiftung_emaileingang SET kategorie = 'destinataer' WHERE destinataer_id IS NOT NULL;",
|
||||
reverse_sql=migrations.RunSQL.noop,
|
||||
),
|
||||
|
||||
# 9. Add verwaltungskosten FK to DokumentDatei
|
||||
migrations.AddField(
|
||||
model_name='dokumentdatei',
|
||||
name='verwaltungskosten',
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name='dms_dokumente',
|
||||
to='stiftung.verwaltungskosten',
|
||||
verbose_name='Verwaltungskosten / Rechnung',
|
||||
),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,29 @@
|
||||
# Generated by Django 5.0.6 on 2026-03-12 09:45
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('stiftung', '0050_generalize_email_rechnungsworkflow'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='emaileingang',
|
||||
name='destinataer',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='email_eingaenge', to='stiftung.destinataer', verbose_name='Destinataer'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='emaileingang',
|
||||
name='dokument_dateien',
|
||||
field=models.ManyToManyField(blank=True, help_text='Automatisch befuellte Anhaenge als Django-DMS-Dateien.', related_name='email_eingaenge', to='stiftung.dokumentdatei', verbose_name='DMS-Dokumente (Anhaenge)'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='emaileingang',
|
||||
name='paperless_dokument_ids',
|
||||
field=models.JSONField(blank=True, default=list, help_text='Veraltet – wird nach vollstaendiger Migration entfernt. Neue Anhaenge in dokument_dateien.', verbose_name='Paperless Dokument-IDs (Anhaenge, veraltet)'),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,23 @@
|
||||
# Generated by Django 5.0.6 on 2026-03-12 10:07
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('stiftung', '0051_alter_emaileingang_destinataer_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='dokumentdatei',
|
||||
name='kontext',
|
||||
field=models.CharField(choices=[('pachtvertrag', 'Pachtvertrag'), ('antrag', 'Antrag / Förderantrag'), ('verwendungsnachweis', 'Verwendungsnachweis'), ('studiennachweis', 'Studiennachweis'), ('rechnung', 'Rechnung'), ('vertrag', 'Vertrag'), ('bericht', 'Bericht'), ('landkarte', 'Landkarte / Kataster'), ('korrespondenz', 'Korrespondenz / Brief'), ('bescheid', 'Bescheid / Behörde'), ('stiftungsgeschichte', 'Stiftungsgeschichte / Archiv'), ('anderes', 'Sonstiges')], default='anderes', max_length=30, verbose_name='Dokumententyp'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='emaileingang',
|
||||
name='kategorie',
|
||||
field=models.CharField(choices=[('destinataer', 'Destinataer'), ('rechnung', 'Rechnung'), ('land_pacht', 'Grundstueck / Pacht'), ('stiftungsgeschichte', 'Stiftungsgeschichte'), ('allgemein', 'Allgemein')], default='allgemein', max_length=20, verbose_name='Kategorie'),
|
||||
),
|
||||
]
|
||||
Reference in New Issue
Block a user