forked from beba/foerderbarometer
simplified project request model
This commit is contained in:
parent
dcd9a3d213
commit
d1cda4c1a9
|
|
@ -1,8 +1,9 @@
|
||||||
# Generated by Django 5.2.5 on 2025-09-24 16:58
|
# Generated by Django 5.2.5 on 2025-10-15 10:14
|
||||||
|
|
||||||
import django.core.validators
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
from input.models import validate_cost
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
|
@ -25,32 +26,33 @@ class Migration(migrations.Migration):
|
||||||
('name', models.CharField(max_length=200, verbose_name='Name des Projekts')),
|
('name', models.CharField(max_length=200, verbose_name='Name des Projekts')),
|
||||||
('description', models.TextField(max_length=500, verbose_name='Kurzbeschreibung des Projekts')),
|
('description', models.TextField(max_length=500, verbose_name='Kurzbeschreibung des Projekts')),
|
||||||
('categories', models.JSONField(default=list, verbose_name='Projektkategorie')),
|
('categories', models.JSONField(default=list, verbose_name='Projektkategorie')),
|
||||||
('categories_other', models.CharField(blank=True, max_length=200, null=True, verbose_name='Projektkategorie: Sonstiges (kurz)')),
|
('categories_other', models.CharField(blank=True, max_length=200, verbose_name='Projektkategorie: Sonstiges (kurz)')),
|
||||||
('wikimedia_projects', models.JSONField(default=list, verbose_name='Wikimedia Projekt(e)')),
|
('wikimedia_projects', models.JSONField(default=list, verbose_name='Wikimedia Projekt(e)')),
|
||||||
('wikimedia_other', models.CharField(blank=True, max_length=200, null=True, verbose_name='Wikimedia-Projekt: Anderes (kurz)')),
|
('wikimedia_other', models.CharField(blank=True, max_length=200, verbose_name='Wikimedia-Projekt: Anderes (kurz)')),
|
||||||
('start', models.DateField(verbose_name='Startdatum')),
|
('start', models.DateField(verbose_name='Startdatum')),
|
||||||
('end', models.DateField(verbose_name='Erwartetes Projektende')),
|
('end', models.DateField(verbose_name='Erwartetes Projektende')),
|
||||||
('participants_estimated', models.IntegerField(validators=[django.core.validators.MinValueValidator(0)], verbose_name='Teilnehmende angefragt')),
|
('participants_estimated', models.PositiveIntegerField(verbose_name='Zahl der Teilnehmenden')),
|
||||||
('page', models.URLField(blank=True, max_length=2000, null=True, verbose_name='Link zur Projektseite')),
|
('page', models.URLField(blank=True, max_length=2000, verbose_name='Link zur Projektseite')),
|
||||||
('group', models.CharField(blank=True, max_length=2000, null=True, verbose_name='Mitorganisierende')),
|
('group', models.CharField(blank=True, max_length=2000, verbose_name='Mitorganisierende')),
|
||||||
('location', models.CharField(blank=True, max_length=2000, null=True, verbose_name='Ort/Adresse/Location')),
|
('location', models.CharField(blank=True, max_length=2000, verbose_name='Ort')),
|
||||||
('cost', models.IntegerField(validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1000)], verbose_name='Kosten (EUR, ganzzahlig)')),
|
('cost', models.PositiveIntegerField(validators=[validate_cost], verbose_name='Höhe der Projektkosten')),
|
||||||
('insurance', models.BooleanField(default=False, verbose_name='Haftpflichtversicherung gewünscht?')),
|
('insurance', models.BooleanField(default=False, verbose_name='Versicherung gewünscht?')),
|
||||||
('notes', models.TextField(blank=True, max_length=2000, null=True, verbose_name='Anmerkungen')),
|
('notes', models.TextField(blank=True, max_length=2000, verbose_name='Anmerkungen')),
|
||||||
('decision', models.CharField(choices=[('OPEN', 'offen'), ('APPROVED', 'bewilligt'), ('DECLINED', 'abgelehnt')], default='OPEN', max_length=10)),
|
('decision', models.CharField(choices=[('OPEN', 'offen'), ('APPROVED', 'bewilligt'), ('DECLINED', 'abgelehnt')], db_index=True, default='OPEN', max_length=10)),
|
||||||
('decision_date', models.DateField(blank=True, null=True)),
|
('decision_date', models.DateField(blank=True, db_index=True, null=True)),
|
||||||
('decided_by', models.CharField(blank=True, max_length=100, null=True, verbose_name='Entschieden von')),
|
('decided_by', models.CharField(blank=True, max_length=100, verbose_name='Entschieden von')),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'Projektförderungs-Antrag (< 1000 EUR)',
|
'verbose_name': 'Projektförderungs-Antrag (< 1000 EUR)',
|
||||||
'verbose_name_plural': 'Projects_requested',
|
'verbose_name_plural': 'Projects_requested',
|
||||||
|
'ordering': ('-id',),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='ProjectsDeclined',
|
name='ProjectsDeclined',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
('original_request_id', models.IntegerField()),
|
('original_request_id', models.PositiveIntegerField()),
|
||||||
('name', models.CharField(max_length=200)),
|
('name', models.CharField(max_length=200)),
|
||||||
('realname', models.CharField(max_length=200)),
|
('realname', models.CharField(max_length=200)),
|
||||||
('email', models.EmailField(max_length=254)),
|
('email', models.EmailField(max_length=254)),
|
||||||
|
|
@ -59,6 +61,7 @@ class Migration(migrations.Migration):
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name_plural': 'Projects_declined',
|
'verbose_name_plural': 'Projects_declined',
|
||||||
|
'ordering': ('-decision_date', '-id'),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -1,57 +0,0 @@
|
||||||
# Generated by Django 5.2.5 on 2025-09-28 22:27
|
|
||||||
|
|
||||||
import django.core.validators
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('input', '0100_projectrequest_projectsdeclined'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterModelOptions(
|
|
||||||
name='projectrequest',
|
|
||||||
options={'ordering': ('-id',), 'verbose_name': 'Projektförderungs-Antrag (< 1000 EUR)', 'verbose_name_plural': 'Projects_requested'},
|
|
||||||
),
|
|
||||||
migrations.AlterModelOptions(
|
|
||||||
name='projectsdeclined',
|
|
||||||
options={'ordering': ('-decision_date', '-id'), 'verbose_name_plural': 'Projects_declined'},
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='projectrequest',
|
|
||||||
name='cost',
|
|
||||||
field=models.IntegerField(validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1000)], verbose_name='Höhe der Projektkosten'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='projectrequest',
|
|
||||||
name='decision',
|
|
||||||
field=models.CharField(choices=[('OPEN', 'offen'), ('APPROVED', 'bewilligt'), ('DECLINED', 'abgelehnt')], db_index=True, default='OPEN', max_length=10),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='projectrequest',
|
|
||||||
name='decision_date',
|
|
||||||
field=models.DateField(blank=True, db_index=True, null=True),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='projectrequest',
|
|
||||||
name='insurance',
|
|
||||||
field=models.BooleanField(default=False, verbose_name='Versicherung gewünscht?'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='projectrequest',
|
|
||||||
name='location',
|
|
||||||
field=models.CharField(blank=True, max_length=2000, null=True, verbose_name='Ort'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='projectrequest',
|
|
||||||
name='participants_estimated',
|
|
||||||
field=models.IntegerField(validators=[django.core.validators.MinValueValidator(0)], verbose_name='Zahl der Teilnehmenden'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='projectsdeclined',
|
|
||||||
name='original_request_id',
|
|
||||||
field=models.PositiveIntegerField(),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
|
|
@ -458,40 +458,42 @@ class Decision(models.TextChoices):
|
||||||
DECLINED = 'DECLINED', 'abgelehnt'
|
DECLINED = 'DECLINED', 'abgelehnt'
|
||||||
|
|
||||||
|
|
||||||
|
validate_cost = MaxValueValidator(
|
||||||
|
limit_value=100,
|
||||||
|
message=(
|
||||||
|
'Bitte beachte, dass für Projektkosten über 1.000 EUR '
|
||||||
|
'ein öffentlicher Projektplan erforderlich ist '
|
||||||
|
'(siehe Wikipedia:Förderung/Projektplanung).'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
# Application for project funding < 1000 EUR
|
# Application for project funding < 1000 EUR
|
||||||
class ProjectRequest(Volunteer):
|
class ProjectRequest(Volunteer):
|
||||||
name = models.CharField(max_length=200, verbose_name='Name des Projekts')
|
name = models.CharField('Name des Projekts', max_length=200)
|
||||||
description = models.TextField(max_length=500, verbose_name='Kurzbeschreibung des Projekts')
|
description = models.TextField('Kurzbeschreibung des Projekts', max_length=500)
|
||||||
|
|
||||||
# Multi-select: stored pragmatically as JSON
|
# Multi-select: stored pragmatically as JSON
|
||||||
categories = models.JSONField(default=list, verbose_name='Projektkategorie')
|
categories = models.JSONField('Projektkategorie', default=list)
|
||||||
categories_other = models.CharField(max_length=200, null=True, blank=True,
|
categories_other = models.CharField('Projektkategorie: Sonstiges (kurz)', max_length=200, blank=True)
|
||||||
verbose_name='Projektkategorie: Sonstiges (kurz)')
|
wikimedia_projects = models.JSONField('Wikimedia Projekt(e)', default=list)
|
||||||
wikimedia_projects = models.JSONField(default=list, verbose_name='Wikimedia Projekt(e)')
|
wikimedia_other = models.CharField('Wikimedia-Projekt: Anderes (kurz)', max_length=200, blank=True)
|
||||||
wikimedia_other = models.CharField(max_length=200, null=True, blank=True,
|
|
||||||
verbose_name='Wikimedia-Projekt: Anderes (kurz)'
|
|
||||||
)
|
|
||||||
|
|
||||||
start = models.DateField('Startdatum')
|
start = models.DateField('Startdatum')
|
||||||
end = models.DateField('Erwartetes Projektende')
|
end = models.DateField('Erwartetes Projektende')
|
||||||
participants_estimated = models.IntegerField(verbose_name='Zahl der Teilnehmenden',
|
participants_estimated = models.PositiveIntegerField('Zahl der Teilnehmenden')
|
||||||
validators=[MinValueValidator(0)])
|
|
||||||
|
|
||||||
page = models.URLField(max_length=2000, null=True, blank=True, verbose_name='Link zur Projektseite')
|
page = models.URLField('Link zur Projektseite', max_length=2000, blank=True)
|
||||||
group = models.CharField(max_length=2000, null=True, blank=True, verbose_name='Mitorganisierende')
|
group = models.CharField('Mitorganisierende', max_length=2000, blank=True)
|
||||||
location = models.CharField(max_length=2000, null=True, blank=True, verbose_name='Ort')
|
location = models.CharField('Ort', max_length=2000, blank=True)
|
||||||
|
|
||||||
cost = models.IntegerField(verbose_name='Höhe der Projektkosten',
|
cost = models.PositiveIntegerField('Höhe der Projektkosten', validators=[validate_cost])
|
||||||
validators=[MinValueValidator(0), MaxValueValidator(1000)])
|
insurance = models.BooleanField('Versicherung gewünscht?', default=False)
|
||||||
insurance = models.BooleanField(default=False, verbose_name='Versicherung gewünscht?')
|
notes = models.TextField('Anmerkungen', max_length=2000, blank=True)
|
||||||
notes = models.TextField(max_length=2000, null=True, blank=True, verbose_name='Anmerkungen')
|
|
||||||
|
|
||||||
# Workflow fields (used only for the request process)
|
# Workflow fields (used only for the request process)
|
||||||
decision = models.CharField(
|
decision = models.CharField(max_length=10, choices=Decision.choices, default=Decision.OPEN, db_index=True)
|
||||||
max_length=10, choices=Decision.choices, default=Decision.OPEN, db_index=True
|
|
||||||
)
|
|
||||||
decision_date = models.DateField(null=True, blank=True, db_index=True)
|
decision_date = models.DateField(null=True, blank=True, db_index=True)
|
||||||
decided_by = models.CharField(max_length=100, null=True, blank=True, verbose_name='Entschieden von')
|
decided_by = models.CharField('Entschieden von', max_length=100, blank=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = 'Projektförderungs-Antrag (< 1000 EUR)'
|
verbose_name = 'Projektförderungs-Antrag (< 1000 EUR)'
|
||||||
|
|
@ -502,16 +504,6 @@ class ProjectRequest(Volunteer):
|
||||||
return f'[Antrag] {self.name} ({self.realname})'
|
return f'[Antrag] {self.name} ({self.realname})'
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
super().clean()
|
|
||||||
|
|
||||||
# 1) Additional guard if MaxValueValidator is removed
|
|
||||||
if self.cost is not None and self.cost > 1000:
|
|
||||||
raise ValidationError({
|
|
||||||
'cost': ('Bitte beachte, dass für Projektkosten über 1.000 EUR '
|
|
||||||
'ein öffentlicher Projektplan erforderlich ist '
|
|
||||||
'(siehe Wikipedia:Förderung/Projektplanung).')
|
|
||||||
})
|
|
||||||
|
|
||||||
# 2) Required and allowed values
|
# 2) Required and allowed values
|
||||||
if not self.categories:
|
if not self.categories:
|
||||||
raise ValidationError({'categories': 'Bitte wähle mindestens eine Projektkategorie.'})
|
raise ValidationError({'categories': 'Bitte wähle mindestens eine Projektkategorie.'})
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue