From 8125b9701144dd4b3bb73a2726940ca1639357f6 Mon Sep 17 00:00:00 2001
From: George Katsikas <giorgakis.katsikas@gmail.com>
Date: Tue, 21 Nov 2023 14:09:10 +0100
Subject: [PATCH] add factories for all submissions models

---
 .../submissions/factories/__init__.py         |  40 ++----
 .../submissions/factories/assignment.py       |  38 +++--
 .../submissions/factories/communication.py    |  20 +++
 .../submissions/factories/decision.py         |  32 +++++
 .../factories/iThenticate_report.py           |  29 ++++
 .../factories/plagiarism_assessment.py        |  43 ++++++
 .../submissions/factories/preprint_server.py  |  32 +++++
 .../submissions/factories/preprintserver.py   |  21 ---
 .../submissions/factories/qualification.py    |  19 +++
 .../submissions/factories/readiness.py        |  23 +++
 .../submissions/factories/recommendation.py   |  45 ++++--
 .../factories/referee_invitation.py           |  73 ++++------
 .../submissions/factories/report.py           |  54 ++++---
 .../submissions/factories/submission.py       | 135 +++++++++++-------
 .../submissions/models/factories.py           |  21 ---
 .../submissions/tests/models/__init__.py      |   2 -
 .../submissions/tests/test_factories.py       | 116 +++++++++++++++
 scipost_django/submissions/urls/__init__.py   |  18 ++-
 18 files changed, 540 insertions(+), 221 deletions(-)
 create mode 100644 scipost_django/submissions/factories/communication.py
 create mode 100644 scipost_django/submissions/factories/decision.py
 create mode 100644 scipost_django/submissions/factories/iThenticate_report.py
 create mode 100644 scipost_django/submissions/factories/plagiarism_assessment.py
 create mode 100644 scipost_django/submissions/factories/preprint_server.py
 delete mode 100644 scipost_django/submissions/factories/preprintserver.py
 create mode 100644 scipost_django/submissions/factories/qualification.py
 create mode 100644 scipost_django/submissions/factories/readiness.py
 delete mode 100644 scipost_django/submissions/models/factories.py
 delete mode 100644 scipost_django/submissions/tests/models/__init__.py
 create mode 100644 scipost_django/submissions/tests/test_factories.py

diff --git a/scipost_django/submissions/factories/__init__.py b/scipost_django/submissions/factories/__init__.py
index f236ef4ba..1b33e7de9 100644
--- a/scipost_django/submissions/factories/__init__.py
+++ b/scipost_django/submissions/factories/__init__.py
@@ -2,31 +2,15 @@ __copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
 __license__ = "AGPL v3"
 
 
-from .submission import (
-    SubmissionFactory,
-    SeekingAssignmentSubmissionFactory,
-    InRefereeingSubmissionFactory,
-    ResubmittedSubmissionFactory,
-    ResubmissionFactory,
-    PublishedSubmissionFactory,
-)
-
-from .assignment import EditorialAssignmentFactory
-
-from .referee_invitation import (
-    RefereeInvitationFactory,
-    AcceptedRefereeInvitationFactory,
-    FulfilledRefereeInvitationFactory,
-    CancelledRefereeInvitationFactory,
-)
-
-from .report import (
-    ReportFactory,
-    DraftReportFactory,
-    UnVettedReportFactory,
-    VettedReportFactory,
-)
-
-from .recommendation import EICRecommendationFactory
-
-from .preprintserver import PreprintServerFactory
+from .assignment import *
+from .communication import *
+from .decision import *
+from .iThenticate_report import *
+from .plagiarism_assessment import *
+from .preprint_server import *
+from .qualification import *
+from .readiness import *
+from .recommendation import *
+from .referee_invitation import *
+from .report import *
+from .submission import *
diff --git a/scipost_django/submissions/factories/assignment.py b/scipost_django/submissions/factories/assignment.py
index 96a5ce88a..019cde55a 100644
--- a/scipost_django/submissions/factories/assignment.py
+++ b/scipost_django/submissions/factories/assignment.py
@@ -4,22 +4,32 @@ __license__ = "AGPL v3"
 
 import factory
 
-from scipost.models import Contributor
-from submissions.models.submission import Submission
-from submissions.models import EditorialAssignment
+from common.faker import LazyRandEnum, fake
 
+from ..models import EditorialAssignment
 
-class EditorialAssignmentFactory(factory.django.DjangoModelFactory):
-    """
-    An EditorialAssignmentFactory should always have a `submission` explicitly assigned. This will
-    mostly be done using the post_generation hook in any SubmissionFactory.
-    """
-
-    submission = None
-    to = factory.Iterator(Contributor.objects.all())
-    status = factory.Iterator(Submission.SUBMISSION_STATUSES, getter=lambda c: c[0])
-    date_created = factory.lazy_attribute(lambda o: o.submission.latest_activity)
-    date_answered = factory.lazy_attribute(lambda o: o.submission.latest_activity)
 
+class EditorialAssignmentFactory(factory.django.DjangoModelFactory):
     class Meta:
         model = EditorialAssignment
+        django_get_or_create = ("submission", "to")
+
+    submission = factory.SubFactory("submissions.factories.SubmissionFactory")
+    to = factory.SubFactory("scipost.factories.ContributorFactory")
+    status = LazyRandEnum(EditorialAssignment.ASSIGNMENT_STATUSES)
+
+    date_created = factory.LazyAttribute(
+        lambda self: fake.aware.date_between(
+            start_date=self.submission.submission_date, end_date="+60d"
+        )
+    )
+    date_invited = factory.LazyAttribute(
+        lambda self: fake.aware.date_between(
+            start_date=self.date_created, end_date="+10d"
+        )
+    )
+    date_answered = factory.LazyAttribute(
+        lambda self: fake.aware.date_between(
+            start_date=self.date_invited, end_date="+10d"
+        )
+    )
diff --git a/scipost_django/submissions/factories/communication.py b/scipost_django/submissions/factories/communication.py
new file mode 100644
index 000000000..226d983d1
--- /dev/null
+++ b/scipost_django/submissions/factories/communication.py
@@ -0,0 +1,20 @@
+__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
+__license__ = "AGPL v3"
+
+import factory
+
+from common.faker import LazyAwareDate, LazyRandEnum
+from submissions.constants import ED_COMM_CHOICES
+
+from ..models import EditorialCommunication
+
+
+class EditorialCommunicationFactory(factory.django.DjangoModelFactory):
+    class Meta:
+        model = EditorialCommunication
+
+    submission = factory.SubFactory("submissions.factories.SubmissionFactory")
+    referee = factory.SubFactory("scipost.factories.ContributorFactory")
+    comtype = LazyRandEnum(ED_COMM_CHOICES)
+    timestamp = LazyAwareDate("date_time_this_year")
+    text = factory.Faker("paragraph")
diff --git a/scipost_django/submissions/factories/decision.py b/scipost_django/submissions/factories/decision.py
new file mode 100644
index 000000000..aa645e4d0
--- /dev/null
+++ b/scipost_django/submissions/factories/decision.py
@@ -0,0 +1,32 @@
+__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
+__license__ = "AGPL v3"
+
+import factory
+
+from common.faker import LazyRandEnum, fake
+from submissions.constants import EDITORIAL_DECISION_CHOICES
+from ..models import EditorialDecision
+
+
+class EditorialDecisionFactory(factory.django.DjangoModelFactory):
+    class Meta:
+        model = EditorialDecision
+        django_get_or_create = ("submission", "version")
+
+    submission = factory.SubFactory("submissions.factories.SubmissionFactory")
+    for_journal = factory.SubFactory("journals.factories.JournalFactory")
+    taken_on = factory.LazyAttribute(
+        lambda self: fake.aware.date_time_between(
+            start_date=self.submission.submission_date, end_date="+2M"
+        )
+    )
+
+    remarks_for_authors = factory.Faker("paragraph")
+    remarks_for_editorial_college = factory.Faker("paragraph")
+
+    decision = LazyRandEnum(EDITORIAL_DECISION_CHOICES)
+    status = EditorialDecision.FIXED_AND_ACCEPTED
+
+    version = factory.LazyAttribute(
+        lambda self: self.submission.editorialdecision_set.count() + 1
+    )
diff --git a/scipost_django/submissions/factories/iThenticate_report.py b/scipost_django/submissions/factories/iThenticate_report.py
new file mode 100644
index 000000000..8ebf5b34f
--- /dev/null
+++ b/scipost_django/submissions/factories/iThenticate_report.py
@@ -0,0 +1,29 @@
+__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
+__license__ = "AGPL v3"
+
+import factory
+import factory.fuzzy
+
+from submissions.constants import PLAGIARISM_STATUSES
+
+from ..models import iThenticateReport
+
+from common.faker import fake, LazyObjectCount, LazyRandEnum
+
+
+class iThenticateReportFactory(factory.django.DjangoModelFactory):
+    class Meta:
+        model = iThenticateReport
+
+    uploaded_time = fake.aware.date_time_this_year()
+    processed_time = factory.LazyAttribute(
+        lambda self: fake.aware.date_time_between(
+            start_date=self.uploaded_time, end_date="+10m"
+        )
+    )
+
+    doc_id = LazyObjectCount(iThenticateReport, offset=1)
+    part_id = LazyObjectCount(iThenticateReport, offset=1)
+
+    percent_match = factory.fuzzy.FuzzyInteger(0, 100)
+    status = LazyRandEnum(PLAGIARISM_STATUSES)
diff --git a/scipost_django/submissions/factories/plagiarism_assessment.py b/scipost_django/submissions/factories/plagiarism_assessment.py
new file mode 100644
index 000000000..c5ee03f30
--- /dev/null
+++ b/scipost_django/submissions/factories/plagiarism_assessment.py
@@ -0,0 +1,43 @@
+__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
+__license__ = "AGPL v3"
+
+import factory
+
+from common.faker import LazyRandEnum, fake
+
+from ..models.plagiarism_assessment import (
+    PlagiarismAssessment,
+    InternalPlagiarismAssessment,
+    iThenticatePlagiarismAssessment,
+)
+
+
+class PlagiarismAssessmentFactory(factory.django.DjangoModelFactory):
+    class Meta:
+        model = PlagiarismAssessment
+        abstract = True
+        django_get_or_create = ("submission",)
+
+    status = LazyRandEnum(PlagiarismAssessment.STATUS_CHOICES)
+    date_set = factory.LazyAttribute(
+        lambda self: fake.aware.date_time_between(
+            start_date=self.submission.submission_date, end_date="+5d"
+        )
+    )
+
+    comments_for_edadmin = factory.Faker("paragraph")
+    comments_for_authors = factory.Faker("paragraph")
+
+
+class InternalPlagiarismAssessmentFactory(PlagiarismAssessmentFactory):
+    class Meta:
+        model = InternalPlagiarismAssessment
+
+    submission = factory.SubFactory("submissions.factories.SubmissionFactory")
+
+
+class iThenticatePlagiarismAssessmentFactory(PlagiarismAssessmentFactory):
+    class Meta:
+        model = iThenticatePlagiarismAssessment
+
+    submission = factory.SubFactory("submissions.factories.SubmissionFactory")
diff --git a/scipost_django/submissions/factories/preprint_server.py b/scipost_django/submissions/factories/preprint_server.py
new file mode 100644
index 000000000..235ce6eef
--- /dev/null
+++ b/scipost_django/submissions/factories/preprint_server.py
@@ -0,0 +1,32 @@
+__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
+__license__ = "AGPL v3"
+
+
+import factory
+
+from ..models.preprint_server import PreprintServer
+
+
+class PreprintServerFactory(factory.django.DjangoModelFactory):
+    class Meta:
+        model = PreprintServer
+
+    name = factory.Faker("sentence")
+    url = factory.Faker("url")
+    served_by = None
+
+    @factory.post_generation
+    def acad_fields(self, create, extracted, **kwargs):
+        if create:
+            return
+        if extracted:
+            for acad_field in extracted:
+                self.acad_fields.add(acad_field)
+        else:
+            self.acad_fields.add(
+                factory.SubFactory("ontology.factories.AcademicFieldFactory")
+            )
+
+    @classmethod
+    def arxiv(cls):
+        return cls(name="arXiv", url="https://arxiv.org/")
diff --git a/scipost_django/submissions/factories/preprintserver.py b/scipost_django/submissions/factories/preprintserver.py
deleted file mode 100644
index 654dcc580..000000000
--- a/scipost_django/submissions/factories/preprintserver.py
+++ /dev/null
@@ -1,21 +0,0 @@
-__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
-__license__ = "AGPL v3"
-
-
-import factory
-
-from faker import Faker
-
-from submissions.models.preprint_server import PreprintServer
-
-
-class PreprintServerFactory(factory.django.DjangoModelFactory):
-    name = factory.Faker("sentence")
-    url = factory.Faker("url")
-
-    class Meta:
-        model = PreprintServer
-
-    @classmethod
-    def arxiv(cls):
-        return cls(name="arXiv", url="https://arxiv.org/")
diff --git a/scipost_django/submissions/factories/qualification.py b/scipost_django/submissions/factories/qualification.py
new file mode 100644
index 000000000..546adcdc0
--- /dev/null
+++ b/scipost_django/submissions/factories/qualification.py
@@ -0,0 +1,19 @@
+__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
+__license__ = "AGPL v3"
+
+import factory
+
+from common.faker import LazyRandEnum
+
+from ..models import Qualification
+
+
+class QualificationFactory(factory.django.DjangoModelFactory):
+    class Meta:
+        model = Qualification
+        django_get_or_create = ("submission", "fellow")
+
+    submission = factory.SubFactory("submissions.factories.SubmissionFactory")
+    fellow = factory.SubFactory("colleges.factories.FellowshipFactory")
+    expertise_level = LazyRandEnum(Qualification.EXPERTISE_LEVEL_CHOICES)
+    comments = factory.Faker("paragraph")
diff --git a/scipost_django/submissions/factories/readiness.py b/scipost_django/submissions/factories/readiness.py
new file mode 100644
index 000000000..8b5131a4d
--- /dev/null
+++ b/scipost_django/submissions/factories/readiness.py
@@ -0,0 +1,23 @@
+__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
+__license__ = "AGPL v3"
+
+import factory
+from ..models import Readiness
+
+from common.faker import LazyRandEnum, fake
+
+
+class ReadinessFactory(factory.django.DjangoModelFactory):
+    class Meta:
+        model = Readiness
+        django_get_or_create = ("submission", "fellow")
+
+    submission = factory.SubFactory("submissions.factories.SubmissionFactory")
+    fellow = factory.SubFactory("colleges.factories.FellowshipFactory")
+    status = LazyRandEnum(Readiness.STATUS_CHOICES)
+    comments = factory.Faker("paragraph")
+    datetime = factory.LazyAttribute(
+        lambda self: fake.aware.date_time_between(
+            start_date=self.submission.submission_date, end_date="+2M"
+        )
+    )
diff --git a/scipost_django/submissions/factories/recommendation.py b/scipost_django/submissions/factories/recommendation.py
index a789b3169..a37b15340 100644
--- a/scipost_django/submissions/factories/recommendation.py
+++ b/scipost_django/submissions/factories/recommendation.py
@@ -3,27 +3,46 @@ __license__ = "AGPL v3"
 
 
 import factory
-import pytz
+import factory.fuzzy
 
-from faker import Faker
+from submissions.constants import EIC_REC_CHOICES, EIC_REC_STATUSES
+from submissions.models import EICRecommendation
 
-from submissions.constants import REPORT_REC
-from submissions.models import Submission, EICRecommendation
+from common.faker import fake, LazyRandEnum
 
 
 class EICRecommendationFactory(factory.django.DjangoModelFactory):
-    submission = factory.Iterator(Submission.objects.all())
-    date_submitted = factory.lazy_attribute(
-        lambda o: Faker().date_time_between(
-            start_date=o.submission.submission_date, end_date="now", tzinfo=pytz.UTC
+    class Meta:
+        model = EICRecommendation
+        django_get_or_create = ("submission", "version")
+
+    submission = factory.SubFactory("submissions.factories.SubmissionFactory")
+    formulated_by = factory.SelfAttribute("submission.editor_in_charge")
+    date_submitted = factory.LazyAttribute(
+        lambda self: fake.aware.date_time_between(
+            start_date=self.submission.submission_date, end_date="+1y"
         )
     )
-    remarks_for_authors = factory.Faker("paragraph")
+
     requested_changes = factory.Faker("paragraph")
+    remarks_for_authors = factory.Faker("paragraph")
     remarks_for_editorial_college = factory.Faker("paragraph")
-    recommendation = factory.Iterator(REPORT_REC[1:], getter=lambda c: c[0])
-    version = 1
+
+    for_journal = factory.SubFactory("journals.factories.JournalFactory")
+
+    recommendation = LazyRandEnum(EIC_REC_CHOICES)
+    status = LazyRandEnum(EIC_REC_STATUSES)
+
+    version = factory.LazyAttribute(
+        lambda self: 1
+        + EICRecommendation.objects.filter(submission=self.submission).count()
+    )
     active = True
 
-    class Meta:
-        model = EICRecommendation
+    voting_deadline = factory.LazyAttribute(
+        lambda self: fake.aware.date_time_between(
+            start_date=self.date_submitted, end_date="+30d"
+        )
+    )
+
+    # TODO: Add fields for the voting process
diff --git a/scipost_django/submissions/factories/referee_invitation.py b/scipost_django/submissions/factories/referee_invitation.py
index 32ec5442f..3d19a7b88 100644
--- a/scipost_django/submissions/factories/referee_invitation.py
+++ b/scipost_django/submissions/factories/referee_invitation.py
@@ -3,44 +3,50 @@ __license__ = "AGPL v3"
 
 
 import factory
-import pytz
-import random
 
-from faker import Faker
+from common.faker import fake
 
-from scipost.models import Contributor
-
-from submissions.models import RefereeInvitation
+from ..models import RefereeInvitation
 
 
 class RefereeInvitationFactory(factory.django.DjangoModelFactory):
+    class Meta:
+        model = RefereeInvitation
+        exclude = ("profile_info",)
+        django_get_or_create = ("submission", "profile")
+
+    class Params:
+        registered = factory.Trait(
+            referee=factory.SubFactory("scipost.factories.ContributorFactory"),
+            profile=None,
+            profile_info=factory.SelfAttribute("referee.profile"),
+        )
+
+    referee = None
+    profile = factory.SubFactory("profiles.factories.ProfileFactory")
+
+    profile_info = factory.SelfAttribute("profile")
+    title = factory.SelfAttribute("profile_info.title")
+    first_name = factory.SelfAttribute("profile_info.first_name")
+    last_name = factory.SelfAttribute("profile_info.last_name")
+    email_address = factory.SelfAttribute("profile_info.email")
+
     submission = factory.SubFactory("submissions.factories.SubmissionFactory")
-    referee = factory.lazy_attribute(
-        lambda o: Contributor.objects.exclude(id__in=o.submission.authors.all())
-        .order_by("?")
-        .first()
-    )
 
-    title = factory.lazy_attribute(lambda o: o.referee.profile.title)
-    first_name = factory.lazy_attribute(lambda o: o.referee.user.first_name)
-    last_name = factory.lazy_attribute(lambda o: o.referee.user.last_name)
-    email_address = factory.lazy_attribute(lambda o: o.referee.user.email)
-    date_invited = factory.lazy_attribute(lambda o: o.submission.latest_activity)
-    nr_reminders = factory.lazy_attribute(lambda o: random.randint(0, 4))
-    date_last_reminded = factory.lazy_attribute(lambda o: o.submission.latest_activity)
+    date_invited = factory.SelfAttribute("submission.latest_activity")
+    date_last_reminded = factory.SelfAttribute("submission.latest_activity")
+    invited_by = factory.SelfAttribute("submission.editor_in_charge")
 
+    nr_reminders = factory.Faker("random_int", min=0, max=3)
     invitation_key = factory.Faker("md5")
-    invited_by = factory.lazy_attribute(lambda o: o.submission.editor_in_charge)
-
-    class Meta:
-        model = RefereeInvitation
 
 
 class AcceptedRefereeInvitationFactory(RefereeInvitationFactory):
+    registered = True
     accepted = True
-    date_responded = factory.lazy_attribute(
-        lambda o: Faker().date_time_between(
-            start_date=o.date_invited, end_date="now", tzinfo=pytz.UTC
+    date_responded = factory.LazyAttribute(
+        lambda self: fake.aware.date_time_between(
+            start_date=self.date_invited, end_date="+1y"
         )
     )
 
@@ -54,25 +60,8 @@ class AcceptedRefereeInvitationFactory(RefereeInvitationFactory):
 
 class FulfilledRefereeInvitationFactory(AcceptedRefereeInvitationFactory):
     fulfilled = True
-    date_responded = factory.lazy_attribute(
-        lambda o: Faker().date_time_between(
-            start_date=o.date_invited, end_date="now", tzinfo=pytz.UTC
-        )
-    )
-
-    @factory.post_generation
-    def report(self, create, extracted, **kwargs):
-        if create:
-            from submissions.factories import VettedReportFactory
-
-            VettedReportFactory(submission=self.submission, author=self.referee)
 
 
 class CancelledRefereeInvitationFactory(AcceptedRefereeInvitationFactory):
     fulfilled = False
     cancelled = True
-    date_responded = factory.lazy_attribute(
-        lambda o: Faker().date_time_between(
-            start_date=o.date_invited, end_date="now", tzinfo=pytz.UTC
-        )
-    )
diff --git a/scipost_django/submissions/factories/report.py b/scipost_django/submissions/factories/report.py
index 03013e71b..7c04bffbd 100644
--- a/scipost_django/submissions/factories/report.py
+++ b/scipost_django/submissions/factories/report.py
@@ -3,11 +3,10 @@ __license__ = "AGPL v3"
 
 
 import factory
-import pytz
 
-from faker import Faker
+from common.faker import LazyRandEnum, fake
+from scipost.factories import ContributorFactory
 
-from scipost.models import Contributor
 from common.helpers import random_scipost_report_doi_label
 
 from submissions.constants import (
@@ -24,41 +23,37 @@ from submissions.models import Report
 
 
 class ReportFactory(factory.django.DjangoModelFactory):
-    status = factory.Iterator(REPORT_STATUSES, getter=lambda c: c[0])
+    class Meta:
+        model = Report
+
+    status = LazyRandEnum(REPORT_STATUSES)
     submission = factory.SubFactory("submissions.factories.SubmissionFactory")
-    report_nr = factory.LazyAttribute(lambda o: o.submission.reports.count() + 1)
-    date_submitted = factory.Faker("date_time_this_decade", tzinfo=pytz.utc)
-    vetted_by = factory.Iterator(Contributor.objects.all())
-    author = factory.Iterator(Contributor.objects.all())
+    report_nr = factory.LazyAttribute(lambda self: self.submission.reports.count() + 1)
+    date_submitted = factory.LazyAttribute(
+        lambda self: fake.aware.date_between(
+            start_date=self.submission.submission_date, end_date="+1y"
+        )
+    )
+    vetted_by = factory.SubFactory(ContributorFactory)
+    author = factory.SubFactory(ContributorFactory)
     strengths = factory.Faker("paragraph")
     weaknesses = factory.Faker("paragraph")
     report = factory.Faker("paragraph")
     requested_changes = factory.Faker("paragraph")
 
-    qualification = factory.Iterator(REFEREE_QUALIFICATION[1:], getter=lambda c: c[0])
-    validity = factory.Iterator(RANKING_CHOICES[1:], getter=lambda c: c[0])
-    significance = factory.Iterator(RANKING_CHOICES[1:], getter=lambda c: c[0])
-    originality = factory.Iterator(RANKING_CHOICES[1:], getter=lambda c: c[0])
-    clarity = factory.Iterator(RANKING_CHOICES[1:], getter=lambda c: c[0])
-    formatting = factory.Iterator(QUALITY_SPEC[1:], getter=lambda c: c[0])
-    grammar = factory.Iterator(QUALITY_SPEC[1:], getter=lambda c: c[0])
-    recommendation = factory.Iterator(REPORT_REC[1:], getter=lambda c: c[0])
+    qualification = LazyRandEnum(REFEREE_QUALIFICATION)
+    validity = LazyRandEnum(RANKING_CHOICES)
+    significance = LazyRandEnum(RANKING_CHOICES)
+    originality = LazyRandEnum(RANKING_CHOICES)
+    clarity = LazyRandEnum(RANKING_CHOICES)
+    formatting = LazyRandEnum(QUALITY_SPEC)
+    grammar = LazyRandEnum(QUALITY_SPEC)
+    recommendation = LazyRandEnum(REPORT_REC)
 
     remarks_for_editors = factory.Faker("paragraph")
     flagged = factory.Faker("boolean", chance_of_getting_true=10)
     anonymous = factory.Faker("boolean", chance_of_getting_true=75)
 
-    class Meta:
-        model = Report
-
-    @classmethod
-    def create(cls, **kwargs):
-        if Contributor.objects.count() < 5:
-            from scipost.factories import ContributorFactory
-
-            ContributorFactory.create_batch(5)
-        return super().create(**kwargs)
-
 
 class DraftReportFactory(ReportFactory):
     status = STATUS_DRAFT
@@ -73,6 +68,5 @@ class UnVettedReportFactory(ReportFactory):
 class VettedReportFactory(ReportFactory):
     status = STATUS_VETTED
     needs_doi = True
-    doideposit_needs_updating = factory.Faker("boolean")
-    doi_label = factory.lazy_attribute(lambda n: random_scipost_report_doi_label())
-    pdf_report = factory.Faker("file_name", extension="pdf")
+    doi_label = factory.LazyAttribute(lambda _: random_scipost_report_doi_label)
+    pdf_report = factory.django.FileField(filename="report.pdf")
diff --git a/scipost_django/submissions/factories/submission.py b/scipost_django/submissions/factories/submission.py
index 7cdcfd44f..7807bb865 100644
--- a/scipost_django/submissions/factories/submission.py
+++ b/scipost_django/submissions/factories/submission.py
@@ -7,9 +7,11 @@ import pytz
 import random
 
 from faker import Faker
+from colleges.factories import FellowshipFactory
 from common.faker import LazyRandEnum, fake
 from journals.factories import JournalFactory
 from ontology.factories import AcademicFieldFactory
+from organizations.factories import OrganizationFactory
 from preprints.factories import PreprintFactory
 
 from scipost.constants import SCIPOST_APPROACHES
@@ -19,7 +21,7 @@ from comments.factories import SubmissionCommentFactory
 from journals.models import Journal
 from ontology.models import Specialty, AcademicField
 
-from ..models import Submission, EditorialAssignment
+from ..models.submission import *
 
 
 class SubmissionFactory(factory.django.DjangoModelFactory):
@@ -27,24 +29,30 @@ class SubmissionFactory(factory.django.DjangoModelFactory):
     Generate random basic Submission instances.
     """
 
-    author_list = factory.Faker("name")
     submitted_by = factory.SubFactory(ContributorFactory)
+    author_list = factory.LazyAttribute(
+        lambda self: self.submitted_by.profile.full_name
+    )
     submitted_to = factory.SubFactory(JournalFactory)
+
     title = factory.Faker("sentence")
     abstract = factory.Faker("paragraph", nb_sentences=10)
-    list_of_changes = factory.Faker("paragraph", nb_sentences=10)
+
     acad_field = factory.SubFactory(AcademicFieldFactory)
-    approaches = [LazyRandEnum(SCIPOST_APPROACHES)]
-    abstract = factory.Faker("paragraph")
+    approaches = LazyRandEnum(SCIPOST_APPROACHES, repeat=2)
+
+    list_of_changes = factory.Faker("paragraph", nb_sentences=10)
     author_comments = factory.Faker("paragraph")
     remarks_for_editors = factory.Faker("paragraph")
-    thread_hash = factory.Faker("uuid4")
+
     submission_date = factory.Faker("date_time_this_decade", tzinfo=pytz.utc)
     latest_activity = factory.LazyAttribute(
         lambda self: fake.date_time_between(
             start_date=self.submission_date, end_date="now", tzinfo=pytz.UTC
         )
     )
+
+    thread_hash = factory.Faker("md5")
     preprint = factory.SubFactory(PreprintFactory)
 
     visible_public = True
@@ -53,49 +61,26 @@ class SubmissionFactory(factory.django.DjangoModelFactory):
     class Meta:
         model = Submission
 
-    # @classmethod
-    # def create(cls, **kwargs):
-    #     if Contributor.objects.count() < 5:
-    #         from scipost.factories import ContributorFactory
-
-    #         ContributorFactory.create_batch(5)
-    #     if Journal.objects.count() < 3:
-    #         from journals.factories import JournalFactory
-
-    #         JournalFactory.create_batch(3)
-    #     if AcademicField.objects.count() < 10:
-    #         from ontology.factories import AcademicFieldFactory
-
-    #         AcademicFieldFactory.create_batch(10)
-    #     if Specialty.objects.count() < 5:
-    #         from ontology.factories import SpecialtyFactory
-
-    #         SpecialtyFactory.create_batch(5)
-    #     return super().create(**kwargs)
-
-    # @factory.post_generation
-    # def add_specialties(self, create, extracted, **kwargs):
-    #     if create:
-    #         self.specialties.set(Specialty.objects.order_by("?")[:3])
-
-    # @factory.post_generation
-    # def contributors(self, create, extracted, **kwargs):
-    #     contribs = Contributor.objects.all()
-    #     if self.editor_in_charge:
-    #         contribs = contribs.exclude(id=self.editor_in_charge.id)
-    #     contribs = contribs.order_by("?")[: random.randint(1, 6)]
-
-    #     # Auto-add the submitter as an author
-    #     self.submitted_by = contribs[0]
-    #     self.author_list = ", ".join(
-    #         ["%s %s" % (c.user.first_name, c.user.last_name) for c in contribs]
-    #     )
+    @factory.post_generation
+    def add_specialties(self, create, extracted, **kwargs):
+        if create:
+            if extracted:
+                self.specialties.add(*extracted)
+            else:
+                self.specialties.set(Specialty.objects.order_by("?")[:3])
 
-    #     if not create:
-    #         return
+    @factory.post_generation
+    def authors(self, create, extracted, **kwargs):
+        if create:
+            if extracted:
+                # Add submitted_by to the list of authors
+                if self.submitted_by not in extracted:
+                    extracted.append(self.submitted_by)
 
-    #     # Add three random authors
-    #     self.authors.add(*contribs)
+                self.authors.add(*extracted)
+                self.author_list = ", ".join(
+                    [f"{c.profile.first_name} {c.profile.last_name}" for c in extracted]
+                )
 
 
 class SeekingAssignmentSubmissionFactory(SubmissionFactory):
@@ -292,15 +277,25 @@ class PublishedSubmissionFactory(InRefereeingSubmissionFactory):
     @factory.post_generation
     def generate_publication(self, create, extracted, **kwargs):
         if create and extracted is not False:
-            from journals.factories import PublicationFactory
+            from journals.factories import JournalPublicationFactory
 
-            PublicationFactory(
+            JournalPublicationFactory(
                 journal=self.submitted_to.doi_label,
                 accepted_submission=self,
                 title=self.title,
                 author_list=self.author_list,
             )
 
+    @factory.post_generation
+    def editor_in_charge(self, create, extracted, **kwargs):
+        if create:
+            return
+        if extracted:
+            return extracted
+
+        eic = FellowshipFactory()
+        return eic.contributor
+
     @factory.post_generation
     def eic_assignment(self, create, extracted, **kwargs):
         if create:
@@ -323,3 +318,45 @@ class PublishedSubmissionFactory(InRefereeingSubmissionFactory):
             FulfilledRefereeInvitationFactory(submission=self)
         for i in range(random.randint(0, 2)):
             CancelledRefereeInvitationFactory(submission=self)
+
+
+class SubmissionAuthorProfileFactory(factory.django.DjangoModelFactory):
+    class Meta:
+        model = SubmissionAuthorProfile
+
+    submission = factory.SubFactory(SubmissionFactory)
+    profile = factory.SubFactory("profiles.factories.ProfileFactory")
+    order = factory.LazyAttribute(
+        lambda self: self.submission.author_profiles.count() + 1
+    )
+
+    @factory.post_generation
+    def affiliations(self, create, extracted, **kwargs):
+        if create:
+            return
+        if extracted:
+            for affiliation in extracted:
+                self.affiliations.add(affiliation)
+        else:
+            self.affiliations.add(
+                *OrganizationFactory.create_batch(random.randint(1, 3))
+            )
+
+
+class SubmissionEventFactory(factory.django.DjangoModelFactory):
+    class Meta:
+        model = SubmissionEvent
+
+    submission = factory.SubFactory(SubmissionFactory)
+    event = LazyRandEnum(EVENT_TYPES)
+    text = factory.Faker("paragraph")
+
+
+class SubmissionTieringFactory(factory.django.DjangoModelFactory):
+    class Meta:
+        model = SubmissionTiering
+
+    submission = factory.SubFactory(SubmissionFactory)
+    fellow = factory.SubFactory(ContributorFactory)
+    for_journal = factory.SelfAttribute("submission.submitted_to")
+    tier = LazyRandEnum(SUBMISSION_TIERS)
diff --git a/scipost_django/submissions/models/factories.py b/scipost_django/submissions/models/factories.py
deleted file mode 100644
index 070465198..000000000
--- a/scipost_django/submissions/models/factories.py
+++ /dev/null
@@ -1,21 +0,0 @@
-__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
-__license__ = "AGPL v3"
-
-import factory
-from common.faker import LazyRandEnum
-from journals.factories import JournalFactory
-from submissions.factories.submission import SubmissionFactory
-from submissions.models.decision import EditorialDecision
-
-
-class EditorialDecisionFactory(factory.django.DjangoModelFactory):
-    class Meta:
-        model = EditorialDecision
-        django_get_or_create = ("submission", "for_journal")
-
-    submission = factory.SubFactory(SubmissionFactory)
-    for_journal = factory.SubFactory(JournalFactory)
-    decision = LazyRandEnum(EditorialDecision.EDITORIAL_DECISION_STATUSES)
-    taken_on = factory.Faker("date_this_decade")
-    remarks_for_authors = factory.Faker("paragraph")
-    status = LazyRandEnum(EditorialDecision.EDITORIAL_DECISION_STATUSES)
diff --git a/scipost_django/submissions/tests/models/__init__.py b/scipost_django/submissions/tests/models/__init__.py
deleted file mode 100644
index 5dfd5d6b6..000000000
--- a/scipost_django/submissions/tests/models/__init__.py
+++ /dev/null
@@ -1,2 +0,0 @@
-__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
-__license__ = "AGPL v3"
diff --git a/scipost_django/submissions/tests/test_factories.py b/scipost_django/submissions/tests/test_factories.py
new file mode 100644
index 000000000..41f3deb4c
--- /dev/null
+++ b/scipost_django/submissions/tests/test_factories.py
@@ -0,0 +1,116 @@
+__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
+__license__ = "AGPL v3"
+
+from django.test import TestCase
+
+
+from ..factories import *
+
+
+# Assignment
+class TestEditorialAssignmentFactory(TestCase):
+    def test_can_create_editorial_assignments(self):
+        editorial_assignment = EditorialAssignmentFactory()
+        self.assertIsNotNone(editorial_assignment)
+
+
+# Communication
+class TestEditorialCommunication(TestCase):
+    def test_can_create_editorial_communications(self):
+        editorial_communication = EditorialCommunicationFactory()
+        self.assertIsNotNone(editorial_communication)
+
+
+# Recommendation
+class TestEICRecommendationFactory(TestCase):
+    def test_can_create_eic_recommendations(self):
+        eic_recommendation = EICRecommendationFactory()
+        self.assertIsNotNone(eic_recommendation)
+
+
+# Submissions
+class TestSubmissionFactory(TestCase):
+    def test_can_create_submissions(self):
+        submission = SubmissionFactory()
+        self.assertIsNotNone(submission)
+
+
+class TestSubmissionAuthorProfileFactory(TestCase):
+    def test_can_create_submission_author_profiles(self):
+        submission_author_profile = SubmissionAuthorProfileFactory()
+        self.assertIsNotNone(submission_author_profile)
+
+
+class TestSubmissionEventFactory(TestCase):
+    def test_can_create_submission_events(self):
+        submission_event = SubmissionEventFactory()
+        self.assertIsNotNone(submission_event)
+
+
+class TestSubmissionTieringFactory(TestCase):
+    def test_can_create_submission_tierings(self):
+        submission_tiering = SubmissionTieringFactory()
+        self.assertIsNotNone(submission_tiering)
+
+
+# Reports
+class TestReportFactory(TestCase):
+    def test_can_create_reports(self):
+        report = ReportFactory()
+        self.assertIsNotNone(report)
+
+
+# Referee Invitation
+class TestRefereeInvitationFactory(TestCase):
+    def test_can_create_unregistered_referee_invitations(self):
+        referee_invitation = RefereeInvitationFactory()
+        self.assertIsNotNone(referee_invitation.profile)
+        self.assertIsNone(referee_invitation.referee)
+        self.assertIsNotNone(referee_invitation)
+
+    def test_can_create_registered_referee_invitations(self):
+        referee_invitation = RefereeInvitationFactory(registered=True)
+        self.assertIsNotNone(referee_invitation.referee)
+        self.assertIsNone(referee_invitation.profile)
+        self.assertIsNotNone(referee_invitation)
+
+
+# Readiness
+class TestReadinessFactory(TestCase):
+    def test_can_create_readinesses(self):
+        readiness = ReadinessFactory()
+        self.assertIsNotNone(readiness)
+
+
+# Qualification
+class TestQualificationFactory(TestCase):
+    def test_can_create_qualifications(self):
+        qualification = QualificationFactory()
+        self.assertIsNotNone(qualification)
+
+
+# Decision
+class TestEditorialDecisionFactory(TestCase):
+    def test_can_create_editorial_decisions(self):
+        editorial_decision = EditorialDecisionFactory()
+        self.assertIsNotNone(editorial_decision)
+
+
+# Plagiarism Assessment
+class TestInternalPlagiarismAssessmentFactory(TestCase):
+    def test_can_create_internal_plagiarism_assessments(self):
+        internal_plagiarism_assessment = InternalPlagiarismAssessmentFactory()
+        self.assertIsNotNone(internal_plagiarism_assessment)
+
+
+class TestiThenticatePlagiarismAssessmentFactory(TestCase):
+    def test_can_create_ithenticate_plagiarism_assessments(self):
+        ithenticate_plagiarism_assessment = iThenticatePlagiarismAssessmentFactory()
+        self.assertIsNotNone(ithenticate_plagiarism_assessment)
+
+
+# iThenticate Report
+class TestiThenticateReportFactory(TestCase):
+    def test_can_create_ithenticate_reports(self):
+        ithenticate_report = iThenticateReportFactory()
+        self.assertIsNotNone(ithenticate_report)
diff --git a/scipost_django/submissions/urls/__init__.py b/scipost_django/submissions/urls/__init__.py
index e05af836e..6b58ea0ff 100644
--- a/scipost_django/submissions/urls/__init__.py
+++ b/scipost_django/submissions/urls/__init__.py
@@ -2,14 +2,30 @@ __copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
 __license__ = "AGPL v3"
 
 
-from django.urls import include, path, re_path
+from django.urls import include, path, re_path, register_converter
 from django.views.generic import TemplateView
 from django.views.generic.base import RedirectView
+from journals.converters import JournalDOILabelConverter
+
+from ontology.converters import AcademicFieldSlugConverter
+
+from ..converters import (
+    IdentifierConverter,
+    IdentifierWithoutVersionNumberConverter,
+    ReportDOILabelConverter,
+)
 
 from .. import views
 
 app_name = "submissions"
 
+# converters
+register_converter(JournalDOILabelConverter, "journal_doi_label")
+register_converter(AcademicFieldSlugConverter, "acad_field")
+register_converter(IdentifierWithoutVersionNumberConverter, "identifier_wo_vn_nr")
+register_converter(IdentifierConverter, "identifier")
+register_converter(ReportDOILabelConverter, "report_doi_label")
+
 
 urlpatterns = [
     # nested namespaces
-- 
GitLab