diff --git a/opentech/apply/dashboard/views.py b/opentech/apply/dashboard/views.py
index 9b963a58f1b778eafe431a0da02875d55bd3a9d1..acfcb49296d9ffbfc4ddad2b5900102a53f5d551 100644
--- a/opentech/apply/dashboard/views.py
+++ b/opentech/apply/dashboard/views.py
@@ -342,7 +342,7 @@ class ApplicantDashboardView(MultiTableMixin, TemplateView):
         return context
 
     def get_active_project_data(self, user):
-        return Project.objects.filter(user=user).in_progress().for_table()
+        return Project.objects.filter(user=user).active().for_table()
 
     def get_active_submissions(self, user):
         active_subs = ApplicationSubmission.objects.filter(
diff --git a/opentech/apply/projects/management/commands/notify_report_due.py b/opentech/apply/projects/management/commands/notify_report_due.py
new file mode 100644
index 0000000000000000000000000000000000000000..d0162caed2ce85338bd212f546daaff1f0ee59f0
--- /dev/null
+++ b/opentech/apply/projects/management/commands/notify_report_due.py
@@ -0,0 +1,23 @@
+from dateutil.relativedelta import relativedelta
+
+from django.core.management.base import BaseCommand
+from django.utils import timezone
+
+from opentech.apply.projects.models import Project
+
+
+class Command(BaseCommand):
+    help = 'Notify users that they have a report due soon'
+
+    def add_arguments(self, parser):
+        parser.add_argument('days', type=int)
+
+    def handle(self, *args, **options):
+        due_date = timezone.now().date() + relativedelta(days=options['days'])
+        for project in Project.objects.in_progress():
+            next_report = project.report_config.current_due_report()
+            if next_report.end_date == due_date:
+                # Notify about the due report
+                self.stdout.write(
+                    self.style.SUCCESS(f'Notified project: {project.id}')
+                )
diff --git a/opentech/apply/projects/models.py b/opentech/apply/projects/models.py
index eb6b6d08b2ed0b39417749370499c7b1c4bbfbfd..c652a2a24c6f86a6b2198f19c6a388bce48b08e5 100644
--- a/opentech/apply/projects/models.py
+++ b/opentech/apply/projects/models.py
@@ -285,9 +285,16 @@ PROJECT_STATUS_CHOICES = [
 
 
 class ProjectQuerySet(models.QuerySet):
-    def in_progress(self):
+    def active(self):
+        "Projects that are not finished"
         return self.exclude(status=COMPLETE)
 
+    def in_progress(self):
+        "Projects that users need to interact with, submitting reports or payment request"
+        return self.filter(
+            status__in=(IN_PROGRESS, CLOSING,)
+        )
+
     def complete(self):
         return self.filter(status=COMPLETE)
 
diff --git a/opentech/apply/projects/tests/factories.py b/opentech/apply/projects/tests/factories.py
index 1768a12ccbd2d8def64cdbaaecea0488d5bc9110..a585a8b0b9d772df05f3d187b48e83f9a4615083 100644
--- a/opentech/apply/projects/tests/factories.py
+++ b/opentech/apply/projects/tests/factories.py
@@ -10,6 +10,7 @@ from opentech.apply.funds.tests.factories import ApplicationSubmissionFactory
 from opentech.apply.projects.models import (
     Contract,
     DocumentCategory,
+    IN_PROGRESS,
     PacketFile,
     PaymentReceipt,
     PaymentRequest,
@@ -97,6 +98,9 @@ class ProjectFactory(factory.DjangoModelFactory):
         in_approval = factory.Trait(
             is_locked=True,
         )
+        in_progress = factory.Trait(
+            status=IN_PROGRESS,
+        )
 
 
 class ContractFactory(factory.DjangoModelFactory):
@@ -155,6 +159,11 @@ class ReportConfigFactory(factory.DjangoModelFactory):
         model = ReportConfig
         django_get_or_create = ('project',)
 
+    class Params:
+        weeks = factory.Trait(
+            frequency=ReportConfig.WEEK,
+        )
+
 
 class ReportVersionFactory(factory.DjangoModelFactory):
     report = factory.SubFactory("opentech.apply.projects.tests.factories.ReportFactory")
diff --git a/opentech/apply/projects/tests/test_commands.py b/opentech/apply/projects/tests/test_commands.py
new file mode 100644
index 0000000000000000000000000000000000000000..b0ee1023a533aab5e979bdeee137f09d3cbe1121
--- /dev/null
+++ b/opentech/apply/projects/tests/test_commands.py
@@ -0,0 +1,46 @@
+from io import StringIO
+
+from dateutil.relativedelta import relativedelta
+
+from django.core.management import call_command
+from django.test import TestCase
+from django.utils import timezone
+
+from .factories import (
+    ProjectFactory,
+    ReportConfigFactory,
+    ReportFactory,
+)
+
+
+class TestNotifyReportDue(TestCase):
+    def test_notify_report_due_in_7_days(self):
+        in_a_week = timezone.now() + relativedelta(days=7)
+        ReportConfigFactory(schedule_start=in_a_week, project__in_progress=True)
+        out = StringIO()
+        call_command('notify_report_due', 7, stdout=out)
+        self.assertIn('Notified project', out.getvalue())
+
+    def test_dont_notify_report_due_in_7_days_already_submitted(self):
+        in_a_week = timezone.now() + relativedelta(days=7)
+        config = ReportConfigFactory(schedule_start=in_a_week)
+        ReportFactory(
+            project=config.project,
+            is_submitted=True,
+            end_date=config.schedule_start,
+        )
+        out = StringIO()
+        call_command('notify_report_due', 7, stdout=out)
+        self.assertNotIn('Notified project', out.getvalue())
+
+    def test_dont_notify_project_not_in_progress(self):
+        ProjectFactory()
+        out = StringIO()
+        call_command('notify_report_due', 7, stdout=out)
+        self.assertNotIn('Notified project', out.getvalue())
+
+    def test_dont_notify_project_closed(self):
+        ProjectFactory()
+        out = StringIO()
+        call_command('notify_report_due', 7, stdout=out)
+        self.assertNotIn('Notified project', out.getvalue())