Skip to content
Snippets Groups Projects
Commit c2a3598a authored by sks444's avatar sks444
Browse files

Move forms to specific files

parent a59c5974
No related branches found
No related tags found
No related merge requests found
from .payment import (
ChangePaymentRequestStatusForm,
CreatePaymentRequestForm,
EditPaymentRequestForm,
SelectDocumentForm,
)
from .project import (
ApproveContractForm,
CreateProjectForm,
CreateApprovalForm,
CreateApprovalForm,
ProjectEditForm,
ProjectApprovalForm,
RejectionForm,
RemoveDocumentForm,
SetPendingForm,
UploadContractForm,
StaffUploadContractForm,
UploadDocumentForm,
UpdateProjectLeadForm,
)
from .report import (
ReportEditForm,
ReportFrequencyForm,
)
__all__ = [
'ChangePaymentRequestStatusForm',
'CreatePaymentRequestForm',
'EditPaymentRequestForm',
'SelectDocumentForm',
'ApproveContractForm',
'CreateProjectForm',
'CreateApprovalForm',
'ProjectEditForm',
'ProjectApprovalForm',
'RejectionForm',
'RemoveDocumentForm',
'SetPendingForm',
'UploadContractForm',
'StaffUploadContractForm',
'UploadDocumentForm',
'UpdateProjectLeadForm',
'ReportEditForm',
'ReportFrequencyForm',
]
import functools
from django import forms
from django.core.files.base import ContentFile
from django.db import transaction
from django_file_form.forms import FileFormMixin
from hypha.apply.stream_forms.fields import MultiFileField
from ..models.payment import (
CHANGES_REQUESTED,
DECLINED,
PAID,
REQUEST_STATUS_CHOICES,
SUBMITTED,
UNDER_REVIEW,
PaymentReceipt,
PaymentRequest,
)
from ..models.project import PacketFile
def filter_choices(available, choices):
return [(k, v) for k, v in available if k in choices]
filter_request_choices = functools.partial(filter_choices, REQUEST_STATUS_CHOICES)
class ChangePaymentRequestStatusForm(forms.ModelForm):
name_prefix = 'change_payment_request_status_form'
class Meta:
fields = ['status', 'comment', 'paid_value']
model = PaymentRequest
def __init__(self, instance, *args, **kwargs):
super().__init__(instance=instance, *args, **kwargs)
self.initial['paid_value'] = self.instance.requested_value
status_field = self.fields['status']
possible_status_transitions_lut = {
CHANGES_REQUESTED: filter_request_choices([DECLINED]),
SUBMITTED: filter_request_choices([CHANGES_REQUESTED, UNDER_REVIEW, DECLINED]),
UNDER_REVIEW: filter_request_choices([PAID]),
}
status_field.choices = possible_status_transitions_lut.get(instance.status, [])
if instance.status != UNDER_REVIEW:
del self.fields['paid_value']
def clean(self):
cleaned_data = super().clean()
status = cleaned_data['status']
paid_value = cleaned_data.get('paid_value')
if paid_value and status != PAID:
self.add_error('paid_value', 'You can only set a value when moving to the Paid status.')
return cleaned_data
class PaymentRequestBaseForm(forms.ModelForm):
class Meta:
fields = ['requested_value', 'invoice', 'date_from', 'date_to']
model = PaymentRequest
widgets = {
'date_from': forms.DateInput,
'date_to': forms.DateInput,
}
labels = {
'requested_value': 'Requested Value ($)'
}
def __init__(self, user=None, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['requested_value'].widget.attrs['min'] = 0
def clean(self):
cleaned_data = super().clean()
date_from = cleaned_data['date_from']
date_to = cleaned_data['date_to']
if date_from > date_to:
self.add_error('date_from', 'Date From must be before Date To')
return cleaned_data
class CreatePaymentRequestForm(FileFormMixin, PaymentRequestBaseForm):
receipts = MultiFileField(required=False)
def save(self, commit=True):
request = super().save(commit=commit)
receipts = self.cleaned_data['receipts'] or []
PaymentReceipt.objects.bulk_create(
PaymentReceipt(payment_request=request, file=receipt)
for receipt in receipts
)
return request
class EditPaymentRequestForm(FileFormMixin, PaymentRequestBaseForm):
receipt_list = forms.ModelMultipleChoiceField(
widget=forms.CheckboxSelectMultiple(attrs={'class': 'delete'}),
queryset=PaymentReceipt.objects.all(),
required=False,
label='Receipts'
)
receipts = MultiFileField(label='', required=False)
def __init__(self, user=None, instance=None, *args, **kwargs):
super().__init__(*args, instance=instance, **kwargs)
self.fields['receipt_list'].queryset = instance.receipts.all()
self.fields['requested_value'].label = 'Value'
@transaction.atomic
def save(self, commit=True):
request = super().save(commit=commit)
removed_receipts = self.cleaned_data['receipt_list']
removed_receipts.delete()
to_add = self.cleaned_data['receipts']
if to_add:
PaymentReceipt.objects.bulk_create(
PaymentReceipt(payment_request=request, file=receipt)
for receipt in to_add
)
return request
class SelectDocumentForm(forms.ModelForm):
document = forms.ChoiceField(
label="Document",
widget=forms.Select(attrs={'id': 'from_submission'})
)
class Meta:
model = PacketFile
fields = ['category', 'document']
def __init__(self, existing_files, *args, **kwargs):
super().__init__(*args, **kwargs)
self.files = existing_files
choices = [(f.url, f.filename) for f in self.files]
self.fields['document'].choices = choices
def clean_document(self):
file_url = self.cleaned_data['document']
for file in self.files:
if file.url == file_url:
new_file = ContentFile(file.read())
new_file.name = file.filename
return new_file
raise forms.ValidationError("File not found on submission")
@transaction.atomic()
def save(self, *args, **kwargs):
return super().save(*args, **kwargs)
import functools
from django import forms
from django.conf import settings
from django.contrib.auth import get_user_model
from django.core.exceptions import ValidationError
from django.core.files.base import ContentFile
from django.db import transaction
from django.db.models import Q
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from django_file_form.forms import FileFormMixin
from addressfield.fields import AddressField
from hypha.apply.funds.models import ApplicationSubmission
from hypha.apply.stream_forms.fields import MultiFileField
from hypha.apply.users.groups import STAFF_GROUP_NAME
from hypha.apply.utils.fields import RichTextField
from .models.payment import (
CHANGES_REQUESTED,
DECLINED,
PAID,
REQUEST_STATUS_CHOICES,
SUBMITTED,
UNDER_REVIEW,
PaymentReceipt,
PaymentRequest,
)
from .models.project import COMMITTED, Approval, Contract, PacketFile, Project
from .models.report import Report, ReportConfig, ReportPrivateFiles, ReportVersion
User = get_user_model()
from ..models.project import COMMITTED, Approval, Contract, PacketFile, Project
def filter_choices(available, choices):
return [(k, v) for k, v in available if k in choices]
filter_request_choices = functools.partial(filter_choices, REQUEST_STATUS_CHOICES)
User = get_user_model()
class ApproveContractForm(forms.Form):
......@@ -51,14 +22,14 @@ class ApproveContractForm(forms.Form):
def clean_id(self):
if self.has_changed():
raise forms.ValidationError(_('Something changed before your approval please re-review'))
raise forms.ValidationError('Something changed before your approval please re-review')
def clean(self):
if not self.instance:
raise forms.ValidationError(_('The contract you were trying to approve has already been approved'))
raise forms.ValidationError('The contract you were trying to approve has already been approved')
if not self.instance.is_signed:
raise forms.ValidationError(_('You can only approve a signed contract'))
raise forms.ValidationError('You can only approve a signed contract')
super().clean()
......@@ -67,40 +38,6 @@ class ApproveContractForm(forms.Form):
return self.instance
class ChangePaymentRequestStatusForm(forms.ModelForm):
name_prefix = 'change_payment_request_status_form'
class Meta:
fields = ['status', 'comment', 'paid_value']
model = PaymentRequest
def __init__(self, instance, *args, **kwargs):
super().__init__(instance=instance, *args, **kwargs)
self.initial['paid_value'] = self.instance.requested_value
status_field = self.fields['status']
possible_status_transitions_lut = {
CHANGES_REQUESTED: filter_request_choices([DECLINED]),
SUBMITTED: filter_request_choices([CHANGES_REQUESTED, UNDER_REVIEW, DECLINED]),
UNDER_REVIEW: filter_request_choices([PAID]),
}
status_field.choices = possible_status_transitions_lut.get(instance.status, [])
if instance.status != UNDER_REVIEW:
del self.fields['paid_value']
def clean(self):
cleaned_data = super().clean()
status = cleaned_data['status']
paid_value = cleaned_data.get('paid_value')
if paid_value and status != PAID:
self.add_error('paid_value', _('You can only set a value when moving to the Paid status.'))
return cleaned_data
class CreateProjectForm(forms.Form):
submission = forms.ModelChoiceField(
queryset=ApplicationSubmission.objects.filter(project__isnull=True),
......@@ -135,7 +72,7 @@ class CreateApprovalForm(forms.ModelForm):
def clean_by(self):
by = self.cleaned_data['by']
if by != self.user:
raise forms.ValidationError(_('Cannot approve for a different user'))
raise forms.ValidationError('Cannot approve for a different user')
return by
......@@ -201,115 +138,6 @@ class RemoveDocumentForm(forms.ModelForm):
super().__init__(*args, **kwargs)
class PaymentRequestBaseForm(forms.ModelForm):
class Meta:
fields = ['requested_value', 'invoice', 'date_from', 'date_to']
model = PaymentRequest
widgets = {
'date_from': forms.DateInput,
'date_to': forms.DateInput,
}
labels = {
'requested_value': _('Requested Value ({currency})').format(currency=settings.CURRENCY_SYMBOL.strip())
}
def __init__(self, user=None, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['requested_value'].widget.attrs['min'] = 0
def clean(self):
cleaned_data = super().clean()
date_from = cleaned_data['date_from']
date_to = cleaned_data['date_to']
if date_from > date_to:
self.add_error('date_from', _('Date From must be before Date To'))
return cleaned_data
class CreatePaymentRequestForm(FileFormMixin, PaymentRequestBaseForm):
receipts = MultiFileField(required=False)
def save(self, commit=True):
request = super().save(commit=commit)
receipts = self.cleaned_data['receipts'] or []
PaymentReceipt.objects.bulk_create(
PaymentReceipt(payment_request=request, file=receipt)
for receipt in receipts
)
return request
class EditPaymentRequestForm(FileFormMixin, PaymentRequestBaseForm):
receipt_list = forms.ModelMultipleChoiceField(
widget=forms.CheckboxSelectMultiple(attrs={'class': 'delete'}),
queryset=PaymentReceipt.objects.all(),
required=False,
label=_('Receipts')
)
receipts = MultiFileField(label='', required=False)
def __init__(self, user=None, instance=None, *args, **kwargs):
super().__init__(*args, instance=instance, **kwargs)
self.fields['receipt_list'].queryset = instance.receipts.all()
self.fields['requested_value'].label = 'Value'
@transaction.atomic
def save(self, commit=True):
request = super().save(commit=commit)
removed_receipts = self.cleaned_data['receipt_list']
removed_receipts.delete()
to_add = self.cleaned_data['receipts']
if to_add:
PaymentReceipt.objects.bulk_create(
PaymentReceipt(payment_request=request, file=receipt)
for receipt in to_add
)
return request
class SelectDocumentForm(forms.ModelForm):
document = forms.ChoiceField(
label=_('Document'),
widget=forms.Select(attrs={'id': 'from_submission'})
)
class Meta:
model = PacketFile
fields = ['category', 'document']
def __init__(self, existing_files, *args, **kwargs):
super().__init__(*args, **kwargs)
self.files = existing_files
choices = [(f.url, f.filename) for f in self.files]
self.fields['document'].choices = choices
def clean_document(self):
file_url = self.cleaned_data['document']
for file in self.files:
if file.url == file_url:
new_file = ContentFile(file.read())
new_file.name = file.filename
return new_file
raise forms.ValidationError(_('File not found on submission'))
@transaction.atomic()
def save(self, *args, **kwargs):
return super().save(*args, **kwargs)
class SetPendingForm(forms.ModelForm):
class Meta:
fields = ['id']
......@@ -321,10 +149,10 @@ class SetPendingForm(forms.ModelForm):
def clean(self):
if self.instance.status != COMMITTED:
raise forms.ValidationError(_('A Project can only be sent for Approval when Committed.'))
raise forms.ValidationError('A Project can only be sent for Approval when Committed.')
if self.instance.is_locked:
raise forms.ValidationError(_('A Project can only be sent for Approval once'))
raise forms.ValidationError('A Project can only be sent for Approval once')
super().clean()
......@@ -367,144 +195,9 @@ class UpdateProjectLeadForm(forms.ModelForm):
super().__init__(*args, **kwargs)
lead_field = self.fields['lead']
lead_field.label = _('Update lead from {lead} to').format(lead=self.instance.lead)
lead_field.label = f'Update lead from {self.instance.lead} to'
qwargs = Q(groups__name=STAFF_GROUP_NAME) | Q(is_superuser=True)
lead_field.queryset = (lead_field.queryset.exclude(pk=self.instance.lead_id)
.filter(qwargs)
.distinct())
class ReportEditForm(FileFormMixin, forms.ModelForm):
public_content = RichTextField(
help_text=_('This section of the report will be shared with the broader community.')
)
private_content = RichTextField(
help_text=_('This section of the report will be shared with staff only.')
)
file_list = forms.ModelMultipleChoiceField(
widget=forms.CheckboxSelectMultiple(attrs={'class': 'delete'}),
queryset=ReportPrivateFiles.objects.all(),
required=False,
label=_('Files')
)
files = MultiFileField(required=False, label='')
class Meta:
model = Report
fields = (
'public_content',
'private_content',
'file_list',
'files',
)
def __init__(self, *args, user=None, initial={}, **kwargs):
self.report_files = initial.pop(
'file_list',
ReportPrivateFiles.objects.none(),
)
super().__init__(*args, initial=initial, **kwargs)
self.fields['file_list'].queryset = self.report_files
self.user = user
def clean(self):
cleaned_data = super().clean()
public = cleaned_data['public_content']
private = cleaned_data['private_content']
if not private and not public:
missing_content = _('Must include either public or private content when submitting a report.')
self.add_error('public_content', missing_content)
self.add_error('private_content', missing_content)
return cleaned_data
@transaction.atomic
def save(self, commit=True):
is_draft = 'save' in self.data
version = ReportVersion.objects.create(
report=self.instance,
public_content=self.cleaned_data['public_content'],
private_content=self.cleaned_data['private_content'],
submitted=timezone.now(),
draft=is_draft,
author=self.user,
)
if is_draft:
self.instance.draft = version
else:
# If this is the first submission of the report we track that as the
# submitted date of the report
if not self.instance.submitted:
self.instance.submitted = version.submitted
self.instance.current = version
self.instance.draft = None
instance = super().save(commit)
removed_files = self.cleaned_data['file_list']
ReportPrivateFiles.objects.bulk_create(
ReportPrivateFiles(report=version, document=file.document)
for file in self.report_files
if file not in removed_files
)
added_files = self.cleaned_data['files']
if added_files:
ReportPrivateFiles.objects.bulk_create(
ReportPrivateFiles(report=version, document=file)
for file in added_files
)
return instance
class ReportFrequencyForm(forms.ModelForm):
start = forms.DateField(label=_('Starting on:'))
class Meta:
model = ReportConfig
fields = ('occurrence', 'frequency', 'start')
labels = {
'occurrence': 'No.',
}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
today = timezone.now().date()
last_report = self.instance.last_report()
self.fields['start'].widget.attrs.update({
'min': max(
last_report.end_date if last_report else today,
today,
),
'max': self.instance.project.end_date,
})
def clean_start(self):
start_date = self.cleaned_data['start']
last_report = self.instance.last_report()
if last_report and start_date <= last_report.end_date:
raise ValidationError(
_("Cannot start a schedule before the current reporting period"),
code="bad_start"
)
if start_date < timezone.now().date():
raise ValidationError(
_("Cannot start a schedule in the past"),
code="bad_start"
)
if start_date > self.instance.project.end_date:
raise ValidationError(
_("Cannot start a schedule beyond the end date"),
code="bad_start"
)
return start_date
def save(self, *args, **kwargs):
self.instance.schedule_start = self.cleaned_data['start']
return super().save(*args, **kwargs)
from django import forms
from django.core.exceptions import ValidationError
from django.db import transaction
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from django_file_form.forms import FileFormMixin
from hypha.apply.stream_forms.fields import MultiFileField
from hypha.apply.utils.fields import RichTextField
from ..models.report import Report, ReportConfig, ReportPrivateFiles, ReportVersion
class ReportEditForm(FileFormMixin, forms.ModelForm):
public_content = RichTextField(
help_text="This section of the report will be shared with the broader community."
)
private_content = RichTextField(
help_text="This section of the report will be shared with staff only."
)
file_list = forms.ModelMultipleChoiceField(
widget=forms.CheckboxSelectMultiple(attrs={'class': 'delete'}),
queryset=ReportPrivateFiles.objects.all(),
required=False,
label='Files'
)
files = MultiFileField(required=False, label='')
class Meta:
model = Report
fields = (
'public_content',
'private_content',
'file_list',
'files',
)
def __init__(self, *args, user=None, initial={}, **kwargs):
self.report_files = initial.pop(
'file_list',
ReportPrivateFiles.objects.none(),
)
super().__init__(*args, initial=initial, **kwargs)
self.fields['file_list'].queryset = self.report_files
self.user = user
def clean(self):
cleaned_data = super().clean()
public = cleaned_data['public_content']
private = cleaned_data['private_content']
if not private and not public:
missing_content = 'Must include either public or private content when submitting a report.'
self.add_error('public_content', missing_content)
self.add_error('private_content', missing_content)
return cleaned_data
@transaction.atomic
def save(self, commit=True):
is_draft = 'save' in self.data
version = ReportVersion.objects.create(
report=self.instance,
public_content=self.cleaned_data['public_content'],
private_content=self.cleaned_data['private_content'],
submitted=timezone.now(),
draft=is_draft,
author=self.user,
)
if is_draft:
self.instance.draft = version
else:
# If this is the first submission of the report we track that as the
# submitted date of the report
if not self.instance.submitted:
self.instance.submitted = version.submitted
self.instance.current = version
self.instance.draft = None
instance = super().save(commit)
removed_files = self.cleaned_data['file_list']
ReportPrivateFiles.objects.bulk_create(
ReportPrivateFiles(report=version, document=file.document)
for file in self.report_files
if file not in removed_files
)
added_files = self.cleaned_data['files']
if added_files:
ReportPrivateFiles.objects.bulk_create(
ReportPrivateFiles(report=version, document=file)
for file in added_files
)
return instance
class ReportFrequencyForm(forms.ModelForm):
start = forms.DateField(label='Starting on:')
class Meta:
model = ReportConfig
fields = ('occurrence', 'frequency', 'start')
labels = {
'occurrence': 'No.',
}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
today = timezone.now().date()
last_report = self.instance.last_report()
self.fields['start'].widget.attrs.update({
'min': max(
last_report.end_date if last_report else today,
today,
),
'max': self.instance.project.end_date,
})
def clean_start(self):
start_date = self.cleaned_data['start']
last_report = self.instance.last_report()
if last_report and start_date <= last_report.end_date:
raise ValidationError(
_("Cannot start a schedule before the current reporting period"),
code="bad_start"
)
if start_date < timezone.now().date():
raise ValidationError(
_("Cannot start a schedule in the past"),
code="bad_start"
)
if start_date > self.instance.project.end_date:
raise ValidationError(
_("Cannot start a schedule beyond the end date"),
code="bad_start"
)
return start_date
def save(self, *args, **kwargs):
self.instance.schedule_start = self.cleaned_data['start']
return super().save(*args, **kwargs)
from os import name
from django.urls import include, path
from .views import (
......@@ -20,6 +21,7 @@ from .views import (
ReportPrivateMedia,
ReportSkipView,
ReportUpdateView,
# CreateVendorView,
)
app_name = 'projects'
......@@ -35,6 +37,7 @@ urlpatterns = [
path('download/', ProjectDetailPDFView.as_view(), name='download'),
path('simplified/', ProjectDetailSimplifiedView.as_view(), name='simplified'),
path('request/', CreatePaymentRequestView.as_view(), name='request'),
# path('vendor/', CreateVendorView.as_view(), name='vendor'),
])),
path('payment-requests/', include(([
path('', PaymentRequestListView.as_view(), name='all'),
......@@ -55,4 +58,13 @@ urlpatterns = [
path('documents/<int:file_pk>/', ReportPrivateMedia.as_view(), name="document"),
])),
], 'reports'))),
path('venor/', include(([
path('', ReportListView.as_view(), name='all'),
path('<int:pk>/', include([
path('', ReportDetailView.as_view(), name='detail'),
path('skip/', ReportSkipView.as_view(), name='skip'),
path('edit/', ReportUpdateView.as_view(), name='edit'),
path('documents/<int:file_pk>/', ReportPrivateMedia.as_view(), name="document"),
])),
], 'reports'))),
]
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment