diff --git a/hypha/apply/projects/forms/vendor.py b/hypha/apply/projects/forms/vendor.py index 86319a0dc0154c521bc79bdaa2f9ae41eaa8ab59..7105da9d881be44a4e6b4193c29eb30d2db9800d 100644 --- a/hypha/apply/projects/forms/vendor.py +++ b/hypha/apply/projects/forms/vendor.py @@ -28,7 +28,7 @@ class BaseVendorForm: return fields -class CreateVendorFormStep1(BaseVendorForm, forms.ModelForm): +class CreateVendorFormStep1(BaseVendorForm, forms.Form): class Meta: fields = [ 'name', @@ -116,7 +116,7 @@ class CreateVendorFormStep6(BaseVendorForm, forms.Form): # ib_branch_address = AddressField() nid_type = forms.CharField(required=False) nid_number = forms.CharField(required=False) - other_info = forms.CharField(required=False) + other_info = forms.CharField(required=False, widget=forms.Textarea) def __init__(self, *args, **kwargs): super(CreateVendorFormStep6, self).__init__(*args, **kwargs) diff --git a/hypha/apply/projects/migrations/0036_add_vendor.py b/hypha/apply/projects/migrations/0036_add_vendor.py index 5c168b9ca800b0731ec6e10373c130734f014a89..2a7583005714e41c1410dd3d5919cfb32b416ca3 100644 --- a/hypha/apply/projects/migrations/0036_add_vendor.py +++ b/hypha/apply/projects/migrations/0036_add_vendor.py @@ -1,18 +1,17 @@ -# Generated by Django 2.2.23 on 2021-06-09 11:56 +# Generated by Django 2.2.24 on 2021-06-14 07:09 from django.conf import settings import django.core.files.storage from django.db import migrations, models import django.db.models.deletion -import hypha.apply.projects.models.vendor import wagtail.core.fields class Migration(migrations.Migration): dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), ('wagtailcore', '0062_comment_models_and_pagesubscription'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), ('application_projects', '0035_add_heading_block_to_form_fields_block'), ] @@ -68,7 +67,7 @@ class Migration(migrations.Migration): ('account_routing_number_help_text', wagtail.core.fields.RichTextField(default='Depending on your country, this might be called the ACH, SWIFT, BIC or ABA number.', verbose_name='help_text')), ('account_number_label', models.TextField(default='Bank Account Number', verbose_name='label')), ('account_number_help_text', wagtail.core.fields.RichTextField(default='Depending on your country, this might be called the account number, IBAN, or BBAN number.', verbose_name='help_text')), - ('account_currency', models.TextField(default='Bank Account Currency', verbose_name='label')), + ('account_currency_label', models.TextField(default='Bank Account Currency', verbose_name='label')), ('account_currency_help_text', wagtail.core.fields.RichTextField(default='This is the currency of this bank account.', verbose_name='label')), ('need_extra_info_label', models.TextField(default='Do you need to provide us with extra information?', verbose_name='label')), ('need_extra_info_help_text', wagtail.core.fields.RichTextField(default='', verbose_name='help_text')), @@ -112,7 +111,7 @@ class Migration(migrations.Migration): name='DueDiligenceDocument', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('document', models.FileField(storage=django.core.files.storage.FileSystemStorage(), upload_to=hypha.apply.projects.models.vendor.due_diligence_documents)), + ('document', models.FileField(storage=django.core.files.storage.FileSystemStorage(), upload_to='due_diligence_documents')), ('vendor', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='due_diligence_documents', to='application_projects.Vendor')), ], ), diff --git a/hypha/apply/projects/migrations/0037_add_vendor.py b/hypha/apply/projects/migrations/0037_add_vendor.py deleted file mode 100644 index 02162eedc958e2b8e60d5752b699c97443ed986a..0000000000000000000000000000000000000000 --- a/hypha/apply/projects/migrations/0037_add_vendor.py +++ /dev/null @@ -1,22 +0,0 @@ -# Generated by Django 2.2.23 on 2021-06-10 10:45 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('application_projects', '0036_add_vendor'), - ] - - operations = [ - migrations.RemoveField( - model_name='vendorformsettings', - name='account_currency', - ), - migrations.AddField( - model_name='vendorformsettings', - name='account_currency_label', - field=models.TextField(default='Bank Account Currency', verbose_name='label'), - ), - ] diff --git a/hypha/apply/projects/models/vendor.py b/hypha/apply/projects/models/vendor.py index 1d2e3375c07dd5b4b17a9c4ff0bbd2c56763b140..57c9c831381c4e9a506895ddbf98838d2dc29ffe 100644 --- a/hypha/apply/projects/models/vendor.py +++ b/hypha/apply/projects/models/vendor.py @@ -11,10 +11,6 @@ from wagtail.admin.edit_handlers import ( from hypha.apply.utils.storage import PrivateStorage -def due_diligence_documents(instance, filename): - return f'vendor/{instance.vendor_id}/due_diligence_documents/{filename}' - - class BankInformation(models.Model): account_holder_name = models.CharField(max_length=150) account_routing_number = models.CharField(max_length=10) @@ -75,7 +71,7 @@ class Vendor(models.Model): class DueDiligenceDocument(models.Model): document = models.FileField( - upload_to=due_diligence_documents, storage=PrivateStorage() + upload_to="due_diligence_documents", storage=PrivateStorage() ) vendor = models.ForeignKey( Vendor, diff --git a/hypha/apply/projects/templates/application_projects/includes/supporting_documents.html b/hypha/apply/projects/templates/application_projects/includes/supporting_documents.html index b6cef459217ec8430e1e3135cc31b6052d57c7db..c6726b2b0be4c6ea6c308ea57e50b37eae95a2bb 100644 --- a/hypha/apply/projects/templates/application_projects/includes/supporting_documents.html +++ b/hypha/apply/projects/templates/application_projects/includes/supporting_documents.html @@ -20,6 +20,16 @@ </div> </li> + <li class="docs-block__row"> + <div class="docs-block__row-inner"> + <svg class="icon docs-block__icon"><use xlink:href="#tick"></use></svg> + <p class="docs-block__title">Contractor Setup Form</p> + </div> + <div class="docs-block__row-inner"> + <a class="docs-block__link" href="{% url 'apply:projects:vendor' pk=project.pk %}">Complete Contractor Setup</a> + </div> + </li> + <li class="docs-block__row"> <div class="docs-block__row-inner"> <svg class="icon docs-block__icon{% if object.user_has_updated_details %} is-complete{% endif %}"> diff --git a/hypha/apply/projects/views/vendor.py b/hypha/apply/projects/views/vendor.py index 91a396c73158ee840b38b3f1cb488b278bbfee5a..4efd239e898d32111c42eab27b061a7fdbc6de71 100644 --- a/hypha/apply/projects/views/vendor.py +++ b/hypha/apply/projects/views/vendor.py @@ -1,4 +1,7 @@ +import json from django.shortcuts import get_object_or_404, render +from django.core.exceptions import PermissionDenied +from django.db.models.fields.files import FieldFile from wagtail.core.models import Site from formtools.wizard.views import SessionWizardView @@ -22,8 +25,17 @@ def show_extra_info_form(wizard): return cleaned_data.get('need_extra_info', True) +class VendorAccessMixin: + def dispatch(self, request, *args, **kwargs): + is_admin = request.user.is_apply_staff + is_owner = request.user == self.get_object().project.user + if not (is_owner or is_admin): + raise PermissionDenied + + return super().dispatch(request, *args, **kwargs) + + class CreateVendorView(SessionWizardView): - model = Vendor file_storage = PrivateStorage() form_list = [ ('basic', CreateVendorFormStep1), @@ -36,13 +48,18 @@ class CreateVendorView(SessionWizardView): condition_dict = {'other': show_extra_info_form} template_name = 'application_projects/vendor_form.html' + def get_project(self): + return get_object_or_404(Project, pk=self.kwargs['pk']) + def done(self, form_list, **kwargs): - project = get_object_or_404(Project, pk=self.kwargs['pk']) + vendor_project = self.get_project() cleaned_data = self.get_all_cleaned_data() - vendor = project.vendor - vendor, _ = Vendor.objects.get_or_create( - user=project.user + vendor, create = Vendor.objects.get_or_create( + user=vendor_project.user ) + if create: + vendor_project.vendor = vendor + vendor_project.save() need_extra_info = cleaned_data['need_extra_info'] bank_information = BankInformation.objects.create( account_holder_name=cleaned_data['account_holder_name'], @@ -59,24 +76,80 @@ class CreateVendorView(SessionWizardView): # branch_address=cleaned_data['ib_branch_address'] ) bank_information.branch_address = cleaned_data['branch_address'] + bank_information.nid_type = cleaned_data['nid_type'] + bank_information.nid_number = cleaned_data['nid_number'] bank_information.iba_info = intermediary_bank_information bank_information.save() vendor.bank_info = bank_information - vendor.full_name = cleaned_data['name'] + vendor.other_info = cleaned_data['other_info'] + vendor.name = cleaned_data['name'] vendor.contractor_name = cleaned_data['contractor_name'] vendor.type = cleaned_data['type'] vendor.required_to_pay_taxes = cleaned_data['required_to_pay_taxes'] vendor.save() + + not_deleted_original_filenames = [ + file['name'] for file in json.loads(cleaned_data['due_diligence_documents-uploads']) + ] + for f in vendor.due_diligence_documents.all(): + if f.document.name not in not_deleted_original_filenames: + f.document.delete() + f.delete() + for f in cleaned_data["due_diligence_documents"]: - try: - DueDiligenceDocument.objects.create(vendor=vendor, document=f) - finally: - f.close() - form = self.get_form(step='documents') + if not isinstance(f, FieldFile): + try: + DueDiligenceDocument.objects.create(vendor=vendor, document=f) + finally: + f.close() + form = self.get_form('documents') form.delete_temporary_files() return render(self.request, 'application_projects/vendor_success.html') + def get_form_initial(self, step): + vendor_project = self.get_project() + vendor = vendor_project.vendor + initial_dict = self.initial_dict.get(step, {}) + if vendor: + initial_dict['basic'] = { + 'name': vendor.name, + 'contractor_name': vendor.contractor_name, + 'type': vendor.type + } + initial_dict['taxes'] = { + 'required_to_pay_taxes': vendor.required_to_pay_taxes + } + initial_dict['documents'] = { + 'due_diligence_documents': [ + f.document for f in vendor.due_diligence_documents.all() + ] + } + bank_info = vendor.bank_info + if bank_info: + initial_dict['bank'] = { + 'account_holder_name': bank_info.account_holder_name, + 'account_routing_number': bank_info.account_routing_number, + 'account_number': bank_info.account_number, + 'account_currency': bank_info.account_currency, + } + initial_dict['extra'] = { + 'need_extra_info': bank_info.need_extra_info + } + initial_dict['other'] = { + 'branch_address': bank_info.branch_address, + 'nid_type': bank_info.nid_type, + 'nid_number': bank_info.nid_number, + 'other_info': vendor.other_info, + } + iba_info = bank_info.iba_info + if iba_info: + initial_dict['other']['ib_account_routing_number'] = iba_info.account_routing_number + initial_dict['other']['ib_account_number'] = iba_info.account_number + initial_dict['other']['ib_account_currency'] = iba_info.account_currency + initial_dict['other']['ib_branch_address'] = iba_info.branch_address + return initial_dict.get(step, {}) + def get_form_kwargs(self, step): kwargs = super(CreateVendorView, self).get_form_kwargs(step) kwargs['site'] = Site.find_for_request(self.request)