def get_form(self, form_class=None): form = super().get_form(form_class) form.helper = FormHelper() if form.instance.id: action = 'Save' cancel_edit_url = reverse('logged-template-question-detail', kwargs={'pk': form.instance.id}) else: action = 'Create' cancel_edit_url = reverse('logged-template-question-add') form.fields['question_text'].widget.attrs = {'rows': 2} form.fields['question_description'].widget.attrs = {'rows': 2} form.helper.layout = Layout( Div(Div('question_text', css_class='col-12'), css_class='row'), Div(Div('question_description', css_class='col-12'), css_class='row'), Div(Div('answer_type', css_class='col-6'), Div('answer_max_length', css_class='col-6'), css_class='row'), Div(Div('answer_required', css_class='col-12'), css_class='row'), Div(Div(HTML('<br>'), css_class='col-12'), css_class='row'), FormActions(Submit('save', f'{action} Template Question'), cancel_edit_button(cancel_edit_url))) return form
def __init__(self, *args, **kwargs): self._call_part_pk = kwargs.pop('call_part_pk', None) super().__init__(*args, **kwargs) assert self.instance.pk, 'Needs to exist - they are created adding template questions' self.helper = FormHelper(self) cancel_edit_url = reverse('logged-call-part-question-detail', kwargs={'call_pk': self.instance.call_part.call.pk, 'call_question_pk': self.instance.pk }) call = self.instance.call_part.call self.fields['call_part'].queryset = CallPart.objects.filter(call=call).order_by('order') self.helper.layout = Layout( Div( Div('order', css_class='col-6'), css_class='row' ), Div( Div('call_part', css_class='col-12'), css_class='row' ), Div( Div('question_text', css_class='col-12'), css_class='row' ), Div( Div('question_description', css_class='col-12'), css_class='row' ), Div( Div('answer_max_length', css_class='col-12'), css_class='row' ), Div( Div('answer_required', css_class='col-12'), css_class='row' ), FormActions( Submit('save', 'Save Call Question'), cancel_edit_button(cancel_edit_url) ) )
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.helper = FormHelper(self) is_edit = self.instance and self.instance.pk if is_edit: cancel_html = cancel_edit_button( reverse('logged-evaluation_criterion-detail', kwargs={'pk': self.instance.pk})) else: cancel_html = cancel_button( reverse('logged-evaluation_criteria-list')) self.helper.layout = Layout( Div(Div('name', css_class='col-6'), css_class='row'), Div(Div('description', css_class='col-12'), css_class='row'), FormActions(Submit('save', 'Save Criterion'), cancel_html))
def __init__(self, *args, **kwargs): call_part_pk = kwargs.pop('call_part_pk') super().__init__(*args, **kwargs) self._call_part = CallPart.objects.get(pk=call_part_pk) used_templates = [] for call_question in self._call_part.callquestion_set.all(): used_templates.append(call_question.template_question) create_template_question_url = reverse('logged-template-question-add') self.fields['template_questions'] = forms.ModelMultipleChoiceField(initial=used_templates, label='', queryset=TemplateQuestion.objects.all(), required=False, widget=FilteredSelectMultiple( is_stacked=True, verbose_name='questions', )) template_questions_label = f'Template questions <div class="pr-3 float-right"><a target="_blank" href="{create_template_question_url}">Create template question <i class="fas fa-external-link-alt"></i></a></div>' cancel_edit_url = reverse('logged-call-update', kwargs={'pk': self._call_part.call.pk}) cancel_edit_url += "#parts" self.helper = FormHelper(self) self.helper.layout = Layout( Div(Div(HTML(template_questions_label), css_class='col-4'), css_class='row'), Div( Div('template_questions', css_class='col-6'), css_class='row' ), FormActions( Submit('save', 'Save Template Questions'), cancel_edit_button(cancel_edit_url) ) )
def __init__(self, *args, **kwargs): project = kwargs.pop('project') super().__init__(*args, **kwargs) XDSoftYearMonthDayPickerInput.set_format_to_field( self.fields['signed_date']) self.fields['project'].initial = project.id self.helper = FormHelper(self) cancel_url = reverse('logged-grant_management-project-detail', kwargs={'pk': project.id}) self.helper.layout = Layout( Div(Div('project', hidden=True), Div('file', css_class='col-6'), css_class='row'), Div(Div('signed_date', css_class='col-6'), css_class='row'), Div(Div('signed_by', css_class='col-6'), css_class='row'), FormActions(Submit('save', 'Save Grant Agreement'), cancel_edit_button(cancel_url)))
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) XDSoftYearMonthDayPickerInput.set_format_to_field( self.fields['start_date']) XDSoftYearMonthDayPickerInput.set_format_to_field( self.fields['end_date']) self.helper = FormHelper(self) cancel_url = reverse('logged-project-detail', kwargs={'pk': self.instance.id}) self.helper.layout = Layout( Div(Div('title', css_class='col-12'), css_class='row'), Div(Div('keywords', css_class='col-12'), css_class='row'), Div(Div('geographical_areas', css_class='col-12'), css_class='row'), Div(Div('location', css_class='col-12'), css_class='row'), Div(Div('start_date', css_class='col-6'), css_class='row'), Div(Div('end_date', css_class='col-6'), css_class='row'), FormActions(Submit('save', 'Save Project'), cancel_edit_button(cancel_url)))
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) XDSoftYearMonthDayPickerInput.set_format_to_field( self.fields['start_date']) XDSoftYearMonthDayPickerInput.set_format_to_field( self.fields['end_date']) self.fields['allocated_budget'].disabled = True self.fields[ 'allocated_budget'].help_text = 'The allocated budget cannot be changed after the project is created' self.helper = FormHelper(self) cancel_url = reverse('logged-grant_management-project-detail', kwargs={'pk': self.instance.id}) self.helper.layout = Layout( Div(Div('allocated_budget', css_class='col-6'), css_class='row'), Div(Div('start_date', css_class='col-6'), css_class='row'), Div(Div('end_date', css_class='col-6'), css_class='row'), FormActions(Submit('save', 'Save Information'), cancel_edit_button(cancel_url)))
def __init__(self, *args, **kwargs): self._proposal_id = kwargs.pop('proposal_id') assert 'form_action' not in kwargs super().__init__(*args, **kwargs) YES_NO_CHOICES = [(True, 'Yes'), (False, 'No')] self.fields['eligible'] = forms.ChoiceField(choices=YES_NO_CHOICES, widget=forms.RadioSelect) self.fields['comment'] = forms.CharField( label='Comment<span class="asteriskField">*</span>', required=False, max_length=1000, help_text= 'Maximum length 1000 characters. Required if proposal is not eligible.', widget=forms.Textarea(attrs={'rows': 4})) proposal = Proposal.objects.get(id=self._proposal_id) if proposal.eligibility == Proposal.ELIGIBLE: self.fields['eligible'].initial = True elif proposal.eligibility == Proposal.NOTELIGIBLE: self.fields['eligible'].initial = False self.fields['comment'].initial = proposal.eligibility_comment self.helper = FormHelper(self) self.helper.form_id = 'eligibility_form' self.helper.form_action = reverse('logged-proposal-eligibility-update', kwargs={'pk': self._proposal_id}) self.helper.layout = Layout( Div(Div('eligible')), Div(Div('comment')), FormActions( Submit('save', 'Save Eligibility'), HTML('<p></p>'), cancel_edit_button( reverse('logged-call-evaluation-proposal-detail', kwargs={'pk': proposal.id}))))
def __init__(self, *args, **kwargs): call = kwargs.pop('call', None) super().__init__(*args, **kwargs) self.helper = FormHelper(self) if self.instance.id: self.helper.form_action = reverse('logged-call-evaluation-update', kwargs={'pk': self.instance.id}) self.fields['call'].initial = call = self.instance.call else: self.helper.form_action = reverse('logged-call-evaluation-add') + f'?call={call.id}' self.fields['call'].initial = call XDSoftYearMonthDayPickerInput.set_format_to_field(self.fields['panel_date']) if hasattr(call, 'callevaluation'): cancel_edit_url = reverse('logged-call-evaluation-detail', kwargs={'pk': call.callevaluation.id}) initial_reviewers = call.reviewer_set.all() else: cancel_edit_url = reverse('logged-call-evaluation-add') + f'?call={call.id}' initial_reviewers = [] self.fields['reviewers'] = ReviewerMultipleChoiceField(initial=initial_reviewers, queryset=Reviewer.objects.all(), required=True, widget=FilteredSelectMultiple( is_stacked=True, verbose_name='reviewers'), help_text=self.Meta.help_texts['reviewers']) criterion_choices, criterion_initial = CheckboxSelectMultipleSortable.get_choices_initial( CriterionCallEvaluation, self.instance, 'call_evaluation', Criterion, 'criterion', label_from_instance=lambda obj: format_html('{} <small>({})</small>', obj.name, obj.description) ) self.fields['criteria'] = forms.MultipleChoiceField(choices=criterion_choices, initial=criterion_initial, widget=CheckboxSelectMultipleSortable, label='Criteria (drag and drop to order them)', help_text='These criteria are used in the Excel Evaluation sheet' ) self.criteria_order_key = f'criteria-{CheckboxSelectMultipleSortable.order_of_values_name}' self.helper.layout = Layout( Div( Div('call', css_class='col-12', hidden=True), css_class='row' ), Div( Div('reviewers', css_class='col-12'), css_class='row' ), Div( Div('panel_date', css_class='col-12'), css_class='row' ), Div( Div('criteria', css_class='col-12'), css_class='row' ), Div( Div('post_panel_management_table', css_class='col-12'), css_class='row' ), FormActions( Submit('save', 'Save Call Evaluation'), cancel_edit_button(cancel_edit_url) ) )
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) XDSoftYearMonthDayPickerInput.set_format_to_field(self.fields['start_date']) XDSoftYearMonthDayPickerInput.set_format_to_field(self.fields['end_date']) self.helper = FormHelper(self) is_standalone_project = self.instance.id is None or self.instance.call is None if self.instance.id: submit_text = 'Save Project' cancel_button_html = cancel_edit_button(reverse('logged-project-detail', kwargs={'pk': self.instance.id})) grant_management_deliverables_url = reverse('logged-grant_management-project-detail', kwargs={'pk': self.instance.id}) locations_link = f'{grant_management_deliverables_url}?tab=other#locations' locations_message = f'Use the <a href="{locations_link}">"Other" tab under grant management</a> to edit the project locations.' else: submit_text = 'Create Project' cancel_button_html = cancel_button(reverse('logged-project-list')) locations_message = 'Use the "Other" tab under grant management to add the project locations after creating it. ' # Applicants need to enter 5 keywords in the proposal, SPI at the moment can create or save them without keywords self.fields['keywords'].required = False if is_standalone_project: self.fields['funding_instrument'].queryset = FundingInstrument.objects.order_by('long_name') self.fields['geographical_areas'].required = False principal_investigator_div = Div( Div('principal_investigator', css_class='col-12'), css_class='row' ) self.fields[ 'principal_investigator'].help_text += new_person_message() create_funding_instrument_url = reverse('logged-funding-instrument-add') self.fields[ 'funding_instrument'].help_text += f'. If the funding instrument is not found <a href="{create_funding_instrument_url}">create</a> the funding instrument, reload the page, then try again' funding_instrument_div = Div( Div('funding_instrument', css_class='col-12'), css_class='row' ) finance_year_div = Div( Div('finance_year', css_class='col-6'), css_class='row' ) allocated_budget_div = Div( Div('allocated_budget', css_class='col-6'), css_class='row' ) else: principal_investigator_div = None funding_instrument_div = None finance_year_div = None allocated_budget_div = Div( Div('allocated_budget', css_class='col-6'), css_class='row' ) if self.instance and self.instance.id and self.instance.status != Project.ONGOING: self.fields['allocated_budget'].disabled = True self.fields['allocated_budget'].help_text += '. Can only be changed for ONGOING projects.' # Used when the project is standalone (not coming from a call) # In Meta.fields they are added - IMHO it's easier to delete them # than add them here del self.fields['principal_investigator'] del self.fields['finance_year'] del self.fields['funding_instrument'] self.helper.layout = Layout( Div( Div('title', css_class='col-12'), css_class='row' ), principal_investigator_div, funding_instrument_div, finance_year_div, allocated_budget_div, Div( Div('keywords', css_class='col-12'), css_class='row' ), Div( Div('geographical_areas', css_class='col-12'), css_class='row' ), Div( Div('location', css_class='col-12'), css_class='row' ), Div( Div(HTML('Locations'), css_class='col-12'), css_class='row' ), Div( Div(HTML( locations_message), css_class='col-12'), css_class='row' ), Div( Div(HTML('<br>'), css_class='col-12'), css_class='row' ), Div( Div('start_date', css_class='col-6'), css_class='row' ), Div( Div('end_date', css_class='col-6'), css_class='row' ), Div( Div('on_website', css_class='col-6'), css_class='row' ), FormActions( Submit('save', submit_text), cancel_button_html ) )
def __init__(self, *args, **kwargs): call = kwargs.pop('call', None) super().__init__(*args, **kwargs) self.helper = FormHelper(self) if self.instance.id: self.helper.form_action = reverse('logged-call-evaluation-update', kwargs={'pk': self.instance.id}) self.fields['call'].initial = call = self.instance.call else: self.helper.form_action = reverse('logged-call-evaluation-add') + f'?call={call.id}' self.fields['call'].initial = call XDSoftYearMonthDayPickerInput.set_format_to_field(self.fields['panel_date']) if hasattr(call, 'callevaluation'): cancel_edit_url = reverse('logged-call-evaluation-detail', kwargs={'pk': call.callevaluation.id}) initial_reviewers = call.reviewer_set.all() else: cancel_edit_url = reverse('logged-call-evaluation-add') + f'?call={call.id}' initial_reviewers = [] reviewer_add_url = reverse('logged-user-add') reviewers_help_text = \ f'Select the reviewers that you would like to be added for this call. This is everyone that ' \ f'will review individual proposals and be on the review panel. If you cannot find the person ' \ f'you are looking for, please <a href="{reviewer_add_url}">add a Reviewer type of user</a> and reload ' \ f'this page.' self.fields['reviewers'] = ReviewerMultipleChoiceField(initial=initial_reviewers, queryset=Reviewer.objects.all(), required=True, widget=FilteredSelectMultiple( is_stacked=True, verbose_name='reviewers'), help_text=reviewers_help_text) criterion_choices, criterion_initial = CheckboxSelectMultipleSortable.get_choices_initial( CriterionCallEvaluation, self.instance, 'call_evaluation', Criterion, 'criterion', label_from_instance=lambda obj: format_html('{} <small>({})</small>', obj.name, obj.description) ) evaluation_criteria_list_url = reverse('logged-evaluation_criteria-list') list_edit_criteria = f'You can list and create criteria in <a href="{evaluation_criteria_list_url}">Evaluation criteria list</a>.' self.fields['criteria'] = forms.MultipleChoiceField(choices=criterion_choices, initial=criterion_initial, widget=CheckboxSelectMultipleSortable, label='Criteria (drag and drop to order them)', help_text=f'These criteria are used in the Excel Evaluation sheet. ' f'{list_edit_criteria}' ) self.criteria_order_key = f'criteria-{CheckboxSelectMultipleSortable.order_of_values_name}' self.helper.layout = Layout( Div( Div('call', css_class='col-12', hidden=True), css_class='row' ), Div( Div('reviewers', css_class='col-12'), css_class='row' ), Div( Div('panel_date', css_class='col-12'), css_class='row' ), Div( Div('criteria', css_class='col-12'), css_class='row' ), Div( Div('post_panel_management_table', css_class='col-12'), css_class='row' ), FormActions( Submit('save', 'Save Call Evaluation'), cancel_edit_button(cancel_edit_url) ) )
def __init__(self, *args, **kwargs): initial_type_of_user = kwargs.pop('type_of_user', None) super().__init__(*args, **kwargs) self.new_password = None self.user_id_new_password = None self.helper = FormHelper(self) self.fields['type_of_user'] = forms.ChoiceField(required=True, choices=[(settings.MANAGEMENT_GROUP_NAME, 'Management'), (settings.REVIEWER_GROUP_NAME, 'Reviewer'), ], widget=forms.RadioSelect, help_text='Reviewers only have access to proposals. Management users have access to everything in Nestor' ) self._is_edit_action = bool(self.instance.id) self._is_create_action = not self._is_edit_action if self._is_edit_action: self._original_username = self.instance.username else: self._original_username = None initial_physical_person = None reviewer = None if self._is_edit_action: cancel_html = cancel_edit_button(reverse('logged-user-detail', kwargs={'pk': self.instance.id})) group_count = 0 if self.instance.groups.filter(name=settings.REVIEWER_GROUP_NAME).exists(): self.fields['type_of_user'].initial = settings.REVIEWER_GROUP_NAME try: reviewer = Reviewer.objects.get(user=self.instance) except Reviewer.DoesNotExist: pass if reviewer: initial_physical_person = reviewer.person group_count += 1 if self.instance.groups.filter(name=settings.MANAGEMENT_GROUP_NAME).exists(): self.fields['type_of_user'].initial = settings.MANAGEMENT_GROUP_NAME group_count += 1 assert group_count < 2, 'A user cannot be a reviewer and management at the same time' else: self.fields['is_active'].required = True self.fields['is_active'].initial = True self.fields['is_active'].disabled = True cancel_html = cancel_button(reverse('logged-user-list')) if initial_type_of_user: self.fields['type_of_user'].initial = initial_type_of_user used_users = list(Reviewer.objects.all().values_list('person', flat=True)) my_physical_person_id = 0 if self.instance and self.instance.id: my_user = self.instance reviewer = Reviewer.objects.filter(user=my_user).first() # It might exist because the User might have been previously a reviewer and then changed to management if reviewer: my_physical_person_id = reviewer.user_id if reviewer: initial_physical_person = reviewer.person used_users.remove(initial_physical_person.id) self.fields['physical_person'] = forms.ModelChoiceField( label='Person<span class="asteriskField">*</span>', required=False, help_text=f"Choose the reviewer's name from the list{new_person_message()}.<br>" f"To give access to different calls add the reviewer to the Call Evaluation.", queryset=PhysicalPerson.objects.all().exclude(id__in=used_users), initial=initial_physical_person, widget=autocomplete.ModelSelect2(url=reverse( 'logged-autocomplete-physical-people-non-reviewers') + f'?force_include={my_physical_person_id}')) self.fields['generate_new_password'] = forms.BooleanField(required=self._is_create_action, disabled=self._is_create_action, initial=self._is_create_action, help_text='If enabled, a new password will be generated for this user. If editing a user, this option can be used to change a forgotten password') self.helper.layout = Layout( Div( Div('username', css_class='col-6'), css_class='row' ), Div( Div('type_of_user', css_class='col-6'), css_class='row' ), Div( Div('physical_person', css_class='col-6'), css_class='row reviewer_information', ), Div( Div('first_name', css_class='col-6'), Div('last_name', css_class='col-6'), css_class='row management_information', ), Div( Div('is_active', css_class='col-6'), Div('generate_new_password', css_class='col-6'), css_class='row' ), FormActions( Submit('save', 'Save User'), cancel_html ) )
def __init__(self, *args, **kwargs): assert 'instance' not in kwargs self._proposal = kwargs.pop('proposal') try: proposal_evaluation = ProposalEvaluation.objects.get( proposal=self._proposal) kwargs['instance'] = proposal_evaluation except ObjectDoesNotExist: pass super().__init__(*args, **kwargs) self.helper = FormHelper(self) self.helper.form_action = reverse('logged-proposal-evaluation-update', kwargs={'pk': self._proposal.id}) XDSoftYearMonthDayPickerInput.set_format_to_field( self.fields['decision_date']) XDSoftYearMonthDayPickerInput.set_format_to_field( self.fields['decision_letter_date']) self.fields['proposal'].initial = self._proposal requested_budget = self._proposal.total_budget() self.fields['allocated_budget'] = FlexibleDecimalField(required=False) self.fields[ 'allocated_budget'].help_text = f'Requested: {thousands_separator(requested_budget)} CHF' self.fields['allocated_budget'].label = 'Allocated budget (CHF)' if hasattr(self._proposal, 'proposalevaluation'): cancel_button_url = reverse( 'logged-proposal-evaluation-detail', kwargs={'pk': self._proposal.proposalevaluation.id}) initial_reviewers = self._proposal.reviewer_set.all() else: cancel_button_url = reverse('logged-proposal-evaluation-add' ) + f'?proposal={self._proposal.id}' initial_reviewers = [] self.fields['reviewers'] = ReviewerMultipleChoiceField( initial=initial_reviewers, queryset=Reviewer.objects.filter(calls=self._proposal.call), required=True, widget=FilteredSelectMultiple(is_stacked=True, verbose_name='reviewers'), help_text=self.Meta.help_texts['reviewers']) self.helper.layout = Layout( Div(Div('proposal', css_class='col-12'), css_class='row'), Div(Div('reviewers', css_class='col-12'), css_class='row'), Div(Div('panel_remarks', css_class='col-12'), css_class='row'), Div(Div('feedback_to_applicant', css_class='col-12'), css_class='row'), Div(Div('panel_recommendation', css_class='col-6'), Div('allocated_budget', css_class='col-6'), css_class='row'), Div(Div('board_decision', css_class='col-6'), Div('decision_date', css_class='col-6'), css_class='row'), Div(Div('decision_letter', css_class='col-6'), Div('decision_letter_date', css_class='col-6'), css_class='row'), FormActions(Submit('save', 'Save Evaluation'), cancel_edit_button(cancel_button_url)))