diff --git a/packages/component-faraday-selectors/src/index.js b/packages/component-faraday-selectors/src/index.js
index 1493dcaf07f232dc17d2ec03e4ea9e9090719b44..3a774ca94dbc52c0786a550c3dc096001946b53e 100644
--- a/packages/component-faraday-selectors/src/index.js
+++ b/packages/component-faraday-selectors/src/index.js
@@ -270,17 +270,9 @@ export const getHERecommendation = (state, collectionId, fragmentId) => {
   )
 }
 
-const canMakeDecisionStatuses = [
-  'submitted',
-  'pendingApproval',
-  'underReview',
-  'reviewCompleted',
-]
 export const canMakeDecision = (state, collection = {}) => {
-  const status = get(collection, 'status', 'draft')
-
   const isEIC = currentUserIs(state, 'adminEiC')
-  return isEIC && canMakeDecisionStatuses.includes(status)
+  return isEIC
 }
 
 const collectionReviewerReports = state =>
diff --git a/packages/component-faraday-ui/src/contextualBoxes/ReviewerReportForm.js b/packages/component-faraday-ui/src/contextualBoxes/ReviewerReportForm.js
index acd472f65bebb023a945a626abc54357b33555d7..27a9917dc42060ebe0e8784d19ad17d87ba56444 100644
--- a/packages/component-faraday-ui/src/contextualBoxes/ReviewerReportForm.js
+++ b/packages/component-faraday-ui/src/contextualBoxes/ReviewerReportForm.js
@@ -3,6 +3,7 @@ import styled from 'styled-components'
 import { th } from '@pubsweet/ui-toolkit'
 import { required } from 'xpub-validators'
 import { Button, FilePicker, Menu, Spinner, ValidatedField } from '@pubsweet/ui'
+import { initial } from 'lodash'
 
 import {
   Row,
@@ -51,7 +52,9 @@ const ReviewerReportForm = ({
         >
           <Label required>Recommendation</Label>
           <ValidatedField
-            component={input => <Menu {...input} options={recommendations} />}
+            component={input => (
+              <Menu {...input} options={initial(recommendations)} />
+            )}
             name="recommendation"
             validate={[required]}
           />
diff --git a/packages/component-faraday-ui/src/manuscriptDetails/ManuscriptEicDecision.js b/packages/component-faraday-ui/src/manuscriptDetails/ManuscriptEicDecision.js
index dc5314f613c215bb949c5735f25c395f83e8b5f6..07fcac0087453c6943265160174beb18b23f95f0 100644
--- a/packages/component-faraday-ui/src/manuscriptDetails/ManuscriptEicDecision.js
+++ b/packages/component-faraday-ui/src/manuscriptDetails/ManuscriptEicDecision.js
@@ -1,5 +1,5 @@
 import React from 'react'
-import { get, last } from 'lodash'
+import { get, initial } from 'lodash'
 import { compose, withProps } from 'recompose'
 import styled from 'styled-components'
 import { reduxForm } from 'redux-form'
@@ -39,11 +39,24 @@ const eicDecisions = [
     modalTitle: 'Reject Manuscript',
     modalSubtitle: 'A rejection decision is final',
   },
+  {
+    value: 'revision',
+    label: 'Request Revision',
+    modalTitle: 'Request Revision',
+  },
 ]
 
+const filterOptions = (eicDecisions, status) => {
+  if (status === 'submitted') return eicDecisions.slice(2)
+  if (status === 'pendingApproval') return initial(eicDecisions)
+  return eicDecisions.slice(2, 3)
+}
 const ManuscriptEicDecision = ({
-  isFetching,
+  status,
+  options,
+  decision,
   formValues,
+  isFetching,
   handleSubmit,
   messagesLabel,
   collection = {},
@@ -55,42 +68,33 @@ const ManuscriptEicDecision = ({
     {...rest}
   >
     <Root>
-      <Row justify="flex-start">
+      <Row justify="flex-start" pl={1} pt={1}>
         <ItemOverrideAlert flex={0} vertical>
           <Label required>Decision</Label>
           <ValidatedField
-            component={input => (
-              <Menu
-                {...input}
-                options={
-                  get(collection, 'status', 'submitted') !== 'pendingApproval'
-                    ? [last(eicDecisions)]
-                    : eicDecisions
-                }
-              />
-            )}
+            component={input => <Menu {...input} options={options} />}
             name="decision"
             validate={[required]}
           />
         </ItemOverrideAlert>
       </Row>
 
-      {get(formValues, 'decision') !== 'publish' && (
-        <Row mt={2}>
+      {decision !== 'publish' && (
+        <Row mt={2} pl={1} pr={1}>
           <Item vertical>
-            <Label required>
+            <Label required={decision !== 'reject'}>
               {messagesLabel[get(formValues, 'decision', 'reject')]}
             </Label>
             <ValidatedField
               component={ValidatedTextArea}
               name="message"
-              validate={[required]}
+              validate={decision !== 'reject' ? [required] : undefined}
             />
           </Item>
         </Row>
       )}
 
-      <Row justify="flex-end" mt={4}>
+      <Row justify="flex-end" mt={1} pr={1}>
         <Button onClick={handleSubmit} primary size="medium">
           SUBMIT DECISION
         </Button>
@@ -106,13 +110,18 @@ export default compose(
     modalKey: 'eic-decision',
     modalComponent: MultiAction,
   })),
-  withProps(({ formValues }) => ({
+  withProps(({ formValues, collection }) => ({
     modalTitle: eicDecisions.find(
       o => o.value === get(formValues, 'decision', 'publish'),
     ).modalTitle,
     modalSubtitle: eicDecisions.find(
       o => o.value === get(formValues, 'decision', 'publish'),
     ).modalSubtitle,
+    decision: get(formValues, 'decision'),
+    options: filterOptions(
+      eicDecisions,
+      get(collection, 'status', 'submitted'),
+    ),
   })),
   reduxForm({
     form: 'eic-decision',
diff --git a/packages/component-fixture-manager/src/fixtures/collectionIDs.js b/packages/component-fixture-manager/src/fixtures/collectionIDs.js
index a964c2c498c452599e68dd3457a24eac4c0a3b49..a6082362b1083a2123f8013aea6451fdb4b23023 100644
--- a/packages/component-fixture-manager/src/fixtures/collectionIDs.js
+++ b/packages/component-fixture-manager/src/fixtures/collectionIDs.js
@@ -4,9 +4,13 @@ const chance = new Chance()
 
 module.exports = {
   standardCollID: chance.guid(),
-  collectionReviewCompletedID: chance.guid(),
   collectionNoInvitesID: chance.guid(),
   twoVersionsCollectionId: chance.guid(),
+  minorRevisionCollectionID: chance.guid(),
+  majorRevisionCollectionID: chance.guid(),
+  collectionReviewCompletedID: chance.guid(),
   oneReviewedFragmentCollectionID: chance.guid(),
   noEditorRecomedationCollectionID: chance.guid(),
+  minorRevisionWithoutReviewCollectionID: chance.guid(),
+  majorRevisionWithoutReviewCollectionID: chance.guid(),
 }
diff --git a/packages/component-fixture-manager/src/fixtures/collections.js b/packages/component-fixture-manager/src/fixtures/collections.js
index 0fbff658ca84fc9266a31674461679e769a1ff13..4d92999127af2422edb3c3edd927ec744f25ea92 100644
--- a/packages/component-fixture-manager/src/fixtures/collections.js
+++ b/packages/component-fixture-manager/src/fixtures/collections.js
@@ -1,24 +1,35 @@
 const Chance = require('chance')
+
 const {
   user,
   handlingEditor,
   answerHE,
   noRecommendationHE,
 } = require('./userData')
+
 const {
   fragment,
   fragment1,
-  reviewCompletedFragment,
   noInvitesFragment,
+  noInvitesFragment1,
+  minorRevisionWithReview,
+  majorRevisionWithReview,
+  reviewCompletedFragment,
+  minorRevisionWithoutReview,
   noEditorRecomedationFragment,
 } = require('./fragments')
+
 const {
   standardCollID,
-  collectionReviewCompletedID,
   collectionNoInvitesID,
   twoVersionsCollectionId,
+  minorRevisionCollectionID,
+  majorRevisionCollectionID,
+  collectionReviewCompletedID,
   oneReviewedFragmentCollectionID,
   noEditorRecomedationCollectionID,
+  minorRevisionWithoutReviewCollectionID,
+  majorRevisionWithoutReviewCollectionID,
 } = require('./collectionIDs')
 
 const chance = new Chance()
@@ -302,6 +313,152 @@ const collections = {
     status: 'revisionRequested',
     customId: chance.natural({ min: 999999, max: 9999999 }),
   },
+  minorRevisionCollection: {
+    id: minorRevisionCollectionID,
+    delete: jest.fn(),
+    title: chance.sentence(),
+    type: 'collection',
+    fragments: [minorRevisionWithReview.id, noInvitesFragment1.id],
+    owners: [user.id],
+    save: jest.fn(() => collections.minorRevisionCollection),
+    getFragments: jest.fn(() => [minorRevisionWithReview, noInvitesFragment1]),
+    invitations: [
+      {
+        id: chance.guid(),
+        role: 'handlingEditor',
+        hasAnswer: true,
+        isAccepted: true,
+        userId: handlingEditor.id,
+        invitedOn: chance.timestamp(),
+        respondedOn: null,
+      },
+    ],
+    handlingEditor: {
+      id: handlingEditor.id,
+      hasAnswer: true,
+      isAccepted: true,
+      email: handlingEditor.email,
+      invitedOn: chance.timestamp(),
+      respondedOn: chance.timestamp(),
+      name: `${handlingEditor.firstName} ${handlingEditor.lastName}`,
+    },
+    technicalChecks: {
+      token: chance.guid(),
+    },
+    status: 'reviewCompleted',
+    customId: chance.natural({ min: 999999, max: 9999999 }),
+  },
+  minorRevisionWithoutReviewCollection: {
+    id: minorRevisionWithoutReviewCollectionID,
+    delete: jest.fn(),
+    title: chance.sentence(),
+    type: 'collection',
+    fragments: [minorRevisionWithoutReview.id, noInvitesFragment1.id],
+    owners: [user.id],
+    save: jest.fn(() => collections.minorRevisionWithoutReviewCollection),
+    getFragments: jest.fn(() => [
+      minorRevisionWithoutReview,
+      noInvitesFragment1,
+    ]),
+    invitations: [
+      {
+        id: chance.guid(),
+        role: 'handlingEditor',
+        hasAnswer: true,
+        isAccepted: true,
+        userId: handlingEditor.id,
+        invitedOn: chance.timestamp(),
+        respondedOn: null,
+      },
+    ],
+    handlingEditor: {
+      id: handlingEditor.id,
+      hasAnswer: true,
+      isAccepted: true,
+      email: handlingEditor.email,
+      invitedOn: chance.timestamp(),
+      respondedOn: chance.timestamp(),
+      name: `${handlingEditor.firstName} ${handlingEditor.lastName}`,
+    },
+    technicalChecks: {
+      token: chance.guid(),
+    },
+    status: 'reviewCompleted',
+    customId: chance.natural({ min: 999999, max: 9999999 }),
+  },
+  majorRevisionCollection: {
+    id: majorRevisionCollectionID,
+    delete: jest.fn(),
+    title: chance.sentence(),
+    type: 'collection',
+    fragments: [majorRevisionWithReview.id, reviewCompletedFragment.id],
+    owners: [user.id],
+    save: jest.fn(() => collections.minorRevisionCollection),
+    getFragments: jest.fn(() => [
+      majorRevisionWithReview,
+      reviewCompletedFragment,
+    ]),
+    invitations: [
+      {
+        id: chance.guid(),
+        role: 'handlingEditor',
+        hasAnswer: true,
+        isAccepted: true,
+        userId: handlingEditor.id,
+        invitedOn: chance.timestamp(),
+        respondedOn: null,
+      },
+    ],
+    handlingEditor: {
+      id: handlingEditor.id,
+      hasAnswer: true,
+      isAccepted: true,
+      email: handlingEditor.email,
+      invitedOn: chance.timestamp(),
+      respondedOn: chance.timestamp(),
+      name: `${handlingEditor.firstName} ${handlingEditor.lastName}`,
+    },
+    technicalChecks: {
+      token: chance.guid(),
+    },
+    status: 'reviewCompleted',
+    customId: chance.natural({ min: 999999, max: 9999999 }),
+  },
+  majorRevisionWithoutReviewCollection: {
+    id: majorRevisionWithoutReviewCollectionID,
+    delete: jest.fn(),
+    title: chance.sentence(),
+    type: 'collection',
+    fragments: [majorRevisionWithReview.id, noInvitesFragment1.id],
+    owners: [user.id],
+    save: jest.fn(() => collections.majorRevisionWithoutReviewCollection),
+    getFragments: jest.fn(() => [majorRevisionWithReview, noInvitesFragment1]),
+    invitations: [
+      {
+        id: chance.guid(),
+        role: 'handlingEditor',
+        hasAnswer: true,
+        isAccepted: true,
+        userId: handlingEditor.id,
+        invitedOn: chance.timestamp(),
+        respondedOn: null,
+      },
+    ],
+    handlingEditor: {
+      id: handlingEditor.id,
+      hasAnswer: true,
+      isAccepted: true,
+      email: handlingEditor.email,
+      invitedOn: chance.timestamp(),
+      respondedOn: chance.timestamp(),
+      name: `${handlingEditor.firstName} ${handlingEditor.lastName}`,
+    },
+    technicalChecks: {
+      token: chance.guid(),
+    },
+    status: 'reviewCompleted',
+    customId: chance.natural({ min: 999999, max: 9999999 }),
+  },
 }
 
 module.exports = collections
diff --git a/packages/component-fixture-manager/src/fixtures/fragments.js b/packages/component-fixture-manager/src/fixtures/fragments.js
index 337c0d943c7e6fd87e47fd3e31ff3458c0fb567d..475a277b97116a14d17d41e0c92bbdb6daba8c75 100644
--- a/packages/component-fixture-manager/src/fixtures/fragments.js
+++ b/packages/component-fixture-manager/src/fixtures/fragments.js
@@ -183,6 +183,27 @@ const fragments = {
         createdOn: 1542361115751,
         updatedOn: chance.timestamp(),
       },
+      {
+        recommendation: 'revision',
+        recommendationType: 'editorRecommendation',
+        comments: [
+          {
+            content: chance.paragraph(),
+            public: true,
+            files: [
+              {
+                id: chance.guid(),
+                name: 'file.pdf',
+                size: chance.natural(),
+              },
+            ],
+          },
+        ],
+        id: chance.guid(),
+        userId: admin.id,
+        createdOn: chance.timestamp(),
+        updatedOn: chance.timestamp(),
+      },
     ],
     authors: [
       {
diff --git a/packages/component-fixture-manager/src/fixtures/teamIDs.js b/packages/component-fixture-manager/src/fixtures/teamIDs.js
index 162cdb391585ed6789018579dbb1469271f8d2f2..1de0429354609073c2809e77c3f470ccc8094562 100644
--- a/packages/component-fixture-manager/src/fixtures/teamIDs.js
+++ b/packages/component-fixture-manager/src/fixtures/teamIDs.js
@@ -5,9 +5,10 @@ const chance = new Chance()
 module.exports = {
   heTeamID: chance.guid(),
   revTeamID: chance.guid(),
+  rev1TeamID: chance.guid(),
   authorTeamID: chance.guid(),
+  majorRevisionHeTeamID: chance.guid(),
   revRecommendationTeamID: chance.guid(),
-  rev1TeamID: chance.guid(),
   heNoRecommendationTeamID: chance.guid(),
   revNoEditorRecommendationTeamID: chance.guid(),
 }
diff --git a/packages/component-fixture-manager/src/fixtures/teams.js b/packages/component-fixture-manager/src/fixtures/teams.js
index dbd51a4aca783c1315e45fe3749b7c2bd1f8145c..79b650069ccefcad84384488bc42b4294186fde9 100644
--- a/packages/component-fixture-manager/src/fixtures/teams.js
+++ b/packages/component-fixture-manager/src/fixtures/teams.js
@@ -5,21 +5,28 @@ const fragments = require('./fragments')
 const {
   heTeamID,
   revTeamID,
+  rev1TeamID,
   authorTeamID,
+  majorRevisionHeTeamID,
   revRecommendationTeamID,
-  rev1TeamID,
   heNoRecommendationTeamID,
   revNoEditorRecommendationTeamID,
 } = require('./teamIDs')
 const { submittingAuthor } = require('./userData')
 
-const { collection, noEditorRecomedationCollection } = collections
+const {
+  collection,
+  majorRevisionCollection,
+  noEditorRecomedationCollection,
+} = collections
+
 const {
   fragment,
-  reviewCompletedFragment,
   fragment1,
+  reviewCompletedFragment,
   noEditorRecomedationFragment,
 } = fragments
+
 const {
   handlingEditor,
   reviewer,
@@ -148,5 +155,22 @@ const teams = {
     updateProperties: jest.fn(() => teams.revNoEditorRecommendationTeam),
     id: revNoEditorRecommendationTeamID,
   },
+  majorRevisionHeTeam: {
+    teamType: {
+      name: 'handlingEditor',
+      permissions: 'handlingEditor',
+    },
+    group: 'handlingEditor',
+    name: 'HandlingEditor',
+    object: {
+      type: 'collection',
+      id: majorRevisionCollection.id,
+    },
+    members: [handlingEditor.id],
+    save: jest.fn(() => teams.majorRevisionHeTeam),
+    delete: jest.fn(),
+    updateProperties: jest.fn(() => teams.majorRevisionHeTeam),
+    id: majorRevisionHeTeamID,
+  },
 }
 module.exports = teams
diff --git a/packages/component-fixture-manager/src/fixtures/users.js b/packages/component-fixture-manager/src/fixtures/users.js
index 0ec653aab24e414415d7a11904367c2fdf94ede3..2b03c59776ada663e00e2a9ac58f8c73a4060db7 100644
--- a/packages/component-fixture-manager/src/fixtures/users.js
+++ b/packages/component-fixture-manager/src/fixtures/users.js
@@ -5,9 +5,10 @@ const chance = new Chance()
 const {
   heTeamID,
   revTeamID,
+  rev1TeamID,
   authorTeamID,
+  majorRevisionHeTeamID,
   revRecommendationTeamID,
-  rev1TeamID,
   heNoRecommendationTeamID,
   revNoEditorRecommendationTeamID,
 } = require('./teamIDs')
@@ -24,7 +25,7 @@ users = keys.reduce((obj, item) => {
       teams = [heTeamID]
       break
     case 'handlingEditor':
-      teams = [heTeamID]
+      teams = [heTeamID, majorRevisionHeTeamID]
       break
     case 'noRecommendationHE':
       teams = [heNoRecommendationTeamID]
diff --git a/packages/component-helper-service/src/services/Collection.js b/packages/component-helper-service/src/services/Collection.js
index b0789f05aa93601db62053ce8f5f18382b944973..e95d5e8666a94464384fac61f693d199fe3c154b 100644
--- a/packages/component-helper-service/src/services/Collection.js
+++ b/packages/component-helper-service/src/services/Collection.js
@@ -1,4 +1,17 @@
-const { findLast, isEmpty, maxBy, get, flatMap } = require('lodash')
+const config = require('config')
+const { v4 } = require('uuid')
+const logger = require('@pubsweet/logger')
+
+const {
+  findLast,
+  isEmpty,
+  maxBy,
+  get,
+  flatMap,
+  last,
+  has,
+  set,
+} = require('lodash')
 
 const Fragment = require('./Fragment')
 
@@ -33,25 +46,6 @@ class Collection {
     return this.updateStatus({ newStatus })
   }
 
-  async updateFinalStatusByRecommendation({ recommendation }) {
-    let newStatus
-    switch (recommendation) {
-      case 'reject':
-        newStatus = 'rejected'
-        break
-      case 'publish':
-        newStatus = 'accepted'
-        break
-      case 'return-to-handling-editor':
-        newStatus = 'reviewCompleted'
-        break
-      default:
-        break
-    }
-
-    await this.updateStatus({ newStatus })
-  }
-
   async updateStatus({ newStatus }) {
     this.collection.status = newStatus
     await this.collection.save()
@@ -89,21 +83,6 @@ class Collection {
       await this.updateStatus({ newStatus: 'heAssigned' })
   }
 
-  async updateStatusOnRecommendation({ isEditorInChief, recommendation }) {
-    if (isEditorInChief) {
-      if (recommendation === 'return-to-handling-editor') {
-        return this.updateStatus({ newStatus: 'reviewCompleted' })
-      }
-      return this.updateFinalStatusByRecommendation({
-        recommendation,
-      })
-    }
-    return this.updateStatusByRecommendation({
-      recommendation,
-      isHandlingEditor: true,
-    })
-  }
-
   getHELastName() {
     const [firstName, lastName] = this.collection.handlingEditor.name.split(' ')
     return lastName || firstName
@@ -114,7 +93,8 @@ class Collection {
     const allCollectionInvitations = flatMap(
       allCollectionFragments,
       fragment => fragment.invitations,
-    )
+    ).filter(Boolean)
+
     const allNumberedInvitationsForUser = allCollectionInvitations
       .filter(invite => invite.userId === userId)
       .filter(invite => invite.reviewerNumber)
@@ -155,7 +135,9 @@ class Collection {
 
     if (lastEditorRecommendation.recommendation === 'minor') {
       return this.hasAtLeastOneReviewReport(fragments)
-    } else if (lastEditorRecommendation.recommendation === 'major') {
+    } else if (
+      ['major', 'revision'].includes(lastEditorRecommendation.recommendation)
+    ) {
       return fragmentHelper.hasReviewReport()
     }
 
@@ -169,6 +151,92 @@ class Collection {
       ),
     )
   }
+
+  isLatestVersion(fragmentId) {
+    return last(this.collection.fragments) === fragmentId
+  }
+
+  hasEQA() {
+    const technicalChecks = get(this.collection, 'technicalChecks', {})
+    return has(technicalChecks, 'eqa')
+  }
+
+  async setTechnicalChecks() {
+    set(this.collection, 'technicalChecks.token', v4())
+    set(this.collection, 'technicalChecks.eqa', false)
+    await this.collection.save()
+  }
+
+  async sendToMTS({ FragmentModel, UserModel, fragmentHelper }) {
+    await Promise.all(
+      this.collection.fragments.map(async fragmentId => {
+        const fragment = await FragmentModel.find(fragmentId)
+
+        let fragmentUsers = []
+        try {
+          fragmentUsers = await fragmentHelper.getReviewersAndEditorsData({
+            collection: this.collection,
+            UserModel,
+          })
+
+          await sendMTSPackage({
+            collection: this.collection,
+            fragment,
+            isEQA: true,
+            fragmentUsers,
+          })
+        } catch (e) {
+          logger.error(e)
+        }
+      }),
+    ).catch(e => {
+      throw new Error('Something went wrong.')
+    })
+  }
+
+  async removeTechnicalChecks() {
+    this.collection.technicalChecks = {}
+    await this.collection.save()
+  }
+
+  hasHandlingEditor() {
+    return has(this.collection, 'handlingEditor')
+  }
+
+  async addFragment(newFragmentId) {
+    this.collection.fragments.push(newFragmentId)
+    await this.collection.save()
+  }
+}
+
+const sendMTSPackage = async ({
+  fragment,
+  collection,
+  isEQA = false,
+  fragmentUsers = [],
+}) => {
+  const s3Config = get(config, 'pubsweet-component-aws-s3', {})
+  const mtsConfig = get(config, 'mts-service', {})
+  const { sendPackage } = require('pubsweet-component-mts-package')
+
+  const { journal, xmlParser, ftp } = mtsConfig
+  const packageFragment = {
+    ...fragment,
+    metadata: {
+      ...fragment.metadata,
+      customId: collection.customId,
+    },
+  }
+
+  await sendPackage({
+    isEQA,
+    s3Config,
+    fragmentUsers,
+    ftpConfig: ftp,
+    config: journal,
+    options: xmlParser,
+    fragment: packageFragment,
+  })
 }
 
 module.exports = Collection
diff --git a/packages/component-helper-service/src/services/Fragment.js b/packages/component-helper-service/src/services/Fragment.js
index 7a0f27ae03d656269c6e5c757c094dd083f1ddb8..8cdd85f609bc51bbf045a3fc3007746b7bf09470 100644
--- a/packages/component-helper-service/src/services/Fragment.js
+++ b/packages/component-helper-service/src/services/Fragment.js
@@ -1,4 +1,5 @@
-const { get, remove, findLast, last } = require('lodash')
+const { get, remove, findLast, pick, chain, omit } = require('lodash')
+
 const config = require('config')
 const User = require('./User')
 
@@ -123,13 +124,12 @@ class Fragment {
 
   getLatestHERequestToRevision() {
     const { fragment: { recommendations = [] } } = this
-    return recommendations
-      .filter(
-        rec =>
-          rec.recommendationType === 'editorRecommendation' &&
-          (rec.recommendation === 'minor' || rec.recommendation === 'major'),
-      )
-      .sort((a, b) => b.createdOn - a.createdOn)[0]
+    return findLast(
+      recommendations,
+      rec =>
+        rec.recommendationType === 'editorRecommendation' &&
+        (rec.recommendation === 'minor' || rec.recommendation === 'major'),
+    )
   }
 
   async getReviewers({ UserModel, type }) {
@@ -150,16 +150,18 @@ class Fragment {
     )
   }
 
-  canHEMakeAnotherRecommendation(currentUserRecommendations) {
-    const lastHERecommendation = last(currentUserRecommendations)
+  canHEMakeAnotherRecommendation(lastHERecommendation) {
     const { fragment: { recommendations = [] } } = this
+
     const returnToHERecommendation = findLast(
       recommendations,
       r => r.recommendation === 'return-to-handling-editor',
     )
+
     if (!returnToHERecommendation) return false
     return returnToHERecommendation.createdOn > lastHERecommendation.createdOn
   }
+
   async getReviewersAndEditorsData({ collection, UserModel }) {
     const {
       invitations = [],
@@ -220,6 +222,71 @@ class Fragment {
 
     return revAndEditorData
   }
+
+  async addRecommendation(newRecommendation) {
+    this.fragment.recommendations = this.fragment.recommendations || []
+
+    this.fragment.recommendations.push(newRecommendation)
+    await this.fragment.save()
+  }
+
+  async addRevision() {
+    this.fragment.revision = pick(this.fragment, [
+      'authors',
+      'files',
+      'metadata',
+    ])
+    await this.fragment.save()
+  }
+
+  hasReviewers() {
+    const { fragment: invitations = [] } = this
+    return invitations.length > 0
+  }
+
+  getLatestUserRecommendation(userId) {
+    return findLast(this.fragment.recommendations, r => r.userId === userId)
+  }
+
+  getLatestRecommendation() {
+    return chain(this.fragment)
+      .get('recommendations', [])
+      .last()
+      .value()
+  }
+
+  async createFragmentFromRevision(FragmentModel) {
+    const newFragmentBody = {
+      ...omit(this.fragment, ['revision', 'recommendations', 'id']),
+      ...this.fragment.revision,
+      invitations: this.getInvitations({
+        isAccepted: true,
+        type: 'submitted',
+      }),
+      version: this.fragment.version + 1,
+      created: new Date(),
+    }
+
+    let newFragment = new FragmentModel(newFragmentBody)
+    newFragment = await newFragment.save()
+
+    return newFragment
+  }
+
+  async removeRevision() {
+    delete this.fragment.revision
+    await this.fragment.save()
+  }
+
+  getLatestEiCRequestToRevision() {
+    const { fragment: { recommendations = [] } } = this
+    return findLast(
+      recommendations,
+      rec =>
+        rec.recommendationType === 'editorRecommendation' &&
+        rec.recommendation === 'revision',
+    )
+  }
 }
 
 module.exports = Fragment
diff --git a/packages/component-helper-service/src/services/User.js b/packages/component-helper-service/src/services/User.js
index dbd0eb1f2bf7b6e5995a27df258efbb6a532fb3d..1878092704ad027560176e161e3a526367ea3363 100644
--- a/packages/component-helper-service/src/services/User.js
+++ b/packages/component-helper-service/src/services/User.js
@@ -67,7 +67,7 @@ class User {
   async updateUserTeams({ userId, teamId }) {
     const user = await this.UserModel.find(userId)
     user.teams.push(teamId)
-    user.save()
+    await user.save()
   }
 
   async getActiveAuthors({ fragmentAuthors }) {
diff --git a/packages/component-helper-service/src/tests/fragment.test.js b/packages/component-helper-service/src/tests/fragment.test.js
index c5623dc18a8d7cf4812d3695189319f48b7e2202..ec7fbb6073f311f844c2ff574c936dfe00b9ff35 100644
--- a/packages/component-helper-service/src/tests/fragment.test.js
+++ b/packages/component-helper-service/src/tests/fragment.test.js
@@ -329,12 +329,13 @@ describe('Fragment helper', () => {
           updatedOn: chance.timestamp(),
         },
       ]
-      const currentUserRecommendations = testFragment.recommendations.filter(
-        r => r.userId === handlingEditorId,
-      )
       const fragmentHelper = new Fragment({ fragment: testFragment })
+      const latestUserRecommendation = fragmentHelper.getLatestUserRecommendation(
+        handlingEditorId,
+      )
+
       const canHEMakeAnotherRecommendation = await fragmentHelper.canHEMakeAnotherRecommendation(
-        currentUserRecommendations,
+        latestUserRecommendation,
       )
       expect(canHEMakeAnotherRecommendation).toBe(true)
     })
@@ -362,12 +363,12 @@ describe('Fragment helper', () => {
           updatedOn: chance.timestamp(),
         },
       ]
-      const currentUserRecommendations = testFragment.recommendations.filter(
-        r => r.userId === handlingEditorId,
-      )
       const fragmentHelper = new Fragment({ fragment: testFragment })
+      const latestUserRecommendation = fragmentHelper.getLatestUserRecommendation(
+        handlingEditorId,
+      )
       const canHEMakeAnotherRecommendation = await fragmentHelper.canHEMakeAnotherRecommendation(
-        currentUserRecommendations,
+        latestUserRecommendation,
       )
       expect(canHEMakeAnotherRecommendation).toBe(false)
     })
diff --git a/packages/component-invite/src/routes/collectionsInvitations/post.js b/packages/component-invite/src/routes/collectionsInvitations/post.js
index 7d404e0cec4a91d3a74808722332a7266963aa78..8e354cf84a9b9b912b10980435ea169741ff994e 100644
--- a/packages/component-invite/src/routes/collectionsInvitations/post.js
+++ b/packages/component-invite/src/routes/collectionsInvitations/post.js
@@ -50,7 +50,6 @@ module.exports = models => async (req, res) => {
       error: 'Unauthorized.',
     })
 
-  // check collection status
   if (!['submitted', 'heInvited'].includes(collection.status)) {
     return res.status(400).json({
       error: `Cannot invite HE while collection is in the status: ${
diff --git a/packages/component-invite/src/tests/collectionsInvitations/post.test.js b/packages/component-invite/src/tests/collectionsInvitations/post.test.js
index de48dc4f84033d9090d303bd4ce1563c1298a992..94dc618a3165e9535d1cb6fce0d4fa92e23eb354 100644
--- a/packages/component-invite/src/tests/collectionsInvitations/post.test.js
+++ b/packages/component-invite/src/tests/collectionsInvitations/post.test.js
@@ -192,7 +192,36 @@ describe('Post collections invitations route handler', () => {
       },
     })
 
-    // expect(res.statusCode).toBe(200)
+    expect(res.statusCode).toBe(400)
+    const data = JSON.parse(res._getData())
+
+    expect(data.error).toEqual(
+      `Cannot invite HE while collection is in the status: ${
+        collection.status
+      }.`,
+    )
+  })
+  it('should return an error when the collection is in the revision requested status', async () => {
+    const { user, editorInChief } = testFixtures.users
+    const { collection } = testFixtures.collections
+    collection.status = 'revisionRequested'
+
+    body = {
+      email: user.email,
+      role: 'handlingEditor',
+    }
+    const res = await requests.sendRequest({
+      body,
+      userId: editorInChief.id,
+      route,
+      models,
+      path,
+      params: {
+        collectionId: collection.id,
+      },
+    })
+
+    expect(res.statusCode).toBe(400)
     const data = JSON.parse(res._getData())
 
     expect(data.error).toEqual(
diff --git a/packages/component-manuscript-manager/src/notifications/emailCopy.js b/packages/component-manuscript-manager/src/notifications/emailCopy.js
index 3aa154fcdd356c251d191cf3d38b02778e1379cf..67bfe04a10871271dec8db264da90e0b619fb7b0 100644
--- a/packages/component-manuscript-manager/src/notifications/emailCopy.js
+++ b/packages/component-manuscript-manager/src/notifications/emailCopy.js
@@ -11,6 +11,7 @@ const getEmailCopy = ({
   comments = '',
   targetUserName = '',
   eicName = 'Editor in Chief',
+  expectedDate = new Date(),
 }) => {
   let paragraph
   let hasLink = true
@@ -131,6 +132,29 @@ const getEmailCopy = ({
       paragraph = `We regret to inform you that ${titleText} has been returned with comments. Please click the link below to access the manuscript.<br/><br/>
         Comments: ${comments}<br/><br/>`
       break
+    case 'submitted-reviewers-after-revision':
+      paragraph = `The authors have submitted a new version of ${titleText}, which you reviewed for ${journalName}.<br/><br/>
+        As you reviewed the previous version of this manuscript, I would be grateful if you could review this revision and submit a new report by ${expectedDate}.
+        To download the updated PDF and proceed with the review process, please visit the manuscript details page.<br/><br/>
+        Thank you again for reviewing for ${journalName}.`
+      break
+    case 'he-new-version-submitted':
+      hasIntro = false
+      hasSignature = false
+      paragraph = `The authors of ${titleText} have submitted a revised version. <br/><br/>
+        To review this new submission and proceed with the review process, please visit the manuscript details page.`
+      break
+    case 'eic-revision-published':
+      hasIntro = false
+      hasSignature = false
+      paragraph = `The authors of ${titleText} have submitted a revised version. <br/><br/>
+        To review this new submission and proceed with the review process, please visit the manuscript details page.`
+      break
+    case 'author-request-to-revision-from-eic':
+      paragraph = `In order for ${titleText} to proceed to the review process, there needs to be a revision. <br/><br/>
+        ${comments}<br/><br/>
+        For more information about what is required, please click the link below.<br/><br/>`
+      break
     default:
       throw new Error(`The ${emailType} email type is not defined.`)
   }
diff --git a/packages/component-manuscript-manager/src/notifications/notification.js b/packages/component-manuscript-manager/src/notifications/notification.js
index 506e9ba191a51fd7a1e34142dac3f5a03895de23..c80f5c29a2efa52a545033d57ca6929d5365ccd5 100644
--- a/packages/component-manuscript-manager/src/notifications/notification.js
+++ b/packages/component-manuscript-manager/src/notifications/notification.js
@@ -407,6 +407,53 @@ class Notification {
     return email.sendEmail()
   }
 
+  async notifySAWhenEiCRequestsRevision() {
+    const {
+      eicName,
+      submittingAuthor,
+      titleText,
+    } = await this._getNotificationProperties()
+
+    const authorNoteText = helpers.getPrivateNoteTextForAuthor({
+      newRecommendation: this.newRecommendation,
+    })
+
+    const { paragraph, ...bodyProps } = getEmailCopy({
+      emailType: 'author-request-to-revision-from-eic',
+      titleText,
+      comments: authorNoteText,
+    })
+
+    const email = new Email({
+      type: 'user',
+      toUser: {
+        email: submittingAuthor.email,
+        name: submittingAuthor.lastName,
+      },
+      fromEmail: `${eicName} <${staffEmail}>`,
+      content: {
+        subject: `${this.collection.customId}: Revision requested`,
+        paragraph,
+        signatureName: eicName,
+        ctaText: 'MANUSCRIPT DETAILS',
+        signatureJournal: journalName,
+        unsubscribeLink: services.createUrl(this.baseUrl, unsubscribeSlug, {
+          id: submittingAuthor.id,
+          token: submittingAuthor.accessTokens.unsubscribe,
+        }),
+        ctaLink: services.createUrl(
+          this.baseUrl,
+          `/projects/${this.collection.id}/versions/${
+            this.fragment.id
+          }/details`,
+        ),
+      },
+      bodyProps,
+    })
+
+    return email.sendEmail()
+  }
+
   async notifyReviewersWhenHEMakesRecommendation() {
     const {
       eicName,
@@ -629,6 +676,144 @@ class Notification {
     })
   }
 
+  async notifyEditorInChiefWhenAuthorSubmitsRevision(newFragment) {
+    const { titleText } = await this._getNotificationProperties()
+
+    const userHelper = new User({ UserModel: this.UserModel })
+    const editors = await userHelper.getEditorsInChief()
+
+    const { paragraph, ...bodyProps } = getEmailCopy({
+      titleText,
+      emailType: 'eic-revision-published',
+    })
+
+    editors.forEach(eic => {
+      const email = new Email({
+        type: 'user',
+        fromEmail: `${journalName} <${staffEmail}>`,
+        toUser: {
+          email: eic.email,
+        },
+        content: {
+          subject: `${this.collection.customId}: Revision submitted`,
+          paragraph,
+          signatureName: '',
+          signatureJournal: journalName,
+          ctaLink: services.createUrl(
+            this.baseUrl,
+            `/projects/${this.collection.id}/versions/${
+              newFragment.id
+            }/details`,
+          ),
+          ctaText: 'MANUSCRIPT DETAILS',
+          unsubscribeLink: services.createUrl(this.baseUrl, unsubscribeSlug, {
+            id: eic.id,
+            token: eic.accessTokens.unsubscribe,
+          }),
+        },
+        bodyProps,
+      })
+
+      return email.sendEmail()
+    })
+  }
+
+  async notifyReviewersWhenAuthorSubmitsMajorRevision(newFragmentId) {
+    const { fragmentHelper } = await this._getNotificationProperties()
+    const { collection, UserModel } = this
+
+    const handlingEditor = get(collection, 'handlingEditor')
+    const parsedFragment = await fragmentHelper.getFragmentData({
+      handlingEditor,
+    })
+
+    const reviewers = await fragmentHelper.getReviewers({
+      UserModel,
+      type: 'submitted',
+    })
+
+    const { paragraph, ...bodyProps } = getEmailCopy({
+      emailType: 'submitted-reviewers-after-revision',
+      titleText: `the manuscript titled "${parsedFragment.title}"`,
+      expectedDate: services.getExpectedDate({ daysExpected: 14 }),
+    })
+
+    reviewers.forEach(reviewer => {
+      const email = new Email({
+        type: 'user',
+        fromEmail: `${handlingEditor.name} <${staffEmail}>`,
+        toUser: {
+          email: reviewer.email,
+          name: `${reviewer.lastName}`,
+        },
+        content: {
+          subject: `${
+            collection.customId
+          }: A manuscript you reviewed has been revised`,
+          paragraph,
+          signatureName: handlingEditor.name,
+          signatureJournal: journalName,
+          ctaLink: services.createUrl(
+            this.baseUrl,
+            `/projects/${collection.id}/versions/${newFragmentId}/details`,
+          ),
+          ctaText: 'MANUSCRIPT DETAILS',
+          unsubscribeLink: services.createUrl(this.baseUrl, unsubscribeSlug, {
+            id: reviewer.id,
+            token: reviewer.accessTokens.unsubscribe,
+          }),
+        },
+        bodyProps,
+      })
+
+      return email.sendEmail()
+    })
+  }
+
+  async notifyHandlingEditorWhenAuthorSubmitsRevision(newFragment) {
+    const { collection, UserModel } = this
+
+    const handlingEditor = get(collection, 'handlingEditor')
+
+    const fragmentHelper = new Fragment({ fragment: newFragment })
+    const parsedFragment = await fragmentHelper.getFragmentData({
+      handlingEditor,
+    })
+
+    const { paragraph, ...bodyProps } = getEmailCopy({
+      emailType: 'he-new-version-submitted',
+      titleText: `the manuscript titled "${parsedFragment.title}"`,
+    })
+
+    const heUser = await UserModel.find(handlingEditor.id)
+
+    const email = new Email({
+      type: 'user',
+      fromEmail: `${journalName} <${staffEmail}>`,
+      toUser: {
+        email: heUser.email,
+      },
+      content: {
+        subject: `${collection.customId}: Revision submitted`,
+        paragraph,
+        signatureName: '',
+        signatureJournal: journalName,
+        ctaLink: services.createUrl(
+          this.baseUrl,
+          `/projects/${collection.id}/versions/${newFragment.id}/details`,
+        ),
+        ctaText: 'MANUSCRIPT DETAILS',
+        unsubscribeLink: services.createUrl(this.baseUrl, unsubscribeSlug, {
+          id: heUser.id,
+          token: heUser.accessTokens.unsubscribe,
+        }),
+      },
+      bodyProps,
+    })
+
+    return email.sendEmail()
+  }
+
   async _getNotificationProperties() {
     const fragmentHelper = new Fragment({ fragment: this.fragment })
     const parsedFragment = await fragmentHelper.getFragmentData({
diff --git a/packages/component-manuscript-manager/src/routes/fragments/notifications/emailCopy.js b/packages/component-manuscript-manager/src/routes/fragments/notifications/emailCopy.js
index ecfadb0a4ae20fb38e8e9511b10120fb33fabfaf..e6ab3f502678fcf09ecd40557b7d9b63607f9fea 100644
--- a/packages/component-manuscript-manager/src/routes/fragments/notifications/emailCopy.js
+++ b/packages/component-manuscript-manager/src/routes/fragments/notifications/emailCopy.js
@@ -5,21 +5,9 @@ const journalName = config.get('journal.name')
 const getEmailCopy = ({ emailType, titleText, expectedDate, customId }) => {
   let paragraph
   const hasLink = true
-  let hasIntro = true
-  let hasSignature = true
+  const hasIntro = true
+  const hasSignature = true
   switch (emailType) {
-    case 'he-new-version-submitted':
-      hasIntro = false
-      hasSignature = false
-      paragraph = `The authors of ${titleText} have submitted a revised version. <br/><br/>
-        To review this new submission and proceed with the review process, please visit the manuscript details page.`
-      break
-    case 'submitted-reviewers-after-revision':
-      paragraph = `The authors have submitted a new version of ${titleText}, which you reviewed for ${journalName}.<br/><br/>
-        As you reviewed the previous version of this manuscript, I would be grateful if you could review this revision and submit a new report by ${expectedDate}.
-        To download the updated PDF and proceed with the review process, please visit the manuscript details page.<br/><br/>
-        Thank you again for reviewing for ${journalName}.`
-      break
     case 'eqs-manuscript-submitted':
       paragraph = `Manuscript ID ${customId} has been submitted and a package has been sent. Please click on the link below to either approve or reject the manuscript:`
       break
diff --git a/packages/component-manuscript-manager/src/routes/fragments/notifications/notifications.js b/packages/component-manuscript-manager/src/routes/fragments/notifications/notifications.js
index c901c343b92e974cc532becf8b6c881411212e89..a1c7422bc45bbe2440213d04d4d6b06524b58896 100644
--- a/packages/component-manuscript-manager/src/routes/fragments/notifications/notifications.js
+++ b/packages/component-manuscript-manager/src/routes/fragments/notifications/notifications.js
@@ -15,103 +15,6 @@ const unsubscribeSlug = config.get('unsubscribe.url')
 const { getEmailCopy } = require('./emailCopy')
 
 module.exports = {
-  async sendHandlingEditorEmail({ baseUrl, fragment, UserModel, collection }) {
-    const fragmentHelper = new Fragment({ fragment })
-    const handlingEditor = get(collection, 'handlingEditor')
-    const parsedFragment = await fragmentHelper.getFragmentData({
-      handlingEditor,
-    })
-
-    const { paragraph, ...bodyProps } = getEmailCopy({
-      emailType: 'he-new-version-submitted',
-      titleText: `the manuscript titled "${parsedFragment.title}"`,
-    })
-
-    const heUser = await UserModel.find(handlingEditor.id)
-
-    const email = new Email({
-      type: 'user',
-      fromEmail: `${journalName} <${staffEmail}>`,
-      toUser: {
-        email: heUser.email,
-      },
-      content: {
-        subject: `${collection.customId}: Revision submitted`,
-        paragraph,
-        signatureName: '',
-        signatureJournal: journalName,
-        ctaLink: services.createUrl(
-          baseUrl,
-          `/projects/${collection.id}/versions/${fragment.id}/details`,
-        ),
-        ctaText: 'MANUSCRIPT DETAILS',
-        unsubscribeLink: services.createUrl(baseUrl, unsubscribeSlug, {
-          id: heUser.id,
-          token: heUser.accessTokens.unsubscribe,
-        }),
-      },
-      bodyProps,
-    })
-
-    return email.sendEmail()
-  },
-
-  async sendReviewersEmail({
-    baseUrl,
-    fragment,
-    UserModel,
-    collection,
-    previousVersion,
-  }) {
-    const fragmentHelper = new Fragment({ fragment: previousVersion })
-    const handlingEditor = get(collection, 'handlingEditor')
-    const parsedFragment = await fragmentHelper.getFragmentData({
-      handlingEditor,
-    })
-
-    const reviewers = await fragmentHelper.getReviewers({
-      UserModel,
-      type: 'submitted',
-    })
-
-    const { paragraph, ...bodyProps } = getEmailCopy({
-      emailType: 'submitted-reviewers-after-revision',
-      titleText: `the manuscript titled "${parsedFragment.title}"`,
-      expectedDate: services.getExpectedDate({ daysExpected: 14 }),
-    })
-
-    reviewers.forEach(reviewer => {
-      const email = new Email({
-        type: 'user',
-        fromEmail: `${handlingEditor.name} <${staffEmail}>`,
-        toUser: {
-          email: reviewer.email,
-          name: `${reviewer.lastName}`,
-        },
-        content: {
-          subject: `${
-            collection.customId
-          }: A manuscript you reviewed has been revised`,
-          paragraph,
-          signatureName: handlingEditor.name,
-          signatureJournal: journalName,
-          ctaLink: services.createUrl(
-            baseUrl,
-            `/projects/${collection.id}/versions/${fragment.id}/details`,
-          ),
-          ctaText: 'MANUSCRIPT DETAILS',
-          unsubscribeLink: services.createUrl(baseUrl, unsubscribeSlug, {
-            id: reviewer.id,
-            token: reviewer.accessTokens.unsubscribe,
-          }),
-        },
-        bodyProps,
-      })
-
-      return email.sendEmail()
-    })
-  },
-
   async sendEQSEmail({ baseUrl, fragment, UserModel, collection }) {
     const userHelper = new User({ UserModel })
     const eicName = await userHelper.getEiCName()
diff --git a/packages/component-manuscript-manager/src/routes/fragments/patch.js b/packages/component-manuscript-manager/src/routes/fragments/patch.js
index 6a3e11ef06411ccd3868b8da6aca8389289f0d6a..4f975c391c34232517734c2c3e920ad4bfefe7ca 100644
--- a/packages/component-manuscript-manager/src/routes/fragments/patch.js
+++ b/packages/component-manuscript-manager/src/routes/fragments/patch.js
@@ -1,14 +1,16 @@
-const { union, omit } = require('lodash')
-
 const {
   Team,
+  User,
   services,
   Fragment,
   Collection,
   authsome: authsomeHelper,
 } = require('pubsweet-component-helper-service')
 
-const notifications = require('./notifications/notifications')
+const Notification = require('../../notifications/notification')
+
+const eicRequestRevision = require('./strategies/eicRequestRevision')
+const heRequestRevision = require('./strategies/heRequestRevision')
 
 module.exports = models => async (req, res) => {
   const { collectionId, fragmentId } = req.params
@@ -42,100 +44,35 @@ module.exports = models => async (req, res) => {
 
     const collectionHelper = new Collection({ collection })
     const fragmentHelper = new Fragment({ fragment })
-    const heRecommendation = fragmentHelper.getLatestHERequestToRevision()
-    if (!heRecommendation) {
-      return res.status(400).json({
-        error: 'No Handling Editor request to revision has been found.',
-      })
-    }
-
-    const newFragmentBody = {
-      ...omit(fragment, ['revision', 'recommendations', 'id']),
-      ...fragment.revision,
-      invitations: fragmentHelper.getInvitations({
-        isAccepted: true,
-        type: 'submitted',
-      }),
-      version: fragment.version + 1,
-      created: new Date(),
-    }
-
-    let newFragment = new models.Fragment(newFragmentBody)
-    newFragment = await newFragment.save()
-    const teamHelper = new Team({
-      TeamModel: models.Team,
-      collectionId,
-      fragmentId: newFragment.id,
-    })
-    delete fragment.revision
-    fragment.save()
-
-    if (heRecommendation.recommendation === 'major') {
-      const reviewerIds = newFragment.invitations.map(inv => inv.userId)
-
-      teamHelper.createTeam({
-        role: 'reviewer',
-        members: reviewerIds,
-        objectType: 'fragment',
-      })
-    } else {
-      delete newFragment.invitations
-      await newFragment.save()
-    }
-
-    const authorIds = newFragment.authors.map(auth => {
-      const { id } = auth
-      return id
-    })
-
-    let authorsTeam = await teamHelper.getTeam({
-      role: 'author',
-      objectType: 'fragment',
-    })
+    const userHelper = new User({ UserModel: models.User })
 
-    if (!authorsTeam) {
-      authorsTeam = await teamHelper.createTeam({
-        role: 'author',
-        members: authorIds,
-        objectType: 'fragment',
-      })
-    } else {
-      authorsTeam.members = union(authorsTeam.members, authorIds)
-      await authorsTeam.save()
+    const strategies = {
+      he: heRequestRevision,
+      eic: eicRequestRevision,
     }
 
-    const fragments = await collectionHelper.getAllFragments({
-      FragmentModel: models.Fragment,
-    })
-
-    await collectionHelper.updateStatusByRecommendation({
-      recommendation: heRecommendation.recommendation,
-      fragments,
-    })
-
-    newFragment.submitted = Date.now()
-    newFragment = await newFragment.save()
-    collection.fragments.push(newFragment.id)
-    collection.save()
+    const role = collection.handlingEditor ? 'he' : 'eic'
 
-    notifications.sendHandlingEditorEmail({
-      baseUrl: services.getBaseUrl(req),
-      fragment: newFragment,
-      UserModel: models.User,
+    const notification = new Notification({
+      fragment,
       collection,
+      UserModel: models.User,
+      baseUrl: services.getBaseUrl(req),
     })
 
-    if (heRecommendation.recommendation === 'major') {
-      notifications.sendReviewersEmail({
-        baseUrl: services.getBaseUrl(req),
-        fragment: newFragment,
-        UserModel: models.User,
-        collection,
-        previousVersion: fragment,
+    try {
+      const newFragment = await strategies[role].execute({
+        models,
+        userHelper,
+        notification,
+        fragmentHelper,
+        collectionHelper,
+        TeamHelper: Team,
       })
+      return res.status(200).json(newFragment)
+    } catch (e) {
+      return res.status(400).json({ error: e.message })
     }
-
-    return res.status(200).json(newFragment)
   } catch (e) {
     const notFoundError = await services.handleNotFoundError(e, 'Item')
     return res.status(notFoundError.status).json({
diff --git a/packages/component-manuscript-manager/src/routes/fragments/strategies/eicRequestRevision.js b/packages/component-manuscript-manager/src/routes/fragments/strategies/eicRequestRevision.js
new file mode 100644
index 0000000000000000000000000000000000000000..eb99d655a56a86d441b9746b51aaac4af9810501
--- /dev/null
+++ b/packages/component-manuscript-manager/src/routes/fragments/strategies/eicRequestRevision.js
@@ -0,0 +1,48 @@
+module.exports = {
+  execute: async ({
+    models,
+    TeamHelper,
+    fragmentHelper,
+    collectionHelper,
+    notification,
+    userHelper,
+  }) => {
+    const eicRequestToRevision = fragmentHelper.getLatestEiCRequestToRevision()
+    if (!eicRequestToRevision) {
+      throw new Error('No Editor in Chief request to revision has been found.')
+    }
+
+    let newFragment = await fragmentHelper.createFragmentFromRevision(
+      models.Fragment,
+    )
+
+    await fragmentHelper.removeRevision()
+
+    const teamHelper = new TeamHelper({
+      TeamModel: models.Team,
+      fragmentId: newFragment.id,
+    })
+
+    const authorIds = newFragment.authors.map(auth => auth.id)
+
+    const { id: teamId } = await teamHelper.createTeam({
+      role: 'author',
+      members: authorIds,
+      objectType: 'fragment',
+    })
+    authorIds.forEach(id => {
+      userHelper.updateUserTeams({ userId: id, teamId })
+    })
+
+    await collectionHelper.updateStatus({ newStatus: 'submitted' })
+
+    newFragment.submitted = Date.now()
+    newFragment = await newFragment.save()
+
+    await collectionHelper.addFragment(newFragment.id)
+
+    await notification.notifyEditorInChiefWhenAuthorSubmitsRevision(newFragment)
+
+    return newFragment
+  },
+}
diff --git a/packages/component-manuscript-manager/src/routes/fragments/strategies/heRequestRevision.js b/packages/component-manuscript-manager/src/routes/fragments/strategies/heRequestRevision.js
new file mode 100644
index 0000000000000000000000000000000000000000..2a20da7ba12d003e43ddd97e7e0e814bc1ed225e
--- /dev/null
+++ b/packages/component-manuscript-manager/src/routes/fragments/strategies/heRequestRevision.js
@@ -0,0 +1,75 @@
+module.exports = {
+  execute: async ({
+    models,
+    userHelper,
+    TeamHelper,
+    notification,
+    fragmentHelper,
+    collectionHelper,
+  }) => {
+    const heRequestToRevision = fragmentHelper.getLatestHERequestToRevision()
+    if (!heRequestToRevision) {
+      throw new Error('No Handling Editor request to revision has been found.')
+    }
+
+    let newFragment = await fragmentHelper.createFragmentFromRevision(
+      models.Fragment,
+    )
+    await fragmentHelper.removeRevision()
+
+    const teamHelper = new TeamHelper({
+      TeamModel: models.Team,
+      fragmentId: newFragment.id,
+    })
+
+    if (heRequestToRevision.recommendation === 'major') {
+      const reviewerIds = newFragment.invitations.map(inv => inv.userId)
+
+      teamHelper.createTeam({
+        role: 'reviewer',
+        members: reviewerIds,
+        objectType: 'fragment',
+      })
+    } else {
+      delete newFragment.invitations
+      await newFragment.save()
+    }
+
+    const authorIds = newFragment.authors.map(auth => auth.id)
+
+    const { id: teamId } = await teamHelper.createTeam({
+      role: 'author',
+      members: authorIds,
+      objectType: 'fragment',
+    })
+    authorIds.forEach(id => {
+      userHelper.updateUserTeams({ userId: id, teamId })
+    })
+
+    const fragments = await collectionHelper.getAllFragments({
+      FragmentModel: models.Fragment,
+    })
+
+    await collectionHelper.updateStatusByRecommendation({
+      recommendation: heRequestToRevision.recommendation,
+      fragments,
+    })
+
+    newFragment.submitted = Date.now()
+    newFragment = await newFragment.save()
+
+    await collectionHelper.addFragment(newFragment.id)
+
+    await notification.notifyHandlingEditorWhenAuthorSubmitsRevision(
+      newFragment,
+    )
+
+    if (heRequestToRevision.recommendation === 'major') {
+      await notification.notifyReviewersWhenAuthorSubmitsMajorRevision(
+        newFragment.id,
+      )
+    }
+
+    return newFragment
+  },
+}
diff --git a/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/post.js b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/post.js
index b47234c1f1a017149269ba6e415ee49d5af6b159..abfd90990a00b6eef6bcea5a764b4e3f028d03b3 100644
--- a/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/post.js
+++ b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/post.js
@@ -1,8 +1,5 @@
-const uuid = require('uuid')
-const { pick, get, set, has, isEmpty, last, chain } = require('lodash')
 const config = require('config')
 const { v4 } = require('uuid')
-const logger = require('@pubsweet/logger')
 
 const {
   services,
@@ -11,21 +8,31 @@ const {
   authsome: authsomeHelper,
 } = require('pubsweet-component-helper-service')
 
-const { features = {}, recommendations } = config
+const { recommendations } = config
 
+const rejectAsHE = require('./strategies/heReject')
+const publishAsHE = require('./strategies/hePublish')
+const rejectAsEiC = require('./strategies/eicReject')
+const publishAsEiC = require('./strategies/eicPublish')
+const returnToHE = require('./strategies/eicReturnToHE')
 const Notification = require('../../notifications/notification')
+const createReview = require('./strategies/reviewerCreateReview')
+const requestRevisionAsHE = require('./strategies/heRequestRevision')
+const requestRevisionAsEiC = require('./strategies/eicRequestRevision')
 
 module.exports = models => async (req, res) => {
-  const { recommendation, comments, recommendationType } = req.body
-  if (!services.checkForUndefinedParams(recommendationType))
+  const { recommendation, comments = [], recommendationType } = req.body
+  if (!services.checkForUndefinedParams(recommendationType, recommendation))
     return res.status(400).json({ error: 'Recommendation type is required.' })
 
   const reqUser = await models.User.find(req.user)
+  const userId = reqUser.id
+
   const isEditorInChief = reqUser.editorInChief || reqUser.admin
 
   const { collectionId, fragmentId } = req.params
 
-  let collection, fragment, fragments
+  let collection, fragment
 
   try {
     collection = await models.Collection.find(collectionId)
@@ -43,28 +50,6 @@ module.exports = models => async (req, res) => {
 
   const collectionHelper = new Collection({ collection })
 
-  try {
-    fragments = await collectionHelper.getAllFragments({
-      FragmentModel: models.Fragment,
-    })
-  } catch (e) {
-    const notFoundError = await services.handleNotFoundError(e, 'Item')
-    fragments = []
-    return res.status(notFoundError.status).json({
-      error: notFoundError.message,
-    })
-  }
-  const currentUserRecommendations = get(
-    fragment,
-    'recommendations',
-    [],
-  ).filter(r => r.userId === req.user)
-
-  const lastFragmentRecommendation = chain(fragment)
-    .get('recommendations', [])
-    .last()
-    .value()
-
   const authsome = authsomeHelper.getAuthsome(models)
   const target = {
     fragment,
@@ -77,219 +62,83 @@ module.exports = models => async (req, res) => {
     })
 
   const fragmentHelper = new Fragment({ fragment })
-  if (
-    recommendationType === recommendations.type.editor &&
-    last(collection.fragments) !== fragmentId
-  ) {
-    return res
-      .status(400)
-      .json({ error: 'Cannot make a recommendation on an older version.' })
-  }
-
-  if (
-    recommendationType === recommendations.type.review &&
-    last(collection.fragments) !== fragmentId
-  ) {
-    return res
-      .status(400)
-      .json({ error: 'Cannot write a review on an older version.' })
-  }
-  if (
-    last(collection.fragments) === fragmentId &&
-    !isEmpty(currentUserRecommendations)
-  ) {
-    if (recommendationType === recommendations.type.review) {
-      return res
-        .status(400)
-        .json({ error: 'Cannot write another review on this version.' })
-    }
-    if (
-      recommendationType === recommendations.type.editor &&
-      !isEditorInChief &&
-      !fragmentHelper.canHEMakeAnotherRecommendation(currentUserRecommendations)
-    ) {
-      return res.status(400).json({
-        error: 'Cannot make another recommendation on this version.',
-      })
-    }
-    if (
-      recommendationType === recommendations.type.editor &&
-      isEditorInChief &&
-      recommendation !== recommendations.reject &&
-      lastFragmentRecommendation.recommendation === 'return-to-handling-editor'
-    ) {
-      return res.status(400).json({
-        error: 'Cannot make another recommendation on this version.',
-      })
-    }
-  }
 
-  if (
-    recommendation === recommendations.publish &&
-    recommendationType === recommendations.type.editor &&
-    collection.handlingEditor &&
-    collection.handlingEditor.id === req.user
-  ) {
-    if (!collectionHelper.canHEMakeRecommendation(fragments, fragmentHelper)) {
-      return res.status(400).json({
-        error: 'Cannot publish without at least one reviewer report.',
-      })
-    }
+  if (!collectionHelper.isLatestVersion(fragmentId)) {
+    const error =
+      recommendationType === recommendations.type.editor
+        ? 'Cannot make a recommendation on an older version.'
+        : 'Cannot write a review on an older version.'
+    return res.status(400).json({ error })
   }
 
-  fragment.recommendations = fragment.recommendations || []
   const newRecommendation = {
-    id: uuid.v4(),
-    userId: reqUser.id,
+    userId,
+    id: v4(),
+    comments,
+    recommendation,
+    recommendationType,
     createdOn: Date.now(),
     updatedOn: Date.now(),
-    recommendationType,
   }
 
-  newRecommendation.recommendation = recommendation || undefined
-  newRecommendation.comments = comments || undefined
-
-  if (recommendationType === 'editorRecommendation') {
-    await collectionHelper.updateStatusOnRecommendation({
-      isEditorInChief,
-      recommendation,
-    })
-
-    if (!isEditorInChief && ['minor', 'major'].includes(recommendation)) {
-      fragment.revision = pick(fragment, ['authors', 'files', 'metadata'])
-    }
-
-    const technicalChecks = get(collection, 'technicalChecks', {})
-    const hasEQA = has(technicalChecks, 'eqa')
-    // the manuscript has not yet passed through the EQA process so we need to upload it to the FTP server
-    if (isEditorInChief && recommendation === 'publish' && !hasEQA) {
-      if (features.mts) {
-        await Promise.all(
-          collection.fragments.map(async fragmentId => {
-            const fragment = await models.Fragment.find(fragmentId)
-            const fragmentHelper = new Fragment({ fragment })
+  const notification = new Notification({
+    fragment,
+    collection,
+    newRecommendation,
+    UserModel: models.User,
+    baseUrl: services.getBaseUrl(req),
+  })
 
-            let fragmentUsers = []
-            try {
-              fragmentUsers = await fragmentHelper.getReviewersAndEditorsData({
-                collection,
-                UserModel: models.User,
-              })
+  const strategies = {
+    he: {
+      reject: rejectAsHE,
+      publish: publishAsHE,
+      major: requestRevisionAsHE,
+      minor: requestRevisionAsHE,
+    },
+    eic: {
+      reject: rejectAsEiC,
+      publish: publishAsEiC,
+      revision: requestRevisionAsEiC,
+      'return-to-handling-editor': returnToHE,
+    },
+  }
 
-              await sendMTSPackage({
-                collection,
-                fragment,
-                isEQA: true,
-                fragmentUsers,
-              })
-            } catch (e) {
-              logger.error(e)
-            }
-          }),
-        ).catch(e =>
-          res.status(500).json({
-            error: 'Something went wrong.',
-          }),
-        )
+  let role = ''
+  switch (recommendationType) {
+    case 'review':
+      role = 'reviewer'
+      try {
+        await createReview.execute({
+          userId,
+          fragmentHelper,
+          newRecommendation,
+        })
+      } catch (e) {
+        return res.status(400).json({ error: e.message })
       }
+      return res.status(200).json(newRecommendation)
+    case 'editorRecommendation':
+      role = isEditorInChief ? 'eic' : 'he'
+      break
+    default:
+      return res.status(400).json({
+        error: `Recommendation ${recommendation} is not defined.`,
+      })
+  }
 
-      collection.status = 'inQA'
-      set(collection, 'technicalChecks.token', v4())
-      set(collection, 'technicalChecks.eqa', false)
-      await collection.save()
-    }
-
-    /* if the EiC returns the manuscript to the HE after the EQA has been performed
-       then remove all properties from the technicalChecks property so that the manuscript
-       can go through the EQA process again
-    */
-    if (
-      isEditorInChief &&
-      recommendation === 'return-to-handling-editor' &&
-      hasEQA
-    ) {
-      collection.technicalChecks = {}
-      await collection.save()
-    }
-
-    const notification = new Notification({
-      fragment,
-      collection,
+  try {
+    await strategies[role][recommendation].execute({
+      userId,
+      models,
+      notification,
+      fragmentHelper,
+      collectionHelper,
       newRecommendation,
-      UserModel: models.User,
-      baseUrl: services.getBaseUrl(req),
     })
-
-    const hasPeerReview = !isEmpty(collection.handlingEditor)
-
-    if (isEditorInChief) {
-      if (recommendation === 'publish' && collection.status === 'inQA') {
-        notification.notifyEAWhenEiCRequestsEQAApproval()
-      }
-
-      if (recommendation === 'publish' && collection.status === 'accepted') {
-        notification.notifyEAWhenEiCMakesFinalDecision()
-      }
-
-      if (hasPeerReview && (recommendation !== 'publish' || hasEQA)) {
-        if (recommendation === 'return-to-handling-editor') {
-          notification.notifyHEWhenEiCReturnsToHE()
-        } else {
-          notification.notifyHEWhenEiCMakesDecision()
-          notification.notifyReviewersWhenEiCMakesDecision()
-        }
-      }
-
-      if (
-        recommendation !== 'return-to-handling-editor' &&
-        (recommendation !== 'publish' || hasEQA)
-      ) {
-        notification.notifyAuthorsWhenEiCMakesDecision()
-      }
-    } else {
-      if (collection.status === 'revisionRequested') {
-        notification.notifySAWhenHERequestsRevision()
-      }
-
-      if (hasPeerReview) {
-        notification.notifyReviewersWhenHEMakesRecommendation()
-        notification.notifyEiCWhenHEMakesRecommendation()
-      }
-    }
+  } catch (e) {
+    return res.status(400).json({ error: e.message })
   }
 
-  fragment.recommendations.push(newRecommendation)
-  fragment.save()
-
   return res.status(200).json(newRecommendation)
 }
-
-const sendMTSPackage = async ({
-  fragment,
-  collection,
-  isEQA = false,
-  fragmentUsers = [],
-}) => {
-  const s3Config = get(config, 'pubsweet-component-aws-s3', {})
-  const mtsConfig = get(config, 'mts-service', {})
-  const { sendPackage } = require('pubsweet-component-mts-package')
-
-  const { journal, xmlParser, ftp } = mtsConfig
-  const packageFragment = {
-    ...fragment,
-    metadata: {
-      ...fragment.metadata,
-      customId: collection.customId,
-    },
-  }
-
-  await sendPackage({
-    isEQA,
-    s3Config,
-    fragmentUsers,
-    ftpConfig: ftp,
-    config: journal,
-    options: xmlParser,
-    fragment: packageFragment,
-  })
-}
diff --git a/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/strategies/eicPublish.js b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/strategies/eicPublish.js
new file mode 100644
index 0000000000000000000000000000000000000000..6915c54324dbaa41b6d1aea25c4634c333940d5a
--- /dev/null
+++ b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/strategies/eicPublish.js
@@ -0,0 +1,45 @@
+const config = require('config')
+
+const { features = {} } = config
+
+module.exports = {
+  execute: async ({
+    models,
+    notification,
+    fragmentHelper,
+    collectionHelper,
+    newRecommendation,
+  }) => {
+    const latestRecommendation = fragmentHelper.getLatestRecommendation()
+    if (latestRecommendation.recommendation === 'return-to-handling-editor') {
+      throw new Error(
+        'Cannot make decision to publish after the manuscript has been returned to Handling Editor.',
+      )
+    }
+
+    await fragmentHelper.addRecommendation(newRecommendation)
+
+    let newStatus = ''
+    if (collectionHelper.hasEQA()) {
+      newStatus = 'accepted'
+      notification.notifyEAWhenEiCMakesFinalDecision()
+      notification.notifyAuthorsWhenEiCMakesDecision()
+      notification.notifyHEWhenEiCMakesDecision()
+      notification.notifyReviewersWhenEiCMakesDecision()
+    } else {
+      if (features.mts) {
+        await collectionHelper.sendToMTS({
+          fragmentHelper,
+          UserModel: models.User,
+          FragmentModel: models.Fragment,
+        })
+      }
+
+      newStatus = 'inQA'
+      await collectionHelper.setTechnicalChecks()
+      notification.notifyEAWhenEiCRequestsEQAApproval()
+    }
+
+    await collectionHelper.updateStatus({ newStatus })
+  },
+}
diff --git a/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/strategies/eicReject.js b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/strategies/eicReject.js
new file mode 100644
index 0000000000000000000000000000000000000000..b10ff0e2a46b93c6d56e85ab0d30f2e345d7f1dd
--- /dev/null
+++ b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/strategies/eicReject.js
@@ -0,0 +1,19 @@
+module.exports = {
+  execute: async ({
+    notification,
+    fragmentHelper,
+    collectionHelper,
+    newRecommendation,
+  }) => {
+    await fragmentHelper.addRecommendation(newRecommendation)
+    await collectionHelper.updateStatus({ newStatus: 'rejected' })
+
+    notification.notifyAuthorsWhenEiCMakesDecision()
+    if (collectionHelper.hasHandlingEditor()) {
+      notification.notifyHEWhenEiCMakesDecision()
+    }
+    if (fragmentHelper.hasReviewers()) {
+      notification.notifyReviewersWhenEiCMakesDecision()
+    }
+  },
+}
diff --git a/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/strategies/eicRequestRevision.js b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/strategies/eicRequestRevision.js
new file mode 100644
index 0000000000000000000000000000000000000000..0f66d8af7163765974379ceee97f12b887cbae5b
--- /dev/null
+++ b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/strategies/eicRequestRevision.js
@@ -0,0 +1,19 @@
+module.exports = {
+  execute: async ({
+    fragmentHelper,
+    collectionHelper,
+    newRecommendation,
+    notification,
+  }) => {
+    if (collectionHelper.hasHandlingEditor()) {
+      throw new Error(
+        'Cannot make request a revision after a Handling Editor has been assigned.',
+      )
+    }
+
+    await fragmentHelper.addRevision()
+    await collectionHelper.updateStatus({ newStatus: 'revisionRequested' })
+    await fragmentHelper.addRecommendation(newRecommendation)
+    await notification.notifySAWhenEiCRequestsRevision()
+  },
+}
diff --git a/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/strategies/eicReturnToHE.js b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/strategies/eicReturnToHE.js
new file mode 100644
index 0000000000000000000000000000000000000000..633d9c1b8c61065ed65841f9c43c9c250cfa7424
--- /dev/null
+++ b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/strategies/eicReturnToHE.js
@@ -0,0 +1,22 @@
+module.exports = {
+  execute: async ({
+    notification,
+    fragmentHelper,
+    collectionHelper,
+    newRecommendation,
+  }) => {
+    const latestRecommendation = fragmentHelper.getLatestRecommendation()
+    if (latestRecommendation.recommendation === 'return-to-handling-editor') {
+      throw new Error('Cannot return to Handling Editor again.')
+    }
+
+    if (collectionHelper.hasEQA()) {
+      await collectionHelper.removeTechnicalChecks()
+    }
+    await collectionHelper.updateStatus({ newStatus: 'reviewCompleted' })
+
+    await fragmentHelper.addRecommendation(newRecommendation)
+
+    notification.notifyHEWhenEiCReturnsToHE()
+  },
+}
diff --git a/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/strategies/hePublish.js b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/strategies/hePublish.js
new file mode 100644
index 0000000000000000000000000000000000000000..238efbc141b40fda46e5c048afb3e9031a8213fb
--- /dev/null
+++ b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/strategies/hePublish.js
@@ -0,0 +1,31 @@
+module.exports = {
+  execute: async ({
+    userId,
+    notification,
+    fragmentHelper,
+    collectionHelper,
+    newRecommendation,
+  }) => {
+    const fragments = await collectionHelper.collection.getFragments()
+
+    if (!collectionHelper.canHEMakeRecommendation(fragments, fragmentHelper)) {
+      throw new Error('Cannot publish without at least one reviewer report.')
+    }
+
+    const latestUserRecommendation = fragmentHelper.getLatestUserRecommendation(
+      userId,
+    )
+    if (
+      latestUserRecommendation &&
+      !fragmentHelper.canHEMakeAnotherRecommendation(latestUserRecommendation)
+    ) {
+      throw new Error('Cannot make another recommendation on this version.')
+    }
+
+    await fragmentHelper.addRecommendation(newRecommendation)
+    await collectionHelper.updateStatus({ newStatus: 'pendingApproval' })
+
+    notification.notifyReviewersWhenHEMakesRecommendation()
+    notification.notifyEiCWhenHEMakesRecommendation()
+  },
+}
diff --git a/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/strategies/heReject.js b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/strategies/heReject.js
new file mode 100644
index 0000000000000000000000000000000000000000..cd76a8beba735d8ef668dec8c3baef86ebbcaa41
--- /dev/null
+++ b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/strategies/heReject.js
@@ -0,0 +1,27 @@
+module.exports = {
+  execute: async ({
+    userId,
+    notification,
+    fragmentHelper,
+    collectionHelper,
+    newRecommendation,
+  }) => {
+    const latestUserRecommendation = fragmentHelper.getLatestUserRecommendation(
+      userId,
+    )
+    if (
+      latestUserRecommendation &&
+      !fragmentHelper.canHEMakeAnotherRecommendation(latestUserRecommendation)
+    ) {
+      throw new Error('Cannot make another recommendation on this version.')
+    }
+
+    await fragmentHelper.addRecommendation(newRecommendation)
+    await collectionHelper.updateStatus({ newStatus: 'pendingApproval' })
+
+    if (fragmentHelper.hasReviewers()) {
+      notification.notifyReviewersWhenHEMakesRecommendation()
+    }
+    notification.notifyEiCWhenHEMakesRecommendation()
+  },
+}
diff --git a/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/strategies/heRequestRevision.js b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/strategies/heRequestRevision.js
new file mode 100644
index 0000000000000000000000000000000000000000..7daeb25d9e400a02de63c8693d1c99a48e02e0c5
--- /dev/null
+++ b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/strategies/heRequestRevision.js
@@ -0,0 +1,30 @@
+module.exports = {
+  execute: async ({
+    userId,
+    notification,
+    fragmentHelper,
+    collectionHelper,
+    newRecommendation,
+  }) => {
+    const latestUserRecommendation = fragmentHelper.getLatestUserRecommendation(
+      userId,
+    )
+    if (
+      latestUserRecommendation &&
+      !fragmentHelper.canHEMakeAnotherRecommendation(latestUserRecommendation)
+    ) {
+      throw new Error('Cannot make another recommendation on this version.')
+    }
+
+    await fragmentHelper.addRevision()
+    await collectionHelper.updateStatus({ newStatus: 'revisionRequested' })
+    await fragmentHelper.addRecommendation(newRecommendation)
+
+    notification.notifySAWhenHERequestsRevision()
+    notification.notifyEiCWhenHEMakesRecommendation()
+
+    if (fragmentHelper.hasReviewers()) {
+      notification.notifyReviewersWhenHEMakesRecommendation()
+    }
+  },
+}
diff --git a/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/strategies/reviewerCreateReview.js b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/strategies/reviewerCreateReview.js
new file mode 100644
index 0000000000000000000000000000000000000000..9b8f450e33a9597a1b25b59f964392cc2befe3b9
--- /dev/null
+++ b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/strategies/reviewerCreateReview.js
@@ -0,0 +1,9 @@
+module.exports = {
+  execute: async ({ fragmentHelper, newRecommendation, userId }) => {
+    if (fragmentHelper.getLatestUserRecommendation(userId)) {
+      throw new Error('Cannot write another review on this version.')
+    }
+
+    await fragmentHelper.addRecommendation(newRecommendation)
+  },
+}
diff --git a/packages/component-manuscript-manager/src/tests/collections/get.test.js b/packages/component-manuscript-manager/src/tests/collections/get.test.js
index b721805c99c9b00833fcb953cc16f5a529840164..7ad0c1284762c4173c9b7e948fb2d273233eb166 100644
--- a/packages/component-manuscript-manager/src/tests/collections/get.test.js
+++ b/packages/component-manuscript-manager/src/tests/collections/get.test.js
@@ -36,7 +36,7 @@ describe('Get collections route handler', () => {
     expect(res.statusCode).toBe(200)
     const data = JSON.parse(res._getData())
 
-    expect(data).toHaveLength(1)
+    expect(data).toHaveLength(handlingEditor.teams.length)
     expect(data[0].type).toEqual('collection')
     expect(data[0]).toHaveProperty('currentVersion')
     expect(data[0]).toHaveProperty('visibleStatus')
@@ -60,7 +60,6 @@ describe('Get collections route handler', () => {
     const data = JSON.parse(res._getData())
     expect(data).toHaveLength(2)
     expect(data[0].type).toEqual('collection')
-    expect(data[0].currentVersion.recommendations).toHaveLength(6)
     expect(data[0].currentVersion.authors[0]).not.toHaveProperty('email')
   })
 
diff --git a/packages/component-manuscript-manager/src/tests/fragments/patch.test.js b/packages/component-manuscript-manager/src/tests/fragments/patch.test.js
index be867cbe7df7674d91c619d7837a94ed08e808e6..b6cb60fb809b12c4b399ef3b38f912ecd7c99974 100644
--- a/packages/component-manuscript-manager/src/tests/fragments/patch.test.js
+++ b/packages/component-manuscript-manager/src/tests/fragments/patch.test.js
@@ -83,7 +83,7 @@ describe('Patch fragments route handler', () => {
     const data = JSON.parse(res._getData())
     expect(data.error).toEqual('Item not found')
   })
-  it('should return an error when no HE recommendation exists', async () => {
+  it('should return an error when no HE request to revision exists', async () => {
     const { user } = testFixtures.users
     const { fragment } = testFixtures.fragments
     const { collection } = testFixtures.collections
@@ -171,4 +171,53 @@ describe('Patch fragments route handler', () => {
     const data = JSON.parse(res._getData())
     expect(data.error).toEqual('Unauthorized.')
   })
+  it('should return an error when no EiC request to revision exists', async () => {
+    const { user } = testFixtures.users
+    const { fragment } = testFixtures.fragments
+    const { collection } = testFixtures.collections
+    fragment.recommendations.length = 0
+    delete collection.handlingEditor
+
+    const res = await requests.sendRequest({
+      body,
+      userId: user.id,
+      models,
+      route,
+      path,
+      params: {
+        collectionId: collection.id,
+        fragmentId: fragment.id,
+      },
+    })
+
+    expect(res.statusCode).toBe(400)
+    const data = JSON.parse(res._getData())
+    expect(data.error).toEqual(
+      'No Editor in Chief request to revision has been found.',
+    )
+  })
+  it('should return success when an EiC request to revision exists', async () => {
+    const { user } = testFixtures.users
+    const { fragment } = testFixtures.fragments
+    const { collection } = testFixtures.collections
+
+    delete collection.handlingEditor
+
+    const res = await requests.sendRequest({
+      body,
+      userId: user.id,
+      models,
+      route,
+      path,
+      params: {
+        collectionId: collection.id,
+        fragmentId: fragment.id,
+      },
+    })
+
+    expect(res.statusCode).toBe(200)
+    const data = JSON.parse(res._getData())
+    expect(data).toHaveProperty('submitted')
+    expect(collection.status).toBe('submitted')
+  })
 })
diff --git a/packages/component-manuscript-manager/src/tests/fragmentsRecommendations/post.test.js b/packages/component-manuscript-manager/src/tests/fragmentsRecommendations/post.test.js
index 5638eb69ff3be3a1a164b0226377f6c38d7f0486..409e5238ef0062715a53031633e33413f27dcbf5 100644
--- a/packages/component-manuscript-manager/src/tests/fragmentsRecommendations/post.test.js
+++ b/packages/component-manuscript-manager/src/tests/fragmentsRecommendations/post.test.js
@@ -63,6 +63,7 @@ describe('Post fragments recommendations route handler', () => {
     const { reviewer } = testFixtures.users
     const { collection } = testFixtures.collections
     const { fragment } = testFixtures.fragments
+    body.recommendationType = 'review'
 
     const res = await requests.sendRequest({
       body,
@@ -102,7 +103,7 @@ describe('Post fragments recommendations route handler', () => {
     expect(data.userId).toEqual(noRecommendationHE.id)
   })
 
-  it('should return an error when creating a recommendation with publish as a HE when there is a single version and there are no reviews.', async () => {
+  it('should return an error when recommending to publish as HE when there is a single version and there are no reviews.', async () => {
     const { handlingEditor } = testFixtures.users
     const { collection } = testFixtures.collections
     const { fragment } = testFixtures.fragments
@@ -129,52 +130,45 @@ describe('Post fragments recommendations route handler', () => {
   })
 
   it('should return success when creating a recommendation as a HE after minor revision and we have at least one review on collection.', async () => {
-    const { handlingEditor } = testFixtures.users
-    const { collection } = testFixtures.collections
+    const { handlingEditor: { id: userId } } = testFixtures.users
     const {
-      minorRevisionWithReview,
-      noInvitesFragment1,
-    } = testFixtures.fragments
+      minorRevisionCollection: { id: collectionId },
+    } = testFixtures.collections
+    const { noInvitesFragment1: { id: fragmentId } } = testFixtures.fragments
 
-    collection.fragments = [minorRevisionWithReview.id, noInvitesFragment1.id]
     const res = await requests.sendRequest({
       body,
-      userId: handlingEditor.id,
+      userId,
       models,
       route,
       path,
       params: {
-        collectionId: collection.id,
-        fragmentId: noInvitesFragment1.id,
+        collectionId,
+        fragmentId,
       },
     })
 
     expect(res.statusCode).toBe(200)
     const data = JSON.parse(res._getData())
-    expect(data.userId).toEqual(handlingEditor.id)
+    expect(data.userId).toEqual(userId)
   })
 
   it('should return error when creating a recommendation as a HE after minor revision and there are no reviews.', async () => {
-    const { handlingEditor } = testFixtures.users
-    const { collection } = testFixtures.collections
+    const { handlingEditor: { id: userId } } = testFixtures.users
     const {
-      minorRevisionWithoutReview,
-      noInvitesFragment1,
-    } = testFixtures.fragments
-
-    collection.fragments = [
-      minorRevisionWithoutReview.id,
-      noInvitesFragment1.id,
-    ]
+      minorRevisionWithoutReviewCollection: { id: collectionId },
+    } = testFixtures.collections
+    const { noInvitesFragment1: { id: fragmentId } } = testFixtures.fragments
+
     const res = await requests.sendRequest({
       body,
-      userId: handlingEditor.id,
+      userId,
       models,
       route,
       path,
       params: {
-        collectionId: collection.id,
-        fragmentId: noInvitesFragment1.id,
+        collectionId,
+        fragmentId,
       },
     })
 
@@ -186,53 +180,46 @@ describe('Post fragments recommendations route handler', () => {
   })
 
   it('should return success when creating a recommendation as a HE after major revision and there are least one review on fragment.', async () => {
-    const { handlingEditor } = testFixtures.users
-    const { collection } = testFixtures.collections
+    const { handlingEditor: { id: userId } } = testFixtures.users
     const {
-      majorRevisionWithReview,
-      reviewCompletedFragment,
-    } = testFixtures.fragments
-
-    reviewCompletedFragment.collectionId = collection.id
-    collection.fragments = [
-      majorRevisionWithReview.id,
-      reviewCompletedFragment.id,
-    ]
+      majorRevisionCollection: { id: collectionId },
+    } = testFixtures.collections
+    const { reviewCompletedFragment } = testFixtures.fragments
+
+    reviewCompletedFragment.collectionId = collectionId
     const res = await requests.sendRequest({
       body,
-      userId: handlingEditor.id,
+      userId,
       models,
       route,
       path,
       params: {
-        collectionId: collection.id,
+        collectionId,
         fragmentId: reviewCompletedFragment.id,
       },
     })
 
     expect(res.statusCode).toBe(200)
     const data = JSON.parse(res._getData())
-    expect(data.userId).toEqual(handlingEditor.id)
+    expect(data.userId).toEqual(userId)
   })
 
   it('should return error when creating a recommendation as a HE after major revision there are no reviews on fragment.', async () => {
-    const { handlingEditor } = testFixtures.users
-    const { collection } = testFixtures.collections
+    const { handlingEditor: { id: userId } } = testFixtures.users
     const {
-      majorRevisionWithReview,
-      noInvitesFragment1,
-    } = testFixtures.fragments
+      majorRevisionWithoutReviewCollection: { id: collectionId },
+    } = testFixtures.collections
+    const { noInvitesFragment1: { id: fragmentId } } = testFixtures.fragments
 
-    collection.fragments = [majorRevisionWithReview.id, noInvitesFragment1.id]
     const res = await requests.sendRequest({
       body,
-      userId: handlingEditor.id,
+      userId,
       models,
       route,
       path,
       params: {
-        collectionId: collection.id,
-        fragmentId: noInvitesFragment1.id,
+        collectionId,
+        fragmentId,
       },
     })
 
@@ -445,9 +432,6 @@ describe('Post fragments recommendations route handler', () => {
     body.recommendationType = 'editorRecommendation'
     body.comments = 'This needs more work'
 
-    delete fragment.recommendations
-    delete fragment.revision
-    delete fragment.invitations
     collection.technicalChecks.eqa = false
 
     const res = await requests.sendRequest({
@@ -464,7 +448,6 @@ describe('Post fragments recommendations route handler', () => {
 
     expect(res.statusCode).toBe(200)
     const data = JSON.parse(res._getData())
-
     expect(collection.status).toBe('reviewCompleted')
     expect(collection.technicalChecks).not.toHaveProperty('token')
     expect(collection.technicalChecks).not.toHaveProperty('eqa')
@@ -643,4 +626,55 @@ describe('Post fragments recommendations route handler', () => {
       'Cannot make a recommendation on an older version.',
     )
   })
+  it('should return success when an EiC requests a revision before the Handling Editor is assigned', async () => {
+    const { editorInChief } = testFixtures.users
+    const { collection } = testFixtures.collections
+    const { fragment } = testFixtures.fragments
+    body.recommendation = 'revision'
+    body.recommendationType = 'editorRecommendation'
+    delete collection.handlingEditor
+
+    const res = await requests.sendRequest({
+      body,
+      userId: editorInChief.id,
+      models,
+      route,
+      path,
+      params: {
+        collectionId: collection.id,
+        fragmentId: fragment.id,
+      },
+    })
+
+    expect(res.statusCode).toBe(200)
+    const data = JSON.parse(res._getData())
+    expect(data.userId).toEqual(editorInChief.id)
+    expect(collection.status).toEqual('revisionRequested')
+    expect(fragment).toHaveProperty('revision')
+  })
+  it('should return an error when an EiC requests a revision after a Handling Editor is assigned', async () => {
+    const { editorInChief } = testFixtures.users
+    const { collection } = testFixtures.collections
+    const { fragment } = testFixtures.fragments
+    body.recommendation = 'revision'
+    body.recommendationType = 'editorRecommendation'
+
+    const res = await requests.sendRequest({
+      body,
+      userId: editorInChief.id,
+      models,
+      route,
+      path,
+      params: {
+        collectionId: collection.id,
+        fragmentId: fragment.id,
+      },
+    })
+
+    expect(res.statusCode).toBe(400)
+    const data = JSON.parse(res._getData())
+    expect(data.error).toEqual(
+      'Cannot make request a revision after a Handling Editor has been assigned.',
+    )
+  })
 })
diff --git a/packages/component-manuscript/src/components/ManuscriptLayout.js b/packages/component-manuscript/src/components/ManuscriptLayout.js
index 5f870ecfa43fe24b4886780c6a78feaf2f0d675b..868b408304a4537d0d39affe98fabaeb3e0c3ff5 100644
--- a/packages/component-manuscript/src/components/ManuscriptLayout.js
+++ b/packages/component-manuscript/src/components/ManuscriptLayout.js
@@ -24,6 +24,7 @@ import ReviewerReports from './ReviewerReports'
 const messagesLabel = {
   'return-to-handling-editor': 'Comments for Handling Editor',
   reject: 'Comments for Author',
+  revision: 'Comments for Author',
 }
 
 const cannotViewReviewersDetails = ['revisionRequested', 'pendingApproval']
diff --git a/packages/component-mts-package/src/MTS.js b/packages/component-mts-package/src/MTS.js
index 3f9e503df78bbf5d3273f0e7e19dd4d3c764b1e1..4b9cdadfcd4ce88fcebde24378b9b5ab6c527a7d 100644
--- a/packages/component-mts-package/src/MTS.js
+++ b/packages/component-mts-package/src/MTS.js
@@ -38,17 +38,21 @@ module.exports = {
       fragment,
       xmlFile,
       isEQA,
-    }).then(() => {
-      const packageName = get(xmlFile, 'name', '').replace('.xml', '')
-      const filename = isEQA
-        ? `ACCEPTED_${packageName}.${fragment.version}.zip`
-        : `${packageName}.zip`
+    })
+      .then(() => {
+        const packageName = get(xmlFile, 'name', '').replace('.xml', '')
+        const filename = isEQA
+          ? `ACCEPTED_${packageName}.${fragment.version}.zip`
+          : `${packageName}.zip`
 
-      return PackageManager.uploadFiles({
-        filename,
-        s3Config,
-        config: ftpConfig,
+        return PackageManager.uploadFiles({
+          filename,
+          s3Config,
+          config: ftpConfig,
+        })
+      })
+      .catch(e => {
+        throw new Error(e)
       })
-    })
   },
 }
diff --git a/packages/xpub-faraday/app/config/journal/recommendations.js b/packages/xpub-faraday/app/config/journal/recommendations.js
index 736effd199a5801309f3fe4e1a4f622c88cc33ad..99b50aa2d2eba35e06e7a127dd19a6631eed2b69 100644
--- a/packages/xpub-faraday/app/config/journal/recommendations.js
+++ b/packages/xpub-faraday/app/config/journal/recommendations.js
@@ -15,4 +15,8 @@ module.exports = [
     value: 'reject',
     label: 'Reject',
   },
+  {
+    value: 'revision',
+    label: 'Revision',
+  },
 ]
diff --git a/packages/xpub-faraday/config/validations.js b/packages/xpub-faraday/config/validations.js
index 6d1ac18d402b9baa6333ed22f7cfbe5d2f566cdf..c60e5f85015904e4218550b1d78ab84567d28d33 100644
--- a/packages/xpub-faraday/config/validations.js
+++ b/packages/xpub-faraday/config/validations.js
@@ -126,6 +126,7 @@ module.exports = {
             'reject',
             'publish',
             'revise',
+            'revision',
             'major',
             'minor',
             'return-to-handling-editor',
diff --git a/packages/xpub-faraday/tests/config/authsome-helpers.test.js b/packages/xpub-faraday/tests/config/authsome-helpers.test.js
index 41fa760afb11a7bb0cb7896549aa19151e3ce79a..10571579af13e2834aa58b9ca6a4f7fe72971397 100644
--- a/packages/xpub-faraday/tests/config/authsome-helpers.test.js
+++ b/packages/xpub-faraday/tests/config/authsome-helpers.test.js
@@ -167,7 +167,7 @@ describe('Authsome Helpers', () => {
         user: answerReviewer,
       })
       const { recommendations } = result
-      expect(recommendations).toHaveLength(7)
+      expect(recommendations).toHaveLength(8)
     })
 
     it('reviewer should not see other reviewers recommendations on latest fragment', () => {
@@ -181,7 +181,7 @@ describe('Authsome Helpers', () => {
         user: answerReviewer,
       })
       const { recommendations } = result
-      expect(recommendations).toHaveLength(6)
+      expect(recommendations).toHaveLength(7)
     })
 
     it('reviewer should not see any reviewer recommendation on previous version if he did not submit a review on that fragment', () => {