diff --git a/openslides/motion/__init__.py b/openslides/motion/__init__.py index ea23517a7..e296be3ce 100644 --- a/openslides/motion/__init__.py +++ b/openslides/motion/__init__.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python # -*- coding: utf-8 -*- """ openslides.motion diff --git a/openslides/motion/forms.py b/openslides/motion/forms.py index 139d4205e..7b81d6524 100644 --- a/openslides/motion/forms.py +++ b/openslides/motion/forms.py @@ -15,7 +15,7 @@ from django.utils.translation import ugettext as _ from openslides.utils.forms import CssClassMixin from openslides.utils.person import PersonFormField, MultiplePersonFormField -from .models import Motion, Workflow +from .models import Motion, Workflow, Category class BaseMotionForm(forms.ModelForm, CssClassMixin): @@ -90,6 +90,18 @@ class MotionDisableVersioningMixin(forms.ModelForm): last_version will be used.""" +class MotionCategoryMixin(forms.ModelForm): + """Mixin to let the user choose the category for the motion.""" + + category = forms.ModelChoiceField(queryset=Category.objects.all(), required=False) + + +class MotionIdentifierMixin(forms.ModelForm): + """Mixin to let the user choose the identifier for the motion.""" + + identifier = forms.CharField(required=False) + + class ConfigForm(CssClassMixin, forms.Form): """Form for the configuration tab of OpenSlides.""" motion_min_supporters = forms.IntegerField( diff --git a/openslides/motion/models.py b/openslides/motion/models.py index 989fe6857..e4cf800b4 100644 --- a/openslides/motion/models.py +++ b/openslides/motion/models.py @@ -16,7 +16,7 @@ from datetime import datetime from django.core.urlresolvers import reverse -from django.db import models +from django.db import models, IntegrityError from django.db.models import Max from django.dispatch import receiver from django.utils import formats @@ -37,6 +37,10 @@ from openslides.agenda.models import Item from .exceptions import MotionError, WorkflowError +# TODO: into the config-tab +config['motion_identifier'] = ('manually', 'per_category', 'serially_numbered')[2] + + class Motion(SlideMixin, models.Model): """The Motion Class. @@ -65,7 +69,15 @@ class Motion(SlideMixin, models.Model): unique=True) """A string as human readable identifier for the motion.""" - # category = models.ForeignKey('Category', null=True, blank=True) + identifier_number = models.IntegerField(null=True) + """Counts the number of the motion in one category. + + Needed to find the next free motion-identifier. + """ + + category = models.ForeignKey('Category', null=True, blank=True) + """ForeignKey to one category of motions.""" + # TODO: proposal #master = models.ForeignKey('self', null=True, blank=True) @@ -168,6 +180,33 @@ class Motion(SlideMixin, models.Model): if link == 'delete': return reverse('motion_delete', args=[str(self.id)]) + def set_identifier(self): + if config['motion_identifier'] == 'manually': + # Do not set an identifier. + return + elif config['motion_identifier'] == 'per_category': + motions = Motion.objects.filter(category=self.category) + else: + motions = Motion.objects.all() + + number = motions.aggregate(Max('identifier_number'))['identifier_number__max'] or 0 + if self.category is None or not self.category.prefix: + prefix = '' + else: + prefix = self.category.prefix + ' ' + + while True: + number += 1 + self.identifier = '%s%d' % (prefix, number) + try: + self.save() + except IntegrityError: + continue + else: + self.number = number + self.save() + break + def get_title(self): """Get the title of the motion. @@ -344,6 +383,18 @@ class Motion(SlideMixin, models.Model): else: raise WorkflowError('You can not create a poll in state %s.' % self.state.name) + def set_state(self, state): + """Set the state of the motion. + + State can be the id of a state object or a state object. + """ + if type(state) is int: + state = State.objects.get(pk=state) + + if not state.dont_set_identifier: + self.set_identifier() + self.state = state + def reset_state(self): """Set the state to the default state. If the motion is new, it chooses the default workflow from config.""" if self.state: @@ -524,12 +575,24 @@ class MotionSupporter(models.Model): return unicode(self.person) -## class Category(models.Model): - ## name = models.CharField(max_length=255, verbose_name=ugettext_lazy("Category name")) - ## prefix = models.CharField(max_length=32, verbose_name=ugettext_lazy("Category prefix")) +class Category(models.Model): + name = models.CharField(max_length=255, verbose_name=ugettext_lazy("Category name")) + """Name of the category.""" - ## def __unicode__(self): - ## return self.name + prefix = models.CharField(blank=True, max_length=32, verbose_name=ugettext_lazy("Category prefix")) + """Prefix of the category. + + Used to build the identifier of a motion. + """ + + def __unicode__(self): + return self.name + + def get_absolute_url(self, link='update'): + if link == 'update' or link == 'edit': + return reverse('motion_category_update', args=[str(self.id)]) + if link == 'delete': + return reverse('motion_category_delete', args=[str(self.id)]) ## class Comment(models.Model): @@ -685,6 +748,12 @@ class State(models.Model): dont_set_new_version_active = models.BooleanField(default=False) """If true, new versions are not automaticly set active.""" + dont_set_identifier = models.BooleanField(default=False) + """Decides if the motion gets an identifier. + + If true, the motion does not get an identifier if the state change to + this one, else it does.""" + def __unicode__(self): """Returns the name of the state.""" return self.name diff --git a/openslides/motion/signals.py b/openslides/motion/signals.py index 526a56783..ff662ddf1 100644 --- a/openslides/motion/signals.py +++ b/openslides/motion/signals.py @@ -61,7 +61,8 @@ def create_builtin_workflows(sender, **kwargs): state_2_1 = State.objects.create(name=ugettext_noop('published'), workflow=workflow_2, allow_support=True, - allow_submitter_edit=True) + allow_submitter_edit=True, + dont_set_identifier=True) state_2_2 = State.objects.create(name=ugettext_noop('permitted'), workflow=workflow_2, action_word=ugettext_noop('Permit'), diff --git a/openslides/motion/templates/motion/category_form.html b/openslides/motion/templates/motion/category_form.html new file mode 100644 index 000000000..5114c9a0a --- /dev/null +++ b/openslides/motion/templates/motion/category_form.html @@ -0,0 +1,33 @@ +{% extends "base.html" %} + +{% load tags %} +{% load i18n %} + +{% block title %} + {{ block.super }} – + {% if motion %} + {% trans "Edit category" %} + {% else %} + {% trans "New category" %} + {% endif %} +{% endblock %} + +{% block content %} +
No Categories
+ {% endfor %} + +{% endblock %} diff --git a/openslides/motion/templates/motion/motion_detail.html b/openslides/motion/templates/motion/motion_detail.html index a9de961b6..12d26fba3 100644 --- a/openslides/motion/templates/motion/motion_detail.html +++ b/openslides/motion/templates/motion/motion_detail.html @@ -8,11 +8,11 @@ {% block content %}