diff --git a/opentech/apply/activity/messaging.py b/opentech/apply/activity/messaging.py
index c9eabcb59e5cb3864f4676d78826aba228d57abb..b1dd270ed98f421560e2ac05a6bf794869601bf2 100644
--- a/opentech/apply/activity/messaging.py
+++ b/opentech/apply/activity/messaging.py
@@ -65,6 +65,7 @@ neat_related = {
     MESSAGES.DELETE_PAYMENT_REQUEST: 'payment_request',
     MESSAGES.UPDATE_PAYMENT_REQUEST: 'payment_request',
     MESSAGES.SUBMIT_REPORT: 'report',
+    MESSAGES.SKIPPED_REPORT: 'report',
 }
 
 
@@ -240,6 +241,7 @@ class ActivityAdapter(AdapterBase):
         MESSAGES.UPDATE_PAYMENT_REQUEST_STATUS: 'Updated Payment Request status to: {payment_request.status_display}',
         MESSAGES.REQUEST_PAYMENT: 'Payment Request submitted',
         MESSAGES.SUBMIT_REPORT: 'Submitted a report',
+        MESSAGES.SKIPPED_REPORT: 'handle_skipped_report',
     }
 
     def recipients(self, message_type, **kwargs):
@@ -340,6 +342,12 @@ class ActivityAdapter(AdapterBase):
 
         return ' '.join(message)
 
+    def handle_skipped_report(self, report, **kwargs):
+        if report.skipped:
+            return "Skipped a Report"
+        else:
+            return "Marked a Report as required"
+
     def send_message(self, message, user, source, sources, **kwargs):
         from .models import Activity
         visibility = kwargs.get('visibility', ALL)
@@ -637,6 +645,7 @@ class EmailAdapter(AdapterBase):
         MESSAGES.UPDATE_PAYMENT_REQUEST: 'messages/email/payment_request_updated.html',
         MESSAGES.UPDATE_PAYMENT_REQUEST_STATUS: 'handle_payment_status_updated',
         MESSAGES.SUBMIT_REPORT: 'messages/email/report_submitted.html',
+        MESSAGES.SKIPPED_REPORT: 'messages/email/report_skipped.html',
     }
 
     def get_subject(self, message_type, source):
@@ -803,6 +812,7 @@ class DjangoMessagesAdapter(AdapterBase):
         MESSAGES.BATCH_DETERMINATION_OUTCOME: 'batch_determinations',
         MESSAGES.UPLOAD_DOCUMENT: 'Successfully uploaded document',
         MESSAGES.REMOVE_DOCUMENT: 'Successfully removed document',
+        MESSAGES.SKIPPED_REPORT: 'handle_skipped_report',
     }
 
     def batch_reviewers_updated(self, added, sources, **kwargs):
@@ -819,6 +829,12 @@ class DjangoMessagesAdapter(AdapterBase):
             ', '.join(['"{}"'.format(source.title) for source in sources])
         )
 
+    def handle_skipped_report(self, report, **kwargs):
+        if report.skipped:
+            return f"Successfully skipped a Report for {report.start_date} to {report.end_date}"
+        else:
+            return f"Successfully unskipped a Report for {report.start_date} to {report.end_date}"
+
     def batch_transition(self, sources, transitions, **kwargs):
         base_message = 'Successfully updated:'
         transition = '{submission} [{old_display} → {new_display}].'
diff --git a/opentech/apply/activity/migrations/0050_add_report_skipping_activity.py b/opentech/apply/activity/migrations/0050_add_report_skipping_activity.py
new file mode 100644
index 0000000000000000000000000000000000000000..7f78e2da67ec312410ab15463d268f1719121b8b
--- /dev/null
+++ b/opentech/apply/activity/migrations/0050_add_report_skipping_activity.py
@@ -0,0 +1,18 @@
+# Generated by Django 2.1.11 on 2019-10-31 16:53
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('activity', '0049_add_submit_report'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='event',
+            name='type',
+            field=models.CharField(choices=[('UPDATE_LEAD', 'Update Lead'), ('BATCH_UPDATE_LEAD', 'Batch Update Lead'), ('EDIT', 'Edit'), ('APPLICANT_EDIT', 'Applicant Edit'), ('NEW_SUBMISSION', 'New Submission'), ('SCREENING', 'Screening'), ('TRANSITION', 'Transition'), ('BATCH_TRANSITION', 'Batch Transition'), ('DETERMINATION_OUTCOME', 'Determination Outcome'), ('BATCH_DETERMINATION_OUTCOME', 'Batch Determination Outcome'), ('INVITED_TO_PROPOSAL', 'Invited To Proposal'), ('REVIEWERS_UPDATED', 'Reviewers Updated'), ('BATCH_REVIEWERS_UPDATED', 'Batch Reviewers Updated'), ('PARTNERS_UPDATED', 'Partners Updated'), ('PARTNERS_UPDATED_PARTNER', 'Partners Updated Partner'), ('READY_FOR_REVIEW', 'Ready For Review'), ('BATCH_READY_FOR_REVIEW', 'Batch Ready For Review'), ('NEW_REVIEW', 'New Review'), ('COMMENT', 'Comment'), ('PROPOSAL_SUBMITTED', 'Proposal Submitted'), ('OPENED_SEALED', 'Opened Sealed Submission'), ('REVIEW_OPINION', 'Review Opinion'), ('DELETE_SUBMISSION', 'Delete Submission'), ('DELETE_REVIEW', 'Delete Review'), ('CREATED_PROJECT', 'Created Project'), ('UPDATE_PROJECT_LEAD', 'Update Project Lead'), ('EDIT_REVIEW', 'Edit Review'), ('SEND_FOR_APPROVAL', 'Send for Approval'), ('APPROVE_PROJECT', 'Project was Approved'), ('PROJECT_TRANSITION', 'Project was Transitioned'), ('REQUEST_PROJECT_CHANGE', 'Project change requested'), ('UPLOAD_DOCUMENT', 'Document was Uploaded to Project'), ('REMOVE_DOCUMENT', 'Document was Removed from Project'), ('UPLOAD_CONTRACT', 'Contract was Uploaded to Project'), ('APPROVE_CONTRACT', 'Contract was Approved'), ('REQUEST_PAYMENT', 'Payment was requested for Project'), ('UPDATE_PAYMENT_REQUEST_STATUS', 'Updated Payment Request Status'), ('DELETE_PAYMENT_REQUEST', 'Delete Payment Request'), ('SENT_TO_COMPLIANCE', 'Project was sent to Compliance'), ('UPDATE_PAYMENT_REQUEST', 'Updated Payment Request'), ('SUBMIT_REPORT', 'Submit Report'), ('SKIPPED_REPORT', 'Skipped Report')], max_length=50),
+        ),
+    ]
diff --git a/opentech/apply/activity/options.py b/opentech/apply/activity/options.py
index e65b5f48436a6bbe2b998fc7512d6c676f15dbd1..34bd2a9016006d68e11feaa84ef9bfe78beec179 100644
--- a/opentech/apply/activity/options.py
+++ b/opentech/apply/activity/options.py
@@ -43,6 +43,7 @@ class MESSAGES(Enum):
     SENT_TO_COMPLIANCE = 'Project was sent to Compliance'
     UPDATE_PAYMENT_REQUEST = 'Updated Payment Request'
     SUBMIT_REPORT = 'Submit Report'
+    SKIPPED_REPORT = 'Skipped Report'
 
     @classmethod
     def choices(cls):
diff --git a/opentech/apply/activity/templates/messages/email/report_skipped.html b/opentech/apply/activity/templates/messages/email/report_skipped.html
new file mode 100644
index 0000000000000000000000000000000000000000..36584004a6a55ed10f4b7c587248fade799a29df
--- /dev/null
+++ b/opentech/apply/activity/templates/messages/email/report_skipped.html
@@ -0,0 +1,13 @@
+{% extends "messages/email/applicant_base.html" %}
+
+{% block content %}
+
+An {{ ORG_SHORT_NAME }} staff member has marked a report as {% if report.skipped %}no longer required{% else %}required{% endif %} for {{ source.title }} for period {{ report.end_date }} to {{ report.end_date }}.
+
+{% if not report.skipped %}
+This report was previously not required. Please ensure you now complete the report.
+{% endif %}
+
+Title: {{ source.title }}
+Link: {{ request.scheme }}://{{ request.get_host }}{{ source.get_absolute_url }}
+{% endblock %}
diff --git a/opentech/apply/activity/templates/messages/email/report_submitted.html b/opentech/apply/activity/templates/messages/email/report_submitted.html
index eb52964243e9019e4b360658d9c61a372cadc9fd..dc9869a83f952e92692ca2154a21535ae98265e5 100644
--- a/opentech/apply/activity/templates/messages/email/report_submitted.html
+++ b/opentech/apply/activity/templates/messages/email/report_submitted.html
@@ -1,8 +1,10 @@
 {% extends "messages/email/applicant_base.html" %}
 
 {% block content %}
-An {{ ORG_SHORT_NAME }} staff member has submitted a report for {{ source.title }} for period ending {{ report.end_date }}.
+An {{ ORG_SHORT_NAME }} staff member has submitted a report for {{ source.title }} for period {{ report.end_date }} to {{ report.end_date }}.
 
-Title: {{ source.title }}
+You can review the report here: {{ request.scheme }}://{{ request.get_host }}{{ report.get_absolute_url }}
+
+Project: {{ source.title }}
 Link: {{ request.scheme }}://{{ request.get_host }}{{ source.get_absolute_url }}
 {% endblock %}
diff --git a/opentech/apply/projects/migrations/0030_report_skipped.py b/opentech/apply/projects/migrations/0030_report_skipped.py
new file mode 100644
index 0000000000000000000000000000000000000000..103f0df3f57e433fe568ed97770ba6c32085f531
--- /dev/null
+++ b/opentech/apply/projects/migrations/0030_report_skipped.py
@@ -0,0 +1,18 @@
+# Generated by Django 2.1.11 on 2019-10-31 14:01
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('application_projects', '0029_report_submitted'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='report',
+            name='skipped',
+            field=models.BooleanField(default=False),
+        ),
+    ]
diff --git a/opentech/apply/projects/models.py b/opentech/apply/projects/models.py
index b99e4a0e41b60add16948c50bbd9308889174b96..5dfd57455d348f281fac3a445b0557e094a23171 100644
--- a/opentech/apply/projects/models.py
+++ b/opentech/apply/projects/models.py
@@ -561,7 +561,7 @@ class ReportConfig(models.Model):
 
     def past_due_reports(self):
         return self.project.reports.filter(
-            current__isnull=True,
+            Q(current__isnull=True) & Q(skipped=False),
             end_date__lt=timezone.now().date(),
         ).order_by('end_date')
 
@@ -615,11 +615,14 @@ class ReportConfig(models.Model):
 
 class ReportQueryset(models.QuerySet):
     def done(self):
-        return self.filter(current__isnull=False)
+        return self.filter(
+            Q(current__isnull=False) | Q(skipped=True),
+        )
 
 
 class Report(models.Model):
     public = models.BooleanField(default=True)
+    skipped = models.BooleanField(default=False)
     end_date = models.DateField()
     project = models.ForeignKey("Project", on_delete=models.CASCADE, related_name="reports")
     submitted = models.DateTimeField(null=True)
diff --git a/opentech/apply/projects/templates/application_projects/includes/report_line.html b/opentech/apply/projects/templates/application_projects/includes/report_line.html
index 61fe9a82d9cb587e7699d5f7a689534c2aa7480c..ef6f6d9c4dc1730415c3d53cedc496d3a438e464 100644
--- a/opentech/apply/projects/templates/application_projects/includes/report_line.html
+++ b/opentech/apply/projects/templates/application_projects/includes/report_line.html
@@ -16,4 +16,10 @@
         {% if report.draft %}Continue Editing{% else %}Add Report{% endif %}
     </a>
     {% endif %}
+    {% if request.user.is_apply_staff and report.can_submit %}
+        <form action="{% url "apply:projects:reports:skip" pk=report.pk %}" method="post">
+            {% csrf_token %}
+            <input type="submit" value="Skip" class="btn"></input>
+        </form>
+    {% endif %}
 </p>
diff --git a/opentech/apply/projects/templates/application_projects/includes/reports.html b/opentech/apply/projects/templates/application_projects/includes/reports.html
index ae2af06007938b28b828a24b2273d1b8aaf2def1..bc7844b970b64ced24e8c06e87db9a8ee08fbcab 100644
--- a/opentech/apply/projects/templates/application_projects/includes/reports.html
+++ b/opentech/apply/projects/templates/application_projects/includes/reports.html
@@ -27,14 +27,20 @@
                     <span class="payment-block__mobile-label">Period End: </span>{{ report.end_date }}
                 </td>
                 <td>
-                    <span class="payment-block__mobile-label">Submitted: </span>{{ report.submitted_date|default:"-" }}
+                    <span class="payment-block__mobile-label">Submitted: </span>{{ report.submitted_date|default:"Skipped" }}
                 </td>
                 <td>
                     <span class="payment-block__mobile-label">Privacy: </span>{% if report.public %}Public{% else %}Private{% endif %}
                 </td>
                 <td>
                     {% if request.user.is_apply_staff %}
-                        <a href="{% url "apply:projects:reports:edit" pk=report.pk %}">edit</a>
+                        <a href="{% url "apply:projects:reports:edit" pk=report.pk %}">Edit</a>
+                        {% if report.skipped %}
+                            <form action="{% url "apply:projects:reports:skip" pk=report.pk %}" method="post">
+                                {% csrf_token %}
+                                <input type="submit" value="Unskip" class="btn"></input>
+                            </form>
+                        {% endif %}
                     {% endif %}
                     <a href="{% url "apply:projects:reports:detail" pk=report.pk %}">view</a>
                 </td>
diff --git a/opentech/apply/projects/templates/application_projects/report_detail.html b/opentech/apply/projects/templates/application_projects/report_detail.html
index 249c07e8cf668de7372e7dda07039cfcb057daf4..d145729ed7f606e06ab24167eef39661283cc8fc 100644
--- a/opentech/apply/projects/templates/application_projects/report_detail.html
+++ b/opentech/apply/projects/templates/application_projects/report_detail.html
@@ -15,6 +15,9 @@
 
 <div class="wrapper wrapper--light-grey-bg wrapper--form wrapper--sidebar">
     <div class="wrapper--sidebar--inner">
+        {% if report.skipped %}
+            <h2>Report Skipped</h2>
+        {% else%}
         <h3>
             {% if object.public %}
                 Public
@@ -35,6 +38,7 @@
                 </ul>
             {% endif %}
         {% endfor %}
+        {% endif %}
     </div>
 </div>
 {% endblock %}
diff --git a/opentech/apply/projects/tests/test_models.py b/opentech/apply/projects/tests/test_models.py
index 15abe89865880e4d7c6ed08300a08e9132772d68..52e6565876e90808787820d7a8b34276977fae79 100644
--- a/opentech/apply/projects/tests/test_models.py
+++ b/opentech/apply/projects/tests/test_models.py
@@ -176,7 +176,7 @@ class TestPaymentRequestsQueryset(TestCase):
         self.assertEqual(PaymentRequest.objects.unpaid_value(), 0)
 
 
-class TestReportConfigCalculations(TestCase):
+class TestReportConfig(TestCase):
     @property
     def today(self):
         return timezone.now().date()
@@ -260,6 +260,31 @@ class TestReportConfigCalculations(TestCase):
         next_report = config.current_due_report()
         self.assertNotEqual(report, next_report)
 
+    def test_past_due(self):
+        report = ReportFactory(past_due=True)
+        config = report.project.report_config
+        self.assertQuerysetEqual(config.past_due_reports(), [report], transform=lambda x: x)
+
+    def test_past_due_has_drafts(self):
+        report = ReportFactory(past_due=True, is_draft=True)
+        config = report.project.report_config
+        self.assertQuerysetEqual(config.past_due_reports(), [report], transform=lambda x: x)
+
+    def test_past_due_no_submitted(self):
+        report = ReportFactory(is_submitted=True, past_due=True)
+        config = report.project.report_config
+        self.assertQuerysetEqual(config.past_due_reports(), [], transform=lambda x: x)
+
+    def test_past_due_no_future(self):
+        report = ReportFactory(end_date=self.today + relativedelta(days=1))
+        config = report.project.report_config
+        self.assertQuerysetEqual(config.past_due_reports(), [], transform=lambda x: x)
+
+    def test_past_due_no_skipped(self):
+        report = ReportFactory(skipped=True, past_due=True)
+        config = report.project.report_config
+        self.assertQuerysetEqual(config.past_due_reports(), [], transform=lambda x: x)
+
 
 class TestReport(TestCase):
     @property
@@ -297,3 +322,19 @@ class TestReport(TestCase):
         ReportFactory(end_date=yesterday)
         report = ReportFactory(end_date=self.from_today(1), is_submitted=True)
         self.assertEqual(report.start_date, self.today)
+
+    def test_queryset_done_includes_submitted(self):
+        report = ReportFactory(is_submitted=True)
+        self.assertQuerysetEqual(Report.objects.done(), [report], transform=lambda x: x)
+
+    def test_queryset_done_includes_skipped(self):
+        report = ReportFactory(skipped=True)
+        self.assertQuerysetEqual(Report.objects.done(), [report], transform=lambda x: x)
+
+    def test_queryset_done_doesnt_includes_draft(self):
+        ReportFactory(is_draft=True)
+        self.assertQuerysetEqual(Report.objects.done(), [], transform=lambda x: x)
+
+    def test_queryset_done_doesnt_includes_to_do(self):
+        ReportFactory()
+        self.assertQuerysetEqual(Report.objects.done(), [], transform=lambda x: x)
diff --git a/opentech/apply/projects/tests/test_views.py b/opentech/apply/projects/tests/test_views.py
index c7e09c139ad4882b91b2956a0a316db8c94e76e2..23b6f729cadf77115ddc874826ba4bb949819456 100644
--- a/opentech/apply/projects/tests/test_views.py
+++ b/opentech/apply/projects/tests/test_views.py
@@ -1424,6 +1424,11 @@ class TestStaffReportDetail(BaseViewTestCase):
         response = self.get_page(report)
         self.assertEqual(response.status_code, 200)
 
+    def test_can_access_skipped_report(self):
+        report = ReportFactory(skipped=True)
+        response = self.get_page(report)
+        self.assertEqual(response.status_code, 200)
+
     def test_cant_access_draft_report(self):
         report = ReportFactory(is_draft=True)
         response = self.get_page(report)
diff --git a/opentech/apply/projects/urls.py b/opentech/apply/projects/urls.py
index 91d07064912a1cf56181221a03e1563292de055a..d5f3798810b84b5a45750e97c9899bb5206de6e8 100644
--- a/opentech/apply/projects/urls.py
+++ b/opentech/apply/projects/urls.py
@@ -16,6 +16,7 @@ from .views import (
     ProjectPrivateMediaView,
     ReportDetailView,
     ReportPrivateMedia,
+    ReportSkipView,
     ReportUpdateView,
 )
 
@@ -45,6 +46,7 @@ urlpatterns = [
     path('reports/', include(([
         path('<int:pk>/', include([
             path('', ReportDetailView.as_view(), name='detail'),
+            path('skip/', ReportSkipView.as_view(), name='skip'),
             path('edit/', ReportUpdateView.as_view(), name='edit'),
             path('documents/<int:file_pk>/', ReportPrivateMedia.as_view(), name="document"),
         ])),
diff --git a/opentech/apply/projects/views/report.py b/opentech/apply/projects/views/report.py
index 70c2603ca579608d91f52f8df08b0f7582dee4ef..5b3d76ce8866cf01c97b08fe048879b967b25d18 100644
--- a/opentech/apply/projects/views/report.py
+++ b/opentech/apply/projects/views/report.py
@@ -4,13 +4,16 @@ from django.core.exceptions import PermissionDenied
 from django.http import Http404
 from django.shortcuts import get_object_or_404, redirect
 from django.utils.decorators import method_decorator
+from django.views import View
 from django.views.generic import (
     DetailView,
     UpdateView,
 )
+from django.views.generic.detail import SingleObjectMixin
 
 from opentech.apply.activity.messaging import MESSAGES, messenger
 from opentech.apply.utils.storage import PrivateMediaView
+from opentech.apply.users.decorators import staff_required
 
 from ..models import Report, ReportConfig, ReportPrivateFiles
 from ..forms import ReportEditForm
@@ -42,7 +45,7 @@ class ReportDetailView(ReportAccessMixin, DetailView):
 
     def dispatch(self, *args, **kwargs):
         report = self.get_object()
-        if not report.current:
+        if not report.current and not report.skipped:
             raise Http404
         return super().dispatch(*args, **kwargs)
 
@@ -139,3 +142,22 @@ class ReportPrivateMedia(UserPassesTestMixin, PrivateMediaView):
             return True
 
         return False
+
+
+@method_decorator(staff_required, name='dispatch')
+class ReportSkipView(SingleObjectMixin, View):
+    model = Report
+
+    def post(self, *args, **kwargs):
+        report = self.get_object()
+        if not report.current:
+            report.skipped = not report.skipped
+            report.save()
+            messenger(
+                MESSAGES.SKIPPED_REPORT,
+                request=self.request,
+                user=self.request.user,
+                source=report.project,
+                related=report,
+            )
+        return redirect(report.project.get_absolute_url())