diff --git a/hypha/apply/dashboard/templates/dashboard/contracting_dashboard.html b/hypha/apply/dashboard/templates/dashboard/contracting_dashboard.html
new file mode 100644
index 0000000000000000000000000000000000000000..8d0b6d7e570b61bab5d8ea41cec3cc8af5fe95e8
--- /dev/null
+++ b/hypha/apply/dashboard/templates/dashboard/contracting_dashboard.html
@@ -0,0 +1,34 @@
+{% extends "base-apply.html" %}
+{% load render_table from django_tables2 %}
+{% load i18n static %}
+
+{% block title %}{% trans "Dashboard" %}{% endblock %}
+
+{% block content %}
+<div class="admin-bar">
+    <div class="admin-bar__inner admin-bar__inner--with-button">
+        {% block page_header %}
+            <h1 class="gamma heading heading--no-margin heading--bold">{% trans "Dashboard" %}</h1>
+        {% endblock %}
+        <a href="{% url 'wagtailadmin_home' %}" class="button button--primary button--arrow-pixels-white">
+            {% trans "Apply admin" %}
+            <svg><use xlink:href="#arrow-head-pixels--solid"></use></svg>
+        </a>
+    </div>
+</div>
+<div class="wrapper wrapper--large wrapper--inner-space-medium">
+    {% if waiting_for_approval.count %}
+    <div id="paf-awaiting-approval" class="wrapper wrapper--bottom-space">
+        <h4 class="heading heading--normal">{% trans "PAF awaiting approval" %}</h4>
+        {% render_table waiting_for_approval.table %}
+    </div>
+    {% endif %}
+</div>
+{% endblock %}
+
+{% block extra_js %}
+    <script src="{% static 'js/apply/url-search-params.js' %}"></script>
+    <script src="{% static 'js/apply/submission-filters.js' %}"></script>
+    <script src="{% static 'js/apply/submission-tooltips.js' %}"></script>
+    <script src="{% static 'js/apply/tabs.js' %}"></script>
+{% endblock %}
diff --git a/hypha/apply/dashboard/templates/dashboard/finance_dashboard.html b/hypha/apply/dashboard/templates/dashboard/finance_dashboard.html
index 98b17737fdc551f8a31a64ffb67ed48a587daeaa..d3985ae2ccb0563c7ff19cd5cda7bf03e4d5f71f 100644
--- a/hypha/apply/dashboard/templates/dashboard/finance_dashboard.html
+++ b/hypha/apply/dashboard/templates/dashboard/finance_dashboard.html
@@ -25,6 +25,13 @@
             {% trans "No Active Invoices" %}
         {% endif %}
     </div>
+
+    {% if waiting_for_approval.count %}
+    <div id="paf-awaiting-approval" class="wrapper wrapper--bottom-space">
+        <h4 class="heading heading--normal">{% trans "PAF awaiting approval" %}</h4>
+        {% render_table waiting_for_approval.table %}
+    </div>
+    {% endif %}
 </div>
 {% endblock %}
 
diff --git a/hypha/apply/dashboard/tests/test_views.py b/hypha/apply/dashboard/tests/test_views.py
index 4f1fc1ae03f6c94f4652f3afbe3dc4e08062c7cc..a4e160acbce7aca7e0e68b5cb1b231cf9b4db15d 100644
--- a/hypha/apply/dashboard/tests/test_views.py
+++ b/hypha/apply/dashboard/tests/test_views.py
@@ -10,7 +10,7 @@ from hypha.apply.projects.models.payment import (
     RESUBMITTED,
     SUBMITTED,
 )
-from hypha.apply.projects.models.project import COMMITTED
+from hypha.apply.projects.models.project import WAITING_FOR_APPROVAL
 from hypha.apply.projects.tests.factories import InvoiceFactory, ProjectFactory
 from hypha.apply.review.tests.factories import ReviewFactory, ReviewOpinionFactory
 from hypha.apply.users.groups import APPROVER_GROUP_NAME
@@ -135,13 +135,13 @@ class TestStaffDashboard(BaseViewTestCase):
         self.assertNotContains(response, "Active Invoices")
 
     def test_non_project_approver_cannot_see_projects_awaiting_review_stats_or_table(self):
-        ProjectFactory(is_locked=True, status=COMMITTED)
+        ProjectFactory(is_locked=False, status=WAITING_FOR_APPROVAL)
 
         response = self.get_page()
         self.assertNotContains(response, "Projects awaiting approval")
 
     def test_project_approver_can_see_projects_awaiting_review_stats_or_table(self):
-        ProjectFactory(is_locked=True, status=COMMITTED)
+        ProjectFactory(is_locked=False, status=WAITING_FOR_APPROVAL)
 
         user = StaffFactory()
         user.groups.add(GroupFactory(name=APPROVER_GROUP_NAME))
diff --git a/hypha/apply/dashboard/views.py b/hypha/apply/dashboard/views.py
index f08e327d03c75d6acf94f7d292fb642b9ba1a288..9ac43c32d82e9ec7b365309490083d2fc595bf93 100644
--- a/hypha/apply/dashboard/views.py
+++ b/hypha/apply/dashboard/views.py
@@ -122,7 +122,7 @@ class AdminDashboardView(MyFlaggedMixin, TemplateView):
                 'table': None,
             }
 
-        to_approve = Project.objects.in_approval().for_table()
+        to_approve = Project.objects.waiting_for_approval().for_table()
 
         return {
             'count': to_approve.count(),
@@ -160,6 +160,7 @@ class FinanceDashboardView(MyFlaggedMixin, TemplateView):
 
         context.update({
             'active_invoices': self.active_invoices(),
+            'waiting_for_approval': self.waiting_for_approval(),
         })
 
         return context
@@ -175,6 +176,19 @@ class FinanceDashboardView(MyFlaggedMixin, TemplateView):
             'table': InvoiceDashboardTable(invoices),
         }
 
+    def waiting_for_approval(self):
+        if not self.request.user.is_finance:
+            return {
+                'count': None,
+                'table': None,
+            }
+
+        to_paf_approve = Project.objects.waiting_for_approval().for_table()
+        return {
+            'count': to_paf_approve.count(),
+            'table': ProjectsDashboardTable(data=to_paf_approve),
+        }
+
 
 class ReviewerDashboardView(MyFlaggedMixin, MySubmissionContextMixin, TemplateView):
     template_name = 'dashboard/reviewer_dashboard.html'
@@ -261,6 +275,31 @@ class PartnerDashboardView(MySubmissionContextMixin, TemplateView):
         return partner_submissions, partner_submissions_table
 
 
+class ContractingDashboardView(MyFlaggedMixin, TemplateView):
+    template_name = 'dashboard/contracting_dashboard.html'
+
+    def get_context_data(self, **kwargs):
+        context = super().get_context_data(**kwargs)
+        context.update({
+            'waiting_for_approval': self.waiting_for_approval()
+        })
+
+        return context
+
+    def waiting_for_approval(self):
+        if not self.request.user.is_contracting:
+            return {
+                'count': None,
+                'table': None,
+            }
+
+        to_paf_approve = Project.objects.waiting_for_approval().for_table()
+        return {
+            'count': to_paf_approve.count(),
+            'table': ProjectsDashboardTable(data=to_paf_approve),
+        }
+
+
 class CommunityDashboardView(MySubmissionContextMixin, TemplateView):
     template_name = 'dashboard/community_dashboard.html'
 
@@ -341,3 +380,4 @@ class DashboardView(ViewDispatcher):
     community_view = CommunityDashboardView
     applicant_view = ApplicantDashboardView
     finance_view = FinanceDashboardView
+    contracting_view = ContractingDashboardView
diff --git a/hypha/apply/funds/admin.py b/hypha/apply/funds/admin.py
index ccb575ed2c2c9f31e9176c0cd90aac1472ee8fb6..d22c52cd70a48d58a0e65394ffa0b989222f191f 100644
--- a/hypha/apply/funds/admin.py
+++ b/hypha/apply/funds/admin.py
@@ -6,6 +6,7 @@ from wagtail.contrib.modeladmin.options import ModelAdmin, ModelAdminGroup
 from hypha.apply.categories.admin import CategoryAdmin, MetaTermAdmin
 from hypha.apply.determinations.admin import DeterminationFormAdmin
 from hypha.apply.funds.models import ReviewerRole, ScreeningStatus
+from hypha.apply.projects.admin import ProjectApprovalFormAdmin
 from hypha.apply.review.admin import ReviewFormAdmin
 from hypha.apply.utils.admin import ListRelatedMixin
 
@@ -210,6 +211,7 @@ class ApplyAdminGroup(ModelAdminGroup):
         ApplicationFormAdmin,
         ReviewFormAdmin,
         DeterminationFormAdmin,
+        ProjectApprovalFormAdmin,
         CategoryAdmin,
         ScreeningStatusAdmin,
         ReviewerRoleAdmin,
diff --git a/hypha/apply/projects/admin.py b/hypha/apply/projects/admin.py
index 2192a905029d65670e97d25449ee6d72694fc0f6..149345f397130576832e72f69e59df0b7fbd5b69 100644
--- a/hypha/apply/projects/admin.py
+++ b/hypha/apply/projects/admin.py
@@ -31,5 +31,4 @@ class ManageAdminGoup(ModelAdminGroup):
     menu_icon = 'folder-open-inverse'
     items = (
         DocumentCategoryAdmin,
-        ProjectApprovalFormAdmin,
     )
diff --git a/hypha/apply/projects/forms/__init__.py b/hypha/apply/projects/forms/__init__.py
index a5f789bb06ce442cca232c51a4d3d3559fa24b26..73beff1943fbe43ff217092ce8a8cd804527f927 100644
--- a/hypha/apply/projects/forms/__init__.py
+++ b/hypha/apply/projects/forms/__init__.py
@@ -6,10 +6,10 @@ from .payment import (
 )
 from .project import (
     ApproveContractForm,
-    CreateApprovalForm,
+    ChangePAFStatusForm,
     CreateProjectForm,
+    FinalApprovalForm,
     ProjectApprovalForm,
-    RejectionForm,
     RemoveDocumentForm,
     SetPendingForm,
     StaffUploadContractForm,
@@ -30,10 +30,10 @@ from .vendor import (
 __all__ = [
     'SelectDocumentForm',
     'ApproveContractForm',
+    'ChangePAFStatusForm',
     'CreateProjectForm',
-    'CreateApprovalForm',
+    'FinalApprovalForm',
     'ProjectApprovalForm',
-    'RejectionForm',
     'RemoveDocumentForm',
     'SetPendingForm',
     'UploadContractForm',
diff --git a/hypha/apply/projects/forms/project.py b/hypha/apply/projects/forms/project.py
index c7e3e2c7329481f3d62d8bd5bcd14e564e5bc41d..b967c98022e550d38d3ee01b945b50791cbe7207 100644
--- a/hypha/apply/projects/forms/project.py
+++ b/hypha/apply/projects/forms/project.py
@@ -7,7 +7,14 @@ from hypha.apply.funds.models import ApplicationSubmission
 from hypha.apply.stream_forms.forms import StreamBaseForm
 from hypha.apply.users.groups import STAFF_GROUP_NAME
 
-from ..models.project import COMMITTED, Approval, Contract, PacketFile, Project
+from ..models.project import (
+    COMMITTED,
+    PAF_STATUS_CHOICES,
+    Contract,
+    PacketFile,
+    PAFReviewersRole,
+    Project,
+)
 
 User = get_user_model()
 
@@ -56,25 +63,17 @@ class CreateProjectForm(forms.Form):
         return Project.create_from_submission(submission)
 
 
-class CreateApprovalForm(forms.ModelForm):
-    by = forms.ModelChoiceField(
-        queryset=User.objects.approvers(),
-        widget=forms.HiddenInput(),
-    )
+class FinalApprovalForm(forms.ModelForm):
+    name_prefix = 'final_approval_form'
+    final_approval_status = forms.ChoiceField(choices=PAF_STATUS_CHOICES)
+    comment = forms.CharField(required=False, widget=forms.Textarea)
 
     class Meta:
-        model = Approval
-        fields = ('by',)
-
-    def __init__(self, user=None, *args, **kwargs):
-        self.user = user
-        super().__init__(*args, **kwargs)
+        model = Project
+        fields = ['final_approval_status', 'comment']
 
-    def clean_by(self):
-        by = self.cleaned_data['by']
-        if by != self.user:
-            raise forms.ValidationError(_('Cannot approve for a different user'))
-        return by
+    def __init__(self, instance, user=None, *args, **kwargs):
+        super().__init__(instance=instance, *args, **kwargs)
 
 
 class MixedMetaClass(type(StreamBaseForm), type(forms.ModelForm)):
@@ -113,11 +112,19 @@ class ProjectApprovalForm(StreamBaseForm, forms.ModelForm, metaclass=MixedMetaCl
         return super().save(*args, **kwargs)
 
 
-class RejectionForm(forms.Form):
-    comment = forms.CharField(widget=forms.Textarea)
+class ChangePAFStatusForm(forms.ModelForm):
+    name_prefix = 'change_paf_status_form'
+    paf_reviewers_roles = PAFReviewersRole.objects.all().only('role')
+    paf_status = forms.ChoiceField(choices=PAF_STATUS_CHOICES)
+    role = forms.ModelChoiceField(queryset=paf_reviewers_roles)
+    comment = forms.CharField(required=False, widget=forms.Textarea)
 
-    def __init__(self, instance=None, user=None, *args, **kwargs):
-        super().__init__(*args, **kwargs)
+    class Meta:
+        fields = ['paf_status', 'role', 'comment']
+        model = Project
+
+    def __init__(self, instance, user, *args, **kwargs):
+        super().__init__(instance=instance, *args, **kwargs)
 
 
 class RemoveDocumentForm(forms.ModelForm):
@@ -144,15 +151,8 @@ class SetPendingForm(forms.ModelForm):
         if self.instance.status != 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'))
-
         super().clean()
 
-    def save(self, *args, **kwargs):
-        self.instance.is_locked = True
-        return super().save(*args, **kwargs)
-
 
 class UploadContractForm(forms.ModelForm):
     class Meta:
diff --git a/hypha/apply/projects/migrations/0055_alter_project_status_add_pafreviewersrole.py b/hypha/apply/projects/migrations/0055_alter_project_status_add_pafreviewersrole.py
new file mode 100644
index 0000000000000000000000000000000000000000..83d1dc25ac02f2070a4ce2592e404a5ce145df19
--- /dev/null
+++ b/hypha/apply/projects/migrations/0055_alter_project_status_add_pafreviewersrole.py
@@ -0,0 +1,38 @@
+# Generated by Django 3.2.14 on 2022-08-09 04:59
+
+from django.db import migrations, models
+import django.db.models.deletion
+import modelcluster.fields
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('application_projects', '0054_alter_project_form_fields'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='project',
+            name='paf_reviews_meta_data',
+            field=models.JSONField(default=dict, help_text='Reviewers role and their actions/comments'),
+        ),
+        migrations.AlterField(
+            model_name='project',
+            name='status',
+            field=models.TextField(choices=[('committed', 'Committed'), ('waiting_for_approval', 'Waiting for Approval'), ('contracting', 'Contracting'), ('in_progress', 'In Progress'), ('closing', 'Closing'), ('complete', 'Complete')], default='committed'),
+        ),
+        migrations.CreateModel(
+            name='PAFReviewersRole',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('sort_order', models.IntegerField(blank=True, editable=False, null=True)),
+                ('role', models.CharField(max_length=200)),
+                ('page', modelcluster.fields.ParentalKey(on_delete=django.db.models.deletion.CASCADE, related_name='paf_reviewers_roles', to='application_projects.projectsettings')),
+            ],
+            options={
+                'ordering': ['sort_order'],
+                'abstract': False,
+            },
+        ),
+    ]
diff --git a/hypha/apply/projects/models/project.py b/hypha/apply/projects/models/project.py
index c1441746d66bba4ce6f2ae8ceb0c6eed896df1fa..594392f62f8c9adf868b8cc8ee52ceb7eb1b4e92 100644
--- a/hypha/apply/projects/models/project.py
+++ b/hypha/apply/projects/models/project.py
@@ -16,8 +16,11 @@ from django.dispatch.dispatcher import receiver
 from django.urls import reverse
 from django.utils import timezone
 from django.utils.translation import gettext_lazy as _
-from wagtail.admin.panels import FieldPanel
+from modelcluster.fields import ParentalKey
+from modelcluster.models import ClusterableModel
+from wagtail.admin.panels import FieldPanel, InlinePanel
 from wagtail.contrib.settings.models import BaseSetting, register_setting
+from wagtail.core.models import Orderable
 from wagtail.fields import StreamField
 
 from addressfield.fields import ADDRESS_FIELDS_ORDER
@@ -40,13 +43,22 @@ def document_path(instance, filename):
     return f'projects/{instance.project_id}/supporting_documents/{filename}'
 
 
+APPROVE = 'approve'
+REQUEST_CHANGE = 'request_change'
+PAF_STATUS_CHOICES = (
+    (APPROVE, 'Approve'),
+    (REQUEST_CHANGE, 'Request Change')
+)
+
 COMMITTED = 'committed'
+WAITING_FOR_APPROVAL = 'waiting_for_approval'
 CONTRACTING = 'contracting'
 IN_PROGRESS = 'in_progress'
 CLOSING = 'closing'
 COMPLETE = 'complete'
 PROJECT_STATUS_CHOICES = [
     (COMMITTED, _('Committed')),
+    (WAITING_FOR_APPROVAL, _('Waiting for Approval')),
     (CONTRACTING, _('Contracting')),
     (IN_PROGRESS, _('In Progress')),
     (CLOSING, _('Closing')),
@@ -68,11 +80,9 @@ class ProjectQuerySet(models.QuerySet):
     def complete(self):
         return self.filter(status=COMPLETE)
 
-    def in_approval(self):
+    def waiting_for_approval(self):
         return self.filter(
-            is_locked=True,
-            status=COMMITTED,
-            approvals__isnull=True,
+            status=WAITING_FOR_APPROVAL,
         )
 
     def by_end_date(self, desc=False):
@@ -169,6 +179,11 @@ class Project(BaseStreamForm, AccessFormData, models.Model):
     )
     sent_to_compliance_at = models.DateTimeField(null=True)
 
+    paf_reviews_meta_data = models.JSONField(
+        default=dict,
+        help_text='Reviewers role and their actions/comments'
+    )
+
     objects = ProjectQuerySet.as_manager()
 
     def __str__(self):
@@ -237,10 +252,12 @@ class Project(BaseStreamForm, AccessFormData, models.Model):
     def end_date(self):
         # Aiming for the proposed end date as the last day of the project
         # If still ongoing assume today is the end
-        return max(
-            self.proposed_end.date(),
-            timezone.now().date(),
-        )
+        if self.proposed_end:
+            return max(
+                self.proposed_end.date(),
+                timezone.now().date(),
+            )
+        return timezone.now().date()
 
     def paid_value(self):
         return self.invoices.paid_value()
@@ -273,22 +290,27 @@ class Project(BaseStreamForm, AccessFormData, models.Model):
 
     def editable_by(self, user):
         if self.editable:
-            return True
+            # 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
 
-        # Approver can edit it when they are approving
-        return user.is_approver and self.can_make_approval
+            # 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
 
     @property
     def editable(self):
-        if self.status not in (CONTRACTING, COMMITTED):
-            return True
-
-        # Someone has approved the project - consider it locked while with contracting
-        if self.approvals.exists():
+        if self.is_locked:
             return False
-
-        # Someone must lead the project to make changes
-        return self.lead and not self.is_locked
+        elif self.status in (COMMITTED, WAITING_FOR_APPROVAL):  # locked condition is enough,it is just for double check
+            return True
+        return False
 
     def get_absolute_url(self):
         if settings.PROJECTS_ENABLED:
@@ -297,7 +319,22 @@ class Project(BaseStreamForm, AccessFormData, models.Model):
 
     @property
     def can_make_approval(self):
-        return self.is_locked and self.status == COMMITTED
+        return self.status == WAITING_FOR_APPROVAL
+
+    @property
+    def can_make_final_approval(self):
+        if self.status == WAITING_FOR_APPROVAL:
+            paf_reviewers_count = PAFReviewersRole.objects.all().count()
+            if paf_reviewers_count == len(self.paf_reviews_meta_data):
+                for paf_review_data in self.paf_reviews_meta_data.values():
+                    if paf_review_data['status'] == REQUEST_CHANGE:
+                        return False
+                return True
+        return False
+
+    @property
+    def can_update_paf_status(self):
+        return self.status == WAITING_FOR_APPROVAL and not self.can_make_final_approval
 
     def can_request_funding(self):
         """
@@ -359,19 +396,6 @@ class Project(BaseStreamForm, AccessFormData, models.Model):
             return reference_number.split('-')[0]
         return ''
 
-    # def send_to_compliance(self, request):
-    #     """Notify Compliance about this Project."""
-
-    #     messenger(
-    #         MESSAGES.SENT_TO_COMPLIANCE,
-    #         request=request,
-    #         user=request.user,
-    #         source=self,
-    #     )
-
-    #     self.sent_to_compliance_at = timezone.now()
-    #     self.save(update_fields=['sent_to_compliance_at'])
-
 
 class ProjectApprovalForm(BaseStreamForm, models.Model):
     name = models.CharField(max_length=255)
@@ -386,11 +410,25 @@ class ProjectApprovalForm(BaseStreamForm, models.Model):
         return self.name
 
 
+class PAFReviewersRole(Orderable):
+    role = models.CharField(max_length=200)
+    page = ParentalKey('ProjectSettings', related_name='paf_reviewers_roles')
+
+    def __str__(self):
+        return str(self.role)
+
+
 @register_setting
-class ProjectSettings(BaseSetting):
+class ProjectSettings(BaseSetting, ClusterableModel):
     compliance_email = models.TextField("Compliance Email")
     vendor_setup_required = models.BooleanField(default=True)
 
+    panels = [
+        FieldPanel('compliance_email'),
+        FieldPanel('vendor_setup_required'),
+        InlinePanel('paf_reviewers_roles', label=_('PAF Reviewers Roles')),
+    ]
+
 
 class Approval(models.Model):
     project = models.ForeignKey("Project", on_delete=models.CASCADE, related_name="approvals")
diff --git a/hypha/apply/projects/templates/application_projects/project_admin_detail.html b/hypha/apply/projects/templates/application_projects/project_admin_detail.html
index 7cc6eb5951f69e00fe74c60ede72fdd38fa49fbf..19d215cc15c2b88cc8a95b2182b7d8fd991169c5 100644
--- a/hypha/apply/projects/templates/application_projects/project_admin_detail.html
+++ b/hypha/apply/projects/templates/application_projects/project_admin_detail.html
@@ -31,17 +31,11 @@
 </div>
 
 <div class="modal" id="approve">
-    <h4 class="modal__header-bar">{% trans "Add Approval" %}</h4>
+    <h4 class="modal__header-bar">{% trans "Update Final Approval Status" %}</h4>
     <p>{% trans "This will move the project into contracting and notify the compliance team." %}</p>
     <p>{% trans "This cannot be undone." %}</p>
-    {% trans "Approve" as approve %}
-    {% include 'funds/includes/delegated_form_base.html' with form=add_approval_form value=approve %}
-</div>
-
-<div class="modal" id="request-project-changes">
-    <h4 class="modal__header-bar">{% trans "Request Changes" %}</h4>
-    {% trans "Request Changes" as request_changes %}
-    {% include 'funds/includes/delegated_form_base.html' with form=rejection_form value=request_changes %}
+    {% trans "Update status" as update %}
+    {% include 'funds/includes/delegated_form_base.html' with form=final_approval_form value=update %}
 </div>
 
 {% if contract_to_approve %}
@@ -63,33 +57,35 @@
                     {% trans "A lead must be assigned" %}
                 {% elif not object.user_has_updated_details %}
                     {% trans "Project approval form must be completed" %}
-                {% elif object.is_locked %}
+                {% elif object.can_make_approval or object.can_make_final_approval %}
                     {% trans "Currently awaiting approval" %}
                 {% endif %}"
         {% endif %}
         data-fancybox
         data-src="#send-for-approval"
-        class="button button--bottom-space button--primary button--full-width {% if not object.can_send_for_approval %}button--tooltip-disabled{% endif %}"
+        class="button button--bottom-space button--primary button--full-width {% if not object.can_send_for_approval or not user.is_apply_staff %}button--tooltip-disabled{% endif %}"
         href="#">
         {% trans "Submit for Approval" %}
     </a>
 {% endif %}
 
 {% if object.can_make_approval %}
-  {% user_can_approve_project object user as user_can_approve %}
+  {% user_can_final_approve_project object user as user_can_approve %}
   <a data-fancybox
       data-src="#approve"
       class="button button--bottom-space button--primary button--full-width {% if user_can_approve %}is-not-disabled{% else %}is-disabled{% endif %}"
       href="#">
-      {% trans "Approve" %}
+      {% trans "Update Project Status" %}
   </a>
 
-  <a data-fancybox
-      data-src="#request-project-changes"
-     class="button button--bottom-space button--primary button--full-width {% if user_can_approve %}is-not-disabled{% else %}is-disabled{% endif %}"
-      href="#">
-      {% trans "Request changes" %}
-  </a>
+  {% user_can_update_paf_status object user as user_can_update_paf_status %}
+  <a data-fancybox data-src="#change-status" class="button button--primary button--full-width {% if not user_can_update_paf_status %} is-disabled {% endif %}" href="#">{% trans "Update PAF Status" %}</a>
+  <div class="modal" id="change-status">
+      <h4 class="modal__header-bar">{% trans "Update PAF Status" %}</h4>
+      <p>{% trans "Project's current status" %}: {{ object.get_status_display }}</p>
+      {% trans "Update Status" as update %}
+      {% include 'funds/includes/delegated_form_base.html' with form=change_paf_status value=update %}
+  </div>
 {% endif %}
 
 {% endblock %}
diff --git a/hypha/apply/projects/templates/application_projects/project_approval_form.html b/hypha/apply/projects/templates/application_projects/project_approval_form.html
index 7f41d66c57c5b4523daeecd67c879d425415940b..1fc5cb378269e2ba0571de0dee42d7b509e0df85 100644
--- a/hypha/apply/projects/templates/application_projects/project_approval_form.html
+++ b/hypha/apply/projects/templates/application_projects/project_approval_form.html
@@ -46,7 +46,6 @@
 {% block extra_js %}
     <script src="{% static 'js/apply/tinymce-word-count.js' %}"></script>
     <script src="{% static 'js/apply/multi-input-fields.js' %}"></script>
-    <script src="{% static 'js/apply/submission-form-copy.js' %}"></script>
     <script src="{% static 'js/apply/application-form-links-new-window.js' %}"></script>
     {% if not show_all_group_fields %}
     <script src="{% static 'js/apply/form-group-toggle.js' %}"></script>
diff --git a/hypha/apply/projects/templates/application_projects/project_detail.html b/hypha/apply/projects/templates/application_projects/project_detail.html
index c33052d289edd43015c4d99c0d055dfae59da4e6..aae7ba9cacedfd21ebd95ba1e83e70c00fc10b02 100644
--- a/hypha/apply/projects/templates/application_projects/project_detail.html
+++ b/hypha/apply/projects/templates/application_projects/project_detail.html
@@ -120,7 +120,7 @@
 
                     <h5>{% trans "Actions to take" %}</h5>
 
-                    {% if request.user.is_apply_staff %}
+                    {% if request.user.is_apply_staff or request.user.is_contracting or request.user.is_finance %}
                     {% block admin_actions %}{% endblock %}
                     {% endif %}
 
@@ -231,14 +231,14 @@
     <div class="tabs__content" id="tab-2">
         <div class="feed">
             {% include "activity/include/comment_form.html" %}
-            {% include "activity/include/comment_list.html" with editable=True %}
+            {% include "activity/include/comment_list.html" with editable=False %}
         </div>
     </div>
 
     {# Tab 3 #}
     <div class="tabs__content" id="tab-3">
         <div class="feed">
-            {% include "activity/include/action_list.html" %}
+            {% include "activity/include/action_list.html" with editable=False %}
         </div>
     </div>
 </div>
diff --git a/hypha/apply/projects/templates/application_projects/project_simplified_detail.html b/hypha/apply/projects/templates/application_projects/project_simplified_detail.html
index 08a8d4be470964b26ca072205b2e89a4ca40a726..5bc3b1bb0539ac16a55a3685d67e87870b22cee1 100644
--- a/hypha/apply/projects/templates/application_projects/project_simplified_detail.html
+++ b/hypha/apply/projects/templates/application_projects/project_simplified_detail.html
@@ -1,8 +1,13 @@
 {% extends "base-apply.html" %}
-{% load i18n %}
+{% load i18n static approval_tools %}
 
 {% block title %}{{ object.title }}{% endblock %}
 
+{% block extra_css %}
+        <link rel="stylesheet" href="{% static 'css/apply/fancybox.css' %}">
+        {{ reviewer_form.media.css }}
+{% endblock %}
+
 {% block body_class %}light-grey-bg{% endblock %}
 
 {% block content %}
@@ -26,109 +31,142 @@
             </a>
         </div>
     </div>
-
-    <div class="simplified__wrapper">
-        <h3>{% trans "Project Information" %}</h3>
-        <div class="card card--solid">
-            <div class="grid grid--proposal-info">
-                <div>
-                    <h5>{% trans "Proposed start date" %}</h5>
-                    <p>{{ object.proposed_start|date:"DATE_FORMAT"|default:"-" }}</p>
-                </div>
-
-                <div>
-                    <h5>{% trans "Project Proposed end date" %}</h5>
-                    <p>{{ object.proposed_end|date:"DATE_FORMAT"|default:"-" }}</p>
-                </div>
-
-                <div>
-                    <h5>{% trans "Legal name" %}</h5>
-                    <p>{{ object.contact_legal_name|default:"-" }}</p>
-                </div>
-
-                <div>
-                    <h5>{% trans "E-mail" %}</h5>
-                    <p>{{ object.contact_email|default:"-" }}</p>
-                </div>
-
-                <div>
-                    <h5>{% trans "Address" %}</h5>
-                    <p>{{ object.get_address_display|default:"-"}}</p>
+    <div class="wrapper wrapper--large wrapper--tabs">
+        <div class="wrapper wrapper--sidebar">
+            <article class="wrapper--sidebar--inner simplified__wrapper">
+                <h3>{% trans "Project Information" %}</h3>
+                <div class="card card--solid">
+                    <div class="grid grid--proposal-info">
+                        <div>
+                            <h5>{% trans "Proposed start date" %}</h5>
+                            <p>{{ object.proposed_start|date:"DATE_FORMAT"|default:"-" }}</p>
+                        </div>
+
+                        <div>
+                            <h5>{% trans "Project Proposed end date" %}</h5>
+                            <p>{{ object.proposed_end|date:"DATE_FORMAT"|default:"-" }}</p>
+                        </div>
+
+                        <div>
+                            <h5>{% trans "Legal name" %}</h5>
+                            <p>{{ object.contact_legal_name|default:"-" }}</p>
+                        </div>
+
+                        <div>
+                            <h5>{% trans "E-mail" %}</h5>
+                            <p>{{ object.contact_email|default:"-" }}</p>
+                        </div>
+
+                        <div>
+                            <h5>{% trans "Address" %}</h5>
+                            <p>{{ object.get_address_display|default:"-"}}</p>
+                        </div>
+
+                        <div>
+                            <h5>{% trans "Phone" %}</h5>
+                            <p>{{ object.phone|default:"-" }}</p>
+                        </div>
+
+                        <div>
+                            <h5>{% trans "Value" %}</h5>
+                            <p>{{ CURRENCY_SYMBOL }}{{ object.value|default:"-" }}</p>
+                        </div>
+
+                        {% if object.sent_to_compliance_at %}
+                        <div>
+                            <h5>{% trans "Sent to Compliance" %}</h5>
+                            <p>{{ object.sent_to_compliance_at|date:"DATE_FORMAT" }}</p>
+                        </div>
+                        {% endif %}
+
+                    </div>
+
+                    {% if object.output_answers %}
+                        <div class="simplified__rich-text">
+                            {{ object.output_answers }}
+                        </div>
+                    {% endif %}
                 </div>
 
-                <div>
-                    <h5>{% trans "Phone" %}</h5>
-                    <p>{{ object.phone|default:"-" }}</p>
+                <h3>{% trans "Approvals" %}</h3>
+                <div class="card card--solid">
+                    <h4>{% trans "Approver" %}</h4>
+                    {% with approval=project.approvals.first %}
+                        <p>{{ approval.by }} - {{ approval.created_at|date:"DATE_FORMAT" }}</p>
+                    {% endwith %}
                 </div>
 
-                <div>
-                    <h5>{% trans "Value" %}</h5>
-                    <p>{{ CURRENCY_SYMBOL }}{{ object.value|default:"-" }}</p>
+                <h3>{% trans "Review" %}</h3>
+                <div class="card card--solid">
+                    <h4>{% trans "Submission lead" %}</h4>
+                    <p>{{ project.submission.lead }}</p>
+
+                    <h4>{% trans "Reviews" %}</h4>
+                    <h5>{% trans "Staff Reviewers" %}</h5>
+                    {% for review in project.submission.reviews.by_staff %}
+                    <div class="card__reviewer-outcome">
+                        <span class="card__reviewer">
+                            {{ review.author }}
+                            {% if review.author.role %}
+                                as {{ review.author.role }}
+                            {% endif %}
+                            - {{ review.created_at|date:"DATE_FORMAT" }}
+                        </span>
+                    </div>
+                    {% empty %}
+                        {% trans "No reviews" %}
+                    {% endfor %}
+                    <h5>{% trans "External Reviewers" %}</h5>
+                    {% for review in project.submission.reviews.by_reviewers %}
+                        <div class="card__reviewer-outcome">
+                            <span class="card__reviewer">
+                                {{ review.author }} - {{ review.created_at|date:"DATE_FORMAT" }}
+                            </span>
+                        </div>
+                    {% empty %}
+                        {% trans "No reviews" %}
+                    {% endfor %}
                 </div>
 
-                {% if object.sent_to_compliance_at %}
-                <div>
-                    <h5>{% trans "Sent to Compliance" %}</h5>
-                    <p>{{ object.sent_to_compliance_at|date:"DATE_FORMAT" }}</p>
+                <h3>{% trans "Supporting Documents" %}</h3>
+                <div class="card card--solid">
+                    <p><a href="{% url 'apply:submissions:simplified' pk=object.submission_id %}">{% trans "Submission" %}</a></p>
+                    {% for packet_file in object.packet_files.all %}
+                        <p><a href="{% url 'apply:projects:document' pk=object.pk file_pk=packet_file.pk %}">{{ packet_file.title }}</a></p>
+                    {% endfor %}
                 </div>
+            </article>
+            {% user_can_update_paf_status object user as user_can_take_actions %}
+            {% if user_can_take_actions %}
+            <aside class="sidebar">
+                {% if mobile %}
+                    <a class="js-actions-toggle button button--white button--full-width button--actions">{% trans "Actions to take" %}</a>
                 {% endif %}
 
-            </div>
-
-            {% if object.output_answers %}
-                <div class="simplified__rich-text">
-                    {{ object.output_answers }}
-                </div>
-            {% endif %}
-        </div>
-
-        <h3>{% trans "Approvals" %}</h3>
-        <div class="card card--solid">
-            <h4>{% trans "Approver" %}</h4>
-            {% with approval=project.approvals.first %}
-                <p>{{ approval.by }} - {{ approval.created_at|date:"DATE_FORMAT" }}</p>
-            {% endwith %}
-        </div>
-
-        <h3>{% trans "Review" %}</h3>
-        <div class="card card--solid">
-            <h4>{% trans "Submission lead" %}</h4>
-            <p>{{ project.submission.lead }}</p>
-
-            <h4>{% trans "Reviews" %}</h4>
-            <h5>{% trans "Staff Reviewers" %}</h5>
-            {% for review in project.submission.reviews.by_staff %}
-            <div class="card__reviewer-outcome">
-                <span class="card__reviewer">
-                    {{ review.author }}
-                    {% if review.author.role %}
-                        as {{ review.author.role }}
+                <div class="js-actions-sidebar sidebar__inner sidebar__inner--light-blue sidebar__inner--actions {% if mobile %}sidebar__inner--mobile{% endif %}">
+                    <h5>{% trans "Actions to take" %}</h5>
+                    {% if request.user.is_contracting or request.user.is_finance %}
+                    {% user_can_final_approve_project object user as user_can_approve %}
+                    <a class="button button--bottom-space button--primary button--full-width {% if user_can_approve %} is-disabled {% endif %}" href="{% url 'apply:projects:edit' pk=object.pk %}">{% trans "Edit PAF" %}</a>
+                    <a data-fancybox data-src="#change-status" class="button button--primary button--full-width {% if user_can_approve %} is-disabled {% endif %}" href="#">{% trans "Update PAF Status" %}</a>
+                    <div class="modal" id="change-status">
+                        <h4 class="modal__header-bar">{% trans "Update PAF Status" %}</h4>
+                        <p>{% trans "Project's current status" %}: {{ object.get_status_display }}</p>
+                        {% trans "Update Status" as update %}
+                        {% include 'funds/includes/delegated_form_base.html' with form=change_paf_status value=update %}
+                    </div>
                     {% endif %}
-                    - {{ review.created_at|date:"DATE_FORMAT" }}
-                </span>
-            </div>
-            {% empty %}
-                {% trans "No reviews" %}
-            {% endfor %}
-            <h5>{% trans "External Reviewers" %}</h5>
-            {% for review in project.submission.reviews.by_reviewers %}
-                <div class="card__reviewer-outcome">
-                    <span class="card__reviewer">
-                        {{ review.author }} - {{ review.created_at|date:"DATE_FORMAT" }}
-                    </span>
                 </div>
-            {% empty %}
-                {% trans "No reviews" %}
-            {% endfor %}
-        </div>
 
-        <h3>{% trans "Supporting Documents" %}</h3>
-        <div class="card card--solid">
-            <p><a href="{% url 'apply:submissions:simplified' pk=object.submission_id %}">{% trans "Submission" %}</a></p>
-            {% for packet_file in object.packet_files.all %}
-                <p><a href="{% url 'apply:projects:document' pk=object.pk file_pk=packet_file.pk %}">{{ packet_file.title }}</a></p>
-            {% endfor %}
+            </aside>
+            {% endif %}
         </div>
     </div>
 </div>
 {% endblock content %}
+
+{% block extra_js %}
+    {{ block.super }}
+    <script src="{% static 'js/apply/jquery.fancybox.min.js' %}"></script>
+    <script src="{% static 'js/apply/fancybox-global.js' %}"></script>
+{% endblock %}
diff --git a/hypha/apply/projects/templatetags/approval_tools.py b/hypha/apply/projects/templatetags/approval_tools.py
index 84dc2891c73fffd61463b7374cb5fe1f0e2faaa5..988d70a77d2fa70bb9bedb62fab790b2acca576d 100644
--- a/hypha/apply/projects/templatetags/approval_tools.py
+++ b/hypha/apply/projects/templatetags/approval_tools.py
@@ -15,7 +15,26 @@ def can_send_for_approval(project, user):
 
 @register.simple_tag
 def user_can_approve_project(project, user):
-    return user.is_approver and not user_has_approved(project, user)
+    if not user_has_approved(project, user):
+        if user.is_finance or user.is_contracting or user.is_approver:
+            return True
+    return False
+
+
+@register.simple_tag
+def user_can_update_paf_status(project, user):
+    if not project.user == user:
+        if project.can_update_paf_status:
+            if user.is_finance or user.is_contracting or user.is_approver:
+                return True
+    return False
+
+
+@register.simple_tag
+def user_can_final_approve_project(project, user):
+    if user.is_approver and user.is_contracting and project.can_make_final_approval:
+        return True
+    return False
 
 
 @register.simple_tag
diff --git a/hypha/apply/projects/templatetags/contract_tools.py b/hypha/apply/projects/templatetags/contract_tools.py
index efb2701a3808cf03d98c609bbafb07907fcafab5..de991f0d9e18764185b31a0c234db84b14fff819 100644
--- a/hypha/apply/projects/templatetags/contract_tools.py
+++ b/hypha/apply/projects/templatetags/contract_tools.py
@@ -1,6 +1,6 @@
 from django import template
 
-from ..models.project import COMMITTED
+from ..models.project import COMMITTED, WAITING_FOR_APPROVAL
 
 register = template.Library()
 
@@ -8,7 +8,7 @@ register = template.Library()
 @register.simple_tag
 def user_can_upload_contract(project, user):
     if user.is_apply_staff:
-        return project.status != COMMITTED
+        return project.status not in [COMMITTED, WAITING_FOR_APPROVAL]
 
     # Does the Project have any unapproved contracts?
     latest_contract = project.contracts.order_by('-created_at').first()
diff --git a/hypha/apply/projects/tests/factories.py b/hypha/apply/projects/tests/factories.py
index 50c7bee415d657efd57f2c4f30941352a4be8d17..d781c7cdb50451af001343918e77bffec735048f 100644
--- a/hypha/apply/projects/tests/factories.py
+++ b/hypha/apply/projects/tests/factories.py
@@ -19,6 +19,7 @@ from ..models.project import (
     Deliverable,
     DocumentCategory,
     PacketFile,
+    PAFReviewersRole,
     Project,
     ProjectApprovalForm,
 )
@@ -103,6 +104,13 @@ class ProjectFactory(factory.django.DjangoModelFactory):
         )
 
 
+class PAFReviewerRoleFactory(factory.django.DjangoModelFactory):
+    role = factory.Faker('name')
+
+    class Meta:
+        model = PAFReviewersRole
+
+
 class ContractFactory(factory.django.DjangoModelFactory):
     approver = factory.SubFactory(StaffFactory)
     project = factory.SubFactory(ProjectFactory)
diff --git a/hypha/apply/projects/tests/test_forms.py b/hypha/apply/projects/tests/test_forms.py
index 769a3d6619da6349ee70d3531e1fe057f9f6c151..20d2c53d1f83fcbb841fd025cd9f83c2eacb4b05 100644
--- a/hypha/apply/projects/tests/test_forms.py
+++ b/hypha/apply/projects/tests/test_forms.py
@@ -5,6 +5,7 @@ from unittest import mock
 from django.core.files.uploadedfile import SimpleUploadedFile
 from django.test import TestCase, override_settings
 
+from hypha.apply.home.factories import ApplySiteFactory
 from hypha.apply.users.tests.factories import (
     Finance2Factory,
     FinanceFactory,
@@ -21,6 +22,8 @@ from ..forms.payment import (
     filter_request_choices,
 )
 from ..forms.project import (
+    ChangePAFStatusForm,
+    FinalApprovalForm,
     ProjectApprovalForm,
     StaffUploadContractForm,
     UploadContractForm,
@@ -37,9 +40,11 @@ from ..models.payment import (
     SUBMITTED,
     invoice_status_user_choices,
 )
+from ..models.project import APPROVE, ProjectSettings
 from .factories import (
     DocumentCategoryFactory,
     InvoiceFactory,
+    PAFReviewerRoleFactory,
     ProjectFactory,
     SupportingDocumentFactory,
     address_to_form_data,
@@ -262,6 +267,56 @@ class TestChangeInvoiceStatusFormForm(TestCase):
         self.assertTrue(form.is_valid(), form.errors.as_text())
 
 
+class TestChangePAFStatusForm(TestCase):
+
+    @classmethod
+    def setUpTestData(cls):
+        super().setUpTestData()
+        apply_site = ApplySiteFactory()
+        cls.project_setting, _ = ProjectSettings.objects.get_or_create(site_id=apply_site.id)
+        cls.project_setting.use_settings = True
+        cls.project_setting.save()
+        cls.role = PAFReviewerRoleFactory(page=cls.project_setting)
+
+    def test_paf_status_is_required(self):
+        project = ProjectFactory(in_approval=True)
+        user = StaffFactory()
+        form = ChangePAFStatusForm(data={'role': self.role}, instance=project, user=user)
+        self.assertFalse(form.is_valid())
+        self.assertIn('paf_status', form.errors.keys())
+
+    def test_role_is_required(self):
+        project = ProjectFactory(in_approval=True)
+        user = StaffFactory()
+        form = ChangePAFStatusForm(data={'paf_status': APPROVE}, instance=project, user=user)
+        self.assertFalse(form.is_valid())
+        self.assertIn('role', form.errors.keys())
+
+    def test_comment_is_not_required(self):
+        project = ProjectFactory(in_approval=True)
+        user = StaffFactory()
+        form = ChangePAFStatusForm(data={'role': self.role, 'paf_status': APPROVE}, instance=project, user=user)
+        self.assertTrue(form.is_valid())
+        self.assertEqual(form.errors, {})
+
+
+class TestFinalApprovalForm(TestCase):
+    def test_final_approval_status_is_required(self):
+        project = ProjectFactory(in_approval=True)
+        user = StaffFactory()
+        form = FinalApprovalForm(data={'comment': ''}, instance=project, user=user)
+        self.assertFalse(form.is_valid())
+        self.assertNotEqual(form.errors, {})
+        self.assertIn('final_approval_status', form.errors.keys())
+
+    def test_comment_is_not_required(self):
+        project = ProjectFactory(in_approval=True)
+        user = StaffFactory()
+        form = FinalApprovalForm(data={'final_approval_status': APPROVE}, instance=project, user=user)
+        self.assertTrue(form.is_valid())
+        self.assertEqual(form.errors, {})
+
+
 class TestProjectApprovalForm(TestCase):
     def test_updating_fields_sets_changed_flag(self):
         project = ProjectFactory()
diff --git a/hypha/apply/projects/tests/test_views.py b/hypha/apply/projects/tests/test_views.py
index d8c1c6e1d934b9b134b4fd693b9b3b1fed9ca9e5..163fd6d4a7a891451289d6bce985c2b497ea197d 100644
--- a/hypha/apply/projects/tests/test_views.py
+++ b/hypha/apply/projects/tests/test_views.py
@@ -9,9 +9,12 @@ from django.urls import reverse
 from django.utils import timezone
 
 from hypha.apply.funds.tests.factories import LabSubmissionFactory
+from hypha.apply.home.factories import ApplySiteFactory
 from hypha.apply.users.tests.factories import (
     ApplicantFactory,
     ApproverFactory,
+    ContractingApproverFactory,
+    ContractingFactory,
     FinanceFactory,
     ReviewerFactory,
     StaffFactory,
@@ -23,13 +26,22 @@ from hypha.apply.utils.testing.tests import BaseViewTestCase
 from ..files import get_files
 from ..forms import SetPendingForm
 from ..models.payment import CHANGES_REQUESTED_BY_STAFF, SUBMITTED
-from ..models.project import COMMITTED, CONTRACTING, IN_PROGRESS
+from ..models.project import (
+    APPROVE,
+    COMMITTED,
+    CONTRACTING,
+    IN_PROGRESS,
+    REQUEST_CHANGE,
+    WAITING_FOR_APPROVAL,
+    ProjectSettings,
+)
 from ..views.project import ContractsMixin, ProjectDetailSimplifiedView
 from .factories import (
     ContractFactory,
     DocumentCategoryFactory,
     InvoiceFactory,
     PacketFileFactory,
+    PAFReviewerRoleFactory,
     ProjectFactory,
     ReportFactory,
     ReportVersionFactory,
@@ -66,40 +78,181 @@ class TestUpdateLeadView(BaseViewTestCase):
         self.assertEqual(project.lead, new_lead)
 
 
-class TestCreateApprovalView(BaseViewTestCase):
+class TestSendForApprovalView(BaseViewTestCase):
     base_view_name = 'detail'
     url_name = 'funds:projects:{}'
-    user_factory = ApproverFactory
+    user_factory = StaffFactory
 
     def get_kwargs(self, instance):
         return {'pk': instance.id}
 
-    def test_creating_an_approval_happy_path(self):
-        project = ProjectFactory(in_approval=True)
-        self.assertEqual(project.approvals.count(), 0)
+    def test_send_for_approval_fails_when_project_is_locked(self):
+        project = ProjectFactory(is_locked=True)
 
-        response = self.post_page(project, {'form-submitted-add_approval_form': '', 'by': self.user.id})
+        # The view doesn't have any custom changes when form validation fails
+        # so check that directly.
+        form = SetPendingForm(instance=project)
+        self.assertFalse(form.is_valid())
+
+    def test_send_for_approval_fails_when_project_is_not_in_committed_state(self):
+        project = ProjectFactory(status='in_progress')
+
+        # The view doesn't have any custom changes when form validation fails
+        # so check that directly.
+        form = SetPendingForm(instance=project)
+        self.assertFalse(form.is_valid())
+
+    def test_send_for_approval_happy_path(self):
+        project = ProjectFactory(is_locked=False, status=COMMITTED)
+
+        response = self.post_page(project, {'form-submitted-request_approval_form': ''})
         self.assertEqual(response.status_code, 200)
 
         project.refresh_from_db()
-        self.assertEqual(project.approvals.count(), 1)
+
         self.assertFalse(project.is_locked)
-        self.assertEqual(project.status, 'contracting')
+        self.assertEqual(project.status, WAITING_FOR_APPROVAL)
+
+
+class TestChangePAFStatusView(BaseViewTestCase):
+    base_view_name = 'detail'
+    url_name = 'funds:projects:{}'
+    user_factory = StaffFactory
+
+    @classmethod
+    def setUpTestData(cls):
+        super().setUpTestData()
+        apply_site = ApplySiteFactory()
+        cls.project_setting, _ = ProjectSettings.objects.get_or_create(site_id=apply_site.id)
+        cls.project_setting.use_settings = True
+        cls.project_setting.save()
+        cls.role = PAFReviewerRoleFactory(page=cls.project_setting)
+
+    def get_kwargs(self, instance):
+        return {'pk': instance.id}
+
+    def test_applicant_cant_update_paf_status(self):
+        user = ApplicantFactory()
+        self.client.force_login(user=user)
+        project = ProjectFactory(in_approval=True)
+
+        response = self.post_page(project, {'form-submitted-change_paf_status': '', 'paf_status': APPROVE,
+                                            'role': self.role.id})
+        self.assertEqual(response.status_code, 403)
 
-        approval = project.approvals.first()
-        self.assertEqual(approval.project_id, project.pk)
+    def test_staff_can_update_paf_status(self):
+        user = StaffFactory()
+        self.client.force_login(user=user)
+        project = ProjectFactory(in_approval=True)
+
+        response = self.post_page(project, {'form-submitted-change_paf_status': '', 'paf_status': APPROVE,
+                                            'role': self.role.id})
+        self.assertEqual(response.status_code, 200)
 
-    def test_creating_an_approval_other_approver(self):
+    def test_finance_can_update_paf_status(self):
+        user = FinanceFactory()
+        self.client.force_login(user=user)
         project = ProjectFactory(in_approval=True)
-        self.assertEqual(project.approvals.count(), 0)
 
-        other = self.user_factory()
-        response = self.post_page(project, {'form-submitted-add_approval_form': '', 'by': other.id})
+        response = self.post_page(project, {'form-submitted-change_paf_status': '', 'paf_status': APPROVE,
+                                            'role': self.role.id})
+        self.assertEqual(response.status_code, 200)
+
+    def test_contracting_can_update_paf_status(self):
+        user = ContractingFactory()
+        self.client.force_login(user=user)
+        project = ProjectFactory(in_approval=True)
+
+        response = self.post_page(project, {'form-submitted-change_paf_status': '', 'paf_status': APPROVE,
+                                            'role': self.role.id})
+        self.assertEqual(response.status_code, 200)
+
+    def test_reviewer_approve_paf(self):
+        # reviewer can be staff, finance or contracting
+        project = ProjectFactory(in_approval=True)
+
+        response = self.post_page(project, {'form-submitted-change_paf_status': '', 'role': self.role.id,
+                                            'paf_status': APPROVE})
+        self.assertEqual(response.status_code, 200)
+        project.refresh_from_db()
+        self.assertIn(self.role.role, project.paf_reviews_meta_data.keys())
+        self.assertIn('approve', project.paf_reviews_meta_data[self.role.role]['status'])
+
+    def test_reviewer_rejects_paf(self):
+        # reviewer can be staff, finance or contracting
+        project = ProjectFactory(in_approval=True)
+
+        response = self.post_page(project, {'form-submitted-change_paf_status': '', 'paf_status': REQUEST_CHANGE,
+                                            'role': self.role.id})
+        self.assertEqual(response.status_code, 200)
+        project.refresh_from_db()
+        self.assertEqual(project.status, COMMITTED)
+        self.assertIn(self.role.role, project.paf_reviews_meta_data.keys())
+        self.assertEqual('request_change', project.paf_reviews_meta_data[self.role.role]['status'])
+
+
+class TestFinalApprovalView(BaseViewTestCase):
+    base_view_name = 'detail'
+    url_name = 'funds:projects:{}'
+    user_factory = ContractingApproverFactory
+
+    def get_kwargs(self, instance):
+        return {'pk': instance.id}
+
+    def test_final_approver_cant_be_staff(self):
+        user = StaffFactory()
+        self.client.force_login(user)
+        project = ProjectFactory(in_approval=True)
+        response = self.post_page(project, {'form-submitted-final_approval_form': '', 'final_approval_status': APPROVE})
+        self.assertEqual(response.status_code, 403)
+
+    def test_final_approver_cant_be_finance(self):
+        user = FinanceFactory()
+        self.client.force_login(user)
+        project = ProjectFactory(in_approval=True)
+        response = self.post_page(project, {'form-submitted-final_approval_form': '', 'final_approval_status': APPROVE})
+        self.assertEqual(response.status_code, 403)
+
+    def test_final_approver_cant_be_contracting(self):
+        user = ContractingFactory()
+        self.client.force_login(user)
+        project = ProjectFactory(in_approval=True)
+        response = self.post_page(project, {'form-submitted-final_approval_form': '', 'final_approval_status': APPROVE})
+        self.assertEqual(response.status_code, 403)
+
+    def test_final_approver_cant_be_approver(self):
+        user = ApproverFactory()
+        self.client.force_login(user)
+        project = ProjectFactory(in_approval=True)
+        response = self.post_page(project, {'form-submitted-final_approval_form': '', 'final_approval_status': APPROVE})
+        self.assertEqual(response.status_code, 403)
+
+    def test_final_approver_cant_be_applicant(self):
+        user = ApplicantFactory()
+        self.client.force_login(user)
+        project = ProjectFactory(in_approval=True)
+        response = self.post_page(project, {'form-submitted-final_approval_form': '', 'final_approval_status': APPROVE})
+        self.assertEqual(response.status_code, 403)
+
+    def test_final_approval(self):
+        project = ProjectFactory(in_approval=True)
+
+        response = self.post_page(project, {'form-submitted-final_approval_form': '', 'final_approval_status': APPROVE})
         self.assertEqual(response.status_code, 200)
 
         project.refresh_from_db()
-        self.assertEqual(project.approvals.count(), 0)
         self.assertTrue(project.is_locked)
+        self.assertEqual(project.status, CONTRACTING)
+
+    def test_final_rejection(self):
+        project = ProjectFactory(in_approval=True)
+
+        response = self.post_page(project, {'form-submitted-final_approval_form': '', 'final_approval_status': REQUEST_CHANGE})
+        self.assertEqual(response.status_code, 200)
+
+        project.refresh_from_db()
+        self.assertFalse(project.is_locked)
+        self.assertEqual(project.status, COMMITTED)
 
 
 class BaseProjectDetailTestCase(BaseViewTestCase):
@@ -170,62 +323,6 @@ class TestReviewerUserProjectDetailView(BaseProjectDetailTestCase):
         self.assertEqual(response.status_code, 403)
 
 
-class TestStaffProjectRejectView(BaseProjectDetailTestCase):
-    user_factory = StaffFactory
-
-    def test_cant_reject(self):
-        project = ProjectFactory(in_approval=True)
-        response = self.post_page(project, {
-            'form-submitted-rejection_form': '',
-            'comment': 'needs to change',
-        })
-        self.assertEqual(response.status_code, 403)
-        project = self.refresh(project)
-        self.assertEqual(project.status, COMMITTED)
-        self.assertTrue(project.is_locked)
-
-
-class TestApproverProjectRejectView(BaseProjectDetailTestCase):
-    user_factory = ApproverFactory
-
-    def test_can_reject(self):
-        project = ProjectFactory(in_approval=True)
-        response = self.post_page(project, {
-            'form-submitted-rejection_form': '',
-            'comment': 'needs to change',
-        })
-        self.assertEqual(response.status_code, 200)
-        project = self.refresh(project)
-        self.assertEqual(project.status, COMMITTED)
-        self.assertFalse(project.is_locked)
-
-    def test_cant_reject_no_comment(self):
-        project = ProjectFactory(in_approval=True)
-        response = self.post_page(project, {
-            'form-submitted-rejection_form': '',
-            'comment': '',
-        })
-        self.assertEqual(response.status_code, 200)
-        project = self.refresh(project)
-        self.assertEqual(project.status, COMMITTED)
-        self.assertTrue(project.is_locked)
-
-
-class TestUserProjectRejectView(BaseProjectDetailTestCase):
-    user_factory = ApplicantFactory
-
-    def test_cant_reject(self):
-        project = ProjectFactory(in_approval=True, user=self.user)
-        response = self.post_page(project, {
-            'form-submitted-rejection_form': '',
-            'comment': 'needs to change',
-        })
-        self.assertEqual(response.status_code, 200)
-        project = self.refresh(project)
-        self.assertEqual(project.status, COMMITTED)
-        self.assertTrue(project.is_locked)
-
-
 class TestRemoveDocumentView(BaseViewTestCase):
     base_view_name = 'detail'
     url_name = 'funds:projects:{}'
@@ -255,42 +352,6 @@ class TestRemoveDocumentView(BaseViewTestCase):
         self.assertEqual(response.status_code, 200)
 
 
-class TestSendForApprovalView(BaseViewTestCase):
-    base_view_name = 'detail'
-    url_name = 'funds:projects:{}'
-    user_factory = StaffFactory
-
-    def get_kwargs(self, instance):
-        return {'pk': instance.id}
-
-    def test_send_for_approval_fails_when_project_is_locked(self):
-        project = ProjectFactory(is_locked=True)
-
-        # The view doesn't have any custom changes when form validation fails
-        # so check that directly.
-        form = SetPendingForm(instance=project)
-        self.assertFalse(form.is_valid())
-
-    def test_send_for_approval_fails_when_project_is_not_in_committed_state(self):
-        project = ProjectFactory(status='in_progress')
-
-        # The view doesn't have any custom changes when form validation fails
-        # so check that directly.
-        form = SetPendingForm(instance=project)
-        self.assertFalse(form.is_valid())
-
-    def test_send_for_approval_happy_path(self):
-        project = ProjectFactory(is_locked=False, status='committed')
-
-        response = self.post_page(project, {'form-submitted-request_approval_form': ''})
-        self.assertEqual(response.status_code, 200)
-
-        project.refresh_from_db()
-
-        self.assertTrue(project.is_locked)
-        self.assertEqual(project.status, 'committed')
-
-
 class TestApplicantUploadContractView(BaseViewTestCase):
     base_view_name = 'detail'
     url_name = 'funds:projects:{}'
diff --git a/hypha/apply/projects/views/__init__.py b/hypha/apply/projects/views/__init__.py
index ca2ae12b2fbe72364883168db7bc5b8c591b61b1..787d33c4611c2e6bec479d4436a5a04170cc144a 100644
--- a/hypha/apply/projects/views/__init__.py
+++ b/hypha/apply/projects/views/__init__.py
@@ -13,7 +13,7 @@ from .project import (
     ApproveContractView,
     BaseProjectDetailView,
     ContractPrivateMediaView,
-    CreateApprovalView,
+    FinalApprovalView,
     ProjectApprovalEditView,
     ProjectDetailPDFView,
     ProjectDetailSimplifiedView,
@@ -21,7 +21,6 @@ from .project import (
     ProjectListView,
     ProjectOverviewView,
     ProjectPrivateMediaView,
-    RejectionView,
     RemoveDocumentView,
     SelectDocumentView,
     SendForApprovalView,
@@ -42,8 +41,7 @@ from .vendor import CreateVendorView, VendorDetailView, VendorPrivateMediaView
 __all__ = [
     'ChangeInvoiceStatusView',
     'SendForApprovalView',
-    'CreateApprovalView',
-    'RejectionView',
+    'FinalApprovalView',
     'UploadDocumentView',
     'RemoveDocumentView',
     'SelectDocumentView',
diff --git a/hypha/apply/projects/views/project.py b/hypha/apply/projects/views/project.py
index b436eb319248176f131024e64ea9a093b193ed32..0f4f800fe1d5887772d6cc59a7946ee6acc3440a 100644
--- a/hypha/apply/projects/views/project.py
+++ b/hypha/apply/projects/views/project.py
@@ -27,10 +27,12 @@ from django_filters.views import FilterView
 from django_tables2 import SingleTableMixin
 
 from hypha.apply.activity.messaging import MESSAGES, messenger
+from hypha.apply.activity.models import ACTION, ALL, COMMENT, Activity
 from hypha.apply.activity.views import ActivityContextMixin, CommentFormView
 from hypha.apply.stream_forms.models import BaseStreamForm
 from hypha.apply.users.decorators import (
-    approver_required,
+    contracting_approver_required,
+    staff_or_finance_or_contracting_required,
     staff_or_finance_required,
     staff_required,
 )
@@ -47,9 +49,9 @@ from ..files import get_files
 from ..filters import InvoiceListFilter, ProjectListFilter, ReportListFilter
 from ..forms import (
     ApproveContractForm,
-    CreateApprovalForm,
+    ChangePAFStatusForm,
+    FinalApprovalForm,
     ProjectApprovalForm,
-    RejectionForm,
     RemoveDocumentForm,
     SelectDocumentForm,
     SetPendingForm,
@@ -60,10 +62,12 @@ from ..forms import (
 )
 from ..models.payment import Invoice
 from ..models.project import (
+    COMMITTED,
     CONTRACTING,
     IN_PROGRESS,
     PROJECT_STATUS_CHOICES,
-    Approval,
+    REQUEST_CHANGE,
+    WAITING_FOR_APPROVAL,
     Contract,
     PacketFile,
     Project,
@@ -79,53 +83,35 @@ class SendForApprovalView(DelegatedViewMixin, UpdateView):
     form_class = SetPendingForm
     model = Project
 
-    def form_valid(self, form):
-        # lock project
-        response = super().form_valid(form)
-
+    def send_to_compliance(self):
+        """Notify Compliance about this Project."""
         messenger(
-            MESSAGES.SEND_FOR_APPROVAL,
+            MESSAGES.SENT_TO_COMPLIANCE,
             request=self.request,
             user=self.request.user,
             source=self.object,
         )
 
-        return response
-
+        self.object.sent_to_compliance_at = timezone.now()
+        self.object.save(update_fields=['sent_to_compliance_at'])
 
-@method_decorator(staff_required, name='dispatch')
-class CreateApprovalView(DelegatedViewMixin, CreateView):
-    context_name = 'add_approval_form'
-    form_class = CreateApprovalForm
-    model = Approval
-
-    def get_form_kwargs(self):
-        kwargs = super().get_form_kwargs()
-        kwargs.pop('instance')
-        kwargs.get('initial', {}).update({'by': kwargs.get('user')})
-        return kwargs
-
-    @transaction.atomic()
     def form_valid(self, form):
         project = self.kwargs['object']
         old_stage = project.get_status_display()
 
-        form.instance.project = project
-
         response = super().form_valid(form)
 
         messenger(
-            MESSAGES.APPROVE_PROJECT,
+            MESSAGES.SEND_FOR_APPROVAL,
             request=self.request,
             user=self.request.user,
-            source=project,
+            source=self.object,
         )
 
-        # project.send_to_compliance(self.request)
+        project.status = WAITING_FOR_APPROVAL
+        project.save(update_fields=['status'])
 
-        project.is_locked = False
-        project.status = CONTRACTING
-        project.save(update_fields=['is_locked', 'status'])
+        self.send_to_compliance()
 
         messenger(
             MESSAGES.PROJECT_TRANSITION,
@@ -138,25 +124,86 @@ class CreateApprovalView(DelegatedViewMixin, CreateView):
         return response
 
 
-@method_decorator(approver_required, name='dispatch')
-class RejectionView(DelegatedViewMixin, UpdateView):
-    context_name = 'rejection_form'
-    form_class = RejectionForm
+@method_decorator(contracting_approver_required, name='dispatch')
+class FinalApprovalView(DelegatedViewMixin, UpdateView):
+    form_class = FinalApprovalForm
+    context_name = 'final_approval_form'
     model = Project
 
     def form_valid(self, form):
+        project = self.object
+        old_stage = project.get_status_display()
+
+        response = super().form_valid(form)
+
+        comment = form.cleaned_data.get('comment', '')
+        status = form.cleaned_data['final_approval_status']
+
+        if status == REQUEST_CHANGE:
+            project.status = COMMITTED
+            project.is_locked = False
+            project.paf_reviews_meta_data = {}
+            project.save(update_fields=['status', 'is_locked', 'paf_reviews_meta_data'])
+
+            project_status_message = _(
+                '<p>{user} request changes the Project and update status to {project_status}.</p>').format(
+                user=self.request.user,
+                project_status=project.status
+            )
+
+            Activity.objects.create(
+                user=self.request.user,
+                type=ACTION,
+                source=project,
+                timestamp=timezone.now(),
+                message=project_status_message,
+                visibility=ALL,
+            )
+
+            messenger(
+                MESSAGES.REQUEST_PROJECT_CHANGE,
+                request=self.request,
+                user=self.request.user,
+                source=self.object,
+                comment=comment,
+            )
+            return response
+
         messenger(
-            MESSAGES.REQUEST_PROJECT_CHANGE,
+            MESSAGES.APPROVE_PROJECT,
             request=self.request,
             user=self.request.user,
-            source=self.object,
-            comment=form.cleaned_data['comment'],
+            source=project,
         )
 
-        self.object.is_locked = False
-        self.object.save(update_fields=['is_locked'])
+        project.is_locked = True
+        project.status = CONTRACTING
+        project.save(update_fields=['is_locked', 'status'])
 
-        return redirect(self.object)
+        project_status_message = _(
+            '<p>{user} approved the Project and update status to {project_status}.</p>').format(
+            user=self.request.user,
+            project_status=project.status
+        )
+
+        Activity.objects.create(
+            user=self.request.user,
+            type=ACTION,
+            source=project,
+            timestamp=timezone.now(),
+            message=project_status_message,
+            visibility=ALL,
+        )
+
+        messenger(
+            MESSAGES.PROJECT_TRANSITION,
+            request=self.request,
+            user=self.request.user,
+            source=project,
+            related=old_stage,
+        )
+
+        return response
 
 
 # PROJECT DOCUMENTS
@@ -412,6 +459,63 @@ class UploadContractView(DelegatedViewMixin, CreateView):
 
 
 # PROJECT VIEW
+
+@method_decorator(staff_or_finance_or_contracting_required, name='dispatch')
+class ChangePAFStatusView(DelegatedViewMixin, UpdateView):
+    form_class = ChangePAFStatusForm
+    context_name = 'change_paf_status'
+    model = Project
+
+    def form_valid(self, form):
+        response = super().form_valid(form)
+        role = form.cleaned_data.get('role')
+        paf_status = form.cleaned_data.get('paf_status')
+        comment = form.cleaned_data.get('comment', '')
+
+        self.object.paf_reviews_meta_data.update({str(role.role): {'status': paf_status, 'comment': comment}})
+        self.object.save(update_fields=['paf_reviews_meta_data'])
+
+        paf_status_update_message = _('<p>{role} has updated PAF status to {paf_status}.</p>').format(
+            role=role, paf_status=paf_status)
+        Activity.objects.create(
+            user=self.request.user,
+            type=ACTION,
+            source=self.object,
+            timestamp=timezone.now(),
+            message=paf_status_update_message,
+            visibility=ALL,
+        )
+
+        if paf_status == REQUEST_CHANGE:
+            self.object.status = COMMITTED
+            self.object.save(update_fields=['status'])
+
+            messenger(
+                MESSAGES.REQUEST_PROJECT_CHANGE,
+                request=self.request,
+                user=self.request.user,
+                source=self.object,
+                comment=comment,
+            )
+
+        if form.cleaned_data['comment']:
+
+            comment = f"<p>{form.cleaned_data['comment']}.</p>"
+
+            message = paf_status_update_message + comment
+
+            Activity.objects.create(
+                user=self.request.user,
+                type=COMMENT,
+                source=self.object,
+                timestamp=timezone.now(),
+                message=message,
+                visibility=ALL,
+            )
+
+        return response
+
+
 class BaseProjectDetailView(ReportingMixin, DetailView):
     def get_context_data(self, **kwargs):
         context = super().get_context_data(**kwargs)
@@ -429,8 +533,7 @@ class AdminProjectDetailView(
     form_views = [
         ApproveContractView,
         CommentFormView,
-        CreateApprovalView,
-        RejectionView,
+        FinalApprovalView,
         RemoveDocumentView,
         SelectDocumentView,
         SendForApprovalView,
@@ -438,6 +541,7 @@ class AdminProjectDetailView(
         UpdateLeadView,
         UploadContractView,
         UploadDocumentView,
+        ChangePAFStatusView,
     ]
     model = Project
     template_name_suffix = '_admin_detail'
@@ -481,6 +585,7 @@ class ApplicantProjectDetailView(
 class ProjectDetailView(ViewDispatcher):
     admin_view = AdminProjectDetailView
     finance_view = AdminProjectDetailView
+    contracting_view = AdminProjectDetailView
     applicant_view = ApplicantProjectDetailView
 
 
@@ -536,13 +641,16 @@ class ContractPrivateMediaView(UserPassesTestMixin, PrivateMediaView):
 
 # PROJECT EDIT
 
-@method_decorator(staff_or_finance_required, name='dispatch')
-class ProjectDetailSimplifiedView(DetailView):
+@method_decorator(staff_or_finance_or_contracting_required, name='dispatch')
+class ProjectDetailSimplifiedView(DelegateableView, DetailView):
+    form_views = [
+        ChangePAFStatusView
+    ]
     model = Project
     template_name_suffix = '_simplified_detail'
 
 
-@method_decorator(staff_required, name='dispatch')
+@method_decorator(staff_or_finance_or_contracting_required, name='dispatch')
 class ProjectDetailPDFView(SingleObjectMixin, View):
     model = Project
 
@@ -590,7 +698,7 @@ class ProjectDetailPDFView(SingleObjectMixin, View):
         )
 
 
-@method_decorator(staff_required, name='dispatch')
+@method_decorator(staff_or_finance_or_contracting_required, name='dispatch')
 class ProjectApprovalEditView(BaseStreamForm, UpdateView):
     submission_form_class = ProjectApprovalForm
     model = Project
@@ -598,7 +706,6 @@ class ProjectApprovalEditView(BaseStreamForm, UpdateView):
 
     def buttons(self):
         yield ('submit', 'primary', _('Submit'))
-        # yield ('save', 'white', _('Save draft'))
 
     def dispatch(self, request, *args, **kwargs):
         project = self.get_object()
diff --git a/hypha/apply/users/decorators.py b/hypha/apply/users/decorators.py
index 1017901b085e34a73fc337926fd04eaa8538633d..3bb0fe4ee3e6787e8f8a03b314ef01bca574c878 100644
--- a/hypha/apply/users/decorators.py
+++ b/hypha/apply/users/decorators.py
@@ -31,12 +31,24 @@ def is_apply_staff_or_finance(user):
     return True
 
 
+def is_apply_staff_or_finance_or_contracting(user):
+    if not (user.is_apply_staff or user.is_finance or user.is_contracting):
+        raise PermissionDenied
+    return True
+
+
 def is_approver(user):
     if not user.is_approver:
         raise PermissionDenied
     return True
 
 
+def is_contracting_approver(user):
+    if not user.is_approver or not user.is_contracting:
+        raise PermissionDenied
+    return True
+
+
 staff_required = [login_required, user_passes_test(is_apply_staff)]
 
 finance_required = [login_required, user_passes_test(is_finance)]
@@ -45,6 +57,10 @@ staff_or_finance_required = [login_required, user_passes_test(is_apply_staff_or_
 
 approver_required = [login_required, user_passes_test(is_approver)]
 
+staff_or_finance_or_contracting_required = [login_required, user_passes_test(is_apply_staff_or_finance_or_contracting)]
+
+contracting_approver_required = [login_required, user_passes_test(is_contracting_approver)]
+
 
 def superuser_decorator(fn):
     check = user_passes_test(lambda user: user.is_superuser)
diff --git a/hypha/apply/users/tests/factories.py b/hypha/apply/users/tests/factories.py
index 08f1907ab15036626c4bdd9c4138384cbe2e5e25..284d91896e74b7b8cbe24a79ad924829eed0b170 100644
--- a/hypha/apply/users/tests/factories.py
+++ b/hypha/apply/users/tests/factories.py
@@ -9,6 +9,7 @@ from ..groups import (
     APPLICANT_GROUP_NAME,
     APPROVER_GROUP_NAME,
     COMMUNITY_REVIEWER_GROUP_NAME,
+    CONTRACTING_GROUP_NAME,
     FINANCE_GROUP_NAME,
     PARTNER_GROUP_NAME,
     REVIEWER_GROUP_NAME,
@@ -130,6 +131,25 @@ class Finance2Factory(FinanceFactory):
             )
 
 
+class ContractingFactory(UserFactory):
+    @factory.post_generation
+    def groups(self, create, extracted, **kwargs):
+        if create:
+            self.groups.add(
+                GroupFactory(name=CONTRACTING_GROUP_NAME),
+            )
+
+
+class ContractingApproverFactory(UserFactory):
+    @factory.post_generation
+    def groups(self, create, extracted, **kwargs):
+        if create:
+            self.groups.add(
+                GroupFactory(name=CONTRACTING_GROUP_NAME),
+                GroupFactory(name=APPROVER_GROUP_NAME)
+            )
+
+
 class SuperUserFactory(StaffFactory):
     is_superuser = True
 
diff --git a/hypha/apply/utils/views.py b/hypha/apply/utils/views.py
index 816d8dc982d8161e7bbaf785786c1cdebd5e29aa..351d1b560fd274f19e42771d9ea12e054f2fd3d3 100644
--- a/hypha/apply/utils/views.py
+++ b/hypha/apply/utils/views.py
@@ -30,6 +30,7 @@ class ViewDispatcher(View):
     community_view: View = None
     applicant_view: View = None
     finance_view: View = None
+    contracting_view: View = None
 
     def admin_check(self, request):
         return request.user.is_apply_staff
@@ -46,6 +47,9 @@ class ViewDispatcher(View):
     def finance_check(self, request):
         return request.user.is_finance
 
+    def contracting_check(self, request):
+        return request.user.is_contracting
+
     def dispatch(self, request, *args, **kwargs):
         view = self.applicant_view
 
@@ -59,6 +63,8 @@ class ViewDispatcher(View):
             view = self.community_view
         elif self.finance_check(request):
             view = self.finance_view
+        elif self.contracting_check(request):
+            view = self.contracting_view
 
         if view:
             return view.as_view()(request, *args, **kwargs)