Skip to content

Index

hypha.apply.projects.models

Invoice

Bases: Model

project class-attribute instance-attribute

project = ForeignKey('Project', on_delete=CASCADE, related_name='invoices')

by class-attribute instance-attribute

by = ForeignKey(AUTH_USER_MODEL, on_delete=CASCADE, related_name='invoices')

paid_value class-attribute instance-attribute

paid_value = DecimalField(max_digits=10, decimal_places=2, validators=[MinValueValidator(Decimal('0.01'))], null=True)

document class-attribute instance-attribute

document = FileField(upload_to=invoice_path, storage=PrivateStorage())

requested_at class-attribute instance-attribute

requested_at = DateTimeField(auto_now_add=True)

message_for_pm class-attribute instance-attribute

message_for_pm = TextField(blank=True, verbose_name=gettext_lazy('Message'))

comment class-attribute instance-attribute

comment = TextField(blank=True)

invoice_number class-attribute instance-attribute

invoice_number = CharField(max_length=50, null=True, verbose_name=gettext_lazy('Invoice number'))

invoice_amount class-attribute instance-attribute

invoice_amount = DecimalField(max_digits=10, decimal_places=2, validators=[MinValueValidator(Decimal('0.01'))], null=True, verbose_name=gettext_lazy('Invoice amount'))

status class-attribute instance-attribute

status = FSMField(default=SUBMITTED, choices=INVOICE_STATUS_CHOICES)

deliverables class-attribute instance-attribute

deliverables = ManyToManyField('InvoiceDeliverable', related_name='invoices')

objects class-attribute instance-attribute

objects = as_manager()

wagtail_reference_index_ignore class-attribute instance-attribute

wagtail_reference_index_ignore = True

has_changes_requested property

has_changes_requested

status_display property

status_display

vendor_document_number property

vendor_document_number

Vendor document number is a required field to create invoices in IntAcct.

Formatting should be HP###### i.e. HP000001 and so on.

value property

value

deliverables_total_amount property

deliverables_total_amount

filename property

filename

transition_invoice_to_resubmitted

transition_invoice_to_resubmitted()

Tranistion invoice to resubmitted status. This method generally gets used on invoice edit.

Source code in hypha/apply/projects/models/payment.py
@transition(
    field=status, source=INVOICE_TRANISTION_TO_RESUBMITTED, target=RESUBMITTED
)
def transition_invoice_to_resubmitted(self):
    """
    Tranistion invoice to resubmitted status.
    This method generally gets used on invoice edit.
    """
    pass

can_user_delete

can_user_delete(user)
Source code in hypha/apply/projects/models/payment.py
def can_user_delete(self, user):
    if user.is_applicant or user.is_apply_staff:
        if self.status in (SUBMITTED):
            return True

    return False

can_user_edit

can_user_edit(user)

Check when an user can edit an invoice. Only applicant and staff have permission to edit invoice based on its current status.

Source code in hypha/apply/projects/models/payment.py
def can_user_edit(self, user):
    """
    Check when an user can edit an invoice.
    Only applicant and staff have permission to edit invoice based on its current status.
    """
    if user.is_applicant:
        if self.status in {SUBMITTED, CHANGES_REQUESTED_BY_STAFF, RESUBMITTED}:
            return True

    if user.is_apply_staff:
        if self.status in {SUBMITTED, RESUBMITTED, CHANGES_REQUESTED_BY_FINANCE}:
            return True

    return False

can_user_change_status

can_user_change_status(user)

Check user roles that can tranistion invoice status based on the current status.

Source code in hypha/apply/projects/models/payment.py
def can_user_change_status(self, user):
    """
    Check user roles that can tranistion invoice status based on the current status.
    """
    if not (
        user.is_contracting
        or user.is_apply_staff
        or user.is_finance_level_1
        or user.is_finance_level_2
    ):
        return False  # Users can't change status

    if self.status in {DECLINED}:
        return False

    if user.is_contracting:
        if self.status in {SUBMITTED, CHANGES_REQUESTED_BY_STAFF, RESUBMITTED}:
            return True

    if user.is_apply_staff:
        if self.status in {
            SUBMITTED,
            RESUBMITTED,
            CHANGES_REQUESTED_BY_STAFF,
            CHANGES_REQUESTED_BY_FINANCE,
        }:
            return True

    if user.is_finance_level_1:
        if settings.INVOICE_EXTENDED_WORKFLOW:
            if self.status in {APPROVED_BY_STAFF, CHANGES_REQUESTED_BY_FINANCE_2}:
                return True
        else:
            if self.status in {
                APPROVED_BY_STAFF,
                APPROVED_BY_FINANCE,
                PAID,
                PAYMENT_FAILED,
            }:
                return True

    if user.is_finance_level_2:
        if self.status in {
            APPROVED_BY_FINANCE,
            APPROVED_BY_FINANCE_2,
            PAID,
            PAYMENT_FAILED,
        }:
            return True

    return False

can_user_edit_deliverables

can_user_edit_deliverables(user)
Source code in hypha/apply/projects/models/payment.py
def can_user_edit_deliverables(self, user):
    if not (
        user.is_apply_staff or user.is_finance_level_1 or user.is_finance_level_2
    ):
        return False
    if user.is_apply_staff:
        if self.status in {SUBMITTED, RESUBMITTED, CHANGES_REQUESTED_BY_FINANCE}:
            return True
    if user.is_finance_level_1:
        if self.status in {APPROVED_BY_STAFF}:
            return True
        elif settings.INVOICE_EXTENDED_WORKFLOW and self.status in [
            CHANGES_REQUESTED_BY_FINANCE_2
        ]:
            return True
    if user.is_finance_level_2:
        if self.status in {APPROVED_BY_FINANCE}:
            return True
    return False

get_absolute_url

get_absolute_url()
Source code in hypha/apply/projects/models/payment.py
def get_absolute_url(self):
    return reverse(
        "apply:projects:invoice-detail",
        kwargs={"pk": self.project.pk, "invoice_pk": self.pk},
    )

InvoiceDeliverable

Bases: Model

deliverable class-attribute instance-attribute

deliverable = ForeignKey('Deliverable', on_delete=CASCADE, related_name='deliverables')

quantity class-attribute instance-attribute

quantity = IntegerField(help_text=gettext_lazy('Quantity Selected on an Invoice'), default=0)

wagtail_reference_index_ignore class-attribute instance-attribute

wagtail_reference_index_ignore = True

get_absolute_api_url

get_absolute_api_url()
Source code in hypha/apply/projects/models/payment.py
def get_absolute_api_url(self):
    return reverse(
        "api:v1:remove-deliverables", kwargs={"pk": self.pk, "invoice_pk": self.pk}
    )

SupportingDocument

Bases: Model

wagtail_reference_index_ignore class-attribute instance-attribute

wagtail_reference_index_ignore = True

document class-attribute instance-attribute

document = FileField(upload_to='supporting_documents', storage=PrivateStorage())

invoice class-attribute instance-attribute

invoice = ForeignKey(Invoice, on_delete=CASCADE, related_name='supporting_documents')

filename property

filename

Contract

Bases: Model

approver class-attribute instance-attribute

approver = ForeignKey(AUTH_USER_MODEL, null=True, on_delete=SET_NULL, related_name='contracts')

project class-attribute instance-attribute

project = ForeignKey('Project', on_delete=CASCADE, related_name='contracts')

file class-attribute instance-attribute

file = FileField(upload_to=contract_path, storage=PrivateStorage())

signed_by_applicant class-attribute instance-attribute

signed_by_applicant = BooleanField('Counter Signed?', default=False)

uploaded_by_contractor_at class-attribute instance-attribute

uploaded_by_contractor_at = DateTimeField(null=True)

uploaded_by_applicant_at class-attribute instance-attribute

uploaded_by_applicant_at = DateTimeField(null=True)

created_at class-attribute instance-attribute

created_at = DateTimeField(auto_now_add=True)

approved_at class-attribute instance-attribute

approved_at = DateTimeField(null=True)

updated_at class-attribute instance-attribute

updated_at = DateTimeField(null=True)

objects class-attribute instance-attribute

objects = as_manager()

state property

state

save

save(*args, **kwargs)
Source code in hypha/apply/projects/models/project.py
def save(self, *args, **kwargs):
    self.updated_at = timezone.now()
    return super().save(*args, **kwargs)

get_absolute_url

get_absolute_url()
Source code in hypha/apply/projects/models/project.py
def get_absolute_url(self):
    return reverse("apply:projects:contract", args=[self.project.pk, self.pk])

ContractDocumentCategory

Bases: Model

name class-attribute instance-attribute

name = CharField(max_length=254)

recommended_minimum class-attribute instance-attribute

recommended_minimum = PositiveIntegerField(null=True, blank=True)

required class-attribute instance-attribute

required = BooleanField(default=True)

template class-attribute instance-attribute

template = FileField(upload_to=contract_document_template_path, storage=PrivateStorage(), blank=True, null=True)

panels class-attribute instance-attribute

panels = [FieldPanel('name'), FieldPanel('required'), FieldPanel('template')]

Meta

ordering class-attribute instance-attribute
ordering = ('-required', 'name')
verbose_name_plural class-attribute instance-attribute
verbose_name_plural = 'Contract Document Categories'

ContractPacketFile

Bases: Model

category class-attribute instance-attribute

category = ForeignKey('ContractDocumentCategory', null=True, on_delete=CASCADE, related_name='contract_packet_files')

project class-attribute instance-attribute

project = ForeignKey('Project', on_delete=CASCADE, related_name='contract_packet_files')

title class-attribute instance-attribute

title = TextField()

document class-attribute instance-attribute

document = FileField(upload_to=contract_document_path, storage=PrivateStorage())

created_at class-attribute instance-attribute

created_at = DateField(auto_now_add=True, null=True)

get_remove_form

get_remove_form()

Get an instantiated RemoveContractDocumentForm with this class as instance.

This allows us to build instances of the RemoveContractDocumentForm for each instance of ContractPacketFile in the contracting documents template. The standard Delegated View flow makes it difficult to create these forms in the view or template.

Source code in hypha/apply/projects/models/project.py
def get_remove_form(self):
    """
    Get an instantiated RemoveContractDocumentForm with this class as `instance`.

    This allows us to build instances of the RemoveContractDocumentForm for each
    instance of ContractPacketFile in the contracting documents template.  The
    standard Delegated View flow makes it difficult to create these forms
    in the view or template.
    """
    from ..forms import RemoveContractDocumentForm

    return RemoveContractDocumentForm(instance=self)

Deliverable

Bases: Model

external_id class-attribute instance-attribute

external_id = CharField(max_length=30, blank=True, help_text='ID of this deliverable at integrated payment service.')

name class-attribute instance-attribute

name = TextField()

available_to_invoice class-attribute instance-attribute

available_to_invoice = IntegerField(default=1)

unit_price class-attribute instance-attribute

unit_price = DecimalField(max_digits=10, decimal_places=2, validators=[MinValueValidator(Decimal('0.01'))])

extra_information class-attribute instance-attribute

extra_information = JSONField(default=dict, help_text='More details of the deliverable at integrated payment service.')

project class-attribute instance-attribute

project = ForeignKey(Project, null=True, blank=True, on_delete=CASCADE, related_name='deliverables')

DocumentCategory

Bases: Model

name class-attribute instance-attribute

name = CharField(max_length=254)

recommended_minimum class-attribute instance-attribute

recommended_minimum = PositiveIntegerField(null=True, blank=True)

required class-attribute instance-attribute

required = BooleanField(default=False)

template class-attribute instance-attribute

template = FileField(upload_to=document_template_path, storage=PrivateStorage(), blank=True, null=True)

panels class-attribute instance-attribute

panels = [FieldPanel('name'), FieldPanel('required'), FieldPanel('template')]

Meta

ordering class-attribute instance-attribute
ordering = ('-required', 'name')
verbose_name_plural class-attribute instance-attribute
verbose_name_plural = 'Project Document Categories'

PacketFile

Bases: Model

category class-attribute instance-attribute

category = ForeignKey('DocumentCategory', null=True, on_delete=CASCADE, related_name='packet_files')

project class-attribute instance-attribute

project = ForeignKey('Project', on_delete=CASCADE, related_name='packet_files')

title class-attribute instance-attribute

title = TextField()

document class-attribute instance-attribute

document = FileField(upload_to=document_path, storage=PrivateStorage())

created_at class-attribute instance-attribute

created_at = DateField(auto_now_add=True, null=True)

Meta

ordering class-attribute instance-attribute
ordering = ('-created_at')

get_remove_form

get_remove_form()

Get an instantiated RemoveDocumentForm with this class as instance.

This allows us to build instances of the RemoveDocumentForm for each instance of PacketFile in the supporting documents template. The standard Delegated View flow makes it difficult to create these forms in the view or template.

Source code in hypha/apply/projects/models/project.py
def get_remove_form(self):
    """
    Get an instantiated RemoveDocumentForm with this class as `instance`.

    This allows us to build instances of the RemoveDocumentForm for each
    instance of PacketFile in the supporting documents template.  The
    standard Delegated View flow makes it difficult to create these forms
    in the view or template.
    """
    from ..forms import RemoveDocumentForm

    return RemoveDocumentForm(instance=self)

PAFApprovals

Bases: Model

project class-attribute instance-attribute

project = ForeignKey('Project', on_delete=CASCADE, related_name='paf_approvals')

paf_reviewer_role class-attribute instance-attribute

paf_reviewer_role = ForeignKey('PAFReviewersRole', on_delete=CASCADE, related_name='paf_approvals')

user class-attribute instance-attribute

user = ForeignKey(AUTH_USER_MODEL, on_delete=SET_NULL, null=True, blank=True, related_name='paf_approvals')

approved class-attribute instance-attribute

approved = BooleanField(default=False)

created_at class-attribute instance-attribute

created_at = DateTimeField(auto_now_add=True)

updated_at class-attribute instance-attribute

updated_at = DateTimeField()

approved_at class-attribute instance-attribute

approved_at = DateTimeField(null=True, blank=True)

Meta

unique_together class-attribute instance-attribute
unique_together = ['project', 'paf_reviewer_role']
ordering class-attribute instance-attribute
ordering = ['paf_reviewer_role__sort_order']

save

save(*args, **kwargs)
Source code in hypha/apply/projects/models/project.py
def save(self, *args, **kwargs):
    self.updated_at = timezone.now()
    return super().save(*args, **kwargs)

Project

Bases: BaseStreamForm, AccessFormData, Model

stream_file_class class-attribute instance-attribute

stream_file_class = SubmissionStreamFieldFile

storage_class class-attribute instance-attribute

storage_class = PrivateStorage

raw_data property

raw_data

question_field_ids property

question_field_ids

file_field_ids property

file_field_ids

question_text_field_ids property

question_text_field_ids

first_group_question_text_field_ids property

first_group_question_text_field_ids

raw_fields property

raw_fields

fields property

fields

named_blocks property

named_blocks

normal_blocks property

normal_blocks

group_toggle_blocks property

group_toggle_blocks

first_group_normal_text_blocks property

first_group_normal_text_blocks

submission_form_class class-attribute instance-attribute

submission_form_class = PageStreamBaseForm

lead class-attribute instance-attribute

lead = ForeignKey(AUTH_USER_MODEL, null=True, on_delete=SET_NULL, related_name='lead_projects')

submission class-attribute instance-attribute

submission = OneToOneField('funds.ApplicationSubmission', on_delete=CASCADE)

user class-attribute instance-attribute

user = ForeignKey(AUTH_USER_MODEL, on_delete=SET_NULL, null=True, related_name='owned_projects')

title class-attribute instance-attribute

title = TextField()

vendor class-attribute instance-attribute

vendor = ForeignKey('application_projects.Vendor', on_delete=SET_NULL, null=True, blank=True, related_name='projects')

value class-attribute instance-attribute

value = DecimalField(default=0, max_digits=20, decimal_places=2, validators=[MinValueValidator(limit_value=0)])

proposed_start class-attribute instance-attribute

proposed_start = DateTimeField(gettext_lazy('Proposed Start Date'), null=True)

proposed_end class-attribute instance-attribute

proposed_end = DateTimeField(gettext_lazy('Proposed End Date'), null=True)

status class-attribute instance-attribute

status = TextField(choices=PROJECT_STATUS_CHOICES, default=DRAFT)

form_data class-attribute instance-attribute

form_data = JSONField(encoder=StreamFieldDataEncoder, default=dict)

form_fields class-attribute instance-attribute

form_fields = StreamField(ProjectApprovalFormCustomFormFieldsBlock(), null=True, use_json_field=True)

is_locked class-attribute instance-attribute

is_locked = BooleanField(default=False)

user_has_updated_details class-attribute instance-attribute

user_has_updated_details = BooleanField(default=False)

submitted_contract_documents class-attribute instance-attribute

submitted_contract_documents = BooleanField('Submit Contracting Documents', default=False)

activities class-attribute instance-attribute

activities = GenericRelation('activity.Activity', content_type_field='source_content_type', object_id_field='source_object_id', related_query_name='project')

created_at class-attribute instance-attribute

created_at = DateTimeField(auto_now_add=True)

external_projectid class-attribute instance-attribute

external_projectid = CharField(max_length=30, blank=True, help_text='ID of this project at integrated payment service.')

external_project_information class-attribute instance-attribute

external_project_information = JSONField(default=dict, help_text='More details of the project integrated at payment service.')

sent_to_compliance_at class-attribute instance-attribute

sent_to_compliance_at = DateTimeField(null=True)

paf_reviews_meta_data class-attribute instance-attribute

paf_reviews_meta_data = JSONField(default=dict, help_text='Reviewers role and their actions/comments')

objects class-attribute instance-attribute

objects = as_manager()

wagtail_reference_index_ignore class-attribute instance-attribute

wagtail_reference_index_ignore = True

status_display property

status_display

start_date property

start_date

end_date property

end_date

editable property

editable

can_make_approval property

can_make_approval

is_approved_by_all_paf_reviewers property

is_approved_by_all_paf_reviewers

can_update_paf_status property

can_update_paf_status

can_send_for_approval property

can_send_for_approval

Wrapper to expose the pending approval state

We don't want to expose a "Sent for Approval" state to the end User so we infer it from the current status being "Comitted" and the Project being locked.

is_in_progress property

is_in_progress

has_deliverables property

has_deliverables

program_project_id property

program_project_id

Program project id is used to fetch deliverables from IntAcct.

Stored in external_project_information as the first item of referenceno(PONUMBER).

stream_file classmethod

stream_file(instance, field, file)
Source code in hypha/apply/funds/models/mixins.py
@classmethod
def stream_file(cls, instance, field, file):
    if not file:
        return []
    if isinstance(file, cls.stream_file_class):
        return file
    if isinstance(file, File):
        return cls.stream_file_class(
            instance, field, file, name=file.name, storage=cls.storage_class()
        )

    if isinstance(file, PlaceholderUploadedFile):
        return cls.stream_file_class(
            instance,
            field,
            None,
            name=file.file_id,
            filename=file.name,
            storage=cls.storage_class(),
        )

    # This fixes a backwards compatibility issue with #507
    # Once every application has been re-saved it should be possible to remove it
    if "path" in file:
        file["filename"] = file["name"]
        file["name"] = file["path"]
    return cls.stream_file_class(
        instance,
        field,
        None,
        name=file["name"],
        filename=file.get("filename"),
        storage=cls.storage_class(),
    )

process_file classmethod

process_file(instance, field, file)
Source code in hypha/apply/funds/models/mixins.py
@classmethod
def process_file(cls, instance, field, file):
    if isinstance(file, list):
        return [cls.stream_file(instance, field, f) for f in file]
    else:
        return cls.stream_file(instance, field, file)

process_file_data

process_file_data(data)
Source code in hypha/apply/funds/models/mixins.py
def process_file_data(self, data):
    for field in self.form_fields:
        if isinstance(field.block, UploadableMediaBlock):
            file = self.process_file(self, field, data.get(field.id, []))
            try:
                file.save()
            except (AttributeError, FileNotFoundError):
                try:
                    for f in file:
                        f.save()
                except FileNotFoundError:
                    pass
            self.form_data[field.id] = file

extract_files

extract_files()
Source code in hypha/apply/funds/models/mixins.py
def extract_files(self):
    files = {}
    for field in self.form_fields:
        if isinstance(field.block, UploadableMediaBlock):
            files[field.id] = self.data(field.id) or []
            self.form_data.pop(field.id, None)
    return files

from_db classmethod

from_db(db, field_names, values)
Source code in hypha/apply/stream_forms/models.py
@classmethod
def from_db(cls, db, field_names, values):
    instance = super().from_db(db, field_names, values)
    if "form_data" in field_names:
        instance.form_data = cls.deserialize_form_data(
            instance, instance.form_data, instance.form_fields
        )
    return instance

deserialised_data classmethod

deserialised_data(instance, data, form_fields)
Source code in hypha/apply/funds/models/mixins.py
@classmethod
def deserialised_data(cls, instance, data, form_fields):
    # Converts the file dicts into actual file objects
    data = data.copy()
    # PERFORMANCE NOTE:
    # Do not attempt to iterate over form_fields - that will fully instantiate the form_fields
    # including any sub queries that they do
    for i, field_data in enumerate(form_fields.raw_data):
        block = form_fields.stream_block.child_blocks[field_data["type"]]
        if isinstance(block, UploadableMediaBlock):
            field_id = field_data.get("id")
            if field_id:
                field = form_fields[i]
                file = data.get(field_id, [])
                data[field_id] = cls.process_file(instance, field, file)
    return data

get_definitive_id

get_definitive_id(id)
Source code in hypha/apply/funds/models/mixins.py
def get_definitive_id(self, id):
    if id in self.named_blocks:
        return self.named_blocks[id]
    return id

field

field(id)
Source code in hypha/apply/funds/models/mixins.py
def field(self, id):
    definitive_id = self.get_definitive_id(id)
    try:
        return self.raw_fields[definitive_id]
    except KeyError:
        raise UnusedFieldException(id) from None

data

data(id)
Source code in hypha/apply/funds/models/mixins.py
def data(self, id):
    definitive_id = self.get_definitive_id(id)
    try:
        return self.raw_data[definitive_id]
    except KeyError:
        # We have most likely progressed application forms so the data isn't in form_data
        return None

get_serialize_multi_inputs_answer

get_serialize_multi_inputs_answer(field)
Source code in hypha/apply/funds/models/mixins.py
def get_serialize_multi_inputs_answer(self, field):
    number_of_inputs = field.value.get("number_of_inputs")
    answers = [self.data(field.id + "_" + str(i)) for i in range(number_of_inputs)]
    data = ", ".join(filter(None, answers))
    return data

serialize

serialize(field_id)
Source code in hypha/apply/funds/models/mixins.py
def serialize(self, field_id):
    field = self.field(field_id)
    if isinstance(field.block, MultiInputCharFieldBlock):
        data = self.get_serialize_multi_inputs_answer(field)
    else:
        data = self.data(field_id)
    return field.render(
        context={
            "serialize": True,
            "data": data,
        }
    )

get_multi_inputs_answer

get_multi_inputs_answer(field, include_question=False)
Source code in hypha/apply/funds/models/mixins.py
def get_multi_inputs_answer(self, field, include_question=False):
    number_of_inputs = field.value.get("number_of_inputs")
    answers = [self.data(field.id + "_" + str(i)) for i in range(number_of_inputs)]

    render_data = [
        field.render(
            context={
                "data": answer,
                "include_question": include_question if i == 0 else False,
            }
        )
        for i, answer in enumerate(filter(None, answers))
    ]
    return "".join(render_data).replace("</section>", "") + "</section>"

render_answer

render_answer(field_id, include_question=False)
Source code in hypha/apply/funds/models/mixins.py
def render_answer(self, field_id, include_question=False):
    try:
        field = self.field(field_id)
    except UnusedFieldException:
        return "-"
    if isinstance(field.block, MultiInputCharFieldBlock):
        render_data = self.get_multi_inputs_answer(field, include_question)
        return render_data
    else:
        data = self.data(field_id)
    # Some migrated content have empty address.
    if not data:
        return field.render(
            context={"data": "", "include_question": include_question}
        )
    return field.render(
        context={"data": data, "include_question": include_question}
    )

render_answers

render_answers()
Source code in hypha/apply/funds/models/mixins.py
def render_answers(self):
    # Returns a list of the rendered answers
    return [
        self.render_answer(field_id, include_question=True)
        for field_id in self.normal_blocks
    ]

render_first_group_text_answers

render_first_group_text_answers()
Source code in hypha/apply/funds/models/mixins.py
def render_first_group_text_answers(self):
    return [
        self.render_answer(field_id, include_question=True)
        for field_id in self.first_group_normal_text_blocks
    ]

render_text_blocks_answers

render_text_blocks_answers()
Source code in hypha/apply/funds/models/mixins.py
def render_text_blocks_answers(self):
    # Returns a list of the rendered answers of type text
    return [
        self.render_answer(field_id, include_question=True)
        for field_id in self.question_text_field_ids
        if field_id not in self.named_blocks
    ]

output_answers

output_answers()
Source code in hypha/apply/funds/models/mixins.py
def output_answers(self):
    # Returns a safe string of the rendered answers
    return mark_safe("".join(self.render_answers()))

output_text_answers

output_text_answers()
Source code in hypha/apply/funds/models/mixins.py
def output_text_answers(self):
    return mark_safe("".join(self.render_text_blocks_answers()))

output_first_group_text_answers

output_first_group_text_answers()
Source code in hypha/apply/funds/models/mixins.py
def output_first_group_text_answers(self):
    return mark_safe("".join(self.render_first_group_text_answers()))

get_answer_from_label

get_answer_from_label(label)
Source code in hypha/apply/funds/models/mixins.py
def get_answer_from_label(self, label):
    for field_id in self.question_text_field_ids:
        if field_id not in self.named_blocks:
            question_field = self.serialize(field_id)
            if label.lower() in question_field["question"].lower():
                if isinstance(question_field["answer"], str):
                    answer = question_field["answer"]
                else:
                    answer = ",".join(question_field["answer"])
                if answer and not answer == "N":
                    return answer
    return None

deserialize_form_data classmethod

deserialize_form_data(instance, form_data, form_fields)
Source code in hypha/apply/stream_forms/models.py
@classmethod
def deserialize_form_data(cls, instance, form_data, form_fields):
    data = form_data.copy()
    # PERFORMANCE NOTE:
    # Do not attempt to iterate over form_fields - that will fully instantiate the form_fields
    # including any sub queries that they do
    for _i, field_data in enumerate(form_fields.raw_data):
        block = form_fields.stream_block.child_blocks[field_data["type"]]
        field_id = field_data.get("id")
        try:
            value = data[field_id]
        except KeyError:
            pass
        else:
            data[field_id] = block.decode(value)
    return data

get_defined_fields

get_defined_fields()
Source code in hypha/apply/stream_forms/models.py
def get_defined_fields(self):
    return self.form_fields

get_form_fields

get_form_fields(draft=False, form_data=None, user=None)
Source code in hypha/apply/stream_forms/models.py
def get_form_fields(self, draft=False, form_data=None, user=None):
    if form_data is None:
        form_data = {}

    form_fields = OrderedDict()
    field_blocks = self.get_defined_fields()
    group_counter = 1
    is_in_group = False

    # If true option 1 is selected
    grouped_fields_visible = False
    for struct_child in field_blocks:
        block = struct_child.block
        struct_value = struct_child.value
        if isinstance(block, FormFieldBlock):
            field_from_block = block.get_field(struct_value)
            disabled_help_text = _(
                "You are logged in so this information is fetched from your user account."
            )
            if isinstance(block, FullNameBlock) and user and user.is_authenticated:
                if user.full_name:
                    field_from_block.disabled = True
                    field_from_block.initial = user.full_name
                    field_from_block.help_text = disabled_help_text
                else:
                    field_from_block.help_text = _(
                        "You are logged in but your user account does not have a "
                        "full name. We'll update your user account with the name you provide here."
                    )
            if isinstance(block, EmailBlock) and user and user.is_authenticated:
                field_from_block.disabled = True
                field_from_block.initial = user.email
                field_from_block.help_text = disabled_help_text
            if draft and not issubclass(
                block.__class__, ApplicationMustIncludeFieldBlock
            ):
                field_from_block.required = False
            field_from_block.help_link = struct_value.get("help_link")
            field_from_block.group_number = group_counter if is_in_group else 1
            if isinstance(block, GroupToggleBlock) and not is_in_group:
                field_from_block.group_number = 1
                field_from_block.grouper_for = group_counter + 1
                group_counter += 1
                is_in_group = True
                grouped_fields_visible = (
                    form_data.get(struct_child.id) == field_from_block.choices[0][0]
                )
            if isinstance(block, TextFieldBlock):
                field_from_block.word_limit = struct_value.get("word_limit")
            if isinstance(block, MultiInputCharFieldBlock):
                number_of_inputs = struct_value.get("number_of_inputs")
                for index in range(number_of_inputs):
                    form_fields[
                        struct_child.id + "_" + str(index)
                    ] = field_from_block
                    field_from_block.multi_input_id = struct_child.id
                    field_from_block.add_button_text = struct_value.get(
                        "add_button_text"
                    )
                    if (
                        index == number_of_inputs - 1
                    ):  # Add button after last input field
                        field_from_block.multi_input_add_button = True
                        # Index for field until which fields will be visible to applicant.
                        # Initially only the first field with id UUID_0 will be visible.
                        field_from_block.visibility_index = 0
                        field_from_block.max_index = index
                    if index != 0:
                        field_from_block.multi_input_field = True
                        field_from_block.required = False
                        field_from_block.initial = None
                    field_from_block = copy.copy(field_from_block)
            else:
                if is_in_group and not isinstance(block, GroupToggleBlock):
                    field_from_block.required_when_visible = (
                        field_from_block.required
                    )
                    field_from_block.required = (
                        field_from_block.required & grouped_fields_visible
                    )
                    field_from_block.visible = grouped_fields_visible
                form_fields[struct_child.id] = field_from_block
        elif isinstance(block, GroupToggleEndBlock):
            # Group toggle end block is used only to group fields and not used in actual form.
            # Todo: Use streamblock to create nested form field blocks, a more elegant method to group form fields.
            is_in_group = False
        else:
            field_wrapper = BlockFieldWrapper(struct_child)
            field_wrapper.group_number = group_counter if is_in_group else 1
            form_fields[struct_child.id] = field_wrapper

    return form_fields

get_form_class

get_form_class(draft=False, form_data=None, user=None)
Source code in hypha/apply/stream_forms/models.py
def get_form_class(self, draft=False, form_data=None, user=None):
    return type(
        "WagtailStreamForm",
        (self.submission_form_class,),
        self.get_form_fields(draft, form_data, user),
    )

get_address_display

get_address_display()
Source code in hypha/apply/projects/models/project.py
def get_address_display(self):
    try:
        address = json.loads(self.vendor.address)
    except (json.JSONDecodeError, AttributeError):
        return ""
    else:
        return ", ".join(
            address.get(field)
            for field in ADDRESS_FIELDS_ORDER
            if address.get(field)
        )

create_from_submission classmethod

create_from_submission(submission, lead=None)

Create a Project from the given submission.

Returns a new Project or the given ApplicationSubmissions existing Project.

Source code in hypha/apply/projects/models/project.py
@classmethod
def create_from_submission(cls, submission, lead=None):
    """
    Create a Project from the given submission.

    Returns a new Project or the given ApplicationSubmissions existing
    Project.
    """
    if not settings.PROJECTS_ENABLED:
        logging.error(
            f"Tried to create a Project for Submission ID={submission.id} while projects are disabled"
        )
        return None

    # OneToOne relations on the targetted model cannot be accessed without
    # an exception when the relation doesn't exist (is None).  Since we
    # want to fail fast here, we can use hasattr instead.
    if hasattr(submission, "project"):
        return submission.project

    # See if there is a form field named "legal name", if not use user name.
    legal_name = (
        submission.get_answer_from_label("legal name") or submission.user.full_name
    )
    vendor, _ = Vendor.objects.get_or_create(user=submission.user)
    vendor.name = legal_name
    vendor.address = submission.form_data.get("address", "")
    vendor.save()
    return Project.objects.create(
        submission=submission,
        user=submission.user,
        title=submission.title,
        vendor=vendor,
        lead=lead if lead else None,
        value=submission.form_data.get("value", 0),
    )

paid_value

paid_value()
Source code in hypha/apply/projects/models/project.py
def paid_value(self):
    return self.invoices.paid_value()

unpaid_value

unpaid_value()
Source code in hypha/apply/projects/models/project.py
def unpaid_value(self):
    return self.invoices.unpaid_value()

clean

clean()
Source code in hypha/apply/projects/models/project.py
def clean(self):
    if self.proposed_start is None:
        return

    if self.proposed_end is None:
        return

    if self.proposed_start > self.proposed_end:
        raise ValidationError(
            _("Proposed End Date must be after Proposed Start Date")
        )

save

save(*args, **kwargs)
Source code in hypha/apply/projects/models/project.py
def save(self, *args, **kwargs):
    creating = not self.pk

    if creating:
        files = self.extract_files()
    else:
        self.process_file_data(self.form_data)

    super().save(*args, **kwargs)

    if creating:
        self.process_file_data(files)

editable_by

editable_by(user)
Source code in hypha/apply/projects/models/project.py
def editable_by(self, user):
    if self.editable:
        # Approver can edit it when they are approving
        if self.can_make_approval:
            if user.is_finance or user.is_approver or user.is_contracting:
                return True

        # Lead can make changes to the project
        if user == self.lead:
            return True

        # Staff can edit project
        if user.is_apply_staff:
            return True
    return False

get_absolute_url

get_absolute_url()
Source code in hypha/apply/projects/models/project.py
def get_absolute_url(self):
    return reverse("apply:projects:detail", args=[self.id])

can_request_funding

can_request_funding()

Should we show this Project's funding block?

Source code in hypha/apply/projects/models/project.py
def can_request_funding(self):
    """
    Should we show this Project's funding block?
    """
    return self.status in (CLOSING, INVOICING_AND_REPORTING)

ProjectApprovalForm

ProjectSettings

Bases: BaseSiteSetting, ClusterableModel

contracting_gp_email class-attribute instance-attribute

contracting_gp_email = TextField('Contracting Group Email', null=True, blank=True)

finance_gp_email class-attribute instance-attribute

finance_gp_email = TextField('Finance Group Email', null=True, blank=True)

staff_gp_email class-attribute instance-attribute

staff_gp_email = TextField('Staff Group Email', null=True, blank=True)

vendor_setup_required class-attribute instance-attribute

vendor_setup_required = BooleanField(default=True)

paf_approval_sequential class-attribute instance-attribute

paf_approval_sequential = BooleanField(default=True, help_text='Uncheck it to approve PAF parallely')

panels class-attribute instance-attribute

panels = [FieldPanel('staff_gp_email'), FieldPanel('contracting_gp_email'), FieldPanel('finance_gp_email'), FieldPanel('vendor_setup_required'), MultiFieldPanel([FieldPanel('paf_approval_sequential', heading='Approve PAF Sequentially'), InlinePanel('paf_reviewers_roles', label=gettext_lazy('PAF Reviewers Roles'))], heading=gettext_lazy('PAF Reviewers Roles'))]

ProjectSOWForm

Report

Bases: Model

skipped class-attribute instance-attribute

skipped = BooleanField(default=False)

end_date class-attribute instance-attribute

end_date = DateField()

project class-attribute instance-attribute

project = ForeignKey('Project', on_delete=CASCADE, related_name='reports')

submitted class-attribute instance-attribute

submitted = DateTimeField(null=True)

notified class-attribute instance-attribute

notified = DateTimeField(null=True)

current class-attribute instance-attribute

current = OneToOneField('ReportVersion', on_delete=CASCADE, related_name='live_for_report', null=True)

draft class-attribute instance-attribute

draft = OneToOneField('ReportVersion', on_delete=CASCADE, related_name='draft_for_report', null=True)

objects class-attribute instance-attribute

objects = as_manager()

wagtail_reference_index_ignore class-attribute instance-attribute

wagtail_reference_index_ignore = True

previous property

previous

next property

next

past_due property

past_due

is_very_late property

is_very_late

can_submit property

can_submit

submitted_date property

submitted_date

Meta

ordering class-attribute instance-attribute
ordering = ('-end_date')

get_absolute_url

get_absolute_url()
Source code in hypha/apply/projects/models/report.py
def get_absolute_url(self):
    return reverse("apply:projects:reports:detail", kwargs={"pk": self.pk})

start_date

start_date()
Source code in hypha/apply/projects/models/report.py
@cached_property
def start_date(self):
    last_report = self.project.reports.filter(end_date__lt=self.end_date).first()
    if last_report:
        return last_report.end_date + relativedelta(days=1)

    return self.project.start_date

ReportConfig

Bases: Model

Persists configuration about the reporting schedule etc

WEEK class-attribute instance-attribute

WEEK = gettext_lazy('week')

MONTH class-attribute instance-attribute

MONTH = gettext_lazy('month')

YEAR class-attribute instance-attribute

YEAR = gettext_lazy('year')

FREQUENCY_CHOICES class-attribute instance-attribute

FREQUENCY_CHOICES = [(WEEK, gettext_lazy('Weeks')), (MONTH, gettext_lazy('Months')), (YEAR, gettext_lazy('Years'))]

project class-attribute instance-attribute

project = OneToOneField('Project', on_delete=CASCADE, related_name='report_config')

schedule_start class-attribute instance-attribute

schedule_start = DateField(null=True)

occurrence class-attribute instance-attribute

occurrence = PositiveSmallIntegerField(default=1)

frequency class-attribute instance-attribute

frequency = CharField(choices=FREQUENCY_CHOICES, default=MONTH, max_length=6)

disable_reporting class-attribute instance-attribute

disable_reporting = BooleanField(default=False)

does_not_repeat class-attribute instance-attribute

does_not_repeat = BooleanField(default=False)

get_frequency_display

get_frequency_display()
Source code in hypha/apply/projects/models/report.py
def get_frequency_display(self):
    if self.disable_reporting:
        return _("Reporting Disabled")
    if self.does_not_repeat:
        last_report = self.last_report()
        if last_report:
            return _(
                "One time, that already has reported on {date}".format(
                    date=last_report.end_date.strftime("%d %B, %Y")
                )
            )
        return _(
            "One time on {date}".format(
                date=self.schedule_start.strftime("%d %B, %Y")
            )
        )
    next_report = self.current_due_report()

    if self.frequency == self.YEAR:
        if self.schedule_start and self.schedule_start.day == 31:
            day_of_month = _("last day")
            month = self.schedule_start.strftime("%B")
        else:
            day_of_month = ordinal(next_report.end_date.day)
            month = next_report.end_date.strftime("%B")
        if self.occurrence == 1:
            return _("Once a year on {month} {day}").format(
                day=day_of_month, month=month
            )
        return _("Every {occurrence} years on {month} {day}").format(
            occurrence=self.occurrence, day=day_of_month, month=month
        )

    if self.frequency == self.MONTH:
        if self.schedule_start and self.schedule_start.day == 31:
            day_of_month = _("last day")
        else:
            day_of_month = ordinal(next_report.end_date.day)
        if self.occurrence == 1:
            return _("Once a month on the {day}").format(day=day_of_month)
        return _("Every {occurrence} months on the {day}").format(
            occurrence=self.occurrence, day=day_of_month
        )

    weekday = next_report.end_date.strftime("%A")

    if self.occurrence == 1:
        return _("Once a week on {weekday}").format(weekday=weekday)
    return _("Every {occurrence} weeks on {weekday}").format(
        occurrence=self.occurrence, weekday=weekday
    )

is_up_to_date

is_up_to_date()
Source code in hypha/apply/projects/models/report.py
def is_up_to_date(self):
    return len(self.project.reports.to_do()) == 0

outstanding_reports

outstanding_reports()
Source code in hypha/apply/projects/models/report.py
def outstanding_reports(self):
    return len(self.project.reports.to_do())

has_very_late_reports

has_very_late_reports()
Source code in hypha/apply/projects/models/report.py
def has_very_late_reports(self):
    return self.project.reports.any_very_late()

past_due_reports

past_due_reports()
Source code in hypha/apply/projects/models/report.py
def past_due_reports(self):
    return self.project.reports.to_do()

last_report

last_report()
Source code in hypha/apply/projects/models/report.py
def last_report(self):
    today = timezone.now().date()
    # Get the most recent report that was either:
    # - due by today and not submitted
    # - was skipped but due after today
    # - was submitted but due after today
    return self.project.reports.filter(
        Q(end_date__lt=today) | Q(skipped=True) | Q(submitted__isnull=False)
    ).first()

current_due_report

current_due_report()
Source code in hypha/apply/projects/models/report.py
def current_due_report(self):
    if self.disable_reporting:
        return None

    # Project not started - no reporting required
    if not self.project.start_date:
        return None

    today = timezone.now().date()

    last_report = self.last_report()

    schedule_date = self.schedule_start or self.project.start_date

    if last_report:
        # Frequency is one time and last report exists - no reporting required anymore
        if self.does_not_repeat:
            return None

        if last_report.end_date < schedule_date:
            # reporting schedule changed schedule_start is now the next report date
            next_due_date = schedule_date
        else:
            # we've had a report since the schedule date so base next deadline from the report
            next_due_date = self.next_date(last_report.end_date)
    else:
        # first report required
        if self.schedule_start and self.schedule_start >= today:
            # Schedule changed since project inception
            next_due_date = self.schedule_start
        else:
            # schedule_start is the first day the project so the "last" period
            # ended one day before that. If date is in past we required report now
            if self.does_not_repeat:
                next_due_date = today
            else:
                next_due_date = max(
                    self.next_date(schedule_date - relativedelta(days=1)),
                    today,
                )

    report, _ = self.project.reports.update_or_create(
        project=self.project,
        current__isnull=True,
        skipped=False,
        end_date__gte=today,
        defaults={"end_date": next_due_date},
    )
    return report

next_date

next_date(last_date)
Source code in hypha/apply/projects/models/report.py
def next_date(self, last_date):
    delta_frequency = self.frequency + "s"
    delta = relativedelta(**{delta_frequency: self.occurrence})
    next_date = last_date + delta
    return next_date

ReportPrivateFiles

Bases: Model

report class-attribute instance-attribute

report = ForeignKey('ReportVersion', on_delete=CASCADE, related_name='files')

document class-attribute instance-attribute

document = FileField(upload_to=report_path, storage=PrivateStorage())

wagtail_reference_index_ignore class-attribute instance-attribute

wagtail_reference_index_ignore = True

filename property

filename

get_absolute_url

get_absolute_url()
Source code in hypha/apply/projects/models/report.py
def get_absolute_url(self):
    return reverse(
        "apply:projects:reports:document",
        kwargs={"pk": self.report.report_id, "file_pk": self.pk},
    )

ReportVersion

Bases: Model

report class-attribute instance-attribute

report = ForeignKey('Report', on_delete=CASCADE, related_name='versions')

submitted class-attribute instance-attribute

submitted = DateTimeField()

public_content class-attribute instance-attribute

public_content = TextField()

private_content class-attribute instance-attribute

private_content = TextField()

draft class-attribute instance-attribute

draft = BooleanField()

author class-attribute instance-attribute

author = ForeignKey(AUTH_USER_MODEL, on_delete=SET_NULL, related_name='reports', null=True)

wagtail_reference_index_ignore class-attribute instance-attribute

wagtail_reference_index_ignore = True

BankInformation

Bases: Model

account_holder_name class-attribute instance-attribute

account_holder_name = CharField(max_length=150)

account_routing_number class-attribute instance-attribute

account_routing_number = CharField(max_length=10)

account_number class-attribute instance-attribute

account_number = CharField(max_length=20)

account_currency class-attribute instance-attribute

account_currency = CharField(max_length=10)

need_extra_info class-attribute instance-attribute

need_extra_info = BooleanField(default=False)

branch_address class-attribute instance-attribute

branch_address = TextField(gettext_lazy('Address'), blank=True)

iba_info class-attribute instance-attribute

iba_info = OneToOneField('self', null=True, blank=True, on_delete=SET_NULL, related_name='bank_info', verbose_name='Intermediary Bank Account Information')

nid_type class-attribute instance-attribute

nid_type = CharField(max_length=25, verbose_name='National Identity Document Type', blank=True)

nid_number class-attribute instance-attribute

nid_number = CharField(max_length=20, blank=True, verbose_name='National Identity Document Number')

wagtail_reference_index_ignore class-attribute instance-attribute

wagtail_reference_index_ignore = True

DueDiligenceDocument

Bases: Model

document class-attribute instance-attribute

document = FileField(upload_to='due_diligence_documents', storage=PrivateStorage())

vendor class-attribute instance-attribute

vendor = ForeignKey(Vendor, on_delete=CASCADE, related_name='due_diligence_documents')

wagtail_reference_index_ignore class-attribute instance-attribute

wagtail_reference_index_ignore = True

Vendor

Bases: Model

TYPE_CHOICES class-attribute instance-attribute

TYPE_CHOICES = [('organization', gettext_lazy('Yes, the account belongs to the organisation above')), ('personal', gettext_lazy('No, it is a personal bank account'))]

created_at class-attribute instance-attribute

created_at = DateTimeField(verbose_name=gettext_lazy('Creation time'), auto_now_add=True)

updated_at class-attribute instance-attribute

updated_at = DateTimeField(verbose_name=gettext_lazy('Update time'), auto_now=True)

user class-attribute instance-attribute

user = OneToOneField(AUTH_USER_MODEL, on_delete=PROTECT, related_name='vendor')

name class-attribute instance-attribute

name = CharField(max_length=150, blank=True)

contractor_name class-attribute instance-attribute

contractor_name = CharField(max_length=150, blank=True)

address class-attribute instance-attribute

address = TextField(gettext_lazy('Address'), blank=True)

type class-attribute instance-attribute

type = CharField(max_length=15, choices=TYPE_CHOICES, blank=True)

required_to_pay_taxes class-attribute instance-attribute

required_to_pay_taxes = BooleanField(default=False)

bank_info class-attribute instance-attribute

bank_info = OneToOneField(BankInformation, on_delete=SET_NULL, null=True, blank=True)

other_info class-attribute instance-attribute

other_info = TextField(blank=True)

user_has_updated_details class-attribute instance-attribute

user_has_updated_details = BooleanField(default=False)

wagtail_reference_index_ignore class-attribute instance-attribute

wagtail_reference_index_ignore = True

get_absolute_url

get_absolute_url()
Source code in hypha/apply/projects/models/vendor.py
def get_absolute_url(self):
    return reverse("apply:projects:vendor-detail", args=[self.pk])

VendorFormSettings

Bases: BaseSiteSetting

wagtail_reference_index_ignore class-attribute instance-attribute

wagtail_reference_index_ignore = True

name_label class-attribute instance-attribute

name_label = TextField('label', default='1. What is the name of the person/organisation on the contract?')

name_help_text class-attribute instance-attribute

name_help_text = RichTextField('help text', blank=True, default='This is the party name in the contract.')

contractor_name_label class-attribute instance-attribute

contractor_name_label = TextField('label', default="2. What is the individual's name who is signing the contract?")

contractor_name_help_text class-attribute instance-attribute

contractor_name_help_text = RichTextField('help text', blank=True, default='This person is is authorised to sign contract on behalf of the person or organization named above.')

type_label class-attribute instance-attribute

type_label = TextField('label', default='3. Is the bank account owned by the person or organisation in the Question 1 above?')

type_help_text class-attribute instance-attribute

type_help_text = RichTextField('help text', blank=True, default='The name of the bank account must be the same as on the contract.')

required_to_pay_taxes_label class-attribute instance-attribute

required_to_pay_taxes_label = TextField('label', default='Is the organisation required to pay US taxes?')

required_to_pay_taxes_help_text class-attribute instance-attribute

required_to_pay_taxes_help_text = RichTextField('help text', default='', blank=True)

due_diligence_documents_label class-attribute instance-attribute

due_diligence_documents_label = TextField('label', default='Due Diligence Documents')

due_diligence_documents_help_text class-attribute instance-attribute

due_diligence_documents_help_text = RichTextField('help text', blank=True, default='Upload Due Diligence Documents. E.g. w8/w9 forms.')

account_holder_name_label class-attribute instance-attribute

account_holder_name_label = TextField('label', default='Bank Account Holder name')

account_holder_name_help_text class-attribute instance-attribute

account_holder_name_help_text = RichTextField('help text', blank=True, default='This name must be same as the person or organisation that signed the contract. This person is authorised to sign contracts on behalf of the person or organisation named above.')

account_routing_number_label class-attribute instance-attribute

account_routing_number_label = TextField('label', default='Bank Account Routing number')

account_routing_number_help_text class-attribute instance-attribute

account_routing_number_help_text = RichTextField('help text', blank=True, default='Depending on your country, this might be called the ACH, SWIFT, BIC or ABA number.')

account_number_label class-attribute instance-attribute

account_number_label = TextField('label', default='Bank Account Number')

account_number_help_text class-attribute instance-attribute

account_number_help_text = RichTextField('help text', blank=True, default='Depending on your country, this might be called the account number, IBAN, or BBAN number.')

account_currency_label class-attribute instance-attribute

account_currency_label = TextField('label', default='Bank Account Currency')

account_currency_help_text class-attribute instance-attribute

account_currency_help_text = RichTextField('help text', blank=True, default='This is the currency of this bank account.')

need_extra_info_label class-attribute instance-attribute

need_extra_info_label = TextField('label', default='Do you need to provide us with extra information?')

need_extra_info_help_text class-attribute instance-attribute

need_extra_info_help_text = RichTextField('help text', blank=True, default='')

branch_address_label class-attribute instance-attribute

branch_address_label = TextField('label', default='Bank Account Branch Address')

branch_address_help_text class-attribute instance-attribute

branch_address_help_text = TextField('help text', blank=True, default='The address of the bank branch where you have the bank account located(not the bank account holder address)')

ib_account_routing_number_label class-attribute instance-attribute

ib_account_routing_number_label = TextField('label', default='Intermediary Bank Account Routing Number')

ib_account_routing_number_help_text class-attribute instance-attribute

ib_account_routing_number_help_text = RichTextField('help text', blank=True, default='Depending on your country, this might be called ACH, SWIFT, BIC or ABA number')

ib_account_number_label class-attribute instance-attribute

ib_account_number_label = TextField('label', default='Intermediary Bank Account Number')

ib_account_number_help_text class-attribute instance-attribute

ib_account_number_help_text = RichTextField('help text', blank=True, default='Depending on your country, this might be called the account number, IBAN, or BBAN number')

ib_account_currency_label class-attribute instance-attribute

ib_account_currency_label = TextField('label', default='Intermediary Bank Account Currency')

ib_account_currency_help_text class-attribute instance-attribute

ib_account_currency_help_text = RichTextField('help text', blank=True, default='This is the currency of this bank account')

ib_branch_address_label class-attribute instance-attribute

ib_branch_address_label = TextField('label', default='Intermediary Bank Branch Address')

ib_branch_address_help_text class-attribute instance-attribute

ib_branch_address_help_text = RichTextField('help text', blank=True, default='Bank branch address(not the bank account holder address)')

nid_type_label class-attribute instance-attribute

nid_type_label = TextField('label', default='Account Holder National Identity Document Type')

nid_type_help_text class-attribute instance-attribute

nid_type_help_text = RichTextField('help text', blank=True, default='This could be a passport, a National Identity number, or other national identity document.')

nid_number_label class-attribute instance-attribute

nid_number_label = TextField('label', default='Account Holder National Identity Document Number')

nid_number_help_text class-attribute instance-attribute

nid_number_help_text = RichTextField('help text', default='', blank=True)

other_info_label class-attribute instance-attribute

other_info_label = TextField('label', default='Other Information')

other_info_help_text class-attribute instance-attribute

other_info_help_text = RichTextField('help text', blank=True, default='If you need to include other information not listed above, provide it here.')

panels class-attribute instance-attribute

panels = [MultiFieldPanel([FieldPanel('name_label'), FieldPanel('name_help_text')], 'Name'), MultiFieldPanel([FieldPanel('contractor_name_label'), FieldPanel('contractor_name_help_text')], 'Contractor Name'), MultiFieldPanel([FieldPanel('type_label'), FieldPanel('type_help_text')], 'Type'), MultiFieldPanel([FieldPanel('required_to_pay_taxes_label'), FieldPanel('required_to_pay_taxes_help_text')], 'Required to pay taxes'), MultiFieldPanel([FieldPanel('due_diligence_documents_label'), FieldPanel('due_diligence_documents_help_text')], 'Due Diligence Documents'), MultiFieldPanel([FieldPanel('account_holder_name_label'), FieldPanel('account_holder_name_help_text')], 'Account Holder Name'), MultiFieldPanel([FieldPanel('account_routing_number_label'), FieldPanel('account_routing_number_help_text')], 'Account Routing Number'), MultiFieldPanel([FieldPanel('account_number_label'), FieldPanel('account_number_help_text')], 'Account Number'), MultiFieldPanel([FieldPanel('account_currency_label'), FieldPanel('account_currency_help_text')], 'Account Currency'), MultiFieldPanel([FieldPanel('need_extra_info_label'), FieldPanel('need_extra_info_help_text')], 'Need Extra Info'), MultiFieldPanel([FieldPanel('branch_address_label'), FieldPanel('branch_address_help_text')], 'Account Branch Address'), MultiFieldPanel([FieldPanel('ib_account_routing_number_label'), FieldPanel('ib_account_routing_number_help_text')], 'Intermediary Account Routing Number'), MultiFieldPanel([FieldPanel('ib_account_number_label'), FieldPanel('ib_account_number_help_text')], 'Intermediary Account Number'), MultiFieldPanel([FieldPanel('ib_account_currency_label'), FieldPanel('ib_account_currency_help_text')], 'Intermediary Account Currency'), MultiFieldPanel([FieldPanel('ib_branch_address_label'), FieldPanel('ib_branch_address_help_text')], 'Intermediary Account Branch Address'), MultiFieldPanel([FieldPanel('nid_type_label'), FieldPanel('nid_type_help_text')], 'National Identity Document Type'), MultiFieldPanel([FieldPanel('nid_number_label'), FieldPanel('nid_number_help_text')], 'National Identity Document Number'), MultiFieldPanel([FieldPanel('other_info_label'), FieldPanel('other_info_help_text')], 'Other Information')]