prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Use person number for appoint->overturn field
  <!-- Do you want to ask a question? Are you looking for support? The system administrator can help you: admin@utn.se -->
  
  ### Prerequisites
  
  * [X] Put an X between the brackets on this line if you have done all of the
  following:
      * Reproduced the problem with clear cache.
      * (If running the application locally:) Made sure your running the newest version on the development branch
      * Checked that your issue isn't already filed: https://github.com/UTNkar/moore/issues
  
  ### Description
  
  Currently the `overturn` field within the `appoint` view of `Position` has a overturn field that works with usernames. The username(s) entered will be appointed to the position, no matter if they applied or not.
  
  _Problem_: Within the old system a similar feature was available, but it was by person number. According to the management team this is preferable.
  
  ### Steps to Reproduce
  
  1. Create new `Position` with past deadline
  2. Click `appoint` in the overview
  
  <!-- Please select the appropriate "topic category"/blue and "issue type"/yellow label -->
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `src/involvement/forms.py`
  Content:
  ```
  1 from django import forms
  2 from django.contrib.auth import get_user_model
  3 from django.utils.translation import ugettext_lazy as _
  4 
  5 from involvement.models import Application, Reference
  6 from utils.forms import AdvancedModelMultipleChoiceField
  7 
  8 
  9 class ApplicationForm(forms.ModelForm):
  10     class Meta:
  11         model = Application
  12         exclude = ['position', 'applicant']
  13         widgets = {
  14             'cover_letter': forms.Textarea(attrs={'style': 'height: 200px',
  15                                                   'class': 'form-control'}),
  16             'qualifications': forms.Textarea(attrs={'style': 'height: 200px',
  17                                                     'class': 'form-control'}),
  18         }
  19 
  20     def clean_status(self):
  21         status = self.cleaned_data['status']
  22         if status not in ['draft', 'submitted'] \
  23                 or (self.initial['status'] == 'submitted'
  24                     and status == 'draft'):
  25             raise forms.ValidationError(_('The submitted status was invalid.'))
  26         return status
  27 
  28 
  29 ReferenceFormSet = forms.inlineformset_factory(
  30     Application,
  31     Reference,
  32     fields=('name', 'position', 'email', 'phone_number', 'comment'),
  33     widgets={
  34         'name': forms.TextInput(attrs={'class': 'form-control'}),
  35         'position': forms.TextInput(attrs={'class': 'form-control'}),
  36         'email': forms.TextInput(attrs={'class': 'form-control'}),
  37         'phone_number': forms.TextInput(attrs={'class': 'form-control'}),
  38         'comment': forms.TextInput(attrs={'class': 'form-control'}),
  39     },
  40     extra=0,
  41 )
  42 
  43 
  44 class ApprovalForm(forms.ModelForm):
  45     status = forms.ChoiceField(
  46         choices=(
  47             ('submitted', '---------'),
  48             ('approved', _('Approved')),
  49             ('disapproved', _('Disapproved')),
  50         ),
  51     )
  52 
  53     class Meta:
  54         model = Application
  55         fields = []
  56 
  57     def clean_status(self):
  58         status = self.cleaned_data['status']
  59         if status not in ['submitted', 'approved', 'disapproved']:
  60             raise forms.ValidationError(_('The submitted status was invalid.'))
  61         return status
  62 
  63     def save(self, commit=True):
  64         self.instance.status = self.cleaned_data['status']
  65 
  66         super(ApprovalForm, self).save(commit)
  67 
  68 
  69 class AppointmentForm(forms.Form):
  70     appoint = AdvancedModelMultipleChoiceField(
  71         Application.objects.none(),
  72         widget=forms.CheckboxSelectMultiple(),
  73         required=False,
  74     )
  75     overturn = forms.CharField(
  76         required=False,
  77         label=_('Overturn'),
  78         help_text=_('Enter a comma separated list of users you want to '
  79                     'appoint to the position, even though did not apply for '
  80                     'the position.')
  81     )
  82 
  83     def __init__(self, position, *args, **kwargs):
  84         super(AppointmentForm, self).__init__(*args, **kwargs)
  85         self.position = position
  86         self.fields['appoint'].queryset = position.applications.filter(
  87             status__in=['submitted', 'approved', 'appointed', 'turned_down']
  88         )
  89         self.initial['appoint'] = position.applications.filter(
  90             status='appointed'
  91         )
  92 
  93     def clean_overturn(self):
  94         string = self.cleaned_data['overturn']
  95         string = string.replace(' ', '')
  96         if string == '':
  97             return []
  98         else:
  99             users = string.split(',')
  100             for u in users:
  101                 if not get_user_model().objects.filter(
  102                     username=u
  103                 ).exists():
  104                     raise forms.ValidationError(
  105                         _('No user with the username %(user)s exists.'),
  106                         params={'user': u},
  107                     )
  108                 elif self.position.applications.filter(
  109                     applicant__username=u
  110                 ).exclude(
  111                     status='draft'
  112                 ).exists():
  113                     raise forms.ValidationError(
  114                         _('User %(user)s already applied for this position '
  115                           'and can not be appointed through the overturn '
  116                           'field.'),
  117                         params={'user': u},
  118                     )
  119             return users
  120 
  121     def clean(self):
  122         super(AppointmentForm, self).clean()
  123         appoint = self.cleaned_data.get('appoint', [])
  124         overturn = self.cleaned_data.get('overturn', [])
  125         nr_appointment = len(appoint) + len(overturn)
  126         if nr_appointment > self.position.appointments:
  127             raise forms.ValidationError(
  128                 _('You cannot appoint %(current)s applicants. The maximum '
  129                   'for this position is %(max)s.'),
  130                 params={
  131                     'current': nr_appointment,
  132                     'max': self.position.appointments,
  133                 },
  134             )
  135         return self.cleaned_data
  136 
  137     def save(self):
  138         for application in self.fields['appoint'].queryset:
  139             if application in self.cleaned_data['appoint']:
  140                 application.status = 'appointed'
  141             else:
  142                 application.status = 'turned_down'
  143             application.save()
  144 
  145         for user in self.cleaned_data['overturn']:
  146             user = get_user_model().objects.get(
  147                     username=user
  148             )
  149             appl, created = Application.objects.get_or_create(
  150                 position=self.position,
  151                 applicant=user,
  152                 defaults={'status': 'appointed'}
  153             )
  154             if not created:
  155                 appl.status = 'appointed'
  156                 appl.save()
  157
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/src/involvement/forms.py b/src/involvement/forms.py
  --- a/src/involvement/forms.py
  +++ b/src/involvement/forms.py
  @@ -3,6 +3,7 @@
   from django.utils.translation import ugettext_lazy as _
   
   from involvement.models import Application, Reference
  +from members.forms import PersonNumberField
   from utils.forms import AdvancedModelMultipleChoiceField
   
   
  @@ -75,9 +76,9 @@
       overturn = forms.CharField(
           required=False,
           label=_('Overturn'),
  -        help_text=_('Enter a comma separated list of users you want to '
  -                    'appoint to the position, even though did not apply for '
  -                    'the position.')
  +        help_text=_('Enter a comma separated list of person numbers you want '
  +                    'to appoint to the position, even though did not apply for'
  +                    ' the position.')
       )
   
       def __init__(self, position, *args, **kwargs):
  @@ -96,26 +97,35 @@
           if string == '':
               return []
           else:
  -            users = string.split(',')
  -            for u in users:
  +            pnrs = string.split(',')
  +            users = []
  +            for pnr in pnrs:
  +                date, number = PersonNumberField().to_python(pnr)
                   if not get_user_model().objects.filter(
  -                    username=u
  +                    birthday=date,
  +                    person_number_ext=number,
                   ).exists():
                       raise forms.ValidationError(
  -                        _('No user with the username %(user)s exists.'),
  -                        params={'user': u},
  +                        _('No user with the person number %(pnr)s exists.'),
  +                        params={'pnr': pnr},
                       )
                   elif self.position.applications.filter(
  -                    applicant__username=u
  +                    applicant__birthday=date,
  +                    applicant__person_number_ext=number,
                   ).exclude(
                       status='draft'
                   ).exists():
                       raise forms.ValidationError(
  -                        _('User %(user)s already applied for this position '
  -                          'and can not be appointed through the overturn '
  -                          'field.'),
  -                        params={'user': u},
  +                        _('User with person number %(pnr)s already applied for'
  +                          ' this position and can not be appointed through the'
  +                          ' overturn field.'),
  +                        params={'pnr': pnr},
                       )
  +                else:
  +                    users.append(get_user_model().objects.get(
  +                        birthday=date,
  +                        person_number_ext=number,
  +                    ))
               return users
   
       def clean(self):
  @@ -143,9 +153,6 @@
               application.save()
   
           for user in self.cleaned_data['overturn']:
  -            user = get_user_model().objects.get(
  -                    username=user
  -            )
               appl, created = Application.objects.get_or_create(
                   position=self.position,
                   applicant=user,
  
verification_info: {"golden_diff": "diff --git a/src/involvement/forms.py b/src/involvement/forms.py\n--- a/src/involvement/forms.py\n+++ b/src/involvement/forms.py\n@@ -3,6 +3,7 @@\n from django.utils.translation import ugettext_lazy as _\n \n from involvement.models import Application, Reference\n+from members.forms import PersonNumberField\n from utils.forms import AdvancedModelMultipleChoiceField\n \n \n@@ -75,9 +76,9 @@\n     overturn = forms.CharField(\n         required=False,\n         label=_('Overturn'),\n-        help_text=_('Enter a comma separated list of users you want to '\n-                    'appoint to the position, even though did not apply for '\n-                    'the position.')\n+        help_text=_('Enter a comma separated list of person numbers you want '\n+                    'to appoint to the position, even though did not apply for'\n+                    ' the position.')\n     )\n \n     def __init__(self, position, *args, **kwargs):\n@@ -96,26 +97,35 @@\n         if string == '':\n             return []\n         else:\n-            users = string.split(',')\n-            for u in users:\n+            pnrs = string.split(',')\n+            users = []\n+            for pnr in pnrs:\n+                date, number = PersonNumberField().to_python(pnr)\n                 if not get_user_model().objects.filter(\n-                    username=u\n+                    birthday=date,\n+                    person_number_ext=number,\n                 ).exists():\n                     raise forms.ValidationError(\n-                        _('No user with the username %(user)s exists.'),\n-                        params={'user': u},\n+                        _('No user with the person number %(pnr)s exists.'),\n+                        params={'pnr': pnr},\n                     )\n                 elif self.position.applications.filter(\n-                    applicant__username=u\n+                    applicant__birthday=date,\n+                    applicant__person_number_ext=number,\n                 ).exclude(\n                     status='draft'\n                 ).exists():\n                     raise forms.ValidationError(\n-                        _('User %(user)s already applied for this position '\n-                          'and can not be appointed through the overturn '\n-                          'field.'),\n-                        params={'user': u},\n+                        _('User with person number %(pnr)s already applied for'\n+                          ' this position and can not be appointed through the'\n+                          ' overturn field.'),\n+                        params={'pnr': pnr},\n                     )\n+                else:\n+                    users.append(get_user_model().objects.get(\n+                        birthday=date,\n+                        person_number_ext=number,\n+                    ))\n             return users\n \n     def clean(self):\n@@ -143,9 +153,6 @@\n             application.save()\n \n         for user in self.cleaned_data['overturn']:\n-            user = get_user_model().objects.get(\n-                    username=user\n-            )\n             appl, created = Application.objects.get_or_create(\n                 position=self.position,\n                 applicant=user,\n", "issue": "Use person number for appoint->overturn field\n<!-- Do you want to ask a question? Are you looking for support? The system administrator can help you: admin@utn.se -->\r\n\r\n### Prerequisites\r\n\r\n* [X] Put an X between the brackets on this line if you have done all of the\r\nfollowing:\r\n    * Reproduced the problem with clear cache.\r\n    * (If running the application locally:) Made sure your running the newest version on the development branch\r\n    * Checked that your issue isn't already filed: https://github.com/UTNkar/moore/issues\r\n\r\n### Description\r\n\r\nCurrently the `overturn` field within the `appoint` view of `Position` has a overturn field that works with usernames. The username(s) entered will be appointed to the position, no matter if they applied or not.\r\n\r\n_Problem_: Within the old system a similar feature was available, but it was by person number. According to the management team this is preferable.\r\n\r\n### Steps to Reproduce\r\n\r\n1. Create new `Position` with past deadline\r\n2. Click `appoint` in the overview\r\n\r\n<!-- Please select the appropriate \"topic category\"/blue and \"issue type\"/yellow label -->\n", "before_files": [{"content": "from django import forms\nfrom django.contrib.auth import get_user_model\nfrom django.utils.translation import ugettext_lazy as _\n\nfrom involvement.models import Application, Reference\nfrom utils.forms import AdvancedModelMultipleChoiceField\n\n\nclass ApplicationForm(forms.ModelForm):\n    class Meta:\n        model = Application\n        exclude = ['position', 'applicant']\n        widgets = {\n            'cover_letter': forms.Textarea(attrs={'style': 'height: 200px',\n                                                  'class': 'form-control'}),\n            'qualifications': forms.Textarea(attrs={'style': 'height: 200px',\n                                                    'class': 'form-control'}),\n        }\n\n    def clean_status(self):\n        status = self.cleaned_data['status']\n        if status not in ['draft', 'submitted'] \\\n                or (self.initial['status'] == 'submitted'\n                    and status == 'draft'):\n            raise forms.ValidationError(_('The submitted status was invalid.'))\n        return status\n\n\nReferenceFormSet = forms.inlineformset_factory(\n    Application,\n    Reference,\n    fields=('name', 'position', 'email', 'phone_number', 'comment'),\n    widgets={\n        'name': forms.TextInput(attrs={'class': 'form-control'}),\n        'position': forms.TextInput(attrs={'class': 'form-control'}),\n        'email': forms.TextInput(attrs={'class': 'form-control'}),\n        'phone_number': forms.TextInput(attrs={'class': 'form-control'}),\n        'comment': forms.TextInput(attrs={'class': 'form-control'}),\n    },\n    extra=0,\n)\n\n\nclass ApprovalForm(forms.ModelForm):\n    status = forms.ChoiceField(\n        choices=(\n            ('submitted', '---------'),\n            ('approved', _('Approved')),\n            ('disapproved', _('Disapproved')),\n        ),\n    )\n\n    class Meta:\n        model = Application\n        fields = []\n\n    def clean_status(self):\n        status = self.cleaned_data['status']\n        if status not in ['submitted', 'approved', 'disapproved']:\n            raise forms.ValidationError(_('The submitted status was invalid.'))\n        return status\n\n    def save(self, commit=True):\n        self.instance.status = self.cleaned_data['status']\n\n        super(ApprovalForm, self).save(commit)\n\n\nclass AppointmentForm(forms.Form):\n    appoint = AdvancedModelMultipleChoiceField(\n        Application.objects.none(),\n        widget=forms.CheckboxSelectMultiple(),\n        required=False,\n    )\n    overturn = forms.CharField(\n        required=False,\n        label=_('Overturn'),\n        help_text=_('Enter a comma separated list of users you want to '\n                    'appoint to the position, even though did not apply for '\n                    'the position.')\n    )\n\n    def __init__(self, position, *args, **kwargs):\n        super(AppointmentForm, self).__init__(*args, **kwargs)\n        self.position = position\n        self.fields['appoint'].queryset = position.applications.filter(\n            status__in=['submitted', 'approved', 'appointed', 'turned_down']\n        )\n        self.initial['appoint'] = position.applications.filter(\n            status='appointed'\n        )\n\n    def clean_overturn(self):\n        string = self.cleaned_data['overturn']\n        string = string.replace(' ', '')\n        if string == '':\n            return []\n        else:\n            users = string.split(',')\n            for u in users:\n                if not get_user_model().objects.filter(\n                    username=u\n                ).exists():\n                    raise forms.ValidationError(\n                        _('No user with the username %(user)s exists.'),\n                        params={'user': u},\n                    )\n                elif self.position.applications.filter(\n                    applicant__username=u\n                ).exclude(\n                    status='draft'\n                ).exists():\n                    raise forms.ValidationError(\n                        _('User %(user)s already applied for this position '\n                          'and can not be appointed through the overturn '\n                          'field.'),\n                        params={'user': u},\n                    )\n            return users\n\n    def clean(self):\n        super(AppointmentForm, self).clean()\n        appoint = self.cleaned_data.get('appoint', [])\n        overturn = self.cleaned_data.get('overturn', [])\n        nr_appointment = len(appoint) + len(overturn)\n        if nr_appointment > self.position.appointments:\n            raise forms.ValidationError(\n                _('You cannot appoint %(current)s applicants. The maximum '\n                  'for this position is %(max)s.'),\n                params={\n                    'current': nr_appointment,\n                    'max': self.position.appointments,\n                },\n            )\n        return self.cleaned_data\n\n    def save(self):\n        for application in self.fields['appoint'].queryset:\n            if application in self.cleaned_data['appoint']:\n                application.status = 'appointed'\n            else:\n                application.status = 'turned_down'\n            application.save()\n\n        for user in self.cleaned_data['overturn']:\n            user = get_user_model().objects.get(\n                    username=user\n            )\n            appl, created = Application.objects.get_or_create(\n                position=self.position,\n                applicant=user,\n                defaults={'status': 'appointed'}\n            )\n            if not created:\n                appl.status = 'appointed'\n                appl.save()\n", "path": "src/involvement/forms.py"}], "after_files": [{"content": "from django import forms\nfrom django.contrib.auth import get_user_model\nfrom django.utils.translation import ugettext_lazy as _\n\nfrom involvement.models import Application, Reference\nfrom members.forms import PersonNumberField\nfrom utils.forms import AdvancedModelMultipleChoiceField\n\n\nclass ApplicationForm(forms.ModelForm):\n    class Meta:\n        model = Application\n        exclude = ['position', 'applicant']\n        widgets = {\n            'cover_letter': forms.Textarea(attrs={'style': 'height: 200px',\n                                                  'class': 'form-control'}),\n            'qualifications': forms.Textarea(attrs={'style': 'height: 200px',\n                                                    'class': 'form-control'}),\n        }\n\n    def clean_status(self):\n        status = self.cleaned_data['status']\n        if status not in ['draft', 'submitted'] \\\n                or (self.initial['status'] == 'submitted'\n                    and status == 'draft'):\n            raise forms.ValidationError(_('The submitted status was invalid.'))\n        return status\n\n\nReferenceFormSet = forms.inlineformset_factory(\n    Application,\n    Reference,\n    fields=('name', 'position', 'email', 'phone_number', 'comment'),\n    widgets={\n        'name': forms.TextInput(attrs={'class': 'form-control'}),\n        'position': forms.TextInput(attrs={'class': 'form-control'}),\n        'email': forms.TextInput(attrs={'class': 'form-control'}),\n        'phone_number': forms.TextInput(attrs={'class': 'form-control'}),\n        'comment': forms.TextInput(attrs={'class': 'form-control'}),\n    },\n    extra=0,\n)\n\n\nclass ApprovalForm(forms.ModelForm):\n    status = forms.ChoiceField(\n        choices=(\n            ('submitted', '---------'),\n            ('approved', _('Approved')),\n            ('disapproved', _('Disapproved')),\n        ),\n    )\n\n    class Meta:\n        model = Application\n        fields = []\n\n    def clean_status(self):\n        status = self.cleaned_data['status']\n        if status not in ['submitted', 'approved', 'disapproved']:\n            raise forms.ValidationError(_('The submitted status was invalid.'))\n        return status\n\n    def save(self, commit=True):\n        self.instance.status = self.cleaned_data['status']\n\n        super(ApprovalForm, self).save(commit)\n\n\nclass AppointmentForm(forms.Form):\n    appoint = AdvancedModelMultipleChoiceField(\n        Application.objects.none(),\n        widget=forms.CheckboxSelectMultiple(),\n        required=False,\n    )\n    overturn = forms.CharField(\n        required=False,\n        label=_('Overturn'),\n        help_text=_('Enter a comma separated list of person numbers you want '\n                    'to appoint to the position, even though did not apply for'\n                    ' the position.')\n    )\n\n    def __init__(self, position, *args, **kwargs):\n        super(AppointmentForm, self).__init__(*args, **kwargs)\n        self.position = position\n        self.fields['appoint'].queryset = position.applications.filter(\n            status__in=['submitted', 'approved', 'appointed', 'turned_down']\n        )\n        self.initial['appoint'] = position.applications.filter(\n            status='appointed'\n        )\n\n    def clean_overturn(self):\n        string = self.cleaned_data['overturn']\n        string = string.replace(' ', '')\n        if string == '':\n            return []\n        else:\n            pnrs = string.split(',')\n            users = []\n            for pnr in pnrs:\n                date, number = PersonNumberField().to_python(pnr)\n                if not get_user_model().objects.filter(\n                    birthday=date,\n                    person_number_ext=number,\n                ).exists():\n                    raise forms.ValidationError(\n                        _('No user with the person number %(pnr)s exists.'),\n                        params={'pnr': pnr},\n                    )\n                elif self.position.applications.filter(\n                    applicant__birthday=date,\n                    applicant__person_number_ext=number,\n                ).exclude(\n                    status='draft'\n                ).exists():\n                    raise forms.ValidationError(\n                        _('User with person number %(pnr)s already applied for'\n                          ' this position and can not be appointed through the'\n                          ' overturn field.'),\n                        params={'pnr': pnr},\n                    )\n                else:\n                    users.append(get_user_model().objects.get(\n                        birthday=date,\n                        person_number_ext=number,\n                    ))\n            return users\n\n    def clean(self):\n        super(AppointmentForm, self).clean()\n        appoint = self.cleaned_data.get('appoint', [])\n        overturn = self.cleaned_data.get('overturn', [])\n        nr_appointment = len(appoint) + len(overturn)\n        if nr_appointment > self.position.appointments:\n            raise forms.ValidationError(\n                _('You cannot appoint %(current)s applicants. The maximum '\n                  'for this position is %(max)s.'),\n                params={\n                    'current': nr_appointment,\n                    'max': self.position.appointments,\n                },\n            )\n        return self.cleaned_data\n\n    def save(self):\n        for application in self.fields['appoint'].queryset:\n            if application in self.cleaned_data['appoint']:\n                application.status = 'appointed'\n            else:\n                application.status = 'turned_down'\n            application.save()\n\n        for user in self.cleaned_data['overturn']:\n            appl, created = Application.objects.get_or_create(\n                position=self.position,\n                applicant=user,\n                defaults={'status': 'appointed'}\n            )\n            if not created:\n                appl.status = 'appointed'\n                appl.save()\n", "path": "src/involvement/forms.py"}]}