diff --git a/packages/component-email-templating/README.md b/packages/component-email-templating/README.md
index 7bb4beb6968da7e1f6eea8f912d37369b15c8786..0249e6568fcda89d746eee9ed34478112184fdbe 100644
--- a/packages/component-email-templating/README.md
+++ b/packages/component-email-templating/README.md
@@ -56,13 +56,15 @@ The `Email` class also provides a `constructor` whose properties will be used wh
     ![notification](https://gitlab.coko.foundation/xpub/xpub-faraday/uploads/27cb6acc8ff4a07758f55e5ea0504d28/notification.png)
 
     ```javascript
-    const emailTemplate = require('@pubsweet/component-email-template')
+    const EmailTemplate = require('@pubsweet/component-email-template')
     const config = require('config')
 
     const { name: journalName, fromEmail: staffEmail } = config.get('journal')
+    
+    const paragraph = `We are please to inform you that the manuscript has passed the technical check process and is now submitted. Please click the link below to access the manuscript.`
 
     const sendNotifications = ({ user, editor, collection, fragment }) => {
-      const email = new emailTemplate({
+      const email = new EmailTemplate({
         type: 'user',
         fromEmail,
         toUser: {
@@ -74,18 +76,19 @@ The `Email` class also provides a `constructor` whose properties will be used wh
           signatureJournal: journalName,
           signatureName: `${editor.name}`,
           subject: `${collection.customId}: Manuscript Update`,
+          paragraph,
           unsubscribeLink: `http://localhost:3000/unsubscribe/${user.id}`,
           ctaLink: `http://localhost:3000/projects/${collection.id}/versions/${
             fragment.id
           }/details`,
         },
+        bodyProps: {
+          hasLink: true,
+          hasIntro: true,
+          hasSignature: true }
       })
 
-      const paragraph = `We are please to inform you that the manuscript has passed the technical check process and is now submitted. Please click the link below to access the manuscript.`
-
-      const { html, text } = email.getNotificationBody({ emailBodyProps: { paragraph, hasLink: true, hasIntro: true, hasSignature: true }})
-
-      email.sendEmail({ html, text })
+      return email.sendEmail()
     }
     ```
 
diff --git a/packages/component-email-templating/src/EmailTemplate.js b/packages/component-email-templating/src/EmailTemplate.js
index 6c08722790cb83b9265917a2950ff56b56919216..ebffbc334d108fc7877c38938b61b1010cd5b263 100644
--- a/packages/component-email-templating/src/EmailTemplate.js
+++ b/packages/component-email-templating/src/EmailTemplate.js
@@ -1,6 +1,7 @@
 const config = require('config')
-const helpers = require('./helpers')
+const htmlTemplateService = require('./HTMLTemplateService')
 const SendEmail = require('@pubsweet/component-send-email')
+const logger = require('@pubsweet/logger')
 
 const configData = {
   logo: config.get('journal.logo'),
@@ -10,9 +11,10 @@ const configData = {
   logoLink: config.get('journal.logoLink'),
   publisher: config.get('journal.publisher'),
 }
-class Email {
+class EmailTemplate {
   constructor({
     type = 'system',
+    templateType = 'notification',
     fromEmail = config.get('journal.staffEmail'),
     toUser = {
       id: '',
@@ -23,15 +25,19 @@ class Email {
       subject: '',
       ctaLink: '',
       ctaText: '',
+      paragraph: '',
       signatureName: '',
       unsubscribeLink: '',
       signatureJournal: '',
     },
+    bodyProps = { hasLink: false, hasIntro: false, hasSignature: false },
   }) {
     this.type = type
     this.toUser = toUser
     this.content = content
+    this.bodyProps = bodyProps
     this.fromEmail = fromEmail
+    this.templateType = templateType
   }
 
   set _toUser(newToUser) {
@@ -46,41 +52,49 @@ class Email {
     this.content = newContent
   }
 
-  getInvitationBody({ emailBodyProps }) {
+  _getInvitationBody() {
     return {
-      html: helpers.getCompiledInvitationBody({
+      html: htmlTemplateService.getCompiledInvitationBody({
         replacements: {
           ...configData,
           ...this.content,
-          ...emailBodyProps,
+          ...this.bodyProps,
           toEmail: this.toUser.email,
           toUserName: this.toUser.name,
         },
       }),
-      text: `${emailBodyProps.resend} ${emailBodyProps.upperContent} ${
-        emailBodyProps.manuscriptText
-      } ${emailBodyProps.lowerContent} ${this.content.signatureName}`,
+      text: `${this.bodyProps.resend} ${this.bodyProps.upperContent} ${
+        this.bodyProps.manuscriptText
+      } ${this.bodyProps.lowerContent} ${this.content.signatureName}`,
     }
   }
 
-  getNotificationBody({ emailBodyProps }) {
+  _getNotificationBody() {
     return {
-      html: helpers.getCompiledNotificationBody({
+      html: htmlTemplateService.getCompiledNotificationBody({
         replacements: {
           ...configData,
           ...this.content,
-          ...emailBodyProps,
+          ...this.bodyProps,
           toEmail: this.toUser.email,
           toUserName: this.toUser.name,
         },
       }),
-      text: `${emailBodyProps.paragraph} ${this.content.ctaLink} ${
+      text: `${this.content.paragraph} ${this.content.ctaLink} ${
         this.content.ctaText
       } ${this.content.signatureName}`,
     }
   }
 
-  async sendEmail({ text, html }) {
+  _getEmailTemplate() {
+    return this.templateType === 'notification'
+      ? this._getNotificationBody()
+      : this._getInvitationBody()
+  }
+
+  async sendEmail() {
+    const { html, text } = this._getEmailTemplate()
+
     const { fromEmail: from } = this
     const { email: to } = this.toUser
     const { subject } = this.content
@@ -95,10 +109,17 @@ class Email {
 
     try {
       await SendEmail.send(mailData)
+      logger.info(
+        `Sent email from: ${from} to: ${to} with subject: "${subject}"`,
+      )
+      logger.debug(
+        `Sent email from: ${from} to: ${to} with subject: "${subject}"`,
+      )
     } catch (e) {
+      logger.error(e)
       throw new Error(e)
     }
   }
 }
 
-module.exports = Email
+module.exports = EmailTemplate
diff --git a/packages/component-email-templating/src/helpers.js b/packages/component-email-templating/src/HTMLTemplateService.js
similarity index 90%
rename from packages/component-email-templating/src/helpers.js
rename to packages/component-email-templating/src/HTMLTemplateService.js
index 8df0e7950b1093bd8df9e03fa096f48d26232644..6dc314521e5533c7fda4166de3726ee3c5c21980 100644
--- a/packages/component-email-templating/src/helpers.js
+++ b/packages/component-email-templating/src/HTMLTemplateService.js
@@ -24,14 +24,7 @@ const getCompiledInvitationBody = ({ replacements }) => {
   return compileBody({ fileName: 'invitation', context: replacements })
 }
 
-const readFile = path =>
-  fs.readFileSync(path, { encoding: 'utf-8' }, (err, file) => {
-    if (err) {
-      throw err
-    } else {
-      return file
-    }
-  })
+const readFile = path => fs.readFileSync(path, 'utf-8')
 
 const handlePartial = (partialName, context = {}) => {
   let partial = readFile(`${__dirname}/templates/partials/${partialName}.hbs`)
diff --git a/packages/component-email-templating/src/templates/partials/invButtons.hbs b/packages/component-email-templating/src/templates/partials/invButtons.hbs
index 7611dc03e966d4e9146cda5bd9b6a535b17ace3d..8deceffee7a2080bd626f746fc7959d815da5a67 100644
--- a/packages/component-email-templating/src/templates/partials/invButtons.hbs
+++ b/packages/component-email-templating/src/templates/partials/invButtons.hbs
@@ -12,7 +12,7 @@
       <td width="300.000px" valign="top" style="padding: 0px 0px 0px 0px;border-collapse: collapse;" >
     <![endif]-->
 
-      <table width="300.000" style="width:300.000px;border-spacing:0;border-collapse:collapse;margin:0px 0px 0px 0px;"
+      <table width="300.000" style="width:'50%';border-spacing:0;border-collapse:collapse;margin:0px 0px 0px 0px;"
         cellpadding="0" cellspacing="0" align="left" border="0" bgcolor="" class="column column-0 of-2
                   empty">
         <tr>
@@ -21,7 +21,7 @@
               role="module" style="table-layout:fixed" width="100%">
               <tbody>
                 <tr>
-                  <td align="center" class="outer-td" style="padding:0px 0px 0px 50px">
+                  <td align="center" class="outer-td padding-decline">
                     <table border="0" cellPadding="0" cellSpacing="0" class="button-css__deep-table___2OZyb wrapper-mobile"
                       style="text-align:center">
                       <tbody>
@@ -47,7 +47,7 @@
       <td width="300.000px" valign="top" style="padding: 0px 0px 0px 0px;border-collapse: collapse;" >
     <![endif]-->
 
-      <table width="300.000" style="width:300.000px;border-spacing:0;border-collapse:collapse;margin:0px 0px 0px 0px;"
+      <table width="300.000" style="width:'50%';border-spacing:0;border-collapse:collapse;margin:0px 0px 0px 0px;"
         cellpadding="0" cellspacing="0" align="left" border="0" bgcolor="" class="column column-1 of-2
                   empty">
         <tr>
@@ -56,7 +56,7 @@
               role="module" style="table-layout:fixed" width="100%">
               <tbody>
                 <tr>
-                  <td align="center" class="outer-td" style="padding:0px 50px 0px 0px">
+                  <td align="center" class="outer-td padding-agree">
                     <table border="0" cellPadding="0" cellSpacing="0" class="button-css__deep-table___2OZyb wrapper-mobile"
                       style="text-align:center">
                       <tbody>
diff --git a/packages/component-email-templating/src/templates/partials/invHeader.hbs b/packages/component-email-templating/src/templates/partials/invHeader.hbs
index d01a40ad4f0645427c966da91a011dbf8ea226a1..473d7b913b24bea5163c4e73aada31056acf8fe3 100644
--- a/packages/component-email-templating/src/templates/partials/invHeader.hbs
+++ b/packages/component-email-templating/src/templates/partials/invHeader.hbs
@@ -76,6 +76,14 @@
       text-decoration: none;
     }
 
+    .padding-decline {
+      padding:0px 0px 0px 50px;
+    }
+
+    .padding-agree {
+      padding:0px 50px 0px 0px;
+    }
+
     @media screen and (max-width:480px) {
 
       .preheader .rightColumnContent,
@@ -126,6 +134,14 @@
         margin-left: 0 !important;
         margin-right: 0 !important;
       }
+
+      .padding-decline {
+        padding: 0px;
+      }
+
+      .padding-agree {
+        padding: 10px 0px 0px 0px;
+      }
     }
   </style>
   <!--user entered Head Start-->
diff --git a/packages/component-email-templating/tests/helpers.test.js b/packages/component-email-templating/tests/HTMLTemplateService.test.js
similarity index 82%
rename from packages/component-email-templating/tests/helpers.test.js
rename to packages/component-email-templating/tests/HTMLTemplateService.test.js
index e655ec191cf012021e8de5ba690c88b0b5afbf38..f30ddf90902d5e14c49acf54dbae54c566b588f5 100644
--- a/packages/component-email-templating/tests/helpers.test.js
+++ b/packages/component-email-templating/tests/HTMLTemplateService.test.js
@@ -2,7 +2,7 @@ process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'
 process.env.SUPPRESS_NO_CONFIG_WARNING = true
 
 const { cloneDeep } = require('lodash')
-const helpers = require('../src/helpers')
+const htmlTemplateService = require('../src/HTMLTemplateService')
 
 const emailProps = {
   toUserName: 'Peter Griffin',
@@ -19,7 +19,7 @@ describe('Email template helpers', () => {
     replacements = cloneDeep(emailProps)
   })
   it('should return the notification HTML with CTA', () => {
-    const notificationBody = helpers.getCompiledNotificationBody({
+    const notificationBody = htmlTemplateService.getCompiledNotificationBody({
       replacements,
     })
 
@@ -32,7 +32,7 @@ describe('Email template helpers', () => {
 
   it('should return the notification HTML without CTA', () => {
     replacements.hasLink = false
-    const notificationBody = helpers.getCompiledNotificationBody({
+    const notificationBody = htmlTemplateService.getCompiledNotificationBody({
       replacements,
     })
     expect(notificationBody).toContain('Peter Griffin')
@@ -41,7 +41,7 @@ describe('Email template helpers', () => {
   })
   it('should return the notification HTML without intro', () => {
     replacements.hasIntro = false
-    const notificationBody = helpers.getCompiledNotificationBody({
+    const notificationBody = htmlTemplateService.getCompiledNotificationBody({
       replacements,
     })
     expect(notificationBody).not.toContain('Peter Griffin')
@@ -50,7 +50,7 @@ describe('Email template helpers', () => {
   })
   it('should return the notification HTML without signature', () => {
     replacements.hasSignature = false
-    const notificationBody = helpers.getCompiledNotificationBody({
+    const notificationBody = htmlTemplateService.getCompiledNotificationBody({
       replacements,
     })
     expect(notificationBody).toContain('Peter Griffin')
diff --git a/packages/component-email/src/routes/emails/emailCopy.js b/packages/component-email/src/routes/emails/emailCopy.js
index d14178be9815e574a83f2e16aefff8495e59affd..34900efe02066d5f4eaff9a081dfc670bfefad4a 100644
--- a/packages/component-email/src/routes/emails/emailCopy.js
+++ b/packages/component-email/src/routes/emails/emailCopy.js
@@ -3,8 +3,6 @@ const config = require('config')
 const journalName = config.get('journal.name')
 const getEmailCopy = ({ emailType, role }) => {
   let paragraph
-  const hasIntro = true
-  const hasSignature = true
   switch (emailType) {
     case 'user-signup':
       paragraph = `Thank you for creating an account on Hindawi’s review system.
@@ -23,7 +21,7 @@ const getEmailCopy = ({ emailType, role }) => {
       throw new Error(`The ${emailType} email type is not defined.`)
   }
 
-  return { paragraph, hasLink: true, hasIntro, hasSignature }
+  return { paragraph, hasLink: true, hasIntro: true, hasSignature: true }
 }
 
 module.exports = {
diff --git a/packages/component-email/src/routes/emails/helpers.js b/packages/component-email/src/routes/emails/helpers.js
deleted file mode 100644
index 35395e3da3bb1fac36c7d2006ca49122f955cb3e..0000000000000000000000000000000000000000
--- a/packages/component-email/src/routes/emails/helpers.js
+++ /dev/null
@@ -1,39 +0,0 @@
-const config = require('config')
-const { services } = require('pubsweet-component-helper-service')
-
-const { getEmailCopy } = require('./emailCopy')
-
-const confirmSignUp = config.get('confirm-signup.url')
-
-module.exports = {
-  sendNewUserEmail: ({ email, role }) => {
-    email.content.subject = 'Confirm your account'
-
-    const emailType =
-      role === 'Handling Editor' ? 'he-added-by-admin' : 'user-added-by-admin'
-
-    const { html, text } = email.getNotificationBody({
-      emailBodyProps: getEmailCopy({
-        role,
-        emailType,
-      }),
-    })
-
-    email.sendEmail({ html, text })
-  },
-  sendSignupEmail: ({ email, baseUrl, user }) => {
-    email.content.subject = 'Confirm your email address'
-    email.content.ctaLink = services.createUrl(baseUrl, confirmSignUp, {
-      userId: user.id,
-      confirmationToken: user.accessTokens.confirmation,
-    })
-
-    const { html, text } = email.getNotificationBody({
-      emailBodyProps: getEmailCopy({
-        emailType: 'user-signup',
-      }),
-    })
-
-    email.sendEmail({ html, text })
-  },
-}
diff --git a/packages/component-email/src/routes/emails/notifications.js b/packages/component-email/src/routes/emails/notifications.js
index 5fe6fc1183bef9386e5b8f811a0ee6084e1387b3..1ff2853be2d98e67d8fb2475e0c9a37bee71ab2f 100644
--- a/packages/component-email/src/routes/emails/notifications.js
+++ b/packages/component-email/src/routes/emails/notifications.js
@@ -1,15 +1,23 @@
 const config = require('config')
 
 const unsubscribeSlug = config.get('unsubscribe.url')
-const resetPath = config.get('invite-reset-password.url')
 const { staffEmail, name: journalName } = config.get('journal')
 const Email = require('@pubsweet/component-email-templating')
 const { services } = require('pubsweet-component-helper-service')
-
-const { sendNewUserEmail, sendSignupEmail } = require('./helpers')
+const { getEmailCopy } = require('./emailCopy')
 
 module.exports = {
-  async sendNotifications({ user, baseUrl, role }) {
+  sendNewUserEmail: ({ user, baseUrl, role }) => {
+    const resetPath = config.get('invite-reset-password.url')
+
+    const emailType =
+      role === 'Handling Editor' ? 'he-added-by-admin' : 'user-added-by-admin'
+
+    const { paragraph, ...bodyProps } = getEmailCopy({
+      role,
+      emailType,
+    })
+
     const email = new Email({
       type: 'user',
       fromEmail: `${journalName} <${staffEmail}>`,
@@ -18,6 +26,7 @@ module.exports = {
         name: `${user.lastName}`,
       },
       content: {
+        subject: 'Confirm your account',
         ctaLink: services.createUrl(baseUrl, resetPath, {
           email: user.email,
           token: user.accessTokens.passwordReset,
@@ -28,18 +37,49 @@ module.exports = {
           country: user.country,
         }),
         ctaText: 'CONFIRM ACCOUNT',
+        paragraph,
+        signatureName: 'Hindawi',
+        unsubscribeLink: services.createUrl(baseUrl, unsubscribeSlug, {
+          id: user.id,
+          token: user.accessTokens.unsubscribe,
+        }),
+      },
+      bodyProps,
+    })
+
+    return email.sendEmail()
+  },
+  sendSignupEmail: ({ user, baseUrl }) => {
+    const confirmSignUp = config.get('confirm-signup.url')
+
+    const { paragraph, ...bodyProps } = getEmailCopy({
+      emailType: 'user-signup',
+    })
+
+    const email = new Email({
+      type: 'user',
+      fromEmail: `${journalName} <${staffEmail}>`,
+      toUser: {
+        email: user.email,
+        name: `${user.lastName}`,
+      },
+      content: {
+        subject: 'Confirm your email address',
+        ctaLink: services.createUrl(baseUrl, confirmSignUp, {
+          userId: user.id,
+          confirmationToken: user.accessTokens.confirmation,
+        }),
+        ctaText: 'CONFIRM ACCOUNT',
+        paragraph,
         signatureName: 'Hindawi',
         unsubscribeLink: services.createUrl(baseUrl, unsubscribeSlug, {
           id: user.id,
           token: user.accessTokens.unsubscribe,
         }),
       },
+      bodyProps,
     })
 
-    if (role) {
-      sendNewUserEmail({ email, role })
-    } else {
-      sendSignupEmail({ email, baseUrl, user })
-    }
+    return email.sendEmail()
   },
 }
diff --git a/packages/component-email/src/routes/emails/post.js b/packages/component-email/src/routes/emails/post.js
index 246322fa3a7da378a16d3ade2b684c405b6ec5b8..67e071e283188b1ed038a3bdf02941ceff7ca862 100644
--- a/packages/component-email/src/routes/emails/post.js
+++ b/packages/component-email/src/routes/emails/post.js
@@ -16,53 +16,49 @@ module.exports = models => async (req, res) => {
     return res.status(400).json({ error: `Email type ${type} is not defined.` })
   }
 
-  const UserModel = models.User
-
+  let user
   try {
-    const user = await UserModel.findByEmail(email)
+    user = await models.User.findByEmail(email)
+  } catch (e) {
+    const notFoundError = await services.handleNotFoundError(e, 'User')
+    return res.status(notFoundError.status).json({
+      error: notFoundError.message,
+    })
+  }
 
-    if (type === 'signup') {
-      if (!user.accessTokens.confirmation) {
-        return res
-          .status(400)
-          .json({ error: 'User does not have a confirmation token.' })
-      }
+  if (type === 'signup') {
+    if (!user.accessTokens.confirmation) {
+      return res
+        .status(400)
+        .json({ error: 'User does not have a confirmation token.' })
     }
-
+    notifications.sendSignupEmail({ user, baseUrl: services.getBaseUrl(req) })
+  } else if (type === 'invite') {
     let emailRole
-    if (type === 'invite') {
-      switch (role) {
-        case 'handlingEditor':
-          emailRole = 'Handling Editor'
-          break
-        case 'editorInChief':
-          emailRole = 'Editor in Chief'
-          break
-        case 'admin':
-          emailRole = 'Administrator'
-          break
-        case 'author':
-          emailRole = 'Author'
-          break
-        default:
-          return res.status(400).json({
-            error: `Role ${role} is not defined.`,
-          })
-      }
+    switch (role) {
+      case 'handlingEditor':
+        emailRole = 'Handling Editor'
+        break
+      case 'editorInChief':
+        emailRole = 'Editor in Chief'
+        break
+      case 'admin':
+        emailRole = 'Administrator'
+        break
+      case 'author':
+        emailRole = 'Author'
+        break
+      default:
+        return res.status(400).json({
+          error: `Role ${role} is not defined.`,
+        })
     }
-
-    notifications.sendNotifications({
+    notifications.sendNewUserEmail({
       user,
-      role: emailRole,
-      UserModel: models.User,
       baseUrl: services.getBaseUrl(req),
-    })
-
-    return res.status(200).json({})
-  } catch (e) {
-    const notFoundError = await services.handleNotFoundError(e, 'User')
-    return res.status(notFoundError.status).json({
-      error: notFoundError.message,
+      role: emailRole,
     })
   }
+
+  return res.status(200).json({})
 }
diff --git a/packages/component-faraday-selectors/src/index.js b/packages/component-faraday-selectors/src/index.js
index 294058e27c0ed9a4636a5075bb6301aae1913a1a..868a670bd4a2db39005389eb4a5319fd7d06e828 100644
--- a/packages/component-faraday-selectors/src/index.js
+++ b/packages/component-faraday-selectors/src/index.js
@@ -1,5 +1,5 @@
 import { selectCurrentUser } from 'xpub-selectors'
-import { get, has, last, chain, some, isEmpty } from 'lodash'
+import { get, has, last, chain, some, isEmpty, slice, find } from 'lodash'
 
 export const isHEToManuscript = (state, collectionId = '') => {
   const { id = '', isAccepted = false } = chain(state)
@@ -48,6 +48,29 @@ export const canInviteReviewers = (state, collection = {}) => {
   return isAccepted && (userId === heId || isAdminEiC)
 }
 
+const canViewContextualBoxOnOldVersionStatuses = [
+  'submitted',
+  'heInvited',
+  'heAssigned',
+]
+const canViewContextualBoxOnOldVersion = (collection, fragmentId) => {
+  const fragments = get(collection, 'fragments', [])
+  const oldVersions = slice(fragments, 0, fragments.length - 1)
+  const isOldVersion = !!find(oldVersions, fragment => fragment === fragmentId)
+  return (
+    isOldVersion &&
+    canViewContextualBoxOnOldVersionStatuses.includes(
+      get(collection, 'status', 'draft'),
+    )
+  )
+}
+
+const canHEViewContextualBoxOnOldVersion = (collection, fragmentId) => {
+  const fragments = get(collection, 'fragments', [])
+  const oldVersions = slice(fragments, 0, fragments.length - 1)
+  const isOldVersion = !!find(oldVersions, fragment => fragment === fragmentId)
+  return isOldVersion && get(collection, 'status', 'draft') === 'heInvited'
+}
 const cannotViewReviewersDetails = [
   'draft',
   'technicalChecks',
@@ -66,8 +89,9 @@ export const canViewReviewersDetails = (state, collection = {}) => {
   return canViewReports(state, get(collection, 'id', ''))
 }
 
-const authorCanViewReportsDetailsStatuses = [
+const authorAndReviewersCanViewReportsDetailsStatuses = [
   'revisionRequested',
+  'underReview',
   'pendingApproval',
   'rejected',
   'accepted',
@@ -82,9 +106,27 @@ export const authorCanViewReportsDetails = (
 ) => {
   const isAuthor = currentUserIsAuthor(state, fragmentId)
   return (
-    authorCanViewReportsDetailsStatuses.includes(
+    isAuthor &&
+    (authorAndReviewersCanViewReportsDetailsStatuses.includes(
+      get(collection, 'status', 'draft'),
+    ) ||
+      canViewContextualBoxOnOldVersion(collection, fragmentId))
+  )
+}
+
+export const reviewersCanViewReviewerReports = (
+  state,
+  collection = {},
+  fragmentId,
+) => {
+  const isReviewer = currentUserIsReviewer(state, fragmentId)
+  const reviewerReports = getFragmentReviewerRecommendations(state, fragmentId)
+  return (
+    isReviewer &&
+    authorAndReviewersCanViewReportsDetailsStatuses.includes(
       get(collection, 'status', 'draft'),
-    ) && isAuthor
+    ) &&
+    reviewerReports.length > 0
   )
 }
 
@@ -175,8 +217,13 @@ export const canViewEditorialComments = (
     state,
     fragmentId,
   )
+  const isHE = currentUserIs(state, 'isHE')
+  const canViewEditorialCommentsOnOldVersion = isHE
+    ? !canHEViewContextualBoxOnOldVersion(collection, fragmentId)
+    : canViewContextualBoxOnOldVersion(collection, fragmentId)
   return (
-    (canHeViewEditorialComments(state, collection) ||
+    (canViewEditorialCommentsOnOldVersion ||
+      canHeViewEditorialComments(state, collection) ||
       canEICViewEditorialComments(state, collection) ||
       canReviewerViewEditorialComments(state, collection, fragment) ||
       canAuthorViewEditorialComments(state, collection, fragmentId)) &&
@@ -184,17 +231,22 @@ export const canViewEditorialComments = (
   )
 }
 
-const cannotViewResponseFromAuthorStatuses = ['reviewersInvited']
 export const canViewResponseFromAuthor = (state, collection, fragmentId) => {
   const authorResponseToRevisonRequest = getFragmentAuthorResponse(
     state,
     fragmentId,
   )
+  const canHEViewResponseFromAuthor =
+    currentUserIs(state, 'isHE') &&
+    get(collection, 'status', 'draft') === 'heInvited'
+
+  const canReviewerViewResponsefromAuthor =
+    currentUserIsReviewerInPending(state, fragmentId) &&
+    get(collection, 'status', 'draft') === 'reviewersInvited'
   return (
     !isEmpty(authorResponseToRevisonRequest) &&
-    !cannotViewResponseFromAuthorStatuses.includes(
-      get(collection, 'status', 'draft'),
-    )
+    !canHEViewResponseFromAuthor &&
+    !canReviewerViewResponsefromAuthor
   )
 }
 
@@ -229,6 +281,34 @@ export const canMakeDecision = (state, collection = {}) => {
   return isEIC && canMakeDecisionStatuses.includes(status)
 }
 
+const collectionReviewerReports = state =>
+  chain(state)
+    .get('fragments', {})
+    .map(r => get(r, 'recommendations', []))
+    .flatten()
+    .find(r => r.recommendationType === 'review' && r.submittedOn)
+    .value()
+
+const cannotHEMakeRecommendationToPublishStatuses = ['heInvited']
+export const canHEMakeRecommendationToPublish = (state, collection = {}) => {
+  const status = get(collection, 'status', 'draft')
+  return (
+    !!collectionReviewerReports(state) ||
+    cannotHEMakeRecommendationToPublishStatuses.includes(status)
+  )
+}
+
+const canHEOnlyRejectStatuses = [
+  'reviewersInvited',
+  'underReview',
+  'revisionRequested',
+]
+
+export const canHEOnlyReject = (collection = {}) => {
+  const { status } = collection
+  return canHEOnlyRejectStatuses.includes(status)
+}
+
 const canEditManuscriptStatuses = ['draft', 'technicalChecks', 'inQA']
 export const canEditManuscript = (state, collection = {}, fragment = {}) => {
   const isAdmin = currentUserIs(state, 'isAdmin')
@@ -297,6 +377,13 @@ export const pendingReviewerInvitation = (state, fragmentId) =>
     )
     .value()
 
+export const currentUserIsReviewerInPending = (state, fragmentId) => {
+  const currentUser = selectCurrentUser(state)
+  const invitations = get(state, `fragments.${fragmentId}.invitations`, [])
+  return !!invitations.find(
+    i => i.userId === currentUser.id && i.role === 'reviewer' && !i.isAccepted,
+  )
+}
 export const currentUserIsReviewer = (state, fragmentId) => {
   const currentUser = selectCurrentUser(state)
   const invitations = get(state, `fragments.${fragmentId}.invitations`, [])
diff --git a/packages/component-faraday-ui/src/AuthorReply.js b/packages/component-faraday-ui/src/AuthorReply.js
index 22649c9636aba91856d4fef278b074951b73b6b7..4bbb8d22b3218279bbedaedb1af03b7bd7f1bca0 100644
--- a/packages/component-faraday-ui/src/AuthorReply.js
+++ b/packages/component-faraday-ui/src/AuthorReply.js
@@ -1,25 +1,32 @@
-import React from 'react'
+import React, { Fragment } from 'react'
 import { get } from 'lodash'
 import { withProps } from 'recompose'
 import styled from 'styled-components'
 import { th } from '@pubsweet/ui-toolkit'
 import { DateParser } from '@pubsweet/ui'
 
-import { Label, Item, Row, Text } from './'
+import { Label, Item, Row, Text, FileItem } from './'
 
 const submittingAuthor = authors => {
   const thisAuthor = authors.filter(e => e.isSubmitting)
   return thisAuthor[0]
 }
 
-const AuthorReply = ({ reply, authorName, submittedOn }) => (
+const AuthorReply = ({
+  authorName,
+  submittedOn,
+  replyContent,
+  replyFile,
+  onDownload,
+  onPreview,
+}) => (
   <Root>
     <Row justify="space-between" mb={2}>
       <Item justify="flex-end">
         <Row mb={1}>
           <Item vertical>
             <Label mb={1 / 2}>Author Reply</Label>
-            <Text>{reply}</Text>
+            <Text>{replyContent}</Text>
           </Item>
         </Row>
         <Text ml={1} mr={1} whiteSpace="nowrap">
@@ -30,17 +37,36 @@ const AuthorReply = ({ reply, authorName, submittedOn }) => (
         </DateParser>
       </Item>
     </Row>
+
+    {replyFile && (
+      <Fragment>
+        <Label mb={1 / 2}>File</Label>
+        <Row justify="flex-start" mb={2}>
+          <Item flex={0} mr={1}>
+            <FileItem
+              item={replyFile}
+              onDownload={onDownload}
+              onPreview={onPreview}
+            />
+          </Item>
+        </Row>
+      </Fragment>
+    )}
   </Root>
 )
 
-export default withProps(({ fragment: { authors, submitted } }) => ({
-  submittedOn: submitted,
-  authorName: `${get(submittingAuthor(authors), 'firstName', '')} ${get(
-    submittingAuthor(authors),
-    'lastName',
-    '',
-  )}`,
-}))(AuthorReply)
+export default withProps(
+  ({ fragment: { authors, submitted }, authorReply }) => ({
+    submittedOn: submitted,
+    authorName: `${get(submittingAuthor(authors), 'firstName', '')} ${get(
+      submittingAuthor(authors),
+      'lastName',
+      '',
+    )}`,
+    replyContent: get(authorReply, 'content', ''),
+    replyFile: get(authorReply, 'file', ''),
+  }),
+)(AuthorReply)
 
 // #region styles
 const Root = styled.div`
diff --git a/packages/component-faraday-ui/src/PersonInvitation.js b/packages/component-faraday-ui/src/PersonInvitation.js
index 138070274f0b470218de34a5dc40042e720098fa..25e281528a87656906bd372c9af299c5c19e9416 100644
--- a/packages/component-faraday-ui/src/PersonInvitation.js
+++ b/packages/component-faraday-ui/src/PersonInvitation.js
@@ -9,6 +9,7 @@ const PersonInvitation = ({
   withName,
   hasAnswer,
   isFetching,
+  isLatestVersion,
   revokeInvitation,
   resendInvitation,
   person: { name, email },
@@ -51,6 +52,29 @@ const PersonInvitation = ({
           </OpenModal>
         </Fragment>
       )}
+    {hasAnswer &&
+      isLatestVersion && (
+        <Fragment>
+          <OpenModal
+            confirmText="Revoke"
+            isFetching={isFetching}
+            modalKey={`remove-${id}`}
+            onConfirm={revokeInvitation}
+            subtitle={`Are you sure you want to remove ${email}? This decision will erase all data from the current fragment.`}
+            title="Revoke invitation?"
+          >
+            {showModal => (
+              <IconButton
+                icon="x-circle"
+                iconSize={2}
+                ml={2}
+                onClick={showModal}
+                secondary
+              />
+            )}
+          </OpenModal>
+        </Fragment>
+      )}
   </Root>
 )
 
diff --git a/packages/component-faraday-ui/src/ReviewerReport.js b/packages/component-faraday-ui/src/ReviewerReport.js
index 12391694d8b8032f53d43932629ba1f4d20a12aa..fc2c942c5bb4fdee93bfcbd64cc2bb05d768d3f2 100644
--- a/packages/component-faraday-ui/src/ReviewerReport.js
+++ b/packages/component-faraday-ui/src/ReviewerReport.js
@@ -11,10 +11,11 @@ const ReviewerReport = ({
   onPreview,
   onDownload,
   reportFile,
+  currentUser,
   publicReport,
   privateReport,
   reviewerName,
-  reviewerIndex,
+  reviewerNumber,
   recommendation,
   showOwner = false,
   report: { submittedOn },
@@ -27,14 +28,12 @@ const ReviewerReport = ({
       </Item>
 
       <Item justify="flex-end">
-        {showOwner && (
-          <Fragment>
-            <Text>{reviewerName}</Text>
-            <Text customId ml={1} mr={1}>
-              {`Reviewer ${reviewerIndex}`}
-            </Text>
-          </Fragment>
-        )}
+        <Fragment>
+          {showOwner && <Text>{reviewerName}</Text>}
+          <Text customId ml={1} mr={1}>
+            {`Reviewer ${reviewerNumber}`}
+          </Text>
+        </Fragment>
         <DateParser timestamp={submittedOn}>
           {date => <Text>{date}</Text>}
         </DateParser>
@@ -76,20 +75,22 @@ const ReviewerReport = ({
   </Root>
 )
 
-export default withProps(({ report, journal: { recommendations = [] } }) => ({
-  recommendation: get(
-    recommendations.find(r => r.value === report.recommendation),
-    'label',
-  ),
-  reportFile: get(report, 'comments.0.files.0'),
-  publicReport: get(report, 'comments.0.content'),
-  privateReport: get(report, 'comments.1.content'),
-  reviewerName: `${get(report, 'reviewer.firstName', '')} ${get(
-    report,
-    'reviewer.lastName',
-    '',
-  )}`,
-}))(ReviewerReport)
+export default withProps(
+  ({ report, currentUser, journal: { recommendations = [] } }) => ({
+    recommendation: get(
+      recommendations.find(r => r.value === report.recommendation),
+      'label',
+    ),
+    reportFile: get(report, 'comments.0.files.0'),
+    publicReport: get(report, 'comments.0.content'),
+    privateReport: get(report, 'comments.1.content'),
+    reviewerName: `${get(currentUser, 'firstName', '')} ${get(
+      currentUser,
+      'lastName',
+      '',
+    )}`,
+  }),
+)(ReviewerReport)
 
 // #region styles
 const Root = styled.div`
diff --git a/packages/component-faraday-ui/src/ReviewerReportAuthor.js b/packages/component-faraday-ui/src/ReviewerReportAuthor.js
index 4df5745b8ce86a109bad547466f3fe5ff57f94de..ded36d3ae2e8128002c2bbde7a0292d172d44d66 100644
--- a/packages/component-faraday-ui/src/ReviewerReportAuthor.js
+++ b/packages/component-faraday-ui/src/ReviewerReportAuthor.js
@@ -21,7 +21,7 @@ const ReviewerReportAuthor = ({
   downloadFile,
   publicReport,
   reviewerName,
-  reviewerIndex,
+  reviewerNumber,
   recommendation,
   showOwner = false,
   report: { submittedOn },
@@ -38,7 +38,7 @@ const ReviewerReportAuthor = ({
           </Row>
         )}
         <Text customId ml={1} mr={1} whiteSpace="nowrap">
-          {`Reviewer ${reviewerIndex}`}
+          {`Reviewer ${reviewerNumber}`}
         </Text>
         <DateParser timestamp={submittedOn}>
           {date => <Text>{date}</Text>}
@@ -78,7 +78,7 @@ export default compose(
       'reviewer.lastName',
       '',
     )}`,
-    reviewerIndex: get(report, 'reviewerIndex', ''),
+    reviewerNumber: get(report, 'reviewerNumber', ''),
   })),
 )(ReviewerReportAuthor)
 
diff --git a/packages/component-faraday-ui/src/ReviewerReportAuthor.md b/packages/component-faraday-ui/src/ReviewerReportAuthor.md
index 48fdf8f4faefd2db6af22906b08d22899c94edaa..0ee98012afcf5a17ddccc438eecce6524d3f195b 100644
--- a/packages/component-faraday-ui/src/ReviewerReportAuthor.md
+++ b/packages/component-faraday-ui/src/ReviewerReportAuthor.md
@@ -29,7 +29,7 @@ const report = {
   submittedOn: 1538053600624,
   recommendation: 'publish',
   recommendationType: 'review',
-  reviewerIndex: 1
+  reviewerNumber: 1
 }
 
 const journal = {
diff --git a/packages/component-faraday-ui/src/ReviewersTable.js b/packages/component-faraday-ui/src/ReviewersTable.js
index 9f9e2aaa75309afd25084e94a65cbcf65e2c646b..e2197d20c406eeff827b6b4051f48062d7e7493e 100644
--- a/packages/component-faraday-ui/src/ReviewersTable.js
+++ b/packages/component-faraday-ui/src/ReviewersTable.js
@@ -41,9 +41,9 @@ const ReviewersTable = ({
                 invitation,
                 'person.lastName',
               )}`}</Text>
-              {invitation.isAccepted && (
+              {invitation.reviewerNumber && (
                 <Text customId ml={1}>
-                  {renderAcceptedLabel(index)}
+                  Reviewer {invitation.reviewerNumber}
                 </Text>
               )}
             </td>
@@ -102,12 +102,7 @@ export default compose(
   withProps(({ invitations = [] }) => ({
     invitations: orderBy(invitations, orderInvitations),
   })),
-  withProps(({ invitations = [] }) => ({
-    firstAccepted: invitations.findIndex(i => i.hasAnswer && i.isAccepted),
-  })),
   withHandlers({
-    renderAcceptedLabel: ({ firstAccepted, invitations }) => index =>
-      `Reviewer ${index - firstAccepted + 1}`,
     getInvitationStatus: () => ({ hasAnswer, isAccepted }) => {
       if (!hasAnswer) return 'PENDING'
       if (isAccepted) return 'ACCEPTED'
diff --git a/packages/component-faraday-ui/src/contextualBoxes/AuthorReviews.js b/packages/component-faraday-ui/src/contextualBoxes/AuthorReviews.js
index 5518b3ebfa9c3803816c871f4f8b32b717c468d3..696e8a4e405ca71b5e6844cfedf81994863060a2 100644
--- a/packages/component-faraday-ui/src/contextualBoxes/AuthorReviews.js
+++ b/packages/component-faraday-ui/src/contextualBoxes/AuthorReviews.js
@@ -1,7 +1,14 @@
 import React from 'react'
 import { withProps, compose } from 'recompose'
+import { get } from 'lodash'
 
-import { ContextualBox, ReviewerReportAuthor, Row, Text } from '../'
+import {
+  ContextualBox,
+  ReviewerReportAuthor,
+  Row,
+  Text,
+  indexReviewers,
+} from '../'
 
 const SubmittedReportsNumberForAuthorReviews = ({ reports }) => (
   <Row fitContent justify="flex-end">
@@ -16,12 +23,13 @@ const SubmittedReportsNumberForAuthorReviews = ({ reports }) => (
 )
 
 const AuthorReviews = ({
-  invitations,
+  token,
   journal,
   reports,
   fragment,
-  token,
+  invitations,
   getSignedUrl,
+  reviewerReports,
 }) =>
   reports.length > 0 && (
     <ContextualBox
@@ -43,4 +51,24 @@ const AuthorReviews = ({
     </ContextualBox>
   )
 
-export default compose(withProps())(AuthorReviews)
+export default compose(
+  withProps(
+    ({
+      invitations = [],
+      publonReviewers = [],
+      reviewerReports = [],
+      currentUser,
+    }) => ({
+      token: get(currentUser, 'token', ''),
+      publonReviewers,
+      invitations: invitations.map(i => ({
+        ...i,
+        review: reviewerReports.find(r => r.userId === i.userId),
+      })),
+      reports: indexReviewers(
+        reviewerReports.filter(r => r.submittedOn),
+        invitations,
+      ),
+    }),
+  ),
+)(AuthorReviews)
diff --git a/packages/component-faraday-ui/src/contextualBoxes/AuthorReviews.md b/packages/component-faraday-ui/src/contextualBoxes/AuthorReviews.md
index aa15139b436a8238511b82742f9202d74516f9ce..6bb32f81d1495f66987b964ce3451a619b57d2ea 100644
--- a/packages/component-faraday-ui/src/contextualBoxes/AuthorReviews.md
+++ b/packages/component-faraday-ui/src/contextualBoxes/AuthorReviews.md
@@ -28,7 +28,7 @@ const reports = [
     submittedOn: 1539339580826,
     recommendation: 'minor',
     recommendationType: 'review',
-    reviewerIndex: 1,
+    reviewerNumber: 1,
   },
   {
     id: '21258b47-aba5-4597-926e-765458c4fda2',
@@ -45,7 +45,7 @@ const reports = [
     submittedOn: 1539689169611,
     recommendation: 'publish',
     recommendationType: 'review',
-    reviewerIndex: 2,
+    reviewerNumber: 2,
   },
 ]
 
diff --git a/packages/component-faraday-ui/src/contextualBoxes/HERecommendation.js b/packages/component-faraday-ui/src/contextualBoxes/HERecommendation.js
index 69f2a7b7f2164e0086292d91dfdc1b458621409a..3eb14eb32d1a156f67e545557886f1366d14b0cf 100644
--- a/packages/component-faraday-ui/src/contextualBoxes/HERecommendation.js
+++ b/packages/component-faraday-ui/src/contextualBoxes/HERecommendation.js
@@ -46,27 +46,14 @@ const options = [
   },
 ]
 
-const optionsWhereHECanOnlyReject = [
-  'reviewersInvited',
-  'underReview',
-  'revisionRequested',
-]
-
 const showHEOptions = ({
-  collection,
-  hasReviewerReports,
-  fragment,
-  options,
-  optionsWhereHECanOnlyReject,
+  canHEMakeRecommendationToPublish,
+  canHEOnlyReject,
 }) => {
-  const { status, fragments } = collection
-  const { invitations } = fragment
-  if (optionsWhereHECanOnlyReject.includes(status)) {
+  if (canHEOnlyReject) {
     return [options[1]]
-  } else if (!hasReviewerReports && fragments.length === 1) {
+  } else if (!canHEMakeRecommendationToPublish) {
     return tail(options)
-  } else if (invitations === []) {
-    return [options[1]]
   }
   return options
 }
@@ -86,12 +73,11 @@ const parseFormValues = ({ recommendation, ...rest }) => {
 }
 
 const HERecommendation = ({
-  formValues,
+  canHEMakeRecommendationToPublish,
+  canHEOnlyReject,
   handleSubmit,
-  hasReviewerReports,
+  formValues,
   highlight,
-  collection,
-  fragment,
 }) => (
   <ContextualBox
     highlight={highlight}
@@ -110,11 +96,8 @@ const HERecommendation = ({
             component={input => (
               <Menu
                 options={showHEOptions({
-                  collection,
-                  hasReviewerReports,
-                  fragment,
-                  options,
-                  optionsWhereHECanOnlyReject,
+                  canHEMakeRecommendationToPublish,
+                  canHEOnlyReject,
                 })}
                 {...input}
               />
diff --git a/packages/component-faraday-ui/src/contextualBoxes/ResponseToRevisionRequest.js b/packages/component-faraday-ui/src/contextualBoxes/ResponseToRevisionRequest.js
index 4d3d4b181d864cd2b5c829ad06902b058a3c09ec..cdb6ed72a1c30a89e4da9bb466549eec443ce1bd 100644
--- a/packages/component-faraday-ui/src/contextualBoxes/ResponseToRevisionRequest.js
+++ b/packages/component-faraday-ui/src/contextualBoxes/ResponseToRevisionRequest.js
@@ -1,21 +1,38 @@
 import React from 'react'
+import { compose } from 'recompose'
 
-import { ContextualBox, AuthorReply } from '../'
+import {
+  ContextualBox,
+  AuthorReply,
+  withFilePreview,
+  withFileDownload,
+} from '../'
 
 const ResponseToRevisionRequest = ({
   fragment,
   authorReply,
   toggle,
   expanded,
+  downloadFile,
+  previewFile,
+  ...rest
 }) => (
   <ContextualBox
     expanded={expanded}
     label="Response to Revision Request"
     mb={2}
     toggle={toggle}
+    {...rest}
   >
-    <AuthorReply fragment={fragment} reply={authorReply} />
+    <AuthorReply
+      authorReply={authorReply}
+      fragment={fragment}
+      onDownload={downloadFile}
+      onPreview={previewFile}
+    />
   </ContextualBox>
 )
 
-export default ResponseToRevisionRequest
+export default compose(withFilePreview, withFileDownload)(
+  ResponseToRevisionRequest,
+)
diff --git a/packages/component-faraday-ui/src/contextualBoxes/ReviewerDetails.js b/packages/component-faraday-ui/src/contextualBoxes/ReviewerDetails.js
index d8a41b821abe0639bbb6f9cfbe6ffe17b9f75189..987aa4a775f7eed363cfcfe0793c5e4baeb1468c 100644
--- a/packages/component-faraday-ui/src/contextualBoxes/ReviewerDetails.js
+++ b/packages/component-faraday-ui/src/contextualBoxes/ReviewerDetails.js
@@ -13,6 +13,7 @@ import {
   ContextualBox,
   ReviewersTable,
   PublonsTable,
+  indexReviewers,
   ReviewerReport,
   InviteReviewers,
   ReviewerBreakdown,
@@ -118,14 +119,14 @@ const ReviewerDetails = ({
                 {reports.length === 0 && (
                   <Text align="center">No reports submitted yet.</Text>
                 )}
-                {reports.map((report, index) => (
+                {reports.map(report => (
                   <ReviewerReport
                     journal={journal}
                     key={report.id}
                     onDownload={downloadFile}
                     onPreview={previewFile}
                     report={report}
-                    reviewerIndex={index + 1}
+                    reviewerNumber={report.reviewerNumber}
                     showOwner
                   />
                 ))}
@@ -154,7 +155,10 @@ export default compose(
         ...i,
         review: reviewerReports.find(r => r.userId === i.userId),
       })),
-      reports: reviewerReports.filter(r => r.submittedOn),
+      reports: indexReviewers(
+        reviewerReports.filter(r => r.submittedOn),
+        invitations,
+      ),
     }),
   ),
   withProps(({ currentUser }) => ({
diff --git a/packages/component-faraday-ui/src/helpers/utils.js b/packages/component-faraday-ui/src/helpers/utils.js
index 898fd3ebc62282763a1331fd359f9d8da85a732c..8b798e34e7b73272c922ab6201019b5b4b221fb9 100644
--- a/packages/component-faraday-ui/src/helpers/utils.js
+++ b/packages/component-faraday-ui/src/helpers/utils.js
@@ -1,4 +1,4 @@
-import { get, chain } from 'lodash'
+import { get, chain, find } from 'lodash'
 
 export const handleError = fn => e => {
   fn(get(JSON.parse(e.response), 'error', 'Oops! Something went wrong!'))
@@ -10,3 +10,14 @@ export const getReportComments = ({ report, isPublic = false }) =>
     .find(c => c.public === isPublic)
     .get('content')
     .value()
+
+export const indexReviewers = (reports = [], invitations = []) => {
+  reports.forEach(report => {
+    report.reviewerNumber = get(
+      find(invitations, ['userId', report.userId]),
+      'reviewerNumber',
+      0,
+    )
+  })
+  return reports
+}
diff --git a/packages/component-faraday-ui/src/manuscriptDetails/ManuscriptHeader.js b/packages/component-faraday-ui/src/manuscriptDetails/ManuscriptHeader.js
index 699edec06e90cfc92695a9cbec10bc2ca8e81d70..9c6f5b851a29553f89aae6ee59db2647f1ee58f6 100644
--- a/packages/component-faraday-ui/src/manuscriptDetails/ManuscriptHeader.js
+++ b/packages/component-faraday-ui/src/manuscriptDetails/ManuscriptHeader.js
@@ -121,6 +121,7 @@ export default compose(
       revokeInvitation,
       pendingInvitation = {},
       handlingEditors = [],
+      isLatestVersion,
       currentUser: {
         permissions: { canAssignHE },
         id: currentUserId,
@@ -128,24 +129,36 @@ export default compose(
         editorInChief,
       },
       collection: { handlingEditor },
+      collection,
       currentUser,
     }) => () => {
       if (pendingInvitation.userId === currentUserId) {
         return <Text ml={1}>Invited</Text>
       }
-      if (pendingInvitation.userId && (admin || editorInChief)) {
+      if (
+        (get(pendingInvitation, 'userId', false) ||
+          get(heInvitation, 'userId', false)) &&
+        (admin || editorInChief)
+      ) {
         const person = chain(handlingEditors)
-          .filter(he => he.id === pendingInvitation.userId)
+          .filter(he => he.id === get(heInvitation, 'userId', false))
           .map(he => ({ ...he, name: `${he.firstName} ${he.lastName}` }))
           .first()
           .value()
 
+        let invitedPerson = {}
+        if (get(pendingInvitation, 'userId', false)) {
+          invitedPerson = pendingInvitation
+        } else if (get(heInvitation, 'userId', false)) {
+          invitedPerson = heInvitation
+        }
         return (
           <PersonInvitation
             isFetching={isFetching}
+            isLatestVersion={isLatestVersion}
             ml={1}
             withName
-            {...pendingInvitation}
+            {...invitedPerson}
             onResend={resendInvitation}
             onRevoke={revokeInvitation}
             person={person}
diff --git a/packages/component-fixture-manager/src/fixtures/collectionIDs.js b/packages/component-fixture-manager/src/fixtures/collectionIDs.js
index 5b0da41bf1758f75c2b1394ca7f42ef812761ccc..a964c2c498c452599e68dd3457a24eac4c0a3b49 100644
--- a/packages/component-fixture-manager/src/fixtures/collectionIDs.js
+++ b/packages/component-fixture-manager/src/fixtures/collectionIDs.js
@@ -7,4 +7,6 @@ module.exports = {
   collectionReviewCompletedID: chance.guid(),
   collectionNoInvitesID: chance.guid(),
   twoVersionsCollectionId: chance.guid(),
+  oneReviewedFragmentCollectionID: chance.guid(),
+  noEditorRecomedationCollectionID: chance.guid(),
 }
diff --git a/packages/component-fixture-manager/src/fixtures/collections.js b/packages/component-fixture-manager/src/fixtures/collections.js
index d982f643c675c55a73ce3a1a4b57289935a9556b..0fbff658ca84fc9266a31674461679e769a1ff13 100644
--- a/packages/component-fixture-manager/src/fixtures/collections.js
+++ b/packages/component-fixture-manager/src/fixtures/collections.js
@@ -1,16 +1,24 @@
 const Chance = require('chance')
-const { user, handlingEditor, answerHE } = require('./userData')
+const {
+  user,
+  handlingEditor,
+  answerHE,
+  noRecommendationHE,
+} = require('./userData')
 const {
   fragment,
   fragment1,
   reviewCompletedFragment,
   noInvitesFragment,
+  noEditorRecomedationFragment,
 } = require('./fragments')
 const {
   standardCollID,
   collectionReviewCompletedID,
   collectionNoInvitesID,
   twoVersionsCollectionId,
+  oneReviewedFragmentCollectionID,
+  noEditorRecomedationCollectionID,
 } = require('./collectionIDs')
 
 const chance = new Chance()
@@ -23,6 +31,7 @@ const collections = {
     fragments: [fragment.id],
     owners: [user.id],
     save: jest.fn(() => collections.collection),
+    getFragments: jest.fn(() => [fragment]),
     invitations: [
       {
         id: chance.guid(),
@@ -66,6 +75,7 @@ const collections = {
     fragments: [fragment.id],
     owners: [user.id],
     save: jest.fn(() => collections.collection),
+    getFragments: jest.fn(() => [fragment]),
     invitations: [
       {
         id: chance.guid(),
@@ -108,6 +118,7 @@ const collections = {
     fragments: [fragment1.id, noInvitesFragment.id],
     owners: [user.id],
     save: jest.fn(() => collections.collection2),
+    getFragments: jest.fn(() => [fragment1, noInvitesFragment]),
     invitations: [
       {
         id: chance.guid(),
@@ -152,6 +163,7 @@ const collections = {
     created: chance.timestamp(),
     customId: '0000001',
     fragments: [reviewCompletedFragment.id],
+    getFragments: jest.fn(() => [reviewCompletedFragment]),
     invitations: [
       {
         id: chance.guid(),
@@ -182,6 +194,7 @@ const collections = {
     fragments: [fragment.id, reviewCompletedFragment.id],
     owners: [user.id],
     save: jest.fn(() => collections.collection),
+    getFragments: jest.fn(() => [fragment, reviewCompletedFragment]),
     invitations: [
       {
         id: chance.guid(),
@@ -212,6 +225,81 @@ const collections = {
     fragments: [],
     owners: [user.id],
     save: jest.fn(() => collections.collection),
+    getFragments: jest.fn(() => []),
+    customId: chance.natural({ min: 999999, max: 9999999 }),
+  },
+  noEditorRecomedationCollection: {
+    id: noEditorRecomedationCollectionID,
+    title: chance.sentence(),
+    type: 'collection',
+    fragments: [noEditorRecomedationFragment.id],
+    owners: [user.id],
+    save: jest.fn(() => collections.noEditorRecomedationCollection),
+    getFragments: jest.fn(() => [noEditorRecomedationFragment]),
+    invitations: [
+      {
+        id: chance.guid(),
+        role: 'handlingEditor',
+        hasAnswer: true,
+        isAccepted: true,
+        userId: noRecommendationHE.id,
+        invitedOn: chance.timestamp(),
+        respondedOn: null,
+      },
+      {
+        id: chance.guid(),
+        role: 'handlingEditor',
+        hasAnswer: false,
+        isAccepted: false,
+        userId: answerHE.id,
+        invitedOn: chance.timestamp(),
+        respondedOn: chance.timestamp(),
+      },
+    ],
+    handlingEditor: {
+      id: handlingEditor.id,
+      hasAnswer: true,
+      isAccepted: true,
+      email: handlingEditor.email,
+      invitedOn: chance.timestamp(),
+      respondedOn: chance.timestamp(),
+      name: `${handlingEditor.firstName} ${handlingEditor.lastName}`,
+    },
+    customId: chance.natural({ min: 999999, max: 9999999 }),
+    technicalChecks: {
+      token: chance.guid(),
+    },
+    status: 'reviewCompleted',
+  },
+  oneReviewedFragmentCollection: {
+    id: oneReviewedFragmentCollectionID,
+    title: chance.sentence(),
+    type: 'collection',
+    fragments: [reviewCompletedFragment.id, noInvitesFragment.id],
+    owners: [user.id],
+    save: jest.fn(() => collections.collection),
+    getFragments: jest.fn(() => [reviewCompletedFragment, noInvitesFragment]),
+    invitations: [
+      {
+        id: chance.guid(),
+        role: 'handlingEditor',
+        hasAnswer: true,
+        isAccepted: false,
+        userId: handlingEditor.id,
+        invitedOn: chance.timestamp(),
+        respondedOn: null,
+      },
+    ],
+    handlingEditor: {
+      id: handlingEditor.id,
+      hasAnswer: false,
+      isAccepted: false,
+      email: handlingEditor.email,
+      invitedOn: chance.timestamp(),
+      respondedOn: null,
+      name: `${handlingEditor.firstName} ${handlingEditor.lastName}`,
+    },
+    status: 'revisionRequested',
     customId: chance.natural({ min: 999999, max: 9999999 }),
   },
 }
diff --git a/packages/component-fixture-manager/src/fixtures/fragments.js b/packages/component-fixture-manager/src/fixtures/fragments.js
index 9fca41e0ffba404be7fd612dd6feb483e6a23763..337c0d943c7e6fd87e47fd3e31ff3458c0fb567d 100644
--- a/packages/component-fixture-manager/src/fixtures/fragments.js
+++ b/packages/component-fixture-manager/src/fixtures/fragments.js
@@ -8,11 +8,13 @@ const {
   admin,
   inactiveReviewer,
   reviewer1,
+  newReviewer,
 } = require('./userData')
 const {
   standardCollID,
   collectionReviewCompletedID,
   collectionNoInvitesID,
+  noEditorRecomedationCollectionID,
 } = require('./collectionIDs')
 const { user } = require('./userData')
 
@@ -71,7 +73,7 @@ const fragments = {
           },
         ],
         id: chance.guid(),
-        userId: '1231njfsdknfkjs23',
+        userId: recReviewer.id,
         createdOn: chance.timestamp(),
         updatedOn: chance.timestamp(),
         submittedOn: chance.timestamp(),
@@ -97,6 +99,69 @@ const fragments = {
         createdOn: chance.timestamp(),
         updatedOn: chance.timestamp(),
       },
+      {
+        recommendation: 'publish',
+        recommendationType: 'editorRecommendation',
+        comments: [
+          {
+            content: chance.paragraph(),
+            public: true,
+            files: [
+              {
+                id: chance.guid(),
+                name: 'file.pdf',
+                size: chance.natural(),
+              },
+            ],
+          },
+        ],
+        id: chance.guid(),
+        userId: handlingEditor.id,
+        createdOn: 1542361074012,
+        updatedOn: chance.timestamp(),
+      },
+      {
+        recommendation: 'return-to-handling-editor',
+        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: 1542361115749,
+        updatedOn: chance.timestamp(),
+      },
+      {
+        recommendation: 'publish',
+        recommendationType: 'editorRecommendation',
+        comments: [
+          {
+            content: chance.paragraph(),
+            public: chance.bool(),
+            files: [
+              {
+                id: chance.guid(),
+                name: 'file.pdf',
+                size: chance.natural(),
+              },
+            ],
+          },
+        ],
+        id: chance.guid(),
+        userId: handlingEditor.id,
+        createdOn: 1542361115750,
+        updatedOn: chance.timestamp(),
+      },
       {
         recommendation: 'publish',
         recommendationType: 'editorRecommendation',
@@ -115,7 +180,7 @@ const fragments = {
         ],
         id: chance.guid(),
         userId: admin.id,
-        createdOn: chance.timestamp(),
+        createdOn: 1542361115751,
         updatedOn: chance.timestamp(),
       },
     ],
@@ -148,7 +213,7 @@ const fragments = {
         id: chance.guid(),
         role: 'reviewer',
         hasAnswer: true,
-        isAccepted: false,
+        isAccepted: true,
         userId: answerReviewer.id,
         invitedOn: chance.timestamp(),
         respondedOn: chance.timestamp(),
@@ -164,6 +229,16 @@ const fragments = {
         respondedOn: chance.timestamp(),
         type: 'invitation',
       },
+      {
+        id: chance.guid(),
+        role: 'reviewer',
+        hasAnswer: true,
+        isAccepted: true,
+        userId: recReviewer.id,
+        invitedOn: chance.timestamp(),
+        respondedOn: chance.timestamp(),
+        type: 'invitation',
+      },
     ],
     save: jest.fn(() => fragments.fragment),
     owners: [user.id],
@@ -265,6 +340,7 @@ const fragments = {
         invitedOn: chance.timestamp(),
         isAccepted: true,
         respondedOn: chance.timestamp(),
+        reviewerNumber: 2,
       },
       {
         id: chance.guid(),
@@ -413,16 +489,242 @@ const fragments = {
           isCorresponding: false,
         },
       ],
-      owners: [user.id],
-      type: 'fragment',
     },
   },
+  noEditorRecomedationFragment: {
+    id: chance.guid(),
+    collectionId: noEditorRecomedationCollectionID,
+    metadata: {
+      title: chance.sentence(),
+      abstract: chance.paragraph(),
+    },
+    recommendations: [
+      {
+        recommendation: 'publish',
+        recommendationType: 'review',
+        comments: [
+          {
+            content: chance.paragraph(),
+            public: chance.bool(),
+            files: [
+              {
+                id: chance.guid(),
+                name: 'file.pdf',
+                size: chance.natural(),
+              },
+            ],
+          },
+        ],
+        id: chance.guid(),
+        userId: newReviewer.id,
+        createdOn: chance.timestamp(),
+        updatedOn: chance.timestamp(),
+        submittedOn: chance.timestamp(),
+      },
+      {
+        recommendation: 'publish',
+        recommendationType: 'editorRecommendation',
+        comments: [
+          {
+            content: chance.paragraph(),
+            public: true,
+            files: [
+              {
+                id: chance.guid(),
+                name: 'file.pdf',
+                size: chance.natural(),
+              },
+            ],
+          },
+        ],
+        id: chance.guid(),
+        userId: handlingEditor.id,
+        createdOn: 1542361074012,
+        updatedOn: chance.timestamp(),
+      },
+      {
+        recommendation: 'return-to-handling-editor',
+        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: 1542361115749,
+        updatedOn: chance.timestamp(),
+      },
+    ],
+    authors: [
+      {
+        email: chance.email(),
+        id: submittingAuthor.id,
+        isSubmitting: true,
+        isCorresponding: false,
+      },
+    ],
+    invitations: [
+      {
+        id: chance.guid(),
+        role: 'reviewer',
+        hasAnswer: true,
+        isAccepted: true,
+        userId: newReviewer.id,
+        invitedOn: chance.timestamp(),
+        respondedOn: chance.timestamp(),
+        type: 'invitation',
+      },
+    ],
+    save: jest.fn(() => fragments.fragment),
+    owners: [user.id],
+    type: 'fragment',
+  },
 }
 
 fragments.noInvitesFragment = {
   ...fragments.fragment1,
+  recommendations: [],
   invites: [],
   id: chance.guid(),
 }
+fragments.noInvitesFragment1 = {
+  ...fragments.fragment,
+  recommendations: [],
+  id: chance.guid(),
+}
+fragments.minorRevisionWithoutReview = {
+  ...fragments.fragment,
+  recommendations: [
+    {
+      recommendation: 'minor',
+      recommendationType: 'editorRecommendation',
+      comments: [
+        {
+          content: chance.paragraph(),
+          public: true,
+          files: [
+            {
+              id: chance.guid(),
+              name: 'file.pdf',
+              size: chance.natural(),
+            },
+          ],
+        },
+      ],
+      id: chance.guid(),
+      userId: handlingEditor.id,
+      createdOn: chance.timestamp(),
+      updatedOn: chance.timestamp(),
+    },
+  ],
+  id: chance.guid(),
+}
+fragments.minorRevisionWithReview = {
+  ...fragments.fragment,
+  recommendations: [
+    {
+      recommendation: 'minor',
+      recommendationType: 'editorRecommendation',
+      comments: [
+        {
+          content: chance.paragraph(),
+          public: true,
+          files: [
+            {
+              id: chance.guid(),
+              name: 'file.pdf',
+              size: chance.natural(),
+            },
+          ],
+        },
+      ],
+      id: chance.guid(),
+      userId: handlingEditor.id,
+      createdOn: chance.timestamp(),
+      updatedOn: chance.timestamp(),
+    },
+    {
+      recommendation: 'publish',
+      recommendationType: 'review',
+      comments: [
+        {
+          content: chance.paragraph(),
+          public: chance.bool(),
+          files: [
+            {
+              id: chance.guid(),
+              name: 'file.pdf',
+              size: chance.natural(),
+            },
+          ],
+        },
+      ],
+      id: chance.guid(),
+      userId: reviewer1.id,
+      createdOn: chance.timestamp(),
+      updatedOn: chance.timestamp(),
+      submittedOn: chance.timestamp(),
+    },
+  ],
+  id: chance.guid(),
+}
+fragments.majorRevisionWithReview = {
+  ...fragments.fragment,
+  recommendations: [
+    {
+      recommendation: 'major',
+      recommendationType: 'editorRecommendation',
+      comments: [
+        {
+          content: chance.paragraph(),
+          public: true,
+          files: [
+            {
+              id: chance.guid(),
+              name: 'file.pdf',
+              size: chance.natural(),
+            },
+          ],
+        },
+      ],
+      id: chance.guid(),
+      userId: handlingEditor.id,
+      createdOn: chance.timestamp(),
+      updatedOn: chance.timestamp(),
+    },
+    {
+      recommendation: 'publish',
+      recommendationType: 'review',
+      comments: [
+        {
+          content: chance.paragraph(),
+          public: chance.bool(),
+          files: [
+            {
+              id: chance.guid(),
+              name: 'file.pdf',
+              size: chance.natural(),
+            },
+          ],
+        },
+      ],
+      id: chance.guid(),
+      userId: reviewer1.id,
+      createdOn: chance.timestamp(),
+      updatedOn: chance.timestamp(),
+      submittedOn: chance.timestamp(),
+    },
+  ],
+  id: chance.guid(),
+}
 
 module.exports = fragments
diff --git a/packages/component-fixture-manager/src/fixtures/teamIDs.js b/packages/component-fixture-manager/src/fixtures/teamIDs.js
index ab1eae10948701757d3d0e745a307204a14b7f4e..162cdb391585ed6789018579dbb1469271f8d2f2 100644
--- a/packages/component-fixture-manager/src/fixtures/teamIDs.js
+++ b/packages/component-fixture-manager/src/fixtures/teamIDs.js
@@ -8,4 +8,6 @@ module.exports = {
   authorTeamID: 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 370a9c0e988c6c886454314b76173613d898bf25..dbd51a4aca783c1315e45fe3749b7c2bd1f8145c 100644
--- a/packages/component-fixture-manager/src/fixtures/teams.js
+++ b/packages/component-fixture-manager/src/fixtures/teams.js
@@ -8,11 +8,18 @@ const {
   authorTeamID,
   revRecommendationTeamID,
   rev1TeamID,
+  heNoRecommendationTeamID,
+  revNoEditorRecommendationTeamID,
 } = require('./teamIDs')
 const { submittingAuthor } = require('./userData')
 
-const { collection } = collections
-const { fragment, reviewCompletedFragment, fragment1 } = fragments
+const { collection, noEditorRecomedationCollection } = collections
+const {
+  fragment,
+  reviewCompletedFragment,
+  fragment1,
+  noEditorRecomedationFragment,
+} = fragments
 const {
   handlingEditor,
   reviewer,
@@ -20,6 +27,8 @@ const {
   answerReviewer,
   recReviewer,
   reviewer1,
+  newReviewer,
+  noRecommendationHE,
 } = users
 const teams = {
   heTeam: {
@@ -39,6 +48,23 @@ const teams = {
     updateProperties: jest.fn(() => teams.heTeam),
     id: heTeamID,
   },
+  heNoRecommendationTeam: {
+    teamType: {
+      name: 'handlingEditor',
+      permissions: 'handlingEditor',
+    },
+    group: 'handlingEditor',
+    name: 'HandlingEditor',
+    object: {
+      type: 'collection',
+      id: noEditorRecomedationCollection.id,
+    },
+    members: [noRecommendationHE.id],
+    save: jest.fn(() => teams.heNoRecommendationTeam),
+    delete: jest.fn(),
+    updateProperties: jest.fn(() => teams.heNoRecommendationTeam),
+    id: heNoRecommendationTeamID,
+  },
   revTeam: {
     teamType: {
       name: 'reviewer',
@@ -106,5 +132,21 @@ const teams = {
     updateProperties: jest.fn(() => teams.authorTeam),
     id: authorTeamID,
   },
+  revNoEditorRecommendationTeam: {
+    teamType: {
+      name: 'reviewer',
+      permissions: 'reviewer',
+    },
+    group: 'reviewer',
+    name: 'reviewer',
+    object: {
+      type: 'fragment',
+      id: noEditorRecomedationFragment.id,
+    },
+    members: [newReviewer.id],
+    save: jest.fn(() => teams.revNoEditorRecommendationTeam),
+    updateProperties: jest.fn(() => teams.revNoEditorRecommendationTeam),
+    id: revNoEditorRecommendationTeamID,
+  },
 }
 module.exports = teams
diff --git a/packages/component-fixture-manager/src/fixtures/userData.js b/packages/component-fixture-manager/src/fixtures/userData.js
index 2335d630e32ce34e6ffc521956dfcd079deaaf94..448301d410f6fb514bad7850c7285671aa235042 100644
--- a/packages/component-fixture-manager/src/fixtures/userData.js
+++ b/packages/component-fixture-manager/src/fixtures/userData.js
@@ -10,11 +10,13 @@ const generateUserData = () => ({
 
 module.exports = {
   handlingEditor: generateUserData(),
+  noRecommendationHE: generateUserData(),
   user: generateUserData(),
   admin: generateUserData(),
   author: generateUserData(),
   reviewer: generateUserData(),
   reviewer1: generateUserData(),
+  newReviewer: generateUserData(),
   answerReviewer: generateUserData(),
   submittingAuthor: generateUserData(),
   recReviewer: generateUserData(),
diff --git a/packages/component-fixture-manager/src/fixtures/users.js b/packages/component-fixture-manager/src/fixtures/users.js
index f0a6737c38eb46d4990c4131828b75e7af74ee4b..0ec653aab24e414415d7a11904367c2fdf94ede3 100644
--- a/packages/component-fixture-manager/src/fixtures/users.js
+++ b/packages/component-fixture-manager/src/fixtures/users.js
@@ -8,6 +8,8 @@ const {
   authorTeamID,
   revRecommendationTeamID,
   rev1TeamID,
+  heNoRecommendationTeamID,
+  revNoEditorRecommendationTeamID,
 } = require('./teamIDs')
 
 const keys = Object.keys(usersData)
@@ -17,21 +19,37 @@ users = keys.reduce((obj, item) => {
   const isHE = item === 'answerHE' || item === 'handlingEditor'
   let teams = []
 
-  if (isHE) {
-    teams = [heTeamID]
-  }
-  if (item === 'author') {
-    teams = [authorTeamID]
-  }
-  if (['reviewer', 'inactiveReviewer', 'answerReviewer'].includes(item)) {
-    teams.push(revTeamID)
-  }
-
-  if (['reviewer', 'answerReviewer', 'recReviewer'].includes(item)) {
-    teams.push(revRecommendationTeamID)
-  }
-  if (item === 'reviewer1') {
-    teams = [rev1TeamID]
+  switch (item) {
+    case 'answerHE':
+      teams = [heTeamID]
+      break
+    case 'handlingEditor':
+      teams = [heTeamID]
+      break
+    case 'noRecommendationHE':
+      teams = [heNoRecommendationTeamID]
+      break
+    case 'author':
+      teams = [authorTeamID]
+      break
+    case 'reviewer1':
+      teams = [rev1TeamID]
+      break
+    case 'newReviewer':
+      teams = [revNoEditorRecommendationTeamID]
+      break
+    case 'reviewer':
+    case 'answerReviewer':
+      teams = [revTeamID, revRecommendationTeamID]
+      break
+    case 'inactiveReviewer':
+      teams.push(revTeamID)
+      break
+    case 'recReviewer':
+      teams.push(revRecommendationTeamID)
+      break
+    default:
+      teams = []
   }
 
   obj[item] = {
diff --git a/packages/component-helper-service/src/services/Collection.js b/packages/component-helper-service/src/services/Collection.js
index d4a4310b2e39b974037596a603de4ecfac7e7354..b0789f05aa93601db62053ce8f5f18382b944973 100644
--- a/packages/component-helper-service/src/services/Collection.js
+++ b/packages/component-helper-service/src/services/Collection.js
@@ -1,3 +1,7 @@
+const { findLast, isEmpty, maxBy, get, flatMap } = require('lodash')
+
+const Fragment = require('./Fragment')
+
 class Collection {
   constructor({ collection = {} }) {
     this.collection = collection
@@ -6,6 +10,7 @@ class Collection {
   async updateStatusByRecommendation({
     recommendation,
     isHandlingEditor = false,
+    fragments,
   }) {
     let newStatus
     if (isHandlingEditor) {
@@ -15,7 +20,9 @@ class Collection {
       }
     } else {
       if (recommendation === 'minor') {
-        newStatus = 'reviewCompleted'
+        newStatus = this.hasAtLeastOneReviewReport(fragments)
+          ? 'reviewCompleted'
+          : 'heAssigned'
       }
 
       if (recommendation === 'major') {
@@ -23,7 +30,7 @@ class Collection {
       }
     }
 
-    this.updateStatus({ newStatus })
+    return this.updateStatus({ newStatus })
   }
 
   async updateFinalStatusByRecommendation({ recommendation }) {
@@ -85,24 +92,83 @@ class Collection {
   async updateStatusOnRecommendation({ isEditorInChief, recommendation }) {
     if (isEditorInChief) {
       if (recommendation === 'return-to-handling-editor') {
-        this.updateStatus({ newStatus: 'reviewCompleted' })
-      } else {
-        this.updateFinalStatusByRecommendation({
-          recommendation,
-        })
+        return this.updateStatus({ newStatus: 'reviewCompleted' })
       }
-    } else {
-      this.updateStatusByRecommendation({
+      return this.updateFinalStatusByRecommendation({
         recommendation,
-        isHandlingEditor: true,
       })
     }
+    return this.updateStatusByRecommendation({
+      recommendation,
+      isHandlingEditor: true,
+    })
   }
 
   getHELastName() {
     const [firstName, lastName] = this.collection.handlingEditor.name.split(' ')
     return lastName || firstName
   }
+
+  async getReviewerNumber({ userId }) {
+    const allCollectionFragments = await this.collection.getFragments()
+    const allCollectionInvitations = flatMap(
+      allCollectionFragments,
+      fragment => fragment.invitations,
+    )
+    const allNumberedInvitationsForUser = allCollectionInvitations
+      .filter(invite => invite.userId === userId)
+      .filter(invite => invite.reviewerNumber)
+
+    if (isEmpty(allNumberedInvitationsForUser)) {
+      const maxReviewerNumber = get(
+        maxBy(allCollectionInvitations, 'reviewerNumber'),
+        'reviewerNumber',
+        0,
+      )
+      return maxReviewerNumber + 1
+    }
+    return allNumberedInvitationsForUser[0].reviewerNumber
+  }
+
+  // eslint-disable-next-line class-methods-use-this
+  hasAtLeastOneReviewReport(fragments) {
+    return fragments.some(fragment =>
+      new Fragment({ fragment }).hasReviewReport(),
+    )
+  }
+
+  canHEMakeRecommendation(fragments, fragmentHelper) {
+    if (this.collection.fragments.length === 1) {
+      return fragmentHelper.hasReviewReport()
+    }
+    const previousVersionRecommendations = get(
+      fragments[fragments.length - 2],
+      'recommendations',
+      [],
+    )
+
+    const lastEditorRecommendation = findLast(
+      previousVersionRecommendations,
+      recommendation =>
+        recommendation.recommendationType === 'editorRecommendation',
+    )
+
+    if (lastEditorRecommendation.recommendation === 'minor') {
+      return this.hasAtLeastOneReviewReport(fragments)
+    } else if (lastEditorRecommendation.recommendation === 'major') {
+      return fragmentHelper.hasReviewReport()
+    }
+
+    return false
+  }
+
+  async getAllFragments({ FragmentModel }) {
+    return Promise.all(
+      this.collection.fragments.map(async fragment =>
+        FragmentModel.find(fragment),
+      ),
+    )
+  }
 }
 
 module.exports = Collection
diff --git a/packages/component-helper-service/src/services/Fragment.js b/packages/component-helper-service/src/services/Fragment.js
index 4b9e5edd4fefe8c3864698ba2ea205be4c3ecbac..7a0f27ae03d656269c6e5c757c094dd083f1ddb8 100644
--- a/packages/component-helper-service/src/services/Fragment.js
+++ b/packages/component-helper-service/src/services/Fragment.js
@@ -1,6 +1,9 @@
-const { get, remove } = require('lodash')
+const { get, remove, findLast, last } = require('lodash')
+const config = require('config')
 const User = require('./User')
 
+const { recommendations: configRecommendations } = config
+
 class Fragment {
   constructor({ fragment }) {
     this.fragment = fragment
@@ -142,10 +145,81 @@ class Fragment {
 
   hasReviewReport() {
     const { fragment: { recommendations = [] } } = this
-    return recommendations.find(
+    return recommendations.some(
       rec => rec.recommendationType === 'review' && rec.submittedOn,
     )
   }
+
+  canHEMakeAnotherRecommendation(currentUserRecommendations) {
+    const lastHERecommendation = last(currentUserRecommendations)
+    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 = [],
+      recommendations = [],
+      submitted = Date.now(),
+    } = this.fragment
+
+    const revAndEditorData = await Promise.all(
+      recommendations
+        .filter(
+          rec =>
+            rec.recommendationType === configRecommendations.type.editor ||
+            (rec.recommendationType === configRecommendations.type.review &&
+              rec.submittedOn),
+        )
+        .map(async rec => {
+          const user = await UserModel.find(rec.userId)
+          let assignmentDate, isReviewer
+
+          if (rec.recommendationType === configRecommendations.type.editor) {
+            if (!collection.handlingEditor) {
+              throw new Error(
+                `Collection ${collection.id} does not have a Handling Editor`,
+              )
+            }
+            if (user.id === collection.handlingEditor.id) {
+              const editorInvitation = collection.invitations.find(
+                inv => inv.userId === user.id,
+              )
+              assignmentDate = editorInvitation.respondedOn
+            } else {
+              assignmentDate = submitted
+            }
+
+            isReviewer = false
+          } else {
+            const reviewerInvitation = invitations.find(
+              inv => inv.userId === user.id,
+            )
+            assignmentDate = reviewerInvitation.respondedOn
+            isReviewer = true
+          }
+
+          return {
+            isReviewer,
+            assignmentDate,
+            email: user.email,
+            title: user.title,
+            recommendation: rec,
+            country: user.country,
+            lastName: user.lastName,
+            firstName: user.firstName,
+            affiliation: user.affiliation,
+            submissionDate: rec.createdOn,
+          }
+        }),
+    )
+
+    return revAndEditorData
+  }
 }
 
 module.exports = Fragment
diff --git a/packages/component-helper-service/src/tests/collection.test.js b/packages/component-helper-service/src/tests/collection.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..167153af8c03fc7149c36a9e8c149de351c0f7db
--- /dev/null
+++ b/packages/component-helper-service/src/tests/collection.test.js
@@ -0,0 +1,234 @@
+process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'
+process.env.SUPPRESS_NO_CONFIG_WARNING = true
+
+const { cloneDeep } = require('lodash')
+const fixturesService = require('pubsweet-component-fixture-service')
+
+const { fixtures, Model } = fixturesService
+const { Collection, Fragment } = require('../Helper')
+
+describe('Collection helper', () => {
+  let testFixtures = {}
+  let models
+
+  beforeEach(() => {
+    testFixtures = cloneDeep(fixtures)
+    models = Model.build(testFixtures)
+  })
+
+  describe('getReviewerNumber', () => {
+    it('should assign reviewer number 1 on invitation if no other reviewer numbers exist', async () => {
+      const { collection } = testFixtures.collections
+      const { reviewer } = testFixtures.users
+      const collectionHelper = new Collection({ collection })
+
+      const reviewerNumber = await collectionHelper.getReviewerNumber({
+        userId: reviewer.id,
+      })
+
+      expect(reviewerNumber).toBe(1)
+    })
+    it('should assign next reviewer number on invitation if another reviewer numbers exist', async () => {
+      const { collectionReviewCompleted } = testFixtures.collections
+      const { reviewer } = testFixtures.users
+      const collectionHelper = new Collection({
+        collection: collectionReviewCompleted,
+      })
+
+      const reviewerNumber = await collectionHelper.getReviewerNumber({
+        userId: reviewer.id,
+      })
+
+      expect(reviewerNumber).toBe(3)
+    })
+    it('should keep reviewer number across fragment versions', async () => {
+      const { oneReviewedFragmentCollection } = testFixtures.collections
+      const { answerReviewer } = testFixtures.users
+      const collectionHelper = new Collection({
+        collection: oneReviewedFragmentCollection,
+      })
+
+      const reviewerNumber = await collectionHelper.getReviewerNumber({
+        userId: answerReviewer.id,
+      })
+
+      expect(reviewerNumber).toBe(2)
+    })
+    it('should assign next reviewer number across fragment versions', async () => {
+      const { oneReviewedFragmentCollection } = testFixtures.collections
+      const { reviewer } = testFixtures.users
+      const collectionHelper = new Collection({
+        collection: oneReviewedFragmentCollection,
+      })
+
+      const reviewerNumber = await collectionHelper.getReviewerNumber({
+        userId: reviewer.id,
+      })
+
+      expect(reviewerNumber).toBe(3)
+    })
+  })
+
+  describe('hasAtLeastOneReviewReport', () => {
+    it('should return true if collection has at least one report from reviewers.', async () => {
+      const { collection } = testFixtures.collections
+      const collectionHelper = new Collection({ collection })
+      const FragmentModel = models.Fragment
+      const fragments = await collectionHelper.getAllFragments({
+        FragmentModel,
+      })
+      const hasReviewReport = await collectionHelper.hasAtLeastOneReviewReport(
+        fragments,
+      )
+      expect(hasReviewReport).toBe(true)
+    })
+    it('should return false if collection has at least one report from reviewers.', async () => {
+      const { noInvitesFragment } = testFixtures.fragments
+      const { collection } = testFixtures.collections
+      collection.fragments = [noInvitesFragment.id]
+      const collectionHelper = new Collection({ collection })
+      const FragmentModel = models.Fragment
+      const fragments = await collectionHelper.getAllFragments({
+        FragmentModel,
+      })
+      const hasReviewReport = await collectionHelper.hasAtLeastOneReviewReport(
+        fragments,
+      )
+      expect(hasReviewReport).toBe(false)
+    })
+  })
+
+  describe('canHEMakeRecommendation', () => {
+    it('should return true when creating a recommendation as a HE when there is a single version with at least one review.', async () => {
+      const { collection } = testFixtures.collections
+      const { fragment } = testFixtures.fragments
+      const collectionHelper = new Collection({
+        collection,
+      })
+      const FragmentModel = models.Fragment
+      const fragments = await collectionHelper.getAllFragments({
+        FragmentModel,
+      })
+      const fragmentHelper = new Fragment({ fragment })
+      const canHEMakeRecommendation = await collectionHelper.canHEMakeRecommendation(
+        fragments,
+        fragmentHelper,
+      )
+      expect(canHEMakeRecommendation).toBe(true)
+    })
+    it('should return false when creating a recommendation with publish as a HE when there is a single version and there are no reviews.', async () => {
+      const { collection } = testFixtures.collections
+      const { fragment } = testFixtures.fragments
+      fragment.recommendations = undefined
+
+      const collectionHelper = new Collection({
+        collection,
+      })
+      const FragmentModel = models.Fragment
+      const fragments = await collectionHelper.getAllFragments({
+        FragmentModel,
+      })
+      const fragmentHelper = new Fragment({ fragment })
+      const canHEMakeRecommendation = await collectionHelper.canHEMakeRecommendation(
+        fragments,
+        fragmentHelper,
+      )
+      expect(canHEMakeRecommendation).toBe(false)
+    })
+    it('should return true when creating a recommendation as a HE after minor revision and we have at least one review on collection.', async () => {
+      const { collection } = testFixtures.collections
+      const {
+        minorRevisionWithReview,
+        noInvitesFragment1,
+      } = testFixtures.fragments
+      collection.fragments = [minorRevisionWithReview.id, noInvitesFragment1.id]
+      const collectionHelper = new Collection({
+        collection,
+      })
+      const FragmentModel = models.Fragment
+      const fragments = await collectionHelper.getAllFragments({
+        FragmentModel,
+      })
+      const fragmentHelper = new Fragment({ fragment: noInvitesFragment1 })
+
+      const canHEMakeRecommendation = await collectionHelper.canHEMakeRecommendation(
+        fragments,
+        fragmentHelper,
+      )
+      expect(canHEMakeRecommendation).toBe(true)
+    })
+    it('should return false when creating a recommendation as a HE after minor revision and there are no reviews.', async () => {
+      const { collection } = testFixtures.collections
+      const {
+        minorRevisionWithoutReview,
+        noInvitesFragment1,
+      } = testFixtures.fragments
+      collection.fragments = [
+        minorRevisionWithoutReview.id,
+        noInvitesFragment1.id,
+      ]
+
+      const collectionHelper = new Collection({
+        collection,
+      })
+      const FragmentModel = models.Fragment
+      const fragments = await collectionHelper.getAllFragments({
+        FragmentModel,
+      })
+      const fragmentHelper = new Fragment({ noInvitesFragment1 })
+      const canHEMakeRecommendation = await collectionHelper.canHEMakeRecommendation(
+        fragments,
+        fragmentHelper,
+      )
+      expect(canHEMakeRecommendation).toBe(false)
+    })
+    it('should return true when creating a recommendation as a HE after major revision and there are least one review on fragment.', async () => {
+      const { collection } = testFixtures.collections
+      const {
+        majorRevisionWithReview,
+        reviewCompletedFragment,
+      } = testFixtures.fragments
+
+      reviewCompletedFragment.collectionId = collection.id
+      collection.fragments = [
+        majorRevisionWithReview.id,
+        reviewCompletedFragment.id,
+      ]
+
+      const collectionHelper = new Collection({
+        collection,
+      })
+      const FragmentModel = models.Fragment
+      const fragments = await collectionHelper.getAllFragments({
+        FragmentModel,
+      })
+      const fragmentHelper = new Fragment({ fragment: reviewCompletedFragment })
+      const canHEMakeRecommendation = await collectionHelper.canHEMakeRecommendation(
+        fragments,
+        fragmentHelper,
+      )
+      expect(canHEMakeRecommendation).toBe(true)
+    })
+    it('should return false when creating a recommendation as a HE after major revision there are no reviews on fragment.', async () => {
+      const { collection } = testFixtures.collections
+      const {
+        majorRevisionWithReview,
+        noInvitesFragment1,
+      } = testFixtures.fragments
+      collection.fragments = [majorRevisionWithReview.id, noInvitesFragment1.id]
+      const collectionHelper = new Collection({
+        collection,
+      })
+      const FragmentModel = models.Fragment
+      const fragments = await collectionHelper.getAllFragments({
+        FragmentModel,
+      })
+      const fragmentHelper = new Fragment({ fragment: noInvitesFragment1 })
+      const canHEMakeRecommendation = await collectionHelper.canHEMakeRecommendation(
+        fragments,
+        fragmentHelper,
+      )
+      expect(canHEMakeRecommendation).toBe(false)
+    })
+  })
+})
diff --git a/packages/component-helper-service/src/tests/fragment.test.js b/packages/component-helper-service/src/tests/fragment.test.js
index 61e86748001df9b64466c7ed461bd1cf0c27c918..c5623dc18a8d7cf4812d3695189319f48b7e2202 100644
--- a/packages/component-helper-service/src/tests/fragment.test.js
+++ b/packages/component-helper-service/src/tests/fragment.test.js
@@ -1,17 +1,22 @@
 process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'
 process.env.SUPPRESS_NO_CONFIG_WARNING = true
 
+const Chance = require('chance')
+const config = require('config')
 const { cloneDeep } = require('lodash')
 const fixturesService = require('pubsweet-component-fixture-service')
-const Chance = require('chance')
 
 const chance = new Chance()
-const { fixtures } = fixturesService
+const { fixtures, Model } = fixturesService
 const { Fragment } = require('../Helper')
 
+const { recommendations: configRecommendations } = config
+
 const acceptedReviewerId = chance.guid()
 const submittedReviewerId1 = chance.guid()
 const submittedReviewerId2 = chance.guid()
+const handlingEditorId = chance.guid()
+const editorInChiefId = chance.guid()
 const fragment = {
   invitations: [
     {
@@ -117,9 +122,11 @@ const fragment = {
 describe('Fragment helper', () => {
   let testFixtures = {}
   let testFragment = {}
+  let models = {}
   beforeEach(() => {
     testFixtures = cloneDeep(fixtures)
     testFragment = cloneDeep(fragment)
+    models = Model.build(testFixtures)
   })
 
   describe('hasReviewReport', () => {
@@ -237,4 +244,132 @@ describe('Fragment helper', () => {
       expect(pendingInvitations).toHaveLength(1)
     })
   })
+  describe('getReviewersAndEditorsData', () => {
+    it('should return an array of users (reviewers, editors) that have submitted a review', async () => {
+      const { collection } = testFixtures.collections
+      const { fragment } = testFixtures.fragments
+      const fragmentHelper = new Fragment({ fragment })
+
+      const fragmentUsers = await fragmentHelper.getReviewersAndEditorsData({
+        collection,
+        UserModel: models.User,
+      })
+
+      expect(fragmentUsers.length).toBeGreaterThan(0)
+      const submittedRecommendations = fragment.recommendations.filter(
+        rec =>
+          rec.recommendationType === configRecommendations.type.editor ||
+          (rec.recommendationType === configRecommendations.type.review &&
+            rec.submittedOn),
+      )
+
+      expect(fragmentUsers).toHaveLength(submittedRecommendations.length)
+    })
+    it('should return an error when the collection does not have a handling editor', async () => {
+      const { collection } = testFixtures.collections
+      const { fragment } = testFixtures.fragments
+      const fragmentHelper = new Fragment({ fragment })
+
+      delete collection.handlingEditor
+      try {
+        await fragmentHelper.getReviewersAndEditorsData({
+          collection,
+          UserModel: models.User,
+        })
+      } catch (e) {
+        expect(e.message).toEqual(
+          `Collection ${collection.id} does not have a Handling Editor`,
+        )
+      }
+    })
+  })
+  describe('canHEMakeAnotherRecommendation', () => {
+    it('should return true when He makes a recommendation after EIC decision was to return to HE', async () => {
+      testFragment.recommendations = [
+        {
+          recommendation: 'publish',
+          recommendationType: 'editorRecommendation',
+          comments: [
+            {
+              content: chance.paragraph(),
+              public: true,
+              files: [
+                {
+                  id: chance.guid(),
+                  name: 'file.pdf',
+                  size: chance.natural(),
+                },
+              ],
+            },
+          ],
+          id: chance.guid(),
+          userId: handlingEditorId,
+          createdOn: 1542361074012,
+          updatedOn: chance.timestamp(),
+        },
+        {
+          recommendation: 'return-to-handling-editor',
+          recommendationType: 'editorRecommendation',
+          comments: [
+            {
+              content: chance.paragraph(),
+              public: true,
+              files: [
+                {
+                  id: chance.guid(),
+                  name: 'file.pdf',
+                  size: chance.natural(),
+                },
+              ],
+            },
+          ],
+          id: chance.guid(),
+          userId: editorInChiefId,
+          createdOn: 1542361115749,
+          updatedOn: chance.timestamp(),
+        },
+      ]
+      const currentUserRecommendations = testFragment.recommendations.filter(
+        r => r.userId === handlingEditorId,
+      )
+      const fragmentHelper = new Fragment({ fragment: testFragment })
+      const canHEMakeAnotherRecommendation = await fragmentHelper.canHEMakeAnotherRecommendation(
+        currentUserRecommendations,
+      )
+      expect(canHEMakeAnotherRecommendation).toBe(true)
+    })
+    it('should return false when He makes another recommendation', async () => {
+      testFragment.recommendations = [
+        {
+          recommendation: 'publish',
+          recommendationType: 'editorRecommendation',
+          comments: [
+            {
+              content: chance.paragraph(),
+              public: true,
+              files: [
+                {
+                  id: chance.guid(),
+                  name: 'file.pdf',
+                  size: chance.natural(),
+                },
+              ],
+            },
+          ],
+          id: chance.guid(),
+          userId: handlingEditorId,
+          createdOn: 1542361074012,
+          updatedOn: chance.timestamp(),
+        },
+      ]
+      const currentUserRecommendations = testFragment.recommendations.filter(
+        r => r.userId === handlingEditorId,
+      )
+      const fragmentHelper = new Fragment({ fragment: testFragment })
+      const canHEMakeAnotherRecommendation = await fragmentHelper.canHEMakeAnotherRecommendation(
+        currentUserRecommendations,
+      )
+      expect(canHEMakeAnotherRecommendation).toBe(false)
+    })
+  })
 })
diff --git a/packages/component-invite/src/CollectionsInvitations.js b/packages/component-invite/src/CollectionsInvitations.js
index 2f80dd1b70e3089a7ab7f9068a4e12dbb84985e5..0b72a54da398154f0b1e82b5f78601d57cf86064 100644
--- a/packages/component-invite/src/CollectionsInvitations.js
+++ b/packages/component-invite/src/CollectionsInvitations.js
@@ -39,7 +39,7 @@ const CollectionsInvitations = app => {
     require(`${routePath}/post`)(app.locals.models),
   )
   /**
-   * @api {delete} /api/collections/:collectionId/invitations/:invitationId Delete invitation
+   * @api {delete} /api/collections/:collectionId/invitations/:invitationId Delete invitation (or revoke HE if invitation is accepted)
    * @apiGroup CollectionsInvitations
    * @apiParam {collectionId} collectionId Collection id
    * @apiParam {invitationId} invitationId Invitation id
diff --git a/packages/component-invite/src/routes/collectionsInvitations/delete.js b/packages/component-invite/src/routes/collectionsInvitations/delete.js
index 5686d03f2ee8df3c62d1e212fea56cc3bc5a46e0..75bc11393f4356d744d9f38f7c4e997db0f129ab 100644
--- a/packages/component-invite/src/routes/collectionsInvitations/delete.js
+++ b/packages/component-invite/src/routes/collectionsInvitations/delete.js
@@ -1,8 +1,17 @@
+const config = require('config')
+
 const {
   Team,
   services,
   authsome: authsomeHelper,
 } = require('pubsweet-component-helper-service')
+const {
+  deleteFilesS3,
+} = require('pubsweet-component-mts-package/src/PackageManager')
+
+const { last, get, chain, difference } = require('lodash')
+
+const s3Config = get(config, 'pubsweet-component-aws-s3', {})
 
 const notifications = require('./emails/notifications')
 
@@ -56,10 +65,49 @@ module.exports = models => async (req, res) => {
     user.teams = user.teams.filter(userTeamId => team.id !== userTeamId)
     await user.save()
 
-    notifications.sendNotifications({
+    if (invitation.hasAnswer && invitation.isAccepted) {
+      const FragmentModel = models.Fragment
+      const fragment = await FragmentModel.find(
+        last(get(collection, 'fragments', [])),
+      )
+
+      const fileKeys = []
+      fragment.recommendations &&
+        fragment.recommendations.forEach(recommendation => {
+          recommendation.comments.forEach(comment => {
+            comment.files &&
+              comment.files.forEach(file => {
+                fileKeys.push(file.id)
+              })
+          })
+        })
+
+      const revision = get(fragment, 'revision', false)
+      if (revision) {
+        const fragmentFilesIds = chain(get(fragment, 'files', []))
+          .flatMap(item => item)
+          .map(item => item.id)
+          .value()
+        const revisionFilesIds = chain(get(fragment, 'revision.files', []))
+          .flatMap(item => item)
+          .map(item => item.id)
+          .value()
+        const revisionFileIds = difference(revisionFilesIds, fragmentFilesIds)
+        fileKeys.concat(revisionFileIds)
+      }
+      if (fileKeys.length > 1) {
+        await deleteFilesS3({ fileKeys, s3Config })
+      }
+
+      fragment.invitations = []
+      fragment.recommendations = []
+      fragment.revision && delete fragment.revision
+      fragment.save()
+    }
+
+    notifications.sendInvitedHEEmail({
       models,
       collection,
-      isEiC: true,
       invitedHE: user,
       isCanceled: true,
       baseUrl: services.getBaseUrl(req),
diff --git a/packages/component-invite/src/routes/collectionsInvitations/emails/helpers.js b/packages/component-invite/src/routes/collectionsInvitations/emails/helpers.js
deleted file mode 100644
index 11a81820196eb1e7d4ac0048892def94fa91b031..0000000000000000000000000000000000000000
--- a/packages/component-invite/src/routes/collectionsInvitations/emails/helpers.js
+++ /dev/null
@@ -1,78 +0,0 @@
-const config = require('config')
-const { services } = require('pubsweet-component-helper-service')
-
-const { getEmailCopy } = require('./emailCopy')
-
-const unsubscribeSlug = config.get('unsubscribe.url')
-
-module.exports = {
-  sendInvitedHEEmail: ({
-    email,
-    eicName,
-    baseUrl,
-    customId,
-    titleText,
-    isCanceled,
-    handlingEditor,
-  }) => {
-    email.toUser = {
-      email: handlingEditor.email,
-    }
-
-    email.content.subject = isCanceled
-      ? `${customId}: Editor invitation cancelled`
-      : `${customId}: Invitation to edit a manuscript`
-
-    email.content.unsubscribeLink = services.createUrl(
-      baseUrl,
-      unsubscribeSlug,
-      {
-        id: handlingEditor.id,
-        token: handlingEditor.accessTokens.unsubscribe,
-      },
-    )
-
-    const { html, text } = email.getNotificationBody({
-      emailBodyProps: getEmailCopy({
-        titleText,
-        targetUserName: eicName,
-        emailType: isCanceled ? 'he-revoked' : 'he-assigned',
-      }),
-    })
-
-    email.sendEmail({ html, text })
-  },
-  sendEiCEmail: async ({
-    eic,
-    email,
-    baseUrl,
-    customId,
-    comments,
-    titleText,
-    isAccepted,
-    targetUserName,
-  }) => {
-    email.content.subject = isAccepted
-      ? `${customId}: Editor invitation accepted`
-      : `${customId}: Editor invitation declined`
-
-    const emailType = isAccepted ? 'he-accepted' : 'he-declined'
-
-    email.toUser = {
-      email: eic.email,
-    }
-
-    email.content.unsubscribeLink = services.createUrl(baseUrl)
-
-    const { html, text } = email.getNotificationBody({
-      emailBodyProps: getEmailCopy({
-        comments,
-        emailType,
-        titleText,
-        targetUserName,
-      }),
-    })
-
-    email.sendEmail({ html, text })
-  },
-}
diff --git a/packages/component-invite/src/routes/collectionsInvitations/emails/notifications.js b/packages/component-invite/src/routes/collectionsInvitations/emails/notifications.js
index 65e1375189adc5fc06576082ad8c8b206ae35dc0..2b85380e873f1a686ed362c33c0b991eabac3aef 100644
--- a/packages/component-invite/src/routes/collectionsInvitations/emails/notifications.js
+++ b/packages/component-invite/src/routes/collectionsInvitations/emails/notifications.js
@@ -10,19 +10,77 @@ const {
   Fragment,
 } = require('pubsweet-component-helper-service')
 
-const { sendInvitedHEEmail, sendEiCEmail } = require('./helpers')
+const { getEmailCopy } = require('./emailCopy')
+
+const unsubscribeSlug = config.get('unsubscribe.url')
 
 module.exports = {
-  async sendNotifications({
-    reason,
+  sendInvitedHEEmail: async ({
     baseUrl,
     invitedHE,
     collection,
-    isEiC = false,
     isCanceled = false,
+    models: { User: UserModel, Fragment: FragmentModel },
+  }) => {
+    const fragmentId = last(collection.fragments)
+    const fragment = await FragmentModel.find(fragmentId)
+    const fragmentHelper = new Fragment({ fragment })
+    const { title } = await fragmentHelper.getFragmentData()
+    const { submittingAuthor } = await fragmentHelper.getAuthorData({
+      UserModel,
+    })
+
+    const titleText = `the manuscript titled "${title}" by ${
+      submittingAuthor.firstName
+    } ${submittingAuthor.lastName}`
+
+    const userHelper = new User({ UserModel })
+    const eics = await userHelper.getEditorsInChief()
+    const eic = eics[0]
+    const eicName = `${eic.firstName} ${eic.lastName}`
+    const { customId } = collection
+
+    const { paragraph, ...bodyProps } = getEmailCopy({
+      titleText,
+      targetUserName: eicName,
+      emailType: isCanceled ? 'he-revoked' : 'he-assigned',
+    })
+
+    const email = new Email({
+      type: 'user',
+      fromEmail: `${journalName} <${staffEmail}>`,
+      toUser: {
+        email: invitedHE.email,
+      },
+      content: {
+        subject: isCanceled
+          ? `${customId}: Editor invitation cancelled`
+          : `${customId}: Invitation to edit a manuscript`,
+        paragraph,
+        signatureName: eicName,
+        ctaLink: services.createUrl(
+          baseUrl,
+          `/projects/${collection.id}/versions/${fragment.id}/details`,
+        ),
+        ctaText: 'MANUSCRIPT DETAILS',
+        unsubscribeLink: services.createUrl(baseUrl, unsubscribeSlug, {
+          id: invitedHE.id,
+          token: invitedHE.accessTokens.unsubscribe,
+        }),
+      },
+      bodyProps,
+    })
+
+    return email.sendEmail()
+  },
+  sendEiCEmail: async ({
+    reason,
+    baseUrl,
+    invitedHE,
+    collection,
     isAccepted = false,
     models: { User: UserModel, Fragment: FragmentModel },
-  }) {
+  }) => {
     const fragmentId = last(collection.fragments)
     const fragment = await FragmentModel.find(fragmentId)
     const fragmentHelper = new Fragment({ fragment })
@@ -41,40 +99,37 @@ module.exports = {
     const eicName = `${eic.firstName} ${eic.lastName}`
     const { customId } = collection
 
+    const emailType = isAccepted ? 'he-accepted' : 'he-declined'
+
+    const { paragraph, ...bodyProps } = getEmailCopy({
+      emailType,
+      titleText,
+      comments: reason ? `Reason: "${reason}"` : '',
+      targetUserName: `${invitedHE.lastName}`,
+    })
+
     const email = new Email({
       type: 'user',
       fromEmail: `${journalName} <${staffEmail}>`,
+      toUser: {
+        email: eic.email,
+      },
       content: {
+        subject: isAccepted
+          ? `${customId}: Editor invitation accepted`
+          : `${customId}: Editor invitation declined`,
+        paragraph,
         signatureName: eicName,
         ctaLink: services.createUrl(
           baseUrl,
           `/projects/${collection.id}/versions/${fragment.id}/details`,
         ),
         ctaText: 'MANUSCRIPT DETAILS',
+        unsubscribeLink: services.createUrl(baseUrl),
       },
+      bodyProps,
     })
 
-    if (isEiC) {
-      sendInvitedHEEmail({
-        email,
-        baseUrl,
-        eicName,
-        customId,
-        titleText,
-        isCanceled,
-        handlingEditor: invitedHE,
-      })
-    } else {
-      sendEiCEmail({
-        eic,
-        email,
-        baseUrl,
-        customId,
-        titleText,
-        isAccepted,
-        comments: reason ? `Reason: "${reason}"` : '',
-        targetUserName: `${invitedHE.lastName}`,
-      })
-    }
+    return email.sendEmail()
   },
 }
diff --git a/packages/component-invite/src/routes/collectionsInvitations/patch.js b/packages/component-invite/src/routes/collectionsInvitations/patch.js
index 28452a347b73af471b0ff6eaaa8bbffc8e259df9..792711ff1717bb6104a72b5b7e9eb3bed4cbf0c4 100644
--- a/packages/component-invite/src/routes/collectionsInvitations/patch.js
+++ b/packages/component-invite/src/routes/collectionsInvitations/patch.js
@@ -10,8 +10,7 @@ module.exports = models => async (req, res) => {
   const { collectionId, invitationId } = req.params
   const { isAccepted, reason } = req.body
 
-  const UserModel = models.User
-  const user = await UserModel.find(req.user)
+  const user = await models.User.find(req.user)
 
   try {
     const collection = await models.Collection.find(collectionId)
@@ -53,7 +52,7 @@ module.exports = models => async (req, res) => {
 
     await collection.save()
 
-    notifications.sendNotifications({
+    notifications.sendEiCEmail({
       models,
       reason,
       collection,
diff --git a/packages/component-invite/src/routes/collectionsInvitations/post.js b/packages/component-invite/src/routes/collectionsInvitations/post.js
index 6f28624ea068201d27a33274b2d4dac016d7a57f..7d404e0cec4a91d3a74808722332a7266963aa78 100644
--- a/packages/component-invite/src/routes/collectionsInvitations/post.js
+++ b/packages/component-invite/src/routes/collectionsInvitations/post.js
@@ -21,8 +21,7 @@ module.exports = models => async (req, res) => {
       error: `Role ${role} is invalid. Only handlingEditor is allowed.`,
     })
 
-  const UserModel = models.User
-  const reqUser = await UserModel.find(req.user)
+  const reqUser = await models.User.find(req.user)
 
   if (email === reqUser.email && !reqUser.admin) {
     logger.error(`${reqUser.email} tried to invite his own email`)
@@ -68,7 +67,7 @@ module.exports = models => async (req, res) => {
   const invitationHelper = new Invitation({ role })
 
   try {
-    const user = await UserModel.findByEmail(email)
+    const user = await models.User.findByEmail(email)
     invitationHelper.userId = user.id
     let invitation = invitationHelper.getInvitation({
       invitations: collection.invitations,
@@ -92,10 +91,9 @@ module.exports = models => async (req, res) => {
     await collection.save()
     await collectionHelper.addHandlingEditor({ user, invitation })
 
-    notifications.sendNotifications({
+    notifications.sendInvitedHEEmail({
       models,
       collection,
-      isEiC: true,
       invitedHE: user,
       baseUrl: services.getBaseUrl(req),
     })
diff --git a/packages/component-invite/src/routes/fragmentsInvitations/decline.js b/packages/component-invite/src/routes/fragmentsInvitations/decline.js
index 8d7e5d97541e08dc4a9ae912867ce58a8e61df4e..41be1c65538556c53046c4c3956176cdfb74c810 100644
--- a/packages/component-invite/src/routes/fragmentsInvitations/decline.js
+++ b/packages/component-invite/src/routes/fragmentsInvitations/decline.js
@@ -93,7 +93,7 @@ module.exports = models => async (req, res) => {
   user.teams = user.teams.filter(userTeamId => reviewerTeam.id !== userTeamId)
   await user.save()
 
-  notifications.sendNotifications({
+  notifications.sendHandlingEditorEmail({
     baseUrl,
     fragment,
     collection,
diff --git a/packages/component-invite/src/routes/fragmentsInvitations/delete.js b/packages/component-invite/src/routes/fragmentsInvitations/delete.js
index 306829c0a9c794b1de1b7fa4932fc69e2a3da46b..68c7e77c2d33ebffb425b0df485c2dbdd547e4c0 100644
--- a/packages/component-invite/src/routes/fragmentsInvitations/delete.js
+++ b/packages/component-invite/src/routes/fragmentsInvitations/delete.js
@@ -70,14 +70,13 @@ module.exports = models => async (req, res) => {
 
     const baseUrl = services.getBaseUrl(req)
 
-    notifications.sendNotifications({
+    notifications.sendReviewerEmail({
       baseUrl,
       fragment,
       collection,
       reviewer: user,
       isCanceled: true,
       UserModel: models.User,
-      emailType: 'reviewer-cancel-invitation',
     })
 
     return res.status(200).json({ fragment })
diff --git a/packages/component-invite/src/routes/fragmentsInvitations/emails/invitations.js b/packages/component-invite/src/routes/fragmentsInvitations/emails/invitations.js
index 2d0df7d2f3effbbc2e51270f0082c74fd770bcdc..2a2e5e0d3f76877c410e835cbe3fc2c9e092da3d 100644
--- a/packages/component-invite/src/routes/fragmentsInvitations/emails/invitations.js
+++ b/packages/component-invite/src/routes/fragmentsInvitations/emails/invitations.js
@@ -11,7 +11,7 @@ const { services, Fragment } = require('pubsweet-component-helper-service')
 const { getEmailCopy } = require('./emailCopy')
 
 module.exports = {
-  async sendInvitations({
+  async sendReviewInvitations({
     resend,
     baseUrl,
     fragment,
@@ -28,41 +28,36 @@ module.exports = {
     const {
       activeAuthors: authors,
       submittingAuthor,
-    } = await fragmentHelper.getAuthorData({
-      UserModel,
-    })
+    } = await fragmentHelper.getAuthorData({ UserModel })
 
-    const subjectBaseText = `${collection.customId}: Review`
-
-    let queryParams = {
-      invitationId: invitation.id,
-      agree: true,
-    }
+    let subjectBaseText = `${collection.customId}: Review invitation`
 
     const detailsPath = `/projects/${collection.id}/versions/${
       fragment.id
     }/details`
 
     const declineLink = services.createUrl(baseUrl, inviteReviewerPath, {
-      ...queryParams,
+      invitationId: invitation.id,
       agree: false,
       fragmentId: fragment.id,
       collectionId: collection.id,
       invitationToken: invitedUser.accessTokens.invitation,
     })
 
-    let agreeLink = services.createUrl(baseUrl, detailsPath, queryParams)
+    let agreeLink = services.createUrl(baseUrl, detailsPath, {
+      invitationId: invitation.id,
+      agree: true,
+    })
 
     if (!invitedUser.isConfirmed) {
-      queryParams = {
-        ...queryParams,
+      agreeLink = services.createUrl(baseUrl, inviteReviewerPath, {
+        invitationId: invitation.id,
         agree: true,
         fragmentId: fragment.id,
         email: invitedUser.email,
         collectionId: collection.id,
         token: invitedUser.accessTokens.passwordReset,
-      }
-      agreeLink = services.createUrl(baseUrl, inviteReviewerPath, queryParams)
+      })
     }
 
     const authorsList = authors.map(
@@ -70,12 +65,35 @@ module.exports = {
     )
 
     const handlingEditor = get(collection, 'handlingEditor', {})
+
+    const authorName = `${submittingAuthor.firstName} ${
+      submittingAuthor.lastName
+    }`
+
+    let daysExpected = 14
+    let emailType = 'reviewer-invitation'
+    let titleText = `A manuscript titled <strong>"${title}"</strong> by <strong>${authorName}</strong> et al.`
+
+    if (resend) {
+      emailType = 'reviewer-resend-invitation'
+      daysExpected = 0
+      subjectBaseText = `${subjectBaseText} reminder`
+      titleText = `the manuscript titled "${title}" by ${authorName}`
+    }
+
+    const { paragraph, ...bodyProps } = getEmailCopy({
+      emailType,
+      titleText,
+      expectedDate: services.getExpectedDate({ timestamp, daysExpected }),
+    })
+
     const email = new Email({
       type: 'user',
+      templateType: 'invitation',
       fromEmail: `${handlingEditor.name} <${staffEmail}>`,
       toUser: {
         email: invitedUser.email,
-        name: `${invitedUser.lastName}`,
+        name: invitedUser.lastName,
       },
       content: {
         title,
@@ -85,50 +103,17 @@ module.exports = {
         signatureJournal: journalName,
         signatureName: handlingEditor.name,
         authorsList: authorsList.join(', '),
-        subject: `${subjectBaseText} invitation`,
+        subject: subjectBaseText,
+        paragraph,
         detailsLink: services.createUrl(baseUrl, detailsPath),
         unsubscribeLink: services.createUrl(baseUrl, unsubscribeSlug, {
           id: invitedUser.id,
           token: invitedUser.accessTokens.unsubscribe,
         }),
       },
+      bodyProps,
     })
 
-    sendInvitedUserEmail({
-      email,
-      title,
-      resend,
-      timestamp,
-      authorName: `${submittingAuthor.firstName} ${submittingAuthor.lastName}`,
-    })
+    return email.sendEmail()
   },
 }
-
-const sendInvitedUserEmail = async ({
-  email,
-  resend,
-  title,
-  authorName,
-  timestamp,
-}) => {
-  let daysExpected = 14
-  let emailType = 'reviewer-invitation'
-  let titleText = `A manuscript titled <strong>"${title}"</strong> by <strong>${authorName}</strong> et al.`
-
-  if (resend) {
-    emailType = 'reviewer-resend-invitation'
-    daysExpected = 0
-    email.content.subject = `${email.content.subject} reminder`
-    titleText = `the manuscript titled "${title}" by ${authorName}`
-  }
-
-  const { html, text } = email.getInvitationBody({
-    emailBodyProps: getEmailCopy({
-      emailType,
-      titleText,
-      expectedDate: services.getExpectedDate({ timestamp, daysExpected }),
-    }),
-  })
-
-  email.sendEmail({ html, text })
-}
diff --git a/packages/component-invite/src/routes/fragmentsInvitations/emails/notifications.js b/packages/component-invite/src/routes/fragmentsInvitations/emails/notifications.js
index c2c04f72476a23ce91749544a279e10a459b16c3..17b38e769558e10ac9f1a1a917356cec91190bbe 100644
--- a/packages/component-invite/src/routes/fragmentsInvitations/emails/notifications.js
+++ b/packages/component-invite/src/routes/fragmentsInvitations/emails/notifications.js
@@ -15,15 +15,14 @@ const {
 const { getEmailCopy } = require('./emailCopy')
 
 module.exports = {
-  async sendNotifications({
+  sendHandlingEditorEmail: async ({
     baseUrl,
     fragment,
     reviewer,
     UserModel,
     emailType,
     collection,
-    isCanceled = false,
-  }) {
+  }) => {
     const fragmentHelper = new Fragment({ fragment })
     const { title } = await fragmentHelper.getFragmentData({
       handlingEditor: collection.handlingEditor,
@@ -40,119 +39,106 @@ module.exports = {
     const userHelper = new User({ UserModel })
     const eicName = await userHelper.getEiCName()
 
+    const heUser = await UserModel.find(handlingEditor.id)
+
+    const { paragraph, ...bodyProps } = getEmailCopy({
+      emailType,
+      titleText,
+      expectedDate: services.getExpectedDate({
+        timestamp: Date.now(),
+        daysExpected: 14,
+      }),
+      targetUserName: reviewer.lastName,
+    })
+
     const email = new Email({
-      fromEmail: `${handlingEditor.name} <${staffEmail}>`,
+      fromEmail: `${eicName} <${staffEmail}>`,
       type: 'user',
+      toUser: {
+        email: heUser.email,
+        name: heUser.lastName,
+      },
       content: {
+        subject:
+          emailType === 'reviewer-accepted'
+            ? `${collection.customId}: A reviewer has agreed`
+            : `${collection.customId}: A reviewer has declined`,
+        paragraph,
         ctaText: 'MANUSCRIPT DETAILS',
-        signatureJournal: journalName,
-        signatureName: handlingEditor.name,
+        signatureJournal: '',
+        signatureName: eicName,
         ctaLink: services.createUrl(
           baseUrl,
           `/projects/${collection.id}/versions/${fragment.id}/details`,
         ),
+        unsubscribeLink: services.createUrl(baseUrl, unsubscribeSlug, {
+          id: heUser.id,
+          token: heUser.accessTokens.unsubscribe,
+        }),
       },
+      bodyProps,
     })
 
-    if (emailType !== 'reviewer-declined') {
-      sendReviewerEmail({
-        email,
-        baseUrl,
-        reviewer,
-        titleText,
-        isCanceled,
-        customId: collection.customId,
-      })
-    }
-
-    if (['reviewer-accepted', 'reviewer-declined'].includes(emailType)) {
-      const heUser = await UserModel.find(handlingEditor.id)
-      email.fromEmail = `${eicName} <${staffEmail}>`
-      sendHandlingEditorEmail({
-        email,
-        eicName,
-        titleText,
-        emailType,
-        handlingEditor: heUser,
-        customId: collection.customId,
-        targetUserName: `${reviewer.lastName}`,
-      })
-    }
+    return email.sendEmail()
   },
-}
+  sendReviewerEmail: async ({
+    baseUrl,
+    fragment,
+    reviewer,
+    UserModel,
+    collection,
+    isCanceled = false,
+  }) => {
+    const fragmentHelper = new Fragment({ fragment })
+    const { title } = await fragmentHelper.getFragmentData({
+      handlingEditor: collection.handlingEditor,
+    })
+    const { submittingAuthor } = await fragmentHelper.getAuthorData({
+      UserModel,
+    })
 
-const sendHandlingEditorEmail = ({
-  email,
-  eicName,
-  baseUrl,
-  customId,
-  titleText,
-  emailType,
-  handlingEditor,
-  targetUserName,
-}) => {
-  email.toUser = {
-    email: handlingEditor.email,
-    name: handlingEditor.lastName,
-  }
-
-  email.content.subject =
-    emailType === 'reviewer-accepted'
-      ? `${customId}: A reviewer has agreed`
-      : `${customId}: A reviewer has declined`
-  email.content.unsubscribeLink = services.createUrl(baseUrl, unsubscribeSlug, {
-    id: handlingEditor.id,
-    token: handlingEditor.accessTokens.unsubscribe,
-  })
-  email.content.signatureName = eicName
-  email.content.signatureJournal = ''
-
-  const { html, text } = email.getNotificationBody({
-    emailBodyProps: getEmailCopy({
-      emailType,
-      titleText,
-      expectedDate: services.getExpectedDate({
-        timestamp: Date.now(),
-        daysExpected: 14,
-      }),
-      targetUserName,
-    }),
-  })
-  email.sendEmail({ html, text })
-}
+    const titleText = `the manuscript titled "${title}" by ${
+      submittingAuthor.firstName
+    } ${submittingAuthor.lastName}`
+
+    const handlingEditor = get(collection, 'handlingEditor')
+
+    const emailType = isCanceled
+      ? 'reviewer-cancel-invitation'
+      : 'reviewer-thank-you'
 
-const sendReviewerEmail = async ({
-  email,
-  baseUrl,
-  reviewer,
-  customId,
-  titleText,
-  isCanceled,
-}) => {
-  email.content.subject = isCanceled
-    ? `${customId}: Review no longer required`
-    : `${customId}: Thank you for agreeing to review`
-
-  const emailType = isCanceled
-    ? 'reviewer-cancel-invitation'
-    : 'reviewer-thank-you'
-
-  email.toUser = {
-    email: reviewer.email,
-    name: `${reviewer.lastName}`,
-  }
-
-  email.content.unsubscribeLink = services.createUrl(baseUrl, unsubscribeSlug, {
-    id: reviewer.id,
-    token: reviewer.accessTokens.unsubscribe,
-  })
-
-  const { html, text } = email.getNotificationBody({
-    emailBodyProps: getEmailCopy({
+    const { paragraph, ...bodyProps } = getEmailCopy({
       emailType,
       titleText,
-    }),
-  })
+    })
 
-  email.sendEmail({ html, text })
+    const email = new Email({
+      fromEmail: `${handlingEditor.name} <${staffEmail}>`,
+      type: 'user',
+      toUser: {
+        email: reviewer.email,
+        name: `${reviewer.lastName}`,
+      },
+      content: {
+        subject: isCanceled
+          ? `${collection.customId}: Review no longer required`
+          : `${collection.customId}: Thank you for agreeing to review`,
+        paragraph,
+        ctaText: 'MANUSCRIPT DETAILS',
+        signatureJournal: journalName,
+        signatureName: handlingEditor.name,
+        ctaLink: services.createUrl(
+          baseUrl,
+          `/projects/${collection.id}/versions/${fragment.id}/details`,
+        ),
+        unsubscribeLink: services.createUrl(baseUrl, unsubscribeSlug, {
+          id: reviewer.id,
+          token: reviewer.accessTokens.unsubscribe,
+        }),
+      },
+      bodyProps,
+    })
+
+    return email.sendEmail()
+  },
 }
diff --git a/packages/component-invite/src/routes/fragmentsInvitations/patch.js b/packages/component-invite/src/routes/fragmentsInvitations/patch.js
index 20d059bcb68b96842426a1f6a71c246c98238c5c..97b397be70feee1e04587001f69ba2fb25ad99bd 100644
--- a/packages/component-invite/src/routes/fragmentsInvitations/patch.js
+++ b/packages/component-invite/src/routes/fragmentsInvitations/patch.js
@@ -90,7 +90,7 @@ module.exports = models => async (req, res) => {
       await user.save()
     }
 
-    notifications.sendNotifications({
+    notifications.sendHandlingEditorEmail({
       baseUrl,
       fragment,
       collection,
@@ -100,6 +100,17 @@ module.exports = models => async (req, res) => {
         isAccepted === true ? 'reviewer-accepted' : 'reviewer-declined',
     })
 
+    if (isAccepted) {
+      notifications.sendReviewerEmail({
+        baseUrl,
+        fragment,
+        collection,
+        reviewer: user,
+        isCanceled: false,
+        UserModel: models.User,
+      })
+    }
+
     return res.status(200).json(invitation)
   } catch (e) {
     const notFoundError = await services.handleNotFoundError(e, 'Item')
diff --git a/packages/component-invite/src/routes/fragmentsInvitations/post.js b/packages/component-invite/src/routes/fragmentsInvitations/post.js
index 43504b33418afb1807932ac303c275d65a291f84..0e45b83faac29aef7b05b2ca588cf07b6dc7fb0e 100644
--- a/packages/component-invite/src/routes/fragmentsInvitations/post.js
+++ b/packages/component-invite/src/routes/fragmentsInvitations/post.js
@@ -4,6 +4,7 @@ const {
   services,
   Collection,
   Invitation,
+  Fragment,
   authsome: authsomeHelper,
 } = require('pubsweet-component-helper-service')
 
@@ -116,11 +117,16 @@ module.exports = models => async (req, res) => {
       })
     }
 
-    if (collection.status === 'heAssigned') {
+    const fragmentHelper = new Fragment({ fragment })
+    if (
+      collection.status === 'heAssigned' ||
+      (collection.status === 'reviewCompleted' &&
+        !fragmentHelper.hasReviewReport())
+    ) {
       collectionHelper.updateStatus({ newStatus: 'reviewersInvited' })
     }
 
-    emailInvitations.sendInvitations({
+    emailInvitations.sendReviewInvitations({
       resend,
       baseUrl,
       fragment,
@@ -174,7 +180,7 @@ module.exports = models => async (req, res) => {
       parentObject: fragment,
     })
 
-    emailInvitations.sendInvitations({
+    emailInvitations.sendReviewInvitations({
       baseUrl,
       fragment,
       collection,
diff --git a/packages/component-invite/src/tests/collectionsInvitations/delete.test.js b/packages/component-invite/src/tests/collectionsInvitations/delete.test.js
index c6e6089b02c4946f6a624911036cf2736a905d77..184f8818018ca0bab8fb24db9a5e844cc1273ed3 100644
--- a/packages/component-invite/src/tests/collectionsInvitations/delete.test.js
+++ b/packages/component-invite/src/tests/collectionsInvitations/delete.test.js
@@ -9,6 +9,9 @@ const { Model, fixtures } = fixturesService
 jest.mock('@pubsweet/component-send-email', () => ({
   send: jest.fn(),
 }))
+jest.mock('pubsweet-component-mts-package/src/PackageManager', () => ({
+  deleteFilesS3: jest.fn(),
+}))
 
 const path = '../routes/collectionsInvitations/delete'
 const route = {
@@ -86,4 +89,19 @@ describe('Delete Collections Invitations route handler', () => {
     const data = JSON.parse(res._getData())
     expect(data.error).toEqual('Unauthorized.')
   })
+  it('should return success when the EiC revokes a HE', async () => {
+    const { editorInChief } = testFixtures.users
+    const { collection } = testFixtures.collections
+    const res = await requests.sendRequest({
+      userId: editorInChief.id,
+      route,
+      models,
+      path,
+      params: {
+        collectionId: collection.id,
+        invitationId: collection.invitations[1].id,
+      },
+    })
+    expect(res.statusCode).toBe(200)
+  })
 })
diff --git a/packages/component-manuscript-manager/src/notifications/notification.js b/packages/component-manuscript-manager/src/notifications/notification.js
index dfb831c3585207a0aacbb7b0f20f4e8f5a20e4eb..506e9ba191a51fd7a1e34142dac3f5a03895de23 100644
--- a/packages/component-manuscript-manager/src/notifications/notification.js
+++ b/packages/component-manuscript-manager/src/notifications/notification.js
@@ -30,11 +30,17 @@ class Notification {
   }
 
   async notifyHEWhenReviewerSubmitsReport(reviewerLastName) {
-    const { eicName, titleText } = await this.getNotificationProperties()
+    const { eicName, titleText } = await this._getNotificationProperties()
 
     const handlingEditorId = get(this.collection, 'handlingEditor.id')
     const heUser = await this.UserModel.find(handlingEditorId)
 
+    const { paragraph, ...bodyProps } = getEmailCopy({
+      emailType: 'he-review-submitted',
+      titleText,
+      targetUserName: reviewerLastName,
+    })
+
     const email = new Email({
       type: 'user',
       toUser: {
@@ -43,9 +49,10 @@ class Notification {
       },
       fromEmail: `${eicName} <${staffEmail}>`,
       content: {
+        subject: `${this.collection.customId}: A review has been submitted`,
+        paragraph,
         signatureName: eicName,
         ctaText: 'MANUSCRIPT DETAILS',
-        subject: `${this.collection.customId}: A review has been submitted`,
         unsubscribeLink: services.createUrl(this.baseUrl, unsubscribeSlug, {
           id: heUser.id,
           token: heUser.accessTokens.unsubscribe,
@@ -57,29 +64,31 @@ class Notification {
           }/details`,
         ),
       },
+      bodyProps,
     })
 
-    const emailBodyProps = getEmailCopy({
-      emailType: 'he-review-submitted',
-      titleText,
-      targetUserName: reviewerLastName,
-    })
-
-    const { html, text } = email.getNotificationBody({ emailBodyProps })
-    email.sendEmail({ html, text })
+    return email.sendEmail()
   }
 
-  // EiC decided to either publish or reject the manuscript
   async notifyHEWhenEiCMakesDecision() {
     const {
       eicName,
       titleText,
       recommendation,
-    } = await this.getNotificationProperties()
+    } = await this._getNotificationProperties()
 
     const handlingEditorId = get(this.collection, 'handlingEditor.id')
     const heUser = await this.UserModel.find(handlingEditorId)
 
+    const { paragraph, ...bodyProps } = getEmailCopy({
+      titleText,
+      targetUserName: eicName,
+      emailType:
+        recommendation === 'publish'
+          ? 'he-manuscript-published'
+          : 'he-manuscript-rejected',
+    })
+
     const email = new Email({
       type: 'user',
       toUser: {
@@ -87,8 +96,9 @@ class Notification {
       },
       fromEmail: `${journalName} <${staffEmail}>`,
       content: {
-        ctaText: 'MANUSCRIPT DETAILS',
         subject: `${this.collection.customId}: Editorial decision confirmed`,
+        paragraph,
+        ctaText: 'MANUSCRIPT DETAILS',
         unsubscribeLink: services.createUrl(this.baseUrl, unsubscribeSlug, {
           id: heUser.id,
           token: heUser.accessTokens.unsubscribe,
@@ -100,27 +110,31 @@ class Notification {
           }/details`,
         ),
       },
+      bodyProps,
     })
 
-    const emailBodyProps = getEmailCopy({
-      titleText,
-      targetUserName: eicName,
-      emailType:
-        recommendation === 'publish'
-          ? 'he-manuscript-published'
-          : 'he-manuscript-rejected',
-    })
-
-    const { html, text } = email.getNotificationBody({ emailBodyProps })
-    email.sendEmail({ html, text })
+    return email.sendEmail()
   }
 
   async notifyHEWhenEiCReturnsToHE() {
-    const { eicName, titleText } = await this.getNotificationProperties()
+    const { eicName, titleText } = await this._getNotificationProperties()
 
     const handlingEditorId = get(this.collection, 'handlingEditor.id')
     const heUser = await this.UserModel.find(handlingEditorId)
 
+    const eicComments = chain(this.newRecommendation)
+      .get('comments')
+      .find(comm => !comm.public)
+      .get('content')
+      .value()
+
+    const { paragraph, ...bodyProps } = getEmailCopy({
+      titleText,
+      comments: eicComments,
+      targetUserName: eicName,
+      emailType: 'he-manuscript-return-with-comments',
+    })
+
     const email = new Email({
       type: 'user',
       toUser: {
@@ -132,6 +146,7 @@ class Notification {
         subject: `${
           this.collection.customId
         }: Editorial decision returned with comments`,
+        paragraph,
         signatureName: eicName,
         ctaText: 'MANUSCRIPT DETAILS',
         unsubscribeLink: services.createUrl(this.baseUrl, unsubscribeSlug, {
@@ -145,29 +160,22 @@ class Notification {
           }/details`,
         ),
       },
+      bodyProps,
     })
 
-    const eicComments = chain(this.newRecommendation)
-      .get('comments')
-      .find(comm => !comm.public)
-      .get('content')
-      .value()
-
-    const emailBodyProps = getEmailCopy({
-      titleText,
-      comments: eicComments,
-      targetUserName: eicName,
-      emailType: 'he-manuscript-return-with-comments',
-    })
-
-    const { html, text } = email.getNotificationBody({ emailBodyProps })
-    email.sendEmail({ html, text })
+    return email.sendEmail()
   }
 
   async notifyEAWhenEiCMakesFinalDecision() {
-    const { eicName, titleText } = await this.getNotificationProperties()
+    const { eicName, titleText } = await this._getNotificationProperties()
     const subjectBaseText = `${this.collection.customId}: Manuscript`
 
+    const { paragraph, ...bodyProps } = getEmailCopy({
+      eicName,
+      titleText,
+      emailType: 'eqa-manuscript-published',
+    })
+
     const email = new Email({
       type: 'system',
       toUser: {
@@ -176,23 +184,25 @@ class Notification {
       fromEmail: `${journalName} <${staffEmail}>`,
       content: {
         subject: `${subjectBaseText} decision finalized`,
+        paragraph,
         unsubscribeLink: this.baseUrl,
       },
+      bodyProps,
     })
 
-    const emailBodyProps = getEmailCopy({
-      eicName,
-      titleText,
-      emailType: 'eqa-manuscript-published',
-    })
-    const { html, text } = email.getNotificationBody({ emailBodyProps })
-    email.sendEmail({ html, text })
+    return email.sendEmail()
   }
 
   async notifyEAWhenEiCRequestsEQAApproval() {
-    const { eicName } = await this.getNotificationProperties()
+    const { eicName } = await this._getNotificationProperties()
     const subjectBaseText = `${this.collection.customId}: Manuscript`
 
+    const { paragraph, ...bodyProps } = getEmailCopy({
+      eicName,
+      customId: this.collection.customId,
+      emailType: 'eqa-manuscript-request-for-approval',
+    })
+
     const email = new Email({
       type: 'system',
       toUser: {
@@ -201,6 +211,7 @@ class Notification {
       fromEmail: `${journalName} <${staffEmail}>`,
       content: {
         subject: `${subjectBaseText} Request for EQA approval`,
+        paragraph,
         unsubscribeLink: this.baseUrl,
         ctaText: 'MAKE DECISION',
         ctaLink: services.createUrl(
@@ -213,16 +224,10 @@ class Notification {
           },
         ),
       },
+      bodyProps,
     })
 
-    const emailBodyProps = getEmailCopy({
-      eicName,
-      customId: this.collection.customId,
-      emailType: 'eqa-manuscript-request-for-approval',
-    })
-
-    const { html, text } = email.getNotificationBody({ emailBodyProps })
-    email.sendEmail({ html, text })
+    return email.sendEmail()
   }
 
   async notifyAuthorsWhenEiCMakesDecision() {
@@ -232,7 +237,7 @@ class Notification {
       activeAuthors,
       recommendation,
       parsedFragment,
-    } = await this.getNotificationProperties()
+    } = await this._getNotificationProperties()
 
     const subjectOpts = {
       publish: `${this.collection.customId}: Manuscript accepted`,
@@ -255,6 +260,12 @@ class Notification {
         })
       : this.newRecommendation.comments[0].content
 
+    const { paragraph, ...bodyProps } = getEmailCopy({
+      titleText,
+      emailType,
+      comments,
+    })
+
     activeAuthors.forEach(async author => {
       const email = new Email({
         type: 'user',
@@ -264,9 +275,10 @@ class Notification {
         },
         fromEmail: `${eicName} <${staffEmail}>`,
         content: {
+          subject,
+          paragraph,
           signatureName: eicName,
           ctaText: 'MANUSCRIPT DETAILS',
-          subject,
           unsubscribeLink: services.createUrl(this.baseUrl, unsubscribeSlug, {
             id: author.id,
             token: author.accessTokens.unsubscribe,
@@ -279,16 +291,10 @@ class Notification {
           ),
           signatureJournal: journalName,
         },
+        bodyProps,
       })
 
-      const emailBodyProps = getEmailCopy({
-        titleText,
-        emailType,
-        comments,
-      })
-
-      const { html, text } = email.getNotificationBody({ emailBodyProps })
-      email.sendEmail({ html, text })
+      return email.sendEmail()
     })
   }
 
@@ -298,7 +304,7 @@ class Notification {
       titleText,
       recommendation,
       fragmentHelper,
-    } = await this.getNotificationProperties()
+    } = await this._getNotificationProperties()
 
     const emailType =
       recommendation === 'publish'
@@ -315,7 +321,7 @@ class Notification {
       type: 'submitted',
     })
 
-    const emailBodyProps = getEmailCopy({
+    const { paragraph, ...bodyProps } = getEmailCopy({
       emailType,
       titleText,
     })
@@ -329,9 +335,10 @@ class Notification {
         },
         fromEmail: `${eicName} <${staffEmail}>`,
         content: {
+          subject: `${this.collection.customId}: ${subject}`,
+          paragraph,
           signatureName: eicName,
           ctaText: 'MANUSCRIPT DETAILS',
-          subject: `${this.collection.customId}: ${subject}`,
           unsubscribeLink: services.createUrl(this.baseUrl, unsubscribeSlug, {
             id: reviewer.id,
             token: reviewer.accessTokens.unsubscribe,
@@ -344,10 +351,10 @@ class Notification {
           ),
           signatureJournal: journalName,
         },
+        bodyProps,
       })
 
-      const { html, text } = email.getNotificationBody({ emailBodyProps })
-      email.sendEmail({ html, text })
+      return email.sendEmail()
     })
   }
 
@@ -356,7 +363,7 @@ class Notification {
       eicName,
       submittingAuthor,
       parsedFragment: { title },
-    } = await this.getNotificationProperties()
+    } = await this._getNotificationProperties()
 
     const authorNoteText = helpers.getPrivateNoteTextForAuthor({
       newRecommendation: this.newRecommendation,
@@ -364,6 +371,12 @@ class Notification {
 
     const signatureName = get(this.collection, 'handlingEditor.name', eicName)
 
+    const { paragraph, ...bodyProps } = getEmailCopy({
+      emailType: 'author-request-to-revision',
+      titleText: `your submission "${title}" to ${journalName}`,
+      comments: authorNoteText,
+    })
+
     const email = new Email({
       type: 'user',
       toUser: {
@@ -372,10 +385,11 @@ class Notification {
       },
       fromEmail: `${signatureName} <${staffEmail}>`,
       content: {
+        subject: `${this.collection.customId}: Revision requested`,
+        paragraph,
         signatureName,
         ctaText: 'MANUSCRIPT DETAILS',
         signatureJournal: journalName,
-        subject: `${this.collection.customId}: Revision requested`,
         unsubscribeLink: services.createUrl(this.baseUrl, unsubscribeSlug, {
           id: submittingAuthor.id,
           token: submittingAuthor.accessTokens.unsubscribe,
@@ -387,16 +401,10 @@ class Notification {
           }/details`,
         ),
       },
+      bodyProps,
     })
 
-    const emailBodyProps = getEmailCopy({
-      emailType: 'author-request-to-revision',
-      titleText: `your submission "${title}" to ${journalName}`,
-      comments: authorNoteText,
-    })
-
-    const { html, text } = email.getNotificationBody({ emailBodyProps })
-    email.sendEmail({ html, text })
+    return email.sendEmail()
   }
 
   async notifyReviewersWhenHEMakesRecommendation() {
@@ -404,7 +412,7 @@ class Notification {
       eicName,
       titleText,
       fragmentHelper,
-    } = await this.getNotificationProperties()
+    } = await this._getNotificationProperties()
 
     const signatureName = get(this.collection, 'handlingEditor.name', eicName)
 
@@ -427,6 +435,8 @@ class Notification {
     })
 
     const buildSendEmailFunction = emailBodyProps => reviewer => {
+      const { paragraph, ...bodyProps } = emailBodyProps
+
       const email = new Email({
         type: 'user',
         toUser: {
@@ -435,9 +445,10 @@ class Notification {
         },
         fromEmail: `${signatureName} <${staffEmail}>`,
         content: {
+          subject: `${this.collection.customId}: Review no longer required`,
+          paragraph,
           signatureName,
           ctaText: 'MANUSCRIPT DETAILS',
-          subject: `${this.collection.customId}: Review no longer required`,
           unsubscribeLink: services.createUrl(this.baseUrl, unsubscribeSlug, {
             id: reviewer.id,
             token: reviewer.accessTokens.unsubscribe,
@@ -450,10 +461,10 @@ class Notification {
           ),
           signatureJournal: journalName,
         },
+        bodyProps,
       })
 
-      const { html, text } = email.getNotificationBody({ emailBodyProps })
-      email.sendEmail({ html, text })
+      return email.sendEmail()
     }
 
     acceptedReviewers.forEach(
@@ -467,7 +478,7 @@ class Notification {
       eicName,
       titleText,
       recommendation,
-    } = await this.getNotificationProperties()
+    } = await this._getNotificationProperties()
 
     let emailType, subject
     switch (recommendation) {
@@ -502,7 +513,7 @@ class Notification {
     const userHelper = new User({ UserModel: this.UserModel })
     const editors = await userHelper.getEditorsInChief()
 
-    const emailBodyProps = getEmailCopy({
+    const { paragraph, ...bodyProps } = getEmailCopy({
       comments,
       emailType,
       titleText,
@@ -518,8 +529,9 @@ class Notification {
         },
         fromEmail: `${journalName} <${staffEmail}>`,
         content: {
-          signatureName: eicName,
           subject,
+          paragraph,
+          signatureName: eicName,
           ctaText: 'MANUSCRIPT DETAILS',
           unsubscribeLink: this.baseUrl,
           ctaLink: services.createUrl(
@@ -529,55 +541,22 @@ class Notification {
             }/details`,
           ),
         },
+        bodyProps,
       })
 
-      const { html, text } = email.getNotificationBody({ emailBodyProps })
-      email.sendEmail({ html, text })
+      return email.sendEmail()
     })
   }
 
-  async getNotificationProperties() {
-    const fragmentHelper = new Fragment({ fragment: this.fragment })
-    const parsedFragment = await fragmentHelper.getFragmentData({
-      handlingEditor: this.collection.handlingEditor,
-    })
-    const {
-      submittingAuthor,
-      activeAuthors,
-    } = await fragmentHelper.getAuthorData({
-      UserModel: this.UserModel,
-    })
-
-    const userHelper = new User({ UserModel: this.UserModel })
-    const eicName = await userHelper.getEiCName()
-
-    const titleText = `the manuscript titled "${parsedFragment.title}" by ${
-      submittingAuthor.firstName
-    } ${submittingAuthor.lastName}`
-
-    const { recommendation, recommendationType } = this.newRecommendation
-
-    return {
-      recommendation,
-      recommendationType,
-      eicName,
-      titleText,
-      submittingAuthor,
-      activeAuthors,
-      parsedFragment,
-      fragmentHelper,
-    }
-  }
-
   async notifyEiCWhenEQSAcceptsManuscript() {
-    const { submittingAuthor } = await this.getNotificationProperties()
+    const { submittingAuthor } = await this._getNotificationProperties()
 
     const userHelper = new User({ UserModel: this.UserModel })
     const editors = await userHelper.getEditorsInChief()
     const fragmentHelper = new Fragment({ fragment: this.fragment })
     const parsedFragment = await fragmentHelper.getFragmentData({})
 
-    const emailBodyProps = getEmailCopy({
+    const { paragraph, ...bodyProps } = getEmailCopy({
       emailType: 'eic-manuscript-accepted-by-eqs',
       titleText: `manuscript titled "${parsedFragment.title}" by ${
         submittingAuthor.firstName
@@ -593,6 +572,7 @@ class Notification {
         fromEmail: `${journalName} <${staffEmail}>`,
         content: {
           subject: `${this.collection.customId}: New manuscript submitted`,
+          paragraph,
           ctaText: 'MANUSCRIPT DETAILS',
           unsubscribeLink: this.baseUrl,
           ctaLink: services.createUrl(
@@ -602,20 +582,20 @@ class Notification {
             }/details`,
           ),
         },
+        bodyProps,
       })
 
-      const { html, text } = email.getNotificationBody({ emailBodyProps })
-      email.sendEmail({ html, text })
+      return email.sendEmail()
     })
   }
 
   async notifyEiCWhenEQARejectsManuscript(comments) {
-    const { titleText } = await this.getNotificationProperties()
+    const { titleText } = await this._getNotificationProperties()
 
     const userHelper = new User({ UserModel: this.UserModel })
     const editors = await userHelper.getEditorsInChief()
 
-    const emailBodyProps = getEmailCopy({
+    const { paragraph, ...bodyProps } = getEmailCopy({
       comments,
       titleText,
       emailType: 'eic-manuscript-returned-by-eqa',
@@ -632,6 +612,7 @@ class Notification {
           subject: `${
             this.collection.customId
           }: Manuscript returned with comments`,
+          paragraph,
           ctaText: 'MANUSCRIPT DETAILS',
           unsubscribeLink: this.baseUrl,
           ctaLink: services.createUrl(
@@ -641,11 +622,44 @@ class Notification {
             }/details`,
           ),
         },
+        bodyProps,
       })
 
-      const { html, text } = email.getNotificationBody({ emailBodyProps })
-      email.sendEmail({ html, text })
+      return email.sendEmail()
+    })
+  }
+
+  async _getNotificationProperties() {
+    const fragmentHelper = new Fragment({ fragment: this.fragment })
+    const parsedFragment = await fragmentHelper.getFragmentData({
+      handlingEditor: this.collection.handlingEditor,
+    })
+    const {
+      submittingAuthor,
+      activeAuthors,
+    } = await fragmentHelper.getAuthorData({
+      UserModel: this.UserModel,
     })
+
+    const userHelper = new User({ UserModel: this.UserModel })
+    const eicName = await userHelper.getEiCName()
+
+    const titleText = `the manuscript titled "${parsedFragment.title}" by ${
+      submittingAuthor.firstName
+    } ${submittingAuthor.lastName}`
+
+    const { recommendation, recommendationType } = this.newRecommendation
+
+    return {
+      recommendation,
+      recommendationType,
+      eicName,
+      titleText,
+      submittingAuthor,
+      activeAuthors,
+      parsedFragment,
+      fragmentHelper,
+    }
   }
 }
 
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 7f0b8fd3d3364ddc038385f6424ec53b9578fba3..dcbe3c22f7278a55af53a9e9477f80860ea4609f 100644
--- a/packages/component-manuscript-manager/src/routes/fragments/notifications/notifications.js
+++ b/packages/component-manuscript-manager/src/routes/fragments/notifications/notifications.js
@@ -15,34 +15,29 @@ const unsubscribeSlug = config.get('unsubscribe.url')
 const { getEmailCopy } = require('./emailCopy')
 
 module.exports = {
-  async sendNotifications({
-    baseUrl,
-    fragment,
-    UserModel,
-    collection,
-    isNewVersion = false,
-    previousVersion,
-    isTechnicalCheck,
-    isMajorRecommendation,
-  }) {
+  async sendHandlingEditorEmail({ baseUrl, fragment, UserModel, collection }) {
     const fragmentHelper = new Fragment({ fragment })
     const handlingEditor = get(collection, 'handlingEditor')
     const parsedFragment = await fragmentHelper.getFragmentData({
       handlingEditor,
     })
-    const {
-      submittingAuthor,
-      activeAuthors: authors,
-    } = await fragmentHelper.getAuthorData({
-      UserModel,
+
+    const { paragraph, ...bodyProps } = getEmailCopy({
+      emailType: 'he-new-version-submitted',
+      titleText: `the manuscript titled "${parsedFragment.title}"`,
     })
 
-    const { customId } = collection
+    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(
@@ -50,240 +45,199 @@ module.exports = {
           `/projects/${collection.id}/versions/${fragment.id}/details`,
         ),
         ctaText: 'MANUSCRIPT DETAILS',
+        unsubscribeLink: services.createUrl(baseUrl, unsubscribeSlug, {
+          id: heUser.id,
+          token: heUser.accessTokens.unsubscribe,
+        }),
       },
+      bodyProps,
     })
 
-    const userHelper = new User({ UserModel })
-    const eicName = await userHelper.getEiCName()
-
-    if (isNewVersion) {
-      const heUser = await UserModel.find(handlingEditor.id)
-      sendHandlingEditorEmail({
-        email,
-        baseUrl,
-        customId,
-        title: parsedFragment.title,
-        handlingEditor: heUser,
-      })
-    }
-
-    if (isMajorRecommendation) {
-      sendReviewersEmail({
-        email,
-        baseUrl,
-        customId,
-        UserModel,
-        previousVersion,
-        title: parsedFragment.title,
-        heName: collection.handlingEditor.name,
-      })
-    }
-
-    if (isTechnicalCheck) {
-      sendEQSEmail({
-        email,
-        eicName,
-        baseUrl,
-        collection,
-      })
-      sendAuthorsEmail({
-        email,
-        baseUrl,
-        UserModel,
-        fragmentId: fragment.id,
-        fragmentAuthors: authors,
-        collectionId: collection.id,
-        title: parsedFragment.title,
-        submittingAuthorName: `${submittingAuthor.firstName} ${
-          submittingAuthor.lastName
-        }`,
-      })
-    }
+    return email.sendEmail()
   },
-}
-
-const sendHandlingEditorEmail = ({
-  email,
-  title,
-  baseUrl,
-  customId,
-  handlingEditor,
-}) => {
-  const emailType = 'he-new-version-submitted'
-
-  email.toUser = {
-    email: handlingEditor.email,
-  }
-  email.content.unsubscribeLink = services.createUrl(baseUrl, unsubscribeSlug, {
-    id: handlingEditor.id,
-    token: handlingEditor.accessTokens.unsubscribe,
-  })
-  email.content.subject = `${customId}: Revision submitted`
-
-  const { html, text } = email.getNotificationBody({
-    emailBodyProps: getEmailCopy({
-      emailType,
-      titleText: `the manuscript titled "${title}"`,
-    }),
-  })
-  email.sendEmail({ html, text })
-}
-
-const sendReviewersEmail = async ({
-  email,
-  title,
-  heName,
-  baseUrl,
-  customId,
-  UserModel,
-  previousVersion,
-}) => {
-  email.content.subject = `${customId}: A manuscript you reviewed has been revised`
-  email.content.signatureName = heName
-  email.fromEmail = `${heName} <${staffEmail}>`
-  const emailType = 'submitted-reviewers-after-revision'
 
-  const fragmentHelper = new Fragment({ fragment: previousVersion })
-  const reviewers = await fragmentHelper.getReviewers({
+  async sendReviewersEmail({
+    baseUrl,
+    fragment,
     UserModel,
-    type: 'submitted',
-  })
-
-  reviewers.forEach(reviewer => {
-    email.toUser = {
-      email: reviewer.email,
-      name: `${reviewer.lastName}`,
-    }
+    collection,
+    previousVersion,
+  }) {
+    const fragmentHelper = new Fragment({ fragment: previousVersion })
+    const handlingEditor = get(collection, 'handlingEditor')
+    const parsedFragment = await fragmentHelper.getFragmentData({
+      handlingEditor,
+    })
 
-    email.content.unsubscribeLink = services.createUrl(
-      baseUrl,
-      unsubscribeSlug,
-      {
-        id: reviewer.id,
-        token: reviewer.accessTokens.unsubscribe,
-      },
-    )
+    const reviewers = await fragmentHelper.getReviewers({
+      UserModel,
+      type: 'submitted',
+    })
 
-    const { html, text } = email.getNotificationBody({
-      emailBodyProps: getEmailCopy({
-        emailType,
-        titleText: `the manuscript titled "${title}"`,
-        expectedDate: services.getExpectedDate({ daysExpected: 14 }),
-      }),
+    const { paragraph, ...bodyProps } = getEmailCopy({
+      emailType: 'submitted-reviewers-after-revision',
+      titleText: `the manuscript titled "${parsedFragment.title}"`,
+      expectedDate: services.getExpectedDate({ daysExpected: 14 }),
     })
 
-    email.sendEmail({ html, text })
-  })
-}
+    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,
+      })
 
-const sendEQSEmail = ({ email, eicName, baseUrl, collection }) => {
-  const emailType = 'eqs-manuscript-submitted'
+      return email.sendEmail()
+    })
+  },
 
-  email.toUser = {
-    email: staffEmail,
-    name: 'Editorial Assistant',
-  }
+  async sendEQSEmail({ baseUrl, fragment, UserModel, collection }) {
+    const userHelper = new User({ UserModel })
+    const eicName = await userHelper.getEiCName()
 
-  email.content.unsubscribeLink = baseUrl
-  email.content.signatureName = eicName
-  email.content.subject = `Manuscript Submitted`
-  email.content.ctaLink = services.createUrl(
-    baseUrl,
-    config.get('eqs-decision.url'),
-    {
-      collectionId: collection.id,
+    const { paragraph, ...bodyProps } = getEmailCopy({
+      emailType: 'eqs-manuscript-submitted',
       customId: collection.customId,
-      token: collection.technicalChecks.token,
-    },
-  )
-  email.content.ctaText = 'MAKE DECISION'
+    })
 
-  const { html, text } = email.getNotificationBody({
-    emailBodyProps: getEmailCopy({
-      emailType,
-      customId: collection.customId,
-    }),
-  })
-  email.sendEmail({ html, text })
-}
+    const email = new Email({
+      type: 'user',
+      fromEmail: `${journalName} <${staffEmail}>`,
+      toUser: {
+        email: staffEmail,
+        name: 'Editorial Assistant',
+      },
+      content: {
+        subject: `Manuscript Submitted`,
+        paragraph,
+        signatureName: eicName,
+        signatureJournal: journalName,
+        ctaLink: services.createUrl(baseUrl, config.get('eqs-decision.url'), {
+          collectionId: collection.id,
+          customId: collection.customId,
+          token: collection.technicalChecks.token,
+        }),
+        ctaText: 'MAKE DECISION',
+        unsubscribeLink: baseUrl,
+      },
+      bodyProps,
+    })
 
-const sendAuthorsEmail = async ({
-  email,
-  title,
-  baseUrl,
-  UserModel,
-  fragmentId,
-  collectionId,
-  fragmentAuthors,
-  submittingAuthorName,
-}) => {
-  email.content.subject = `Manuscript submitted to ${journalName}`
-  email.content.signatureName = ''
+    return email.sendEmail()
+  },
 
-  const userEmailData = await Promise.all(
-    fragmentAuthors.map(async author => {
-      const user = await UserModel.find(author.id)
-      return {
-        ...author,
-        isConfirmed: user.isConfirmed,
-        unsubscribeToken: user.accessTokens.unsubscribe,
-        passwordResetToken: user.accessTokens.passwordReset,
-        ...getEmailCopy({
+  async sendAuthorsEmail({ baseUrl, fragment, UserModel, collection }) {
+    const fragmentHelper = new Fragment({ fragment })
+    const handlingEditor = get(collection, 'handlingEditor')
+    const parsedFragment = await fragmentHelper.getFragmentData({
+      handlingEditor,
+    })
+    const {
+      submittingAuthor,
+      activeAuthors: fragmentAuthors,
+    } = await fragmentHelper.getAuthorData({
+      UserModel,
+    })
+
+    const submittingAuthorName = `${submittingAuthor.firstName} ${
+      submittingAuthor.lastName
+    }`
+
+    const userEmailData = await Promise.all(
+      fragmentAuthors.map(async author => {
+        const { paragraph, ...bodyProps } = getEmailCopy({
           emailType: author.isSubmitting
             ? 'submitting-author-manuscript-submitted'
             : 'coauthors-manuscript-submitted',
           titleText: author.isSubmitting
-            ? `the manuscript titled "${title}"`
-            : `The manuscript titled "${title}" has been submitted to ${journalName} by ${submittingAuthorName}`,
-        }),
-      }
-    }),
-  )
-
-  userEmailData.forEach(author => {
-    email.toUser = {
-      email: author.email,
-      name: `${author.lastName}`,
-    }
-    email.content.unsubscribeLink = services.createUrl(
-      baseUrl,
-      unsubscribeSlug,
-      {
-        id: author.id,
-        token: author.unsubscribeToken,
-      },
+            ? `the manuscript titled "${parsedFragment.title}"`
+            : `The manuscript titled "${
+                parsedFragment.title
+              }" has been submitted to ${journalName} by ${submittingAuthorName}`,
+        })
+        const user = await UserModel.find(author.id)
+        return {
+          author: Object.assign(author, {
+            isConfirmed: user.isConfirmed,
+            unsubscribeToken: user.accessTokens.unsubscribe,
+            passwordResetToken: user.accessTokens.passwordReset,
+          }),
+          paragraph,
+          bodyProps,
+        }
+      }),
     )
 
-    if (author.isSubmitting) {
-      email.content.ctaLink = services.createUrl(
-        baseUrl,
-        `/projects/${collectionId}/versions/${fragmentId}/details`,
-      )
-      email.content.ctaText = 'MANUSCRIPT DETAILS'
-    } else if (author.isConfirmed) {
-      email.content.ctaLink = services.createUrl(baseUrl, '')
-      email.content.ctaText = 'LOG IN'
-    } else {
-      email.content.ctaLink = services.createUrl(baseUrl, resetPath, {
-        email: author.email,
-        token: author.passwordResetToken,
-        firstName: author.firstName,
-        lastName: author.lastName,
-        affiliation: author.affiliation,
-        title: author.title,
-        country: author.country,
+    userEmailData.forEach(({ author, paragraph, bodyProps }) => {
+      const email = new Email({
+        type: 'user',
+        fromEmail: `${journalName} <${staffEmail}>`,
+        toUser: {
+          email: author.email,
+          name: `${author.lastName}`,
+        },
+        content: {
+          subject: `Manuscript submitted to ${journalName}`,
+          paragraph,
+          signatureName: '',
+          signatureJournal: journalName,
+          ctaLink: services.createUrl(
+            baseUrl,
+            `/projects/${collection.id}/versions/${fragment.id}/details`,
+          ),
+          ctaText: 'MANUSCRIPT DETAILS',
+          unsubscribeLink: services.createUrl(baseUrl, unsubscribeSlug, {
+            id: author.id,
+            token: author.unsubscribeToken,
+          }),
+        },
+        bodyProps,
       })
-      email.content.ctaText = 'CONFIRM ACCOUNT'
-    }
 
-    const { html, text } = email.getNotificationBody({
-      emailBodyProps: {
-        paragraph: author.paragraph,
-        hasLink: author.hasLink,
-        hasIntro: author.hasIntro,
-        hasSignature: author.hasSignature,
-      },
+      if (author.isSubmitting) {
+        email.content.ctaLink = services.createUrl(
+          baseUrl,
+          `/projects/${collection.id}/versions/${fragment.id}/details`,
+        )
+        email.content.ctaText = 'MANUSCRIPT DETAILS'
+      } else if (author.isConfirmed) {
+        email.content.ctaLink = services.createUrl(baseUrl, '')
+        email.content.ctaText = 'LOG IN'
+      } else {
+        email.content.ctaLink = services.createUrl(baseUrl, resetPath, {
+          email: author.email,
+          token: author.passwordResetToken,
+          firstName: author.firstName,
+          lastName: author.lastName,
+          affiliation: author.affiliation,
+          title: author.title,
+          country: author.country,
+        })
+        email.content.ctaText = 'CONFIRM ACCOUNT'
+      }
+
+      return email.sendEmail()
     })
-    email.sendEmail({ html, text })
-  })
+  },
 }
diff --git a/packages/component-manuscript-manager/src/routes/fragments/patch.js b/packages/component-manuscript-manager/src/routes/fragments/patch.js
index f28b8cc0847abbbdaff894bc7f4337572a28877c..acd037254ddb9ada6417d99980a2a30588799d08 100644
--- a/packages/component-manuscript-manager/src/routes/fragments/patch.js
+++ b/packages/component-manuscript-manager/src/routes/fragments/patch.js
@@ -103,8 +103,13 @@ module.exports = models => async (req, res) => {
       await authorsTeam.save()
     }
 
-    collectionHelper.updateStatusByRecommendation({
+    const fragments = await collectionHelper.getAllFragments({
+      FragmentModel: models.Fragment,
+    })
+
+    await collectionHelper.updateStatusByRecommendation({
       recommendation: heRecommendation.recommendation,
+      fragments,
     })
 
     newFragment.submitted = Date.now()
@@ -112,16 +117,23 @@ module.exports = models => async (req, res) => {
     collection.fragments.push(newFragment.id)
     collection.save()
 
-    notifications.sendNotifications({
-      collection,
-      isNewVersion: true,
+    notifications.sendHandlingEditorEmail({
+      baseUrl: services.getBaseUrl(req),
       fragment: newFragment,
       UserModel: models.User,
-      previousVersion: fragment,
-      baseUrl: services.getBaseUrl(req),
-      isMajorRecommendation: heRecommendation.recommendation === 'major',
+      collection,
     })
 
+    if (heRecommendation.recommendation === 'major') {
+      notifications.sendReviewersEmail({
+        baseUrl: services.getBaseUrl(req),
+        fragment: newFragment,
+        UserModel: models.User,
+        collection,
+        previousVersion: fragment,
+      })
+    }
+
     return res.status(200).json(newFragment)
   } catch (e) {
     const notFoundError = await services.handleNotFoundError(e, 'Item')
diff --git a/packages/component-manuscript-manager/src/routes/fragments/post.js b/packages/component-manuscript-manager/src/routes/fragments/post.js
index 7b541025809ee4dea338b7f5cd6f2136e47dd034..0d2b1f900df0cf60913afbff6229dad71b2b9bd2 100644
--- a/packages/component-manuscript-manager/src/routes/fragments/post.js
+++ b/packages/component-manuscript-manager/src/routes/fragments/post.js
@@ -13,10 +13,10 @@ const { features = {} } = config
 const sendMTSPackage = async (collection, fragment) => {
   const s3Config = get(config, 'pubsweet-component-aws-s3', {})
   const mtsConfig = get(config, 'mts-service', {})
-  const MTSService = require('pubsweet-component-mts-package')
+  const { sendPackage } = require('pubsweet-component-mts-package')
 
   const { journal, xmlParser, ftp } = mtsConfig
-  const MTS = new MTSService(journal, xmlParser, s3Config, ftp)
+
   const packageFragment = {
     ...fragment,
     metadata: {
@@ -25,7 +25,13 @@ const sendMTSPackage = async (collection, fragment) => {
     },
   }
 
-  await MTS.sendPackage({ fragment: packageFragment })
+  await sendPackage({
+    s3Config,
+    ftpConfig: ftp,
+    config: journal,
+    options: xmlParser,
+    fragment: packageFragment,
+  })
 }
 
 module.exports = models => async (req, res) => {
@@ -62,11 +68,17 @@ module.exports = models => async (req, res) => {
       await sendMTSPackage(collection, fragment)
     }
 
-    notifications.sendNotifications({
+    notifications.sendEQSEmail({
+      fragment,
+      collection,
+      UserModel: models.User,
+      baseUrl: services.getBaseUrl(req),
+    })
+
+    notifications.sendAuthorsEmail({
       fragment,
       collection,
       UserModel: models.User,
-      isTechnicalCheck: true,
       baseUrl: services.getBaseUrl(req),
     })
 
diff --git a/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/patch.js b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/patch.js
index 7846722ed2f83db255a59ff80f95c142ccf2d3ec..7cd5b2ae49984d23fff26a53ae1bfb38a19f8244 100644
--- a/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/patch.js
+++ b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/patch.js
@@ -1,3 +1,4 @@
+const { find } = require('lodash')
 const {
   services,
   authsome: authsomeHelper,
@@ -8,6 +9,7 @@ const Notification = require('../../notifications/notification')
 
 module.exports = models => async (req, res) => {
   const { collectionId, fragmentId, recommendationId } = req.params
+  const userId = req.user
   let collection, fragment
   try {
     collection = await models.Collection.find(collectionId)
@@ -25,7 +27,7 @@ module.exports = models => async (req, res) => {
     if (!recommendation)
       return res.status(404).json({ error: 'Recommendation not found.' })
 
-    if (recommendation.userId !== req.user)
+    if (recommendation.userId !== userId)
       return res.status(403).json({
         error: 'Unauthorized.',
       })
@@ -35,14 +37,14 @@ module.exports = models => async (req, res) => {
       fragment,
       path: req.route.path,
     }
-    const canPatch = await authsome.can(req.user, 'PATCH', target)
+    const canPatch = await authsome.can(userId, 'PATCH', target)
     if (!canPatch)
       return res.status(403).json({
         error: 'Unauthorized.',
       })
 
     const UserModel = models.User
-    const reviewer = await UserModel.find(req.user)
+    const reviewer = await UserModel.find(userId)
 
     Object.assign(recommendation, req.body)
     recommendation.updatedOn = Date.now()
@@ -62,6 +64,16 @@ module.exports = models => async (req, res) => {
         const collectionHelper = new Collection({ collection })
         collectionHelper.updateStatus({ newStatus: 'reviewCompleted' })
       }
+
+      const collectionHelper = new Collection({ collection })
+      const reviewerNumber = await collectionHelper.getReviewerNumber({
+        userId,
+      })
+
+      find(fragment.invitations, [
+        'userId',
+        userId,
+      ]).reviewerNumber = reviewerNumber
     }
 
     fragment.save()
diff --git a/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/post.js b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/post.js
index c0301c0d5162d064f9b89c3fc660f1d745562b3f..b47234c1f1a017149269ba6e415ee49d5af6b159 100644
--- a/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/post.js
+++ b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/post.js
@@ -1,7 +1,8 @@
 const uuid = require('uuid')
-const { pick, get, set, has, isEmpty, last } = require('lodash')
+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,
@@ -12,24 +13,6 @@ const {
 
 const { features = {}, recommendations } = config
 
-const sendMTSPackage = async (collection, fragment, isEQA = false) => {
-  const s3Config = get(config, 'pubsweet-component-aws-s3', {})
-  const mtsConfig = get(config, 'mts-service', {})
-  const MTSService = require('pubsweet-component-mts-package')
-
-  const { journal, xmlParser, ftp } = mtsConfig
-  const MTS = new MTSService(journal, xmlParser, s3Config, ftp)
-  const packageFragment = {
-    ...fragment,
-    metadata: {
-      ...fragment.metadata,
-      customId: collection.customId,
-    },
-  }
-
-  await MTS.sendPackage({ fragment: packageFragment, isEQA })
-}
-
 const Notification = require('../../notifications/notification')
 
 module.exports = models => async (req, res) => {
@@ -42,7 +25,7 @@ module.exports = models => async (req, res) => {
 
   const { collectionId, fragmentId } = req.params
 
-  let collection, fragment
+  let collection, fragment, fragments
 
   try {
     collection = await models.Collection.find(collectionId)
@@ -58,6 +41,30 @@ 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,
@@ -69,6 +76,7 @@ module.exports = models => async (req, res) => {
       error: 'Unauthorized.',
     })
 
+  const fragmentHelper = new Fragment({ fragment })
   if (
     recommendationType === recommendations.type.editor &&
     last(collection.fragments) !== fragmentId
@@ -86,6 +94,35 @@ module.exports = models => async (req, 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 &&
@@ -93,11 +130,10 @@ module.exports = models => async (req, res) => {
     collection.handlingEditor &&
     collection.handlingEditor.id === req.user
   ) {
-    const fragmentHelper = new Fragment({ fragment })
-    if (!fragmentHelper.hasReviewReport()) {
-      return res
-        .status(400)
-        .json({ error: 'Cannot publish without at least one reviewer report.' })
+    if (!collectionHelper.canHEMakeRecommendation(fragments, fragmentHelper)) {
+      return res.status(400).json({
+        error: 'Cannot publish without at least one reviewer report.',
+      })
     }
   }
 
@@ -114,9 +150,7 @@ module.exports = models => async (req, res) => {
   newRecommendation.comments = comments || undefined
 
   if (recommendationType === 'editorRecommendation') {
-    const collectionHelper = new Collection({ collection })
-
-    collectionHelper.updateStatusOnRecommendation({
+    await collectionHelper.updateStatusOnRecommendation({
       isEditorInChief,
       recommendation,
     })
@@ -130,7 +164,33 @@ module.exports = models => async (req, res) => {
     // 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 sendMTSPackage(collection, fragment, true)
+        await Promise.all(
+          collection.fragments.map(async fragmentId => {
+            const fragment = await models.Fragment.find(fragmentId)
+            const fragmentHelper = new Fragment({ fragment })
+
+            let fragmentUsers = []
+            try {
+              fragmentUsers = await fragmentHelper.getReviewersAndEditorsData({
+                collection,
+                UserModel: models.User,
+              })
+
+              await sendMTSPackage({
+                collection,
+                fragment,
+                isEQA: true,
+                fragmentUsers,
+              })
+            } catch (e) {
+              logger.error(e)
+            }
+          }),
+        ).catch(e =>
+          res.status(500).json({
+            error: 'Something went wrong.',
+          }),
+        )
       }
 
       collection.status = 'inQA'
@@ -203,3 +263,33 @@ module.exports = models => async (req, res) => {
 
   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/tests/collections/get.test.js b/packages/component-manuscript-manager/src/tests/collections/get.test.js
index fb88e5658444b5c3bad2f2cf5ac7760bf9900537..b721805c99c9b00833fcb953cc16f5a529840164 100644
--- a/packages/component-manuscript-manager/src/tests/collections/get.test.js
+++ b/packages/component-manuscript-manager/src/tests/collections/get.test.js
@@ -58,10 +58,9 @@ describe('Get collections route handler', () => {
 
     expect(res.statusCode).toBe(200)
     const data = JSON.parse(res._getData())
-
     expect(data).toHaveLength(2)
     expect(data[0].type).toEqual('collection')
-    expect(data[0].currentVersion.recommendations).toHaveLength(3)
+    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/fragmentsRecommendations/post.test.js b/packages/component-manuscript-manager/src/tests/fragmentsRecommendations/post.test.js
index 05ae4193c249185b9c160ed1a1c74cbba2fbbf72..5638eb69ff3be3a1a164b0226377f6c38d7f0486 100644
--- a/packages/component-manuscript-manager/src/tests/fragmentsRecommendations/post.test.js
+++ b/packages/component-manuscript-manager/src/tests/fragmentsRecommendations/post.test.js
@@ -28,7 +28,7 @@ const reqBody = {
       ],
     },
   ],
-  recommendationType: 'review',
+  recommendationType: 'editorRecommendation',
 }
 
 const path = '../routes/fragmentsRecommendations/post'
@@ -80,11 +80,35 @@ describe('Post fragments recommendations route handler', () => {
     const data = JSON.parse(res._getData())
     expect(data.userId).toEqual(reviewer.id)
   })
-  it('should return success when creating a recommendation as a HE', async () => {
+
+  it('should return success when creating a recommendation as a HE when there is a single version with at least one review.', async () => {
+    const { noRecommendationHE } = testFixtures.users
+    const { noEditorRecomedationCollection } = testFixtures.collections
+    const { noEditorRecomedationFragment } = testFixtures.fragments
+
+    const res = await requests.sendRequest({
+      body,
+      userId: noRecommendationHE.id,
+      models,
+      route,
+      path,
+      params: {
+        collectionId: noEditorRecomedationCollection.id,
+        fragmentId: noEditorRecomedationFragment.id,
+      },
+    })
+    expect(res.statusCode).toBe(200)
+    const data = JSON.parse(res._getData())
+    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 () => {
     const { handlingEditor } = testFixtures.users
     const { collection } = testFixtures.collections
     const { fragment } = testFixtures.fragments
 
+    fragment.recommendations = []
+
     const res = await requests.sendRequest({
       body,
       userId: handlingEditor.id,
@@ -97,10 +121,128 @@ describe('Post fragments recommendations route handler', () => {
       },
     })
 
+    expect(res.statusCode).toBe(400)
+    const data = JSON.parse(res._getData())
+    expect(data.error).toEqual(
+      'Cannot publish without at least one reviewer report.',
+    )
+  })
+
+  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 {
+      minorRevisionWithReview,
+      noInvitesFragment1,
+    } = testFixtures.fragments
+
+    collection.fragments = [minorRevisionWithReview.id, noInvitesFragment1.id]
+    const res = await requests.sendRequest({
+      body,
+      userId: handlingEditor.id,
+      models,
+      route,
+      path,
+      params: {
+        collectionId: collection.id,
+        fragmentId: noInvitesFragment1.id,
+      },
+    })
+
+    expect(res.statusCode).toBe(200)
+    const data = JSON.parse(res._getData())
+    expect(data.userId).toEqual(handlingEditor.id)
+  })
+
+  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 {
+      minorRevisionWithoutReview,
+      noInvitesFragment1,
+    } = testFixtures.fragments
+
+    collection.fragments = [
+      minorRevisionWithoutReview.id,
+      noInvitesFragment1.id,
+    ]
+    const res = await requests.sendRequest({
+      body,
+      userId: handlingEditor.id,
+      models,
+      route,
+      path,
+      params: {
+        collectionId: collection.id,
+        fragmentId: noInvitesFragment1.id,
+      },
+    })
+
+    expect(res.statusCode).toBe(400)
+    const data = JSON.parse(res._getData())
+    expect(data.error).toEqual(
+      'Cannot publish without at least one reviewer report.',
+    )
+  })
+
+  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 {
+      majorRevisionWithReview,
+      reviewCompletedFragment,
+    } = testFixtures.fragments
+
+    reviewCompletedFragment.collectionId = collection.id
+    collection.fragments = [
+      majorRevisionWithReview.id,
+      reviewCompletedFragment.id,
+    ]
+    const res = await requests.sendRequest({
+      body,
+      userId: handlingEditor.id,
+      models,
+      route,
+      path,
+      params: {
+        collectionId: collection.id,
+        fragmentId: reviewCompletedFragment.id,
+      },
+    })
+
     expect(res.statusCode).toBe(200)
     const data = JSON.parse(res._getData())
     expect(data.userId).toEqual(handlingEditor.id)
   })
+
+  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 {
+      majorRevisionWithReview,
+      noInvitesFragment1,
+    } = testFixtures.fragments
+
+    collection.fragments = [majorRevisionWithReview.id, noInvitesFragment1.id]
+    const res = await requests.sendRequest({
+      body,
+      userId: handlingEditor.id,
+      models,
+      route,
+      path,
+      params: {
+        collectionId: collection.id,
+        fragmentId: noInvitesFragment1.id,
+      },
+    })
+
+    expect(res.statusCode).toBe(400)
+    const data = JSON.parse(res._getData())
+    expect(data.error).toEqual(
+      'Cannot publish without at least one reviewer report.',
+    )
+  })
+
   it('should return an error when the fragmentId does not match the collectionId', async () => {
     const { reviewer } = testFixtures.users
     const { collection } = testFixtures.collections
@@ -163,28 +305,28 @@ describe('Post fragments recommendations route handler', () => {
     expect(data.error).toEqual('Unauthorized.')
   })
   it('should return success when a HE recommends to reject', async () => {
-    const { handlingEditor } = testFixtures.users
-    const { collection } = testFixtures.collections
-    const { fragment } = testFixtures.fragments
+    const { noRecommendationHE } = testFixtures.users
+    const { noEditorRecomedationCollection } = testFixtures.collections
+    const { noEditorRecomedationFragment } = testFixtures.fragments
     body.recommendation = 'reject'
     body.recommendationType = 'editorRecommendation'
 
     const res = await requests.sendRequest({
       body,
-      userId: handlingEditor.id,
+      userId: noRecommendationHE.id,
       models,
       route,
       path,
       params: {
-        collectionId: collection.id,
-        fragmentId: fragment.id,
+        collectionId: noEditorRecomedationCollection.id,
+        fragmentId: noEditorRecomedationFragment.id,
       },
     })
 
     expect(res.statusCode).toBe(200)
     const data = JSON.parse(res._getData())
 
-    expect(data.userId).toEqual(handlingEditor.id)
+    expect(data.userId).toEqual(noRecommendationHE.id)
     expect(data.recommendation).toBe('reject')
   })
   it('should return an error when the user is inactive', async () => {
@@ -357,7 +499,6 @@ describe('Post fragments recommendations route handler', () => {
       'Cannot publish without at least one reviewer report.',
     )
   })
-
   it('should return an error when a HE makes a recommendation on an older version of a manuscript', async () => {
     const { handlingEditor } = testFixtures.users
     const { twoVersionsCollection } = testFixtures.collections
@@ -407,6 +548,74 @@ describe('Post fragments recommendations route handler', () => {
 
     expect(data.error).toEqual('Cannot write a review on an older version.')
   })
+  it('should return an error when a reviewer writes another review on the current version of a manuscript', async () => {
+    const { newReviewer } = testFixtures.users
+    const { noEditorRecomedationCollection } = testFixtures.collections
+    const { noEditorRecomedationFragment } = testFixtures.fragments
+    body.recommendationType = 'review'
+
+    const res = await requests.sendRequest({
+      body,
+      userId: newReviewer.id,
+      models,
+      route,
+      path,
+      params: {
+        collectionId: noEditorRecomedationCollection.id,
+        fragmentId: noEditorRecomedationFragment.id,
+      },
+    })
+    expect(res.statusCode).toBe(400)
+    const data = JSON.parse(res._getData())
+
+    expect(data.error).toEqual('Cannot write another review on this version.')
+  })
+
+  it('should return success when creating another recommendation as a HE on the same version when EiC returned manuscript to He ', async () => {
+    const { noRecommendationHE } = testFixtures.users
+    const { noEditorRecomedationCollection } = testFixtures.collections
+    const { noEditorRecomedationFragment } = testFixtures.fragments
+
+    const res = await requests.sendRequest({
+      body,
+      userId: noRecommendationHE.id,
+      models,
+      route,
+      path,
+      params: {
+        collectionId: noEditorRecomedationCollection.id,
+        fragmentId: noEditorRecomedationFragment.id,
+      },
+    })
+    expect(res.statusCode).toBe(200)
+    const data = JSON.parse(res._getData())
+    expect(data.userId).toEqual(noRecommendationHE.id)
+  })
+
+  it('should return an error when creating another recommendation as a HE on the same version after EiC made decision to publish', async () => {
+    const { handlingEditor } = testFixtures.users
+    const { collection } = testFixtures.collections
+    const { fragment } = testFixtures.fragments
+    body.recommendation = 'publish'
+    body.recommendationType = 'editorRecommendation'
+
+    const res = await requests.sendRequest({
+      body,
+      userId: handlingEditor.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 another recommendation on this version.',
+    )
+  })
 
   it('should return an error when an EiC makes a decision on an older version of a manuscript', async () => {
     const { editorInChief } = testFixtures.users
diff --git a/packages/component-manuscript/src/components/ManuscriptLayout.js b/packages/component-manuscript/src/components/ManuscriptLayout.js
index f47d2b1db70a6490611df692ced8a250a9b598cf..5f870ecfa43fe24b4886780c6a78feaf2f0d675b 100644
--- a/packages/component-manuscript/src/components/ManuscriptLayout.js
+++ b/packages/component-manuscript/src/components/ManuscriptLayout.js
@@ -17,9 +17,9 @@ import {
   ResponseToRevisionRequest,
 } from 'pubsweet-component-faraday-ui'
 
-import ReviewerReportCard from './ReviewReportCard'
 import ReviewerReportForm from './ReviewerReportForm'
 import EditorialCommentCard from './EditorialCommentCard'
+import ReviewerReports from './ReviewerReports'
 
 const messagesLabel = {
   'return-to-handling-editor': 'Comments for Handling Editor',
@@ -30,51 +30,52 @@ const cannotViewReviewersDetails = ['revisionRequested', 'pendingApproval']
 
 const ManuscriptLayout = ({
   history,
-  currentUser,
-  getSignedUrl,
-  editorInChief,
-  handlingEditors,
-  editorialRecommendations,
   journal = {},
-  collection = {},
   fragment = {},
-  changeForm,
+  versions,
   isFetching,
-  isFetchingData,
-  publonsFetching,
-  fetchingError,
+  changeForm,
   formValues,
   heExpanded,
+  collection = {},
+  currentUser,
+  getSignedUrl,
+  shouldReview,
+  editorInChief,
+  fetchingError,
   toggleAssignHE,
+  isFetchingData,
+  submitRevision,
+  inviteReviewer,
+  isLatestVersion,
+  publonsFetching,
+  publonReviewers,
+  reviewerReports,
+  handlingEditors,
+  canHEOnlyReject,
   toggleHEResponse,
   heResponseExpanded,
+  inviteHandlingEditor,
+  toggleReviewerDetails,
+  recommendationHandler,
   toggleReviewerResponse,
+  reviewerDetailsExpanded,
+  toggleEditorialComments,
+  reviewerRecommendations,
   invitationsWithReviewers,
-  responseToRevisionRequest,
-  publonReviewers,
   reviewerResponseExpanded,
   pendingOwnRecommendation,
+  editorialRecommendations,
+  responseToRevisionRequest,
+  editorialCommentsExpanded,
+  submittedOwnRecommendation,
   toggleReviewerRecommendations,
   reviewerRecommendationExpanded,
   authorResponseToRevisonRequest,
   toggleResponeToRevisionRequest,
-  responseToRevisionRequestExpanded,
-  shouldReview,
-  submittedOwnRecommendation,
-  reviewerReports,
-  reviewerRecommendations,
-  toggleReviewerDetails,
-  reviewerDetailsExpanded,
   toggleResponseToRevisionRequest,
-  editorialCommentsExpanded,
-  toggleEditorialComments,
-  submitRevision,
-  inviteReviewer,
-  recommendationHandler,
-  inviteHandlingEditor,
-
-  versions,
-  isLatestVersion,
+  canHEMakeRecommendationToPublish,
+  responseToRevisionRequestExpanded,
 }) => (
   <Root pb={30}>
     {!isEmpty(collection) && !isEmpty(fragment) ? (
@@ -101,7 +102,6 @@ const ManuscriptLayout = ({
           revokeInvitation={inviteHandlingEditor.revokeHE}
           versions={versions}
         />
-
         <ManuscriptMetadata
           currentUser={currentUser}
           fragment={fragment}
@@ -122,27 +122,37 @@ const ManuscriptLayout = ({
           <AuthorReviews
             currentUser={currentUser}
             getSignedUrl={getSignedUrl}
+            invitations={invitationsWithReviewers}
             journal={journal}
-            reports={reviewerReports}
+            reviewerReports={reviewerReports}
             token={get(currentUser, 'token')}
           />
         )}
 
-        {submittedOwnRecommendation && (
-          <ReviewerReportCard
+        {get(
+          currentUser,
+          'permissions.reviewersCanViewReviewerReports',
+          false,
+        ) && (
+          <ReviewerReports
+            currentUser={currentUser}
             getSignedUrl={getSignedUrl}
+            invitations={invitationsWithReviewers}
+            isLatestVersion={isLatestVersion}
             journal={journal}
-            report={submittedOwnRecommendation}
+            reviewerReports={reviewerRecommendations}
             token={get(currentUser, 'token')}
           />
         )}
 
         {get(currentUser, 'permissions.canViewResponseFromAuthor', false) && (
           <ResponseToRevisionRequest
-            authorReply={get(authorResponseToRevisonRequest, 'content', '')}
-            expanded={responseToRevisionRequest}
+            authorReply={get(fragment, 'responseToReviewers', {})}
+            expanded={responseToRevisionRequestExpanded}
             fragment={fragment}
+            getSignedUrl={getSignedUrl}
             toggle={toggleResponseToRevisionRequest}
+            token={get(currentUser, 'token')}
           />
         )}
 
@@ -161,17 +171,18 @@ const ManuscriptLayout = ({
             />
           )}
 
-        {get(currentUser, 'isInvitedHE', false) && (
-          <ResponseToInvitation
-            commentsOn="decline"
-            expanded={heResponseExpanded}
-            formValues={formValues.responseToInvitation}
-            label="Do you agree to be the handling editor for this manuscript?"
-            onResponse={inviteHandlingEditor.onHEResponse}
-            title="Respond to Editorial Invitation"
-            toggle={toggleHEResponse}
-          />
-        )}
+        {isLatestVersion &&
+          get(currentUser, 'isInvitedHE', false) && (
+            <ResponseToInvitation
+              commentsOn="decline"
+              expanded={heResponseExpanded}
+              formValues={formValues.responseToInvitation}
+              label="Do you agree to be the handling editor for this manuscript?"
+              onResponse={inviteHandlingEditor.onHEResponse}
+              title="Respond to Editorial Invitation"
+              toggle={toggleHEResponse}
+            />
+          )}
 
         {get(currentUser, 'isInvitedToReview', false) && (
           <ResponseToInvitation
@@ -183,14 +194,16 @@ const ManuscriptLayout = ({
           />
         )}
 
-        <ManuscriptAssignHE
-          assignHE={inviteHandlingEditor.assignHE}
-          currentUser={currentUser}
-          expanded={heExpanded}
-          handlingEditors={handlingEditors}
-          isFetching={isFetchingData.editorsFetching}
-          toggle={toggleAssignHE}
-        />
+        {isLatestVersion && (
+          <ManuscriptAssignHE
+            assignHE={inviteHandlingEditor.assignHE}
+            currentUser={currentUser}
+            expanded={heExpanded}
+            handlingEditors={handlingEditors}
+            isFetching={isFetchingData.editorsFetching}
+            toggle={toggleAssignHE}
+          />
+        )}
 
         {get(currentUser, 'permissions.canViewReviewersDetails', false) && (
           <ReviewerDetails
@@ -228,10 +241,11 @@ const ManuscriptLayout = ({
         {isLatestVersion &&
           get(currentUser, 'permissions.canMakeHERecommendation', false) && (
             <HERecommendation
-              collection={collection}
+              canHEMakeRecommendationToPublish={
+                canHEMakeRecommendationToPublish
+              }
+              canHEOnlyReject={canHEOnlyReject}
               formValues={get(formValues, 'editorialRecommendation', {})}
-              fragment={fragment}
-              hasReviewerReports={reviewerRecommendations.length > 0}
               highlight={reviewerRecommendations.length > 0}
               modalKey="heRecommendation"
               onRecommendationSubmit={
diff --git a/packages/component-manuscript/src/components/ManuscriptPage.js b/packages/component-manuscript/src/components/ManuscriptPage.js
index 030805e20e8baeb68ab9919f3cf34379c392ca51..9ecbb8297bdce18ebcfd1b00c0b26e2b624af545 100644
--- a/packages/component-manuscript/src/components/ManuscriptPage.js
+++ b/packages/component-manuscript/src/components/ManuscriptPage.js
@@ -36,6 +36,7 @@ import {
   currentUserIs,
   canViewReports,
   canMakeRevision,
+  canHEOnlyReject,
   canMakeDecision,
   isHEToManuscript,
   canSubmitRevision,
@@ -56,6 +57,8 @@ import {
   getOwnPendingRecommendation,
   getOwnSubmittedRecommendation,
   canAuthorViewEditorialComments,
+  reviewersCanViewReviewerReports,
+  canHEMakeRecommendationToPublish,
   getFragmentReviewerRecommendations,
   getInvitationsWithReviewersForFragment,
 } from 'pubsweet-component-faraday-selectors'
@@ -175,7 +178,11 @@ export default compose(
             collection,
             statuses: get(journal, 'statuses', {}),
           }),
-          canAssignHE: canAssignHE(state, collection),
+          canAssignHE: canAssignHE(
+            state,
+            collection,
+            isLatestVersion(collection, fragment),
+          ),
           canViewReports: canViewReports(state, match.params.project),
           canViewEditorialComments: canViewEditorialComments(
             state,
@@ -193,6 +200,11 @@ export default compose(
             collection,
             get(fragment, 'id', ''),
           ),
+          reviewersCanViewReviewerReports: reviewersCanViewReviewerReports(
+            state,
+            collection,
+            get(fragment, 'id', ''),
+          ),
           canOverrideTechChecks: canOverrideTechnicalChecks(state, collection),
           canAuthorViewEditorialComments: canAuthorViewEditorialComments(
             state,
@@ -206,6 +218,11 @@ export default compose(
           ),
         },
       },
+      canHEMakeRecommendationToPublish: canHEMakeRecommendationToPublish(
+        state,
+        collection,
+      ),
+      canHEOnlyReject: canHEOnlyReject(collection),
       isFetchingData: {
         editorsFetching: selectFetching(state),
         publonsFetching: isFetching,
@@ -290,7 +307,7 @@ export default compose(
   })),
   fromRenderProps(RemoteOpener, ({ toggle, expanded }) => ({
     toggleResponseToRevisionRequest: toggle,
-    responseToRevisionRequest: expanded,
+    responseToRevisionRequestExpanded: expanded,
   })),
   fromRenderProps(RemoteOpener, ({ toggle, expanded }) => ({
     toggleReviewerDetails: toggle,
@@ -385,7 +402,8 @@ export default compose(
 
       if (
         get(fragment, 'responseToReviewers.content', false) &&
-        !editorialRecommendations.length
+        !editorialRecommendations.length &&
+        !reviewerReports.length
       ) {
         this.props.toggleResponseToRevisionRequest()
       }
diff --git a/packages/component-manuscript/src/components/ReviewerReports.js b/packages/component-manuscript/src/components/ReviewerReports.js
new file mode 100644
index 0000000000000000000000000000000000000000..9d838360390efb16be9bb8a837d299b866c55c8a
--- /dev/null
+++ b/packages/component-manuscript/src/components/ReviewerReports.js
@@ -0,0 +1,88 @@
+import React from 'react'
+import { compose, withProps } from 'recompose'
+import { get } from 'lodash'
+import {
+  ReviewerReport,
+  ContextualBox,
+  withFilePreview,
+  withFileDownload,
+  Text,
+  Row,
+  indexReviewers,
+} from 'pubsweet-component-faraday-ui'
+
+const SubmittedReports = ({ reports }) => (
+  <Row fitContent justify="flex-end">
+    <Text customId mr={1 / 2}>
+      {reports}
+    </Text>
+    <Text mr={1 / 2} pr={1 / 2} secondary>
+      {' '}
+      submitted
+    </Text>
+  </Row>
+)
+
+const ReviewerReports = ({
+  journal,
+  reports,
+  previewFile,
+  downloadFile,
+  isLatestVersion,
+  currentUser,
+  token,
+  invitations,
+  reviwerReports,
+}) => (
+  <ContextualBox
+    label={isLatestVersion ? 'Your Report' : 'Reviewer Reports'}
+    mb={2}
+    rightChildren={<SubmittedReports reports={reports.length} />}
+    startExpanded
+  >
+    {reports.map(report => (
+      <ReviewerReport
+        currentUser={currentUser}
+        journal={journal}
+        key={report.id}
+        onDownload={downloadFile}
+        onPreview={previewFile}
+        report={report}
+        reviewerNumber={report.reviewerNumber}
+        showOwner={report.userId === currentUser.id}
+      />
+    ))}
+  </ContextualBox>
+)
+
+export default compose(
+  withFileDownload,
+  withFilePreview,
+  withProps(
+    ({
+      invitations = [],
+      publonReviewers = [],
+      reviewerReports = [],
+      currentUser,
+      isLatestVersion,
+    }) => ({
+      token: get(currentUser, 'token', ''),
+      publonReviewers,
+      invitations: invitations.map(i => ({
+        ...i,
+        review: reviewerReports.find(r => r.userId === i.userId),
+      })),
+      reports: isLatestVersion
+        ? indexReviewers(
+            reviewerReports.filter(
+              r => r.submittedOn && r.userId === currentUser.id,
+            ),
+            invitations,
+          )
+        : indexReviewers(
+            reviewerReports.filter(r => r.submittedOn),
+            invitations,
+          ),
+    }),
+  ),
+)(ReviewerReports)
diff --git a/packages/component-manuscript/src/redux/editors.js b/packages/component-manuscript/src/redux/editors.js
index e28c0dd29ff392776fa2092639ec8fceda19026a..2ff500a7c82c6d94db4b74faaa837b961b6c1b04 100644
--- a/packages/component-manuscript/src/redux/editors.js
+++ b/packages/component-manuscript/src/redux/editors.js
@@ -24,13 +24,14 @@ export const selectHandlingEditors = state =>
     .value()
 
 const canAssignHEStatuses = ['submitted']
-export const canAssignHE = (state, collection = {}) => {
+export const canAssignHE = (state, collection = {}, isLatestVersion) => {
   const isEIC = currentUserIs(state, 'adminEiC')
   const hasHE = get(collection, 'handlingEditor', false)
 
   return (
     isEIC &&
     !hasHE &&
+    isLatestVersion &&
     canAssignHEStatuses.includes(get(collection, 'status', 'draft'))
   )
 }
diff --git a/packages/component-mts-package/src/MTS.js b/packages/component-mts-package/src/MTS.js
index 22d862896b71ffa81a67478a708a0dadcc262974..3f9e503df78bbf5d3273f0e7e19dd4d3c764b1e1 100644
--- a/packages/component-mts-package/src/MTS.js
+++ b/packages/component-mts-package/src/MTS.js
@@ -1,324 +1,54 @@
-const convert = require('xml-js')
-const config = require('config')
-const { set, get, reduce, isEmpty, capitalize } = require('lodash')
+const { get } = require('lodash')
 
 const PackageManager = require('./PackageManager')
-const mts = require('./mts-json-template')
-
-const manuscriptTypes = config.get('journalConfig.manuscriptTypes')
 
 const {
   defaultConfig,
-  defaultParseXmlOptions,
   defaultS3Config,
   defaultFTPConfig,
+  defaultParseXmlOptions,
 } = require('../config/default')
 
-class MTS {
-  constructor(
+const { convertToXML, composeJson } = require('./helpers')
+
+module.exports = {
+  sendPackage({
+    fragment = {},
+    isEQA = false,
+    fragmentUsers = [],
     config = defaultConfig,
-    options = defaultParseXmlOptions,
     s3Config = defaultS3Config,
     ftpConfig = defaultFTPConfig,
-  ) {
-    this.config = config
-    this.options = options
-    this.jsonTemplate = mts.getJsonTemplate(config)
-    this.s3Config = s3Config
-    this.ftpConfig = ftpConfig
-  }
-
-  createFileName(id = Date.now()) {
-    return `${this.config.prefix}${id}`
-  }
-
-  parseHtml(content = '') {
-    if (/<\/?[^>]*>/.test(content)) {
-      return convert.xml2js(content, this.options)
-    }
-    return content
-  }
-
-  convertToXML(json = {}) {
-    const content = convert.json2xml(json, this.options)
-    const customId = get(
-      json,
-      'article.front.article-meta.article-id[0]._text',
-      this.createFileName(),
-    )
-    const name = `${customId}.xml`
-    return {
-      name,
-      content,
-    }
-  }
-
-  setMetadata(metadata, jsonTemplate) {
-    const fileName = this.createFileName(metadata.customId)
-    const titleGroup = {
-      'article-title': this.parseHtml(metadata.title),
-    }
-    const articleId = [
-      {
-        _attributes: {
-          'pub-id-type': 'publisher-id',
-        },
-        _text: fileName,
-      },
-      {
-        _attributes: {
-          'pub-id-type': 'manuscript',
-        },
-        _text: fileName,
-      },
-    ]
-
-    const articleType = {
-      'subj-group': [
-        {
-          _attributes: {
-            'subj-group-type': 'Article Type',
-          },
-          subject: {
-            _text: get(
-              manuscriptTypes.find(v => v.value === metadata.type),
-              'label',
-              'Research Article',
-            ),
-          },
-        },
-      ],
-    }
-    set(jsonTemplate, 'article.front.article-meta.title-group', titleGroup)
-    set(jsonTemplate, 'article.front.article-meta.article-id', articleId)
-    set(
-      jsonTemplate,
-      'article.front.article-meta.article-categories',
-      articleType,
-    )
-    set(jsonTemplate, 'article.front.article-meta.abstract', metadata.abstract)
-
-    return jsonTemplate
-  }
-
-  static setHistory(submitted, jsonTemplate) {
-    const date = new Date(submitted)
-    const parsedDate = {
-      date: {
-        _attributes: {
-          'date-type': 'received',
-        },
-        day: {
-          _text: date.getDate(),
-        },
-        month: {
-          _text: date.getMonth() + 1,
-        },
-        year: {
-          _text: date.getFullYear(),
-        },
-      },
-    }
-    set(jsonTemplate, 'article.front.article-meta.history', parsedDate)
-
-    return jsonTemplate
-  }
-
-  static setFiles(files, jsonTemplate) {
-    const jsonFiles = reduce(
-      files,
-      (result, value, key) => {
-        value.map(v =>
-          result.push({
-            item_type: {
-              _text: key,
-            },
-            item_description: {
-              _text: v.originalName,
-            },
-            item_name: {
-              _text: v.name,
-            },
-          }),
-        )
-
-        return result
-      },
-      [],
-    )
-    set(jsonTemplate, 'article.front.files.file', jsonFiles)
-
-    return jsonTemplate
-  }
-
-  static setQuestions(conflicts, jsonTemplate) {
-    const {
-      hasConflicts = 'no',
-      message = '',
-      hasDataAvailability = 'no',
-      dataAvailabilityMessage = '',
-      hasFunding = 'no',
-      fundingMessage = '',
-    } = conflicts
-    const questions = []
-    const funding = isEmpty(hasFunding) ? 'no' : hasFunding
-    const dataAvailability = isEmpty(hasDataAvailability)
-      ? 'no'
-      : hasDataAvailability
-
-    const getQuestionMessage = (selection, message, defaultMessage) => {
-      if (selection === 'yes') {
-        return ''
-      }
-      return isEmpty(message) ? defaultMessage : message
-    }
-    if (!isEmpty(hasConflicts)) {
-      questions.push({
-        _attributes: {
-          type: 'COI',
-        },
-        answer: {
-          _text: capitalize(hasConflicts),
-        },
-        statement: {
-          _text: message,
-        },
-      })
-    }
-    if (!isEmpty(dataAvailability)) {
-      questions.push({
-        _attributes: {
-          type: 'DA',
-        },
-        answer: {
-          _text: capitalize(dataAvailability),
-        },
-        statement: {
-          _text: getQuestionMessage(
-            dataAvailability,
-            dataAvailabilityMessage,
-            'The authors for this paper did not provide a data availability statement',
-          ),
-        },
-      })
-    }
-    if (!isEmpty(funding)) {
-      questions.push({
-        _attributes: {
-          type: 'Fund',
-        },
-        answer: {
-          _text: capitalize(funding),
-        },
-        statement: {
-          _text: getQuestionMessage(
-            funding,
-            fundingMessage,
-            'The authors for this paper did not provide a funding statement',
-          ),
-        },
-      })
-    }
-
-    set(jsonTemplate, 'article.front.questions.question', questions)
-    return jsonTemplate
-  }
-
-  static setContributors(authors = [], jsonTemplate) {
-    const contrib = authors.map((a, i) => ({
-      _attributes: {
-        'contrib-type': 'author',
-        corresp: a.isCorresponding ? 'Yes' : 'No',
-      },
-      role: {
-        _attributes: {
-          'content-type': '1',
-        },
-      },
-      name: {
-        surname: {
-          _text: a.firstName,
-        },
-        'given-names': {
-          _text: a.lastName,
-        },
-        prefix: {
-          _text: a.title || 'Dr.',
-        },
-      },
-      email: {
-        _text: a.email,
-      },
-      xref: {
-        _attributes: {
-          'ref-type': 'aff',
-          rid: `aff${i + 1}`,
-        },
-      },
-    }))
-    const aff = authors.map((a, i) => ({
-      _attributes: {
-        id: `aff${i + 1}`,
-      },
-      country: a.country || 'UK',
-      'addr-line': {
-        _text: a.affiliation || '',
-      },
-    }))
-
-    set(
-      jsonTemplate,
-      'article.front.article-meta.contrib-group.contrib',
-      contrib,
-    )
-    set(jsonTemplate, 'article.front.article-meta.contrib-group.aff', aff)
-
-    return jsonTemplate
-  }
-
-  composeJson(fragment = {}) {
-    const {
-      authors = [],
-      files = [],
-      metadata = { title: 'untitled', abstract: '' },
-      submitted = new Date(),
-      conflicts = {},
-    } = fragment
-
-    return {
-      ...this.jsonTemplate,
-      ...this.setMetadata(metadata, this.jsonTemplate),
-      ...this.constructor.setContributors(authors, this.jsonTemplate),
-      ...this.constructor.setHistory(submitted, this.jsonTemplate),
-      ...this.constructor.setFiles(files, this.jsonTemplate),
-      ...this.constructor.setQuestions(conflicts, this.jsonTemplate),
-    }
-  }
-
-  convertFragmentToXML(fragment = {}) {
-    return this.convertToXML(this.composeJson(fragment))
-  }
-
-  sendPackage({ fragment = {}, isEQA = false }) {
-    const xmlFile = this.convertFragmentToXML(fragment)
+    options = defaultParseXmlOptions,
+  }) {
+    const composedJson = composeJson({
+      isEQA,
+      config,
+      options,
+      fragment,
+      fragmentUsers,
+    })
+    const xmlFile = convertToXML({
+      options,
+      json: composedJson,
+      prefix: config.prefix,
+    })
 
-    return PackageManager.createFilesPackage(this.s3Config)({
+    return PackageManager.createFilesPackage(s3Config)({
       fragment,
       xmlFile,
       isEQA,
     }).then(() => {
       const packageName = get(xmlFile, 'name', '').replace('.xml', '')
       const filename = isEQA
-        ? `ACCEPTED_${packageName}.zip`
+        ? `ACCEPTED_${packageName}.${fragment.version}.zip`
         : `${packageName}.zip`
 
       return PackageManager.uploadFiles({
         filename,
-        s3Config: this.s3Config,
-        config: this.ftpConfig,
+        s3Config,
+        config: ftpConfig,
       })
     })
-  }
+  },
 }
-
-module.exports = MTS
diff --git a/packages/component-mts-package/src/PackageManager.js b/packages/component-mts-package/src/PackageManager.js
index cb9b8ea4c9fd644ef72c146706dde13348283cc4..367567b1c36f8f8d528fe60dc1ec5581cb0865f8 100644
--- a/packages/component-mts-package/src/PackageManager.js
+++ b/packages/component-mts-package/src/PackageManager.js
@@ -22,7 +22,7 @@ const createFilesPackage = (s3Config, archiver = nodeArchiver) => {
     const { files = {} } = fragment
     let packageName = get(xmlFile, 'name', '').replace('.xml', '')
     if (isEQA) {
-      packageName = `ACCEPTED_${packageName}`
+      packageName = `ACCEPTED_${packageName}.${fragment.version}`
     }
     try {
       const s3FileIDs = Object.values(files)
diff --git a/packages/component-mts-package/src/getJsonTemplate.js b/packages/component-mts-package/src/getJsonTemplate.js
new file mode 100644
index 0000000000000000000000000000000000000000..2450cea1b72ec8ef03365016748612f4f9e9abf4
--- /dev/null
+++ b/packages/component-mts-package/src/getJsonTemplate.js
@@ -0,0 +1,229 @@
+module.exports = {
+  getJsonTemplate: (config = {}) => ({
+    _declaration: {
+      _attributes: {
+        version: '1.0',
+        encoding: 'utf-8',
+      },
+    },
+    _doctype: config.doctype,
+    article: {
+      _attributes: {
+        'dtd-version': config.dtdVersion,
+        'article-type': config.articleType,
+      },
+      front: {
+        'journal-meta': {
+          'journal-id': [
+            {
+              _attributes: {
+                'journal-id-type': 'publisher',
+              },
+              _text: config.journalIdPublisher,
+            },
+            {
+              _attributes: {
+                'journal-id-type': 'email',
+              },
+              _text: config.email,
+            },
+          ],
+          'journal-title-group': {
+            'journal-title': {
+              _text: config.journalTitle,
+            },
+          },
+          issn: [
+            {
+              _attributes: {
+                'pub-type': 'ppub',
+              },
+              _text: config.issn,
+            },
+            {
+              _attributes: {
+                'pub-type': 'epub',
+              },
+            },
+          ],
+        },
+        'article-meta': {
+          'article-id': [
+            {
+              _attributes: {
+                'pub-id-type': 'publisher-id',
+              },
+              _text: 'FARADAY-D-00-00000',
+            },
+            {
+              _attributes: {
+                'pub-id-type': 'manuscript',
+              },
+              _text: 'FARADAY-D-00-00000',
+            },
+          ],
+          'article-categories': {
+            'subj-group': [
+              {
+                _attributes: {
+                  'subj-group-type': 'Article Type',
+                },
+                subject: {
+                  _text: 'Research Article',
+                },
+              },
+            ],
+          },
+          'title-group': {
+            'article-title': {
+              _text: 'Untitled Article Title ',
+            },
+          },
+          'contrib-group': {
+            contrib: {
+              _attributes: {
+                'contrib-type': 'author',
+                corresp: 'yes',
+              },
+              role: {
+                _attributes: {
+                  'content-type': '1',
+                },
+              },
+              name: {
+                surname: {
+                  _text: 'First Name',
+                },
+                'given-names': {
+                  _text: 'Last Name',
+                },
+                prefix: {
+                  _text: 'Dr.',
+                },
+              },
+              email: {
+                _text: 'faraday@hindawi.com',
+              },
+              xref: {
+                _attributes: {
+                  'ref-type': 'aff',
+                  rid: 'aff1',
+                },
+              },
+            },
+            aff: {
+              _attributes: {
+                id: 'aff1',
+              },
+              country: {
+                _text: 'UNITED STATES',
+              },
+            },
+          },
+          history: {
+            date: {
+              _attributes: {
+                'date-type': 'received',
+              },
+              day: {
+                _text: '01',
+              },
+              month: {
+                _text: '01',
+              },
+              year: {
+                _text: '1970',
+              },
+            },
+          },
+          abstract: {
+            p: {
+              _text: 'No abstract provided',
+            },
+          },
+          'funding-group': {},
+        },
+        files: {
+          file: [],
+        },
+        questions: {
+          question: [],
+        },
+        'rev-group': {
+          rev: [
+            {
+              _attributes: {
+                'rev-type': 'reviewer',
+              },
+              name: {
+                surname: {
+                  _text: 'Last Name',
+                },
+                'given-names': {
+                  _text: 'First Name',
+                },
+                prefix: {
+                  _text: 'Dr',
+                },
+              },
+              email: {
+                _text: 'faraday@hindawi.com',
+              },
+              xref: {
+                _attributes: {
+                  'ref-type': 'aff',
+                  rid: 'aff1',
+                },
+              },
+              date: [
+                {
+                  _attributes: {
+                    'date-type': 'assignment',
+                  },
+                  day: {
+                    _text: '24',
+                  },
+                  month: {
+                    _text: '10',
+                  },
+                  year: {
+                    _text: '2018',
+                  },
+                },
+                {
+                  _attributes: {
+                    'date-type': 'submission',
+                  },
+                  day: {
+                    _text: '24',
+                  },
+                  month: {
+                    _text: '10',
+                  },
+                  year: {
+                    _text: '2018',
+                  },
+                },
+              ],
+              comment: {
+                _attributes: {
+                  'comment-type': 'comment',
+                },
+                _text:
+                  'This article is really great! well written and does not need any update. Please publish it as such',
+              },
+            },
+          ],
+          aff: {
+            _attributes: {
+              id: 'aff1',
+            },
+            'addr-line': {
+              _text: 'University of Fort Hare, Alice 5700, South Africa',
+            },
+          },
+        },
+      },
+    },
+  }),
+}
diff --git a/packages/component-mts-package/src/helpers.js b/packages/component-mts-package/src/helpers.js
new file mode 100644
index 0000000000000000000000000000000000000000..3490eeb2d7d8b1fa7ddb39f36fe85f1a1d122821
--- /dev/null
+++ b/packages/component-mts-package/src/helpers.js
@@ -0,0 +1,71 @@
+const convert = require('xml-js')
+const { get } = require('lodash')
+
+const { getJsonTemplate } = require('./getJsonTemplate')
+
+const {
+  setFiles,
+  setHistory,
+  setMetadata,
+  setQuestions,
+  setReviewers,
+  createFileName,
+  setContributors,
+} = require('./templateSetters')
+
+module.exports = {
+  convertToXML: ({ json = {}, options, prefix }) => {
+    const content = convert.json2xml(json, options)
+    const customId = get(
+      json,
+      'article.front.article-meta.article-id[0]._text',
+      createFileName({ prefix }),
+    )
+    const name = `${customId}.xml`
+    return {
+      name,
+      content,
+    }
+  },
+  composeJson: ({
+    config,
+    options,
+    isEQA = false,
+    fragment = {},
+    fragmentUsers = [],
+  }) => {
+    const {
+      authors = [],
+      files = [],
+      metadata = { title: 'untitled', abstract: '' },
+      submitted = new Date(),
+      conflicts = {},
+    } = fragment
+
+    const jsonTemplate = getJsonTemplate(config)
+    const fileName = createFileName({
+      id: metadata.customId,
+      prefix: config.prefix,
+    })
+
+    let composedJson = {
+      ...jsonTemplate,
+      ...setMetadata({
+        options,
+        metadata,
+        fileName,
+        jsonTemplate,
+      }),
+      ...setContributors(authors, jsonTemplate),
+      ...setHistory(submitted, jsonTemplate),
+      ...setFiles(files, jsonTemplate),
+      ...setQuestions(conflicts, jsonTemplate),
+    }
+
+    if (isEQA) {
+      composedJson = setReviewers(fragmentUsers, jsonTemplate)
+    }
+
+    return composedJson
+  },
+}
diff --git a/packages/component-mts-package/src/mts-json-template.js b/packages/component-mts-package/src/mts-json-template.js
deleted file mode 100644
index f1fe175dc8ce08040c41cffb49f59b930fb8051f..0000000000000000000000000000000000000000
--- a/packages/component-mts-package/src/mts-json-template.js
+++ /dev/null
@@ -1,157 +0,0 @@
-const getJsonTemplate = (config = {}) => ({
-  _declaration: {
-    _attributes: {
-      version: '1.0',
-      encoding: 'utf-8',
-    },
-  },
-  _doctype: config.doctype,
-  article: {
-    _attributes: {
-      'dtd-version': config.dtdVersion,
-      'article-type': config.articleType,
-    },
-    front: {
-      'journal-meta': {
-        'journal-id': [
-          {
-            _attributes: {
-              'journal-id-type': 'publisher',
-            },
-            _text: config.journalIdPublisher,
-          },
-          {
-            _attributes: {
-              'journal-id-type': 'email',
-            },
-            _text: config.email,
-          },
-        ],
-        'journal-title-group': {
-          'journal-title': {
-            _text: config.journalTitle,
-          },
-        },
-        issn: [
-          {
-            _attributes: {
-              'pub-type': 'ppub',
-            },
-            _text: config.issn,
-          },
-          {
-            _attributes: {
-              'pub-type': 'epub',
-            },
-          },
-        ],
-      },
-      'article-meta': {
-        'article-id': [
-          {
-            _attributes: {
-              'pub-id-type': 'publisher-id',
-            },
-            _text: 'FARADAY-D-00-00000',
-          },
-          {
-            _attributes: {
-              'pub-id-type': 'manuscript',
-            },
-            _text: 'FARADAY-D-00-00000',
-          },
-        ],
-        'article-categories': {
-          'subj-group': [
-            {
-              _attributes: {
-                'subj-group-type': 'Article Type',
-              },
-              subject: {
-                _text: 'Research Article',
-              },
-            },
-          ],
-        },
-        'title-group': {
-          'article-title': {
-            _text: 'Untitled Article Title ',
-          },
-        },
-        'contrib-group': {
-          contrib: {
-            _attributes: {
-              'contrib-type': 'author',
-              corresp: 'yes',
-            },
-            role: {
-              _attributes: {
-                'content-type': '1',
-              },
-            },
-            name: {
-              surname: {
-                _text: 'First Name',
-              },
-              'given-names': {
-                _text: 'Last Name',
-              },
-              prefix: {
-                _text: 'Dr.',
-              },
-            },
-            email: {
-              _text: 'faraday@hindawi.com',
-            },
-            xref: {
-              _attributes: {
-                'ref-type': 'aff',
-                rid: 'aff1',
-              },
-            },
-          },
-          aff: {
-            _attributes: {
-              id: 'aff1',
-            },
-            country: {
-              _text: 'UNITED STATES',
-            },
-          },
-        },
-        history: {
-          date: {
-            _attributes: {
-              'date-type': 'received',
-            },
-            day: {
-              _text: '01',
-            },
-            month: {
-              _text: '01',
-            },
-            year: {
-              _text: '1970',
-            },
-          },
-        },
-        abstract: {
-          p: {
-            _text: 'No abstract provided',
-          },
-        },
-        'funding-group': {},
-      },
-      files: {
-        file: [],
-      },
-      questions: {
-        question: [],
-      },
-    },
-  },
-})
-
-module.exports = {
-  getJsonTemplate,
-}
diff --git a/packages/component-mts-package/src/templateSetters.js b/packages/component-mts-package/src/templateSetters.js
new file mode 100644
index 0000000000000000000000000000000000000000..31de2d28e374ef4536a8d842be5f7efacc3c638c
--- /dev/null
+++ b/packages/component-mts-package/src/templateSetters.js
@@ -0,0 +1,321 @@
+const config = require('config')
+const convert = require('xml-js')
+
+const { set, get, reduce, isEmpty, capitalize } = require('lodash')
+
+const manuscriptTypes = config.get('journalConfig.manuscriptTypes')
+
+module.exports = {
+  setMetadata: ({ metadata, jsonTemplate, options, fileName }) => {
+    const titleGroup = {
+      'article-title': parseHtml(metadata.title, options),
+    }
+    const articleId = [
+      {
+        _attributes: {
+          'pub-id-type': 'publisher-id',
+        },
+        _text: fileName,
+      },
+      {
+        _attributes: {
+          'pub-id-type': 'manuscript',
+        },
+        _text: fileName,
+      },
+    ]
+
+    const articleType = {
+      'subj-group': [
+        {
+          _attributes: {
+            'subj-group-type': 'Article Type',
+          },
+          subject: {
+            _text: get(
+              manuscriptTypes.find(v => v.value === metadata.type),
+              'label',
+              'Research Article',
+            ),
+          },
+        },
+      ],
+    }
+    set(jsonTemplate, 'article.front.article-meta.title-group', titleGroup)
+    set(jsonTemplate, 'article.front.article-meta.article-id', articleId)
+    set(
+      jsonTemplate,
+      'article.front.article-meta.article-categories',
+      articleType,
+    )
+    set(jsonTemplate, 'article.front.article-meta.abstract', metadata.abstract)
+
+    return jsonTemplate
+  },
+  setHistory: (submitted, jsonTemplate) => {
+    const date = new Date(submitted)
+    const parsedDate = {
+      date: {
+        _attributes: {
+          'date-type': 'received',
+        },
+        day: {
+          _text: date.getDate(),
+        },
+        month: {
+          _text: date.getMonth() + 1,
+        },
+        year: {
+          _text: date.getFullYear(),
+        },
+      },
+    }
+    set(jsonTemplate, 'article.front.article-meta.history', parsedDate)
+
+    return jsonTemplate
+  },
+  setFiles: (files, jsonTemplate) => {
+    const jsonFiles = reduce(
+      files,
+      (result, value, key) => {
+        value.map(v =>
+          result.push({
+            item_type: {
+              _text: key,
+            },
+            item_description: {
+              _text: v.originalName,
+            },
+            item_name: {
+              _text: v.name,
+            },
+          }),
+        )
+
+        return result
+      },
+      [],
+    )
+    set(jsonTemplate, 'article.front.files.file', jsonFiles)
+
+    return jsonTemplate
+  },
+  setQuestions: (conflicts, jsonTemplate) => {
+    const {
+      hasConflicts = 'no',
+      message = '',
+      hasDataAvailability = 'no',
+      dataAvailabilityMessage = '',
+      hasFunding = 'no',
+      fundingMessage = '',
+    } = conflicts
+    const questions = []
+    const funding = isEmpty(hasFunding) ? 'no' : hasFunding
+    const dataAvailability = isEmpty(hasDataAvailability)
+      ? 'no'
+      : hasDataAvailability
+
+    const getQuestionMessage = (selection, message, defaultMessage) => {
+      if (selection === 'yes') {
+        return ''
+      }
+      return isEmpty(message) ? defaultMessage : message
+    }
+    if (!isEmpty(hasConflicts)) {
+      questions.push({
+        _attributes: {
+          type: 'COI',
+        },
+        answer: {
+          _text: capitalize(hasConflicts),
+        },
+        statement: {
+          _text: message,
+        },
+      })
+    }
+    if (!isEmpty(dataAvailability)) {
+      questions.push({
+        _attributes: {
+          type: 'DA',
+        },
+        answer: {
+          _text: capitalize(dataAvailability),
+        },
+        statement: {
+          _text: getQuestionMessage(
+            dataAvailability,
+            dataAvailabilityMessage,
+            'The authors for this paper did not provide a data availability statement',
+          ),
+        },
+      })
+    }
+    if (!isEmpty(funding)) {
+      questions.push({
+        _attributes: {
+          type: 'Fund',
+        },
+        answer: {
+          _text: capitalize(funding),
+        },
+        statement: {
+          _text: getQuestionMessage(
+            funding,
+            fundingMessage,
+            'The authors for this paper did not provide a funding statement',
+          ),
+        },
+      })
+    }
+
+    set(jsonTemplate, 'article.front.questions.question', questions)
+    return jsonTemplate
+  },
+  setContributors: (authors = [], jsonTemplate) => {
+    const contrib = authors.map((a, i) => ({
+      _attributes: {
+        'contrib-type': 'author',
+        corresp: a.isCorresponding ? 'Yes' : 'No',
+      },
+      role: {
+        _attributes: {
+          'content-type': '1',
+        },
+      },
+      name: {
+        surname: {
+          _text: a.firstName,
+        },
+        'given-names': {
+          _text: a.lastName,
+        },
+        prefix: {
+          _text: a.title || 'Dr.',
+        },
+      },
+      email: {
+        _text: a.email,
+      },
+      xref: {
+        _attributes: {
+          'ref-type': 'aff',
+          rid: `aff${i + 1}`,
+        },
+      },
+    }))
+    const aff = authors.map((a, i) => ({
+      _attributes: {
+        id: `aff${i + 1}`,
+      },
+      country: a.country || 'UK',
+      'addr-line': {
+        _text: a.affiliation || '',
+      },
+    }))
+
+    set(
+      jsonTemplate,
+      'article.front.article-meta.contrib-group.contrib',
+      contrib,
+    )
+    set(jsonTemplate, 'article.front.article-meta.contrib-group.aff', aff)
+
+    return jsonTemplate
+  },
+  createFileName: ({ id = Date.now(), prefix }) => `${prefix}${id}`,
+  setReviewers: (users = [], jsonTemplate) => {
+    const xmlReviewers = users.map((user, i) => {
+      const assigmentDate = new Date(user.assignmentDate)
+      const revType = user.isReviewer ? 'reviewer' : 'editor'
+      const revObj = {
+        _attributes: {
+          'rev-type': revType,
+        },
+        name: {
+          surname: {
+            _text: user.lastName,
+          },
+          'given-names': {
+            _text: user.firstName,
+          },
+          prefix: {
+            _text: user.title || 'Dr.',
+          },
+        },
+        email: {
+          _text: user.email,
+        },
+        xref: {
+          _attributes: {
+            'ref-type': 'aff',
+            rid: `aff${i + 1}`,
+          },
+        },
+        date: [
+          {
+            _attributes: {
+              'date-type': 'assignment',
+            },
+            day: {
+              _text: assigmentDate.getDate(),
+            },
+            month: {
+              _text: assigmentDate.getMonth() + 1,
+            },
+            year: {
+              _text: assigmentDate.getFullYear(),
+            },
+          },
+        ],
+      }
+
+      if (user.recommendation) {
+        const submissionDate = new Date(user.submissionDate)
+        revObj.date.push({
+          _attributes: {
+            'date-type': 'submission',
+          },
+          day: {
+            _text: submissionDate.getDate(),
+          },
+          month: {
+            _text: submissionDate.getMonth() + 1,
+          },
+          year: {
+            _text: submissionDate.getFullYear(),
+          },
+        })
+        revObj.comment = user.recommendation.comments.map(comm => ({
+          _attributes: {
+            'comment-type': comm.public ? 'comment' : 'Confidential',
+          },
+          _text: comm.content,
+        }))
+      }
+
+      return revObj
+    })
+    const aff = users.map((user, i) => ({
+      _attributes: {
+        id: `aff${i + 1}`,
+      },
+      country: user.country || 'UK',
+      'addr-line': {
+        _text: user.affiliation || '',
+      },
+    }))
+
+    set(jsonTemplate, 'article.front.rev-group.rev', xmlReviewers)
+    set(jsonTemplate, 'article.front.rev-group.aff', aff)
+
+    return jsonTemplate
+  },
+}
+
+const parseHtml = (content = '', options) => {
+  if (/<\/?[^>]*>/.test(content)) {
+    return convert.xml2js(content, options)
+  }
+  return content
+}
diff --git a/packages/component-mts-package/tests/MTS.test.js b/packages/component-mts-package/tests/MTS.test.js
deleted file mode 100644
index 42c67eafd272402699e9be402e3f9d3f1860e0a6..0000000000000000000000000000000000000000
--- a/packages/component-mts-package/tests/MTS.test.js
+++ /dev/null
@@ -1,36 +0,0 @@
-process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'
-process.env.SUPPRESS_NO_CONFIG_WARNING = true
-
-const MTSService = require('../src/MTS')
-const mocks = require('./mocks')
-
-jest.mock('xml-js', () => ({
-  json2xml: jest.fn(),
-  xml2js: jest.fn(),
-}))
-
-describe('MTS integration', () => {
-  let MTS
-
-  beforeEach(() => {
-    MTS = new MTSService(mocks.config.defaultConfig)
-  })
-
-  it('should be instantiated', () => {
-    const result = MTS
-    expect(result).toBeDefined()
-  })
-
-  it('should return basic json for XML parsing', () => {
-    const result = MTS.composeJson({})
-    expect(result).toHaveProperty('article')
-  })
-
-  it('should contain configured journal name ', () => {
-    const result = MTS.composeJson({ fragment: mocks.fragment })
-    expect(result).toHaveProperty(
-      'article.front.journal-meta.journal-title-group.journal-title._text',
-      'Bioinorganic Chemistry and Applications',
-    )
-  })
-})
diff --git a/packages/component-mts-package/tests/helpers.test.js b/packages/component-mts-package/tests/helpers.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..501214eb7932ca94cc0dfe95a29ad599fa7155a1
--- /dev/null
+++ b/packages/component-mts-package/tests/helpers.test.js
@@ -0,0 +1,142 @@
+process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'
+process.env.SUPPRESS_NO_CONFIG_WARNING = true
+
+const { cloneDeep } = require('lodash')
+const Chance = require('chance')
+const fixturesService = require('pubsweet-component-fixture-service')
+
+const { getJsonTemplate } = require('../src/getJsonTemplate')
+const { defaultConfig, defaultParseXmlOptions } = require('../config/default')
+
+const { convertToXML, composeJson } = require('../src/helpers')
+
+const { fixtures } = fixturesService
+const chance = new Chance()
+describe('MTS helpers', () => {
+  let testFixtures = {}
+  beforeEach(() => {
+    testFixtures = cloneDeep(fixtures)
+  })
+  describe('composeJson', () => {
+    it('should return a json with a rev-group when isEQA is true', async () => {
+      const { fragment } = testFixtures.fragments
+      const fragmentUsers = [
+        {
+          isReviewer: true,
+          assignmentDate: chance.timestamp(),
+          email: chance.email(),
+          title: 'Dr',
+          recommendation: {
+            id: chance.guid(),
+            userId: chance.guid(),
+            comments: [
+              {
+                files: [],
+                public: true,
+                content: chance.sentence(),
+              },
+              {
+                files: [],
+                public: false,
+                content: chance.sentence(),
+              },
+            ],
+            createdOn: chance.timestamp(),
+            updatedOn: chance.timestamp(),
+            submittedOn: chance.timestamp(),
+            recommendation: 'publish',
+            recommendationType: 'review',
+          },
+          country: chance.country(),
+          lastName: chance.first(),
+          firstName: chance.last(),
+          affiliation: chance.company(),
+          submissionDate: chance.timestamp(),
+        },
+        {
+          isReviewer: false,
+          assignmentDate: chance.timestamp(),
+          email: chance.email(),
+          title: 'Dr',
+          recommendation: {
+            id: chance.guid(),
+            userId: chance.guid(),
+            comments: [
+              {
+                files: [],
+                public: true,
+                content: chance.sentence(),
+              },
+              {
+                files: [],
+                public: false,
+                content: chance.sentence(),
+              },
+            ],
+            createdOn: chance.timestamp(),
+            updatedOn: chance.timestamp(),
+            submittedOn: chance.timestamp(),
+            recommendation: 'publish',
+            recommendationType: 'editorRecommendation',
+          },
+          country: chance.country(),
+          lastName: chance.first(),
+          firstName: chance.last(),
+          affiliation: chance.company(),
+          submissionDate: chance.timestamp(),
+        },
+      ]
+      const composedJson = composeJson({
+        fragment,
+        isEQA: true,
+        fragmentUsers,
+        config: defaultConfig,
+        options: defaultParseXmlOptions,
+      })
+
+      expect(composedJson.article.front['rev-group']).toHaveProperty('rev')
+      expect(composedJson.article.front['rev-group'].rev).toHaveLength(
+        fragmentUsers.length,
+      )
+    })
+    it('should return a json with correct article-meta data', async () => {
+      const { fragment } = testFixtures.fragments
+      const composedJson = composeJson({
+        fragment,
+        isEQA: false,
+        config: defaultConfig,
+        options: defaultParseXmlOptions,
+      })
+
+      expect(
+        composedJson.article.front['article-meta']['contrib-group'],
+      ).toHaveProperty('contrib')
+      expect(
+        composedJson.article.front['article-meta']['contrib-group'].contrib,
+      ).toHaveLength(fragment.authors.length)
+      expect(
+        composedJson.article.front['article-meta']['title-group'][
+          'article-title'
+        ],
+      ).toEqual(fragment.metadata.title)
+    })
+  })
+  describe('convertToXML', () => {
+    it('should return a properly formatted object', async () => {
+      const jsonTemplate = getJsonTemplate(defaultConfig)
+      const xmlFile = convertToXML({
+        prefix: defaultConfig.prefix,
+        options: defaultParseXmlOptions,
+        json: jsonTemplate,
+      })
+
+      expect(xmlFile).toHaveProperty('name')
+      expect(xmlFile).toHaveProperty('content')
+      expect(xmlFile.content).toContain(
+        jsonTemplate.article.front['article-meta']['title-group'][
+          'article-title'
+        ]._text,
+      )
+    })
+  })
+})
diff --git a/packages/component-mts-package/tests/mocks.js b/packages/component-mts-package/tests/mocks.js
index 20519ab022db5e2c935bd3f65a322275a5b51209..d88427c2a66635c2e3fd58b0a48122dca0e90dcd 100644
--- a/packages/component-mts-package/tests/mocks.js
+++ b/packages/component-mts-package/tests/mocks.js
@@ -1,90 +1,160 @@
 const config = require('../config/default')
 
-const fragment = {
-  id: '57c7560b-6c1c-480d-a207-cb388d60a213',
+const fragmentWithRecommendations = {
   type: 'fragment',
   files: {
     coverLetter: [],
     manuscripts: [
       {
         id:
-          '57c7560b-6c1c-480d-a207-cb388d60a213/170ef7b5-bdfd-4637-908d-a693b8c07928',
-        name: 'Revolut-EUR-Statement-Jan 8, 2018.pdf',
-        size: 63347,
+          '9de6c313-1c3e-49eb-bc76-b5d2d045b271/f9916cb6-97a4-4d4c-8a2a-a89b0d10bbdf',
+        name: 'scimakelatex.2898.adrian+onofrei.pdf',
+        size: 76051,
+        originalName: 'scimakelatex.2898.adrian+onofrei.pdf',
       },
     ],
-    supplementary: [
-      {
-        id:
-          '57c7560b-6c1c-480d-a207-cb388d60a213/170ef7b5-bdfd-4637-908d-a693b8c07928',
-        name: 'SUP__Revolut-EUR-Statement-Jan 8, 2018.pdf',
-        size: 63347,
-      },
-    ],
-    responseToReviewers: [],
+    supplementary: [],
   },
-  owners: [
-    {
-      id: '79a35051-7744-49f0-bdfb-388dfe9d7bd3',
-      username: 'hindawi+auth@thinslices.com',
-    },
-  ],
+  owners: ['34b0f0be-ea6a-4f5c-81b2-8eca299bdd51'],
   authors: [
     {
-      id: '79a35051-7744-49f0-bdfb-388dfe9d7bd3',
-      email: 'hindawi+auth@thinslices.com',
+      id: '34b0f0be-ea6a-4f5c-81b2-8eca299bdd51',
+      email: 'adrian.onofrei+auth1@thinslices.com',
       title: 'mr',
-      lastName: 'Manuscriptunson',
-      firstName: 'Author',
-      affiliation: 'Hindawi',
+      country: 'AL',
+      lastName: 'Adi',
+      firstName: 'Auth',
+      affiliation: 'TS',
       isSubmitting: true,
       isCorresponding: true,
     },
-    {
-      id: 'd2c4aac6-af51-4421-98c6-cbbc862160d4',
-      email: 'hindawi+coauthor@thinslices.com',
-      lastName: 'Southgate',
-      firstName: 'Gareth 4thplace',
-      affiliation: 'UK',
-      isSubmitting: false,
-      isCorresponding: false,
-    },
   ],
-  created: '2018-07-20T13:16:39.635Z',
+  created: '2018-10-18T11:39:40.722Z',
   version: 1,
   metadata: {
-    type: 'clinical-study',
-    issue: 'regular-issue',
-    title: '<p>Harry Kane</p>',
-    journal: 'hindawi-faraday',
-    abstract: '<p>Golden boot, golden boy.</p>',
-    customId: '7654321',
+    customId: '9999999',
+    type: 'research',
+    title: 'Approve by he',
+    journal: 'Bioinorganic Chemistry and Applications',
+    abstract: 'test',
   },
-  conflicts: { hasConflicts: 'no' },
-  submitted: 1532092696032,
-  collectionId: 'afe691b5-8134-4e5c-b6e3-354a2ed473b5',
-  declarations: [
-    'has-email',
-    'has-manuscript',
-    'has-efiles',
-    'ok-article-processing',
-    'has-orcid',
-    'ok-institutional',
+  conflicts: {
+    hasFunding: '',
+    hasConflicts: 'no',
+    hasDataAvailability: '',
+  },
+  submitted: 1539862801961,
+  invitations: [
+    {
+      id: '625d7cef-201a-429a-8a91-97404e5e2f31',
+      role: 'reviewer',
+      type: 'invitation',
+      userId: '41ccfd11-9ff8-49b7-a513-58bfede153e8',
+      hasAnswer: true,
+      invitedOn: 1539863340777,
+      isAccepted: true,
+      respondedOn: 1539863456467,
+    },
   ],
+  collectionId: '9c9d9cf1-179f-4f7a-87fa-6e70cffbd3f3',
+  declarations: {
+    agree: true,
+  },
   fragmentType: 'version',
   recommendations: [
     {
-      id: '3f86ab07-14c8-4151-8185-d83054cb1c93',
-      userId: '36319eb1-d245-47d1-b010-4fc1b33d0e41',
-      createdOn: 1532094805409,
-      updatedOn: 1532094805409,
+      id: '9e77f9a8-ad88-4996-ae02-7bd2d7b42a00',
+      userId: '41ccfd11-9ff8-49b7-a513-58bfede153e8',
+      comments: [
+        {
+          files: [],
+          public: true,
+          content: 'revision pls - rev report',
+        },
+        {
+          files: [],
+          public: false,
+          content: 'Rev confidential note for ET',
+        },
+      ],
+      createdOn: 1539863473823,
+      updatedOn: 1539863502691,
+      submittedOn: 1539863502506,
+      recommendation: 'major',
+      recommendationType: 'review',
+    },
+    {
+      id: 'eb4abe60-6484-40e2-b31e-4bf1f1592278',
+      userId: '46841a2c-0b37-47c0-8847-9cedcaeeb082',
+      comments: [
+        {
+          files: [],
+          public: true,
+          content: 'Author publish message',
+        },
+        {
+          files: [],
+          public: false,
+          content: 'EiC publish message',
+        },
+      ],
+      createdOn: 1539863568158,
+      updatedOn: 1539863568158,
       recommendation: 'publish',
       recommendationType: 'editorRecommendation',
     },
+    {
+      id: '6e8cf67c-a969-48d3-9d90-52d02975a65a',
+      userId: 'f12e0a14-4b6b-4d22-a506-d03c0ac7562f',
+      comments: [
+        {
+          public: false,
+          content: 'HE you have to change this',
+        },
+      ],
+      createdOn: 1539863677902,
+      updatedOn: 1539863677902,
+      recommendation: 'return-to-handling-editor',
+      recommendationType: 'editorRecommendation',
+    },
+    {
+      id: '0e48444f-dd21-4e91-9b88-cdcfd9cc84d7',
+      userId: '46841a2c-0b37-47c0-8847-9cedcaeeb082',
+      comments: [
+        {
+          files: [],
+          public: true,
+          content: 'reject author',
+        },
+        {
+          files: [],
+          public: false,
+          content: 'reject eic',
+        },
+      ],
+      createdOn: 1539863792764,
+      updatedOn: 1539863792764,
+      recommendation: 'reject',
+      recommendationType: 'editorRecommendation',
+    },
+    {
+      id: '9730b9b0-fd37-46f6-943c-f3666984e2ab',
+      userId: 'f12e0a14-4b6b-4d22-a506-d03c0ac7562f',
+      comments: [
+        {
+          public: true,
+          content: 'shit man',
+        },
+      ],
+      createdOn: 1539864067558,
+      updatedOn: 1539864067558,
+      recommendation: 'reject',
+      recommendationType: 'editorRecommendation',
+    },
   ],
 }
 
 module.exports = {
-  fragment,
+  fragment: fragmentWithRecommendations,
   config,
 }
diff --git a/packages/component-mts-package/tests/sampleUpdated.json b/packages/component-mts-package/tests/sampleUpdated.json
new file mode 100644
index 0000000000000000000000000000000000000000..760cf8f00cc9453a0e6c61db44a998800592718f
--- /dev/null
+++ b/packages/component-mts-package/tests/sampleUpdated.json
@@ -0,0 +1,182 @@
+{
+  "_declaration": { "_attributes": { "version": "1.0", "encoding": "utf-8" } },
+  "_doctype": "article SYSTEM \"JATS-archivearticle1-mathml3.dtd\"",
+  "article": {
+    "_attributes": {
+      "dtd-version": "1.1d1",
+      "article-type": "Research Article"
+    },
+    "front": {
+      "journal-meta": {
+        "journal-id": [
+          { "_attributes": { "journal-id-type": "publisher" }, "_text": "BCA" },
+          {
+            "_attributes": { "journal-id-type": "email" },
+            "_text": "bca.support@hindawi.com"
+          }
+        ],
+        "journal-title-group": {
+          "journal-title": {
+            "_text": "Bioinorganic Chemistry and Applications"
+          }
+        },
+        "issn": [
+          { "_attributes": { "pub-type": "ppub" }, "_text": "2474-7394" },
+          { "_attributes": { "pub-type": "epub" } }
+        ]
+      },
+      "article-meta": {
+        "article-id": [
+          {
+            "_attributes": { "pub-id-type": "publisher-id" },
+            "_text": "BCA-5402665"
+          },
+          {
+            "_attributes": { "pub-id-type": "manuscript" },
+            "_text": "BCA-5402665"
+          }
+        ],
+        "article-categories": {
+          "subj-group": {
+            "_attributes": { "subj-group-type": "Article Type" },
+            "subject": { "_text": "Review Article" }
+          }
+        },
+        "title-group": {
+          "article-title": {
+            "_text": "Advances in iron compounds as biological agents"
+          }
+        },
+        "contrib-group": {
+          "contrib": {
+            "_attributes": { "contrib-type": "author", "corresp": "Yes" },
+            "role": { "_attributes": { "content-type": "1" } },
+            "name": {
+              "surname": { "_text": "Ayodele" },
+              "given-names": { "_text": "Odularu" },
+              "prefix": { "_text": "dr" }
+            },
+            "email": { "_text": "201106223@ufh.ac.za" },
+            "xref": { "_attributes": { "ref-type": "aff", "rid": "aff1" } }
+          },
+          "aff": {
+            "_attributes": { "id": "aff1" },
+            "country": { "_text": "ZA" },
+            "addr-line": {
+              "_text": "University of Fort Hare, Alice 5700, South Africa"
+            }
+          }
+        },
+        "history": {
+          "date": {
+            "_attributes": { "date-type": "received" },
+            "day": { "_text": "24" },
+            "month": { "_text": "10" },
+            "year": { "_text": "2018" }
+          }
+        },
+        "abstract": {
+          "_text":
+            "Abstract\nThis mini review gives a report of the progresses in the use of iron compounds as biological agents. Review entails coordination of ligands in form of pharmaceutical drugs, reagents used directly as supplied, synthesized organic compounds and natural products from plants to iron(II) or iron(III) ions to yield compounds which were applied as antibacterial, iron natural product, antioxidant and anticancer agents. In addition, in the aspect of material chemistry, holistic application of iron nanoparticles was assessed in relation to health. Iron nanoparticles are best approaches to apply as biological agents when compared to bulk materials because of its affordable, biocompatibity, biodegradability, simple approach to synthesis, ease of modification and non-toxic nature.\n\nKeywords: history of iron; chemistry of iron, uses of iron compounds, iron nanoparticles; biological screening techniques\n"
+        },
+        "funding-group": {}
+      },
+      "rev-group": {
+        "rev": [
+          {
+            "_attributes": { "rev-type": "reviewer" },
+            "name": {
+              "surname": { "_text": "Mohammed" },
+              "given-names": { "_text": "Rizk" },
+              "prefix": { "_text": "dr" }
+            },
+            "email": { "_text": "mohammed.rizk@hindawi.com" },
+            "date": [
+              {
+                "_attributes": { "date-type": "assignment" },
+                "day": { "_text": "24" },
+                "month": { "_text": "10" },
+                "year": { "_text": "2018" }
+              },
+              {
+                "_attributes": { "date-type": "submission" },
+                "day": { "_text": "24" },
+                "month": { "_text": "10" },
+                "year": { "_text": "2018" }
+              }
+            ],
+            "comment": {
+              "_attributes": { "comment-type": "" },
+              "_text":
+                "\n                This article is really great! well written and does not need any update. Please publish it as such\n        "
+            }
+          },
+          {
+            "_attributes": { "rev-type": "editor" },
+            "name": {
+              "surname": { "_text": "Matt" },
+              "given-names": { "_text": "Green" },
+              "prefix": { "_text": "dr" }
+            },
+            "email": { "_text": "matt.green@hindawi.com" },
+            "date": [
+              {
+                "_attributes": { "date-type": "assignment" },
+                "day": { "_text": "24" },
+                "month": { "_text": "10" },
+                "year": { "_text": "2018" }
+              },
+              {
+                "_attributes": { "date-type": "submission" },
+                "day": { "_text": "24" },
+                "month": { "_text": "10" },
+                "year": { "_text": "2018" }
+              }
+            ],
+            "comment": {
+              "_attributes": { "comment-type": "" },
+              "_text":
+                "\n                This article is really great! well written and does not need any update. Please publish it as such\n        "
+            }
+          }
+        ],
+        "aff": {
+          "_attributes": { "id": "aff1" },
+          "country": { "_text": "ZA" },
+          "addr-line": {
+            "_text": "University of Fort Hare, Alice 5700, South Africa"
+          }
+        }
+      },
+      "files": {
+        "file": {
+          "item_type": { "_text": "manuscripts" },
+          "item_description": { "_text": "23 2018.docx" },
+          "item_name": { "_text": "23 2018.docx" }
+        }
+      },
+      "questions": {
+        "question": [
+          {
+            "_attributes": { "type": "COI" },
+            "answer": { "_text": "No" },
+            "statement": {}
+          },
+          {
+            "_attributes": { "type": "DA" },
+            "answer": { "_text": "No" },
+            "statement": {
+              "_text":
+                "The authors for this paper did not provide a data availability statement"
+            }
+          },
+          {
+            "_attributes": { "type": "Fund" },
+            "answer": { "_text": "Yes" },
+            "statement": {}
+          }
+        ]
+      }
+    }
+  }
+}
diff --git a/packages/component-mts-package/tests/sampleUpdated.xml b/packages/component-mts-package/tests/sampleUpdated.xml
new file mode 100644
index 0000000000000000000000000000000000000000..ef088637df68cdb076bdebcbe47d6226ca10e35f
--- /dev/null
+++ b/packages/component-mts-package/tests/sampleUpdated.xml
@@ -0,0 +1,131 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE article SYSTEM "JATS-archivearticle1-mathml3.dtd">
+<article dtd-version="1.1d1" article-type="Research Article">
+  <front>
+    <journal-meta>
+      <journal-id journal-id-type="publisher">BCA</journal-id>
+      <journal-id journal-id-type="email">bca.support@hindawi.com</journal-id>
+      <journal-title-group>
+        <journal-title>Bioinorganic Chemistry and Applications</journal-title>
+      </journal-title-group>
+      <issn pub-type="ppub">2474-7394</issn>
+      <issn pub-type="epub"></issn>
+    </journal-meta>
+    <article-meta>
+      <article-id pub-id-type="publisher-id">BCA-5402665</article-id>
+      <article-id pub-id-type="manuscript">BCA-5402665</article-id>
+      <article-categories>
+        <subj-group subj-group-type="Article Type">
+          <subject>Review Article</subject>
+        </subj-group>
+      </article-categories>
+      <title-group>
+        <article-title>Advances in iron compounds as biological agents</article-title>
+      </title-group>
+      <contrib-group>
+        <contrib contrib-type="author" corresp="Yes">
+          <role content-type="1"></role>
+          <name>
+            <surname>Ayodele</surname>
+            <given-names>Odularu</given-names>
+            <prefix>dr</prefix>
+          </name>
+          <email>201106223@ufh.ac.za</email>
+          <xref ref-type="aff" rid="aff1"></xref>
+        </contrib>
+        <aff id="aff1">
+          <country>ZA</country>
+          <addr-line>University of Fort Hare, Alice 5700, South Africa</addr-line>
+        </aff>
+      </contrib-group>
+      <history>
+        <date date-type="received">
+          <day>24</day>
+          <month>10</month>
+          <year>2018</year>
+        </date>
+      </history>
+      <abstract>Abstract
+This mini review gives a report of the progresses in the use of iron compounds as biological agents. Review entails coordination of ligands in form of pharmaceutical drugs, reagents used directly as supplied, synthesized organic compounds and natural products from plants to iron(II) or iron(III) ions to yield compounds which were applied as antibacterial, iron natural product, antioxidant and anticancer agents. In addition, in the aspect of material chemistry, holistic application of iron nanoparticles was assessed in relation to health. Iron nanoparticles are best approaches to apply as biological agents when compared to bulk materials because of its affordable, biocompatibity, biodegradability, simple approach to synthesis, ease of modification and non-toxic nature.
+
+Keywords: history of iron; chemistry of iron, uses of iron compounds, iron nanoparticles; biological screening techniques
+</abstract>
+      <funding-group></funding-group>
+    </article-meta>
+
+          <rev-group>
+        <rev rev-type="reviewer">
+
+          <name>
+            <surname>Mohammed</surname>
+            <given-names>Rizk</given-names>
+            <prefix>dr</prefix>
+          </name>
+          <email>mohammed.rizk@hindawi.com</email>
+        <date date-type="assignment">
+          <day>24</day>
+          <month>10</month>
+          <year>2018</year>
+        </date>
+        <date date-type="submission">
+          <day>24</day>
+          <month>10</month>
+          <year>2018</year>
+        </date>
+        <comment comment-type="">
+                This article is really great! well written and does not need any update. Please publish it as such
+        </comment>
+        </rev>
+        <rev rev-type="editor">
+
+          <name>
+            <surname>Matt</surname>
+            <given-names>Green</given-names>
+            <prefix>dr</prefix>
+          </name>
+          <email>matt.green@hindawi.com</email>
+        <date date-type="assignment">
+          <day>24</day>
+          <month>10</month>
+          <year>2018</year>
+        </date>
+        <date date-type="submission">
+          <day>24</day>
+          <month>10</month>
+          <year>2018</year>
+        </date>
+        <comment comment-type="">
+                This article is really great! well written and does not need any update. Please publish it as such
+        </comment>
+
+
+        </rev>
+        <aff id="aff1">
+          <country>ZA</country>
+          <addr-line>University of Fort Hare, Alice 5700, South Africa</addr-line>
+        </aff>
+      </rev-group>
+
+    <files>
+      <file>
+        <item_type>manuscripts</item_type>
+        <item_description>23 2018.docx</item_description>
+        <item_name>23 2018.docx</item_name>
+      </file>
+    </files>
+    <questions>
+      <question type="COI">
+        <answer>No</answer>
+        <statement></statement>
+      </question>
+      <question type="DA">
+        <answer>No</answer>
+        <statement>The authors for this paper did not provide a data availability statement</statement>
+      </question>
+      <question type="Fund">
+        <answer>Yes</answer>
+        <statement></statement>
+      </question>
+    </questions>
+  </front>
+</article>
\ No newline at end of file
diff --git a/packages/component-mts-package/tests/sampleWithReviewers.json b/packages/component-mts-package/tests/sampleWithReviewers.json
new file mode 100644
index 0000000000000000000000000000000000000000..6611a93047c9279dcf2079ab4661133e35457d87
--- /dev/null
+++ b/packages/component-mts-package/tests/sampleWithReviewers.json
@@ -0,0 +1,337 @@
+{
+  "_declaration": {
+    "_attributes": {
+      "version": "1.0",
+      "encoding": "utf-8"
+    }
+  },
+  "_doctype": "article SYSTEM \"JATS-archivearticle1-mathml3.dtd\"",
+  "article": {
+    "_attributes": {
+      "dtd-version": "1.1d1",
+      "article-type": "Research Article"
+    },
+    "front": {
+      "journal-meta": {
+        "journal-id": [
+          {
+            "_attributes": {
+              "journal-id-type": "publisher"
+            },
+            "_text": "BCA"
+          },
+          {
+            "_attributes": {
+              "journal-id-type": "email"
+            },
+            "_text": "bca.support@hindawi.com"
+          }
+        ],
+        "journal-title-group": {
+          "journal-title": {
+            "_text": "Bioinorganic Chemistry and Applications"
+          }
+        },
+        "issn": [
+          {
+            "_attributes": {
+              "pub-type": "ppub"
+            },
+            "_text": "2474-7394"
+          },
+          {
+            "_attributes": {
+              "pub-type": "epub"
+            }
+          }
+        ]
+      },
+      "article-meta": {
+        "article-id": [
+          {
+            "_attributes": {
+              "pub-id-type": "publisher-id"
+            },
+            "_text": "BCA-5402665"
+          },
+          {
+            "_attributes": {
+              "pub-id-type": "manuscript"
+            },
+            "_text": "BCA-5402665"
+          }
+        ],
+        "article-categories": {
+          "subj-group": {
+            "_attributes": {
+              "subj-group-type": "Article Type"
+            },
+            "subject": {
+              "_text": "Review Article"
+            }
+          }
+        },
+        "title-group": {
+          "article-title": {
+            "_text": "Advances in iron compounds as biological agents"
+          }
+        },
+        "contrib-group": {
+          "contrib": {
+            "_attributes": {
+              "contrib-type": "author",
+              "corresp": "Yes"
+            },
+            "role": {
+              "_attributes": {
+                "content-type": "1"
+              }
+            },
+            "name": {
+              "surname": {
+                "_text": "Ayodele"
+              },
+              "given-names": {
+                "_text": "Odularu"
+              },
+              "prefix": {
+                "_text": "dr"
+              }
+            },
+            "email": {
+              "_text": "201106223@ufh.ac.za"
+            },
+            "xref": {
+              "_attributes": {
+                "ref-type": "aff",
+                "rid": "aff1"
+              }
+            }
+          },
+          "aff": {
+            "_attributes": {
+              "id": "aff1"
+            },
+            "country": {
+              "_text": "ZA"
+            },
+            "addr-line": {
+              "_text": "University of Fort Hare, Alice 5700, South Africa"
+            }
+          }
+        },
+        "history": {
+          "date": {
+            "_attributes": {
+              "date-type": "received"
+            },
+            "day": {
+              "_text": "24"
+            },
+            "month": {
+              "_text": "10"
+            },
+            "year": {
+              "_text": "2018"
+            }
+          }
+        },
+        "abstract": {
+          "_text": "Abstract\nThis mini review gives a report of the progresses in the use of iron compounds as biological agents. Review entails coordination of ligands in form of pharmaceutical drugs, reagents used directly as supplied, synthesized organic compounds and natural products from plants to iron(II) or iron(III) ions to yield compounds which were applied as antibacterial, iron natural product, antioxidant and anticancer agents. In addition, in the aspect of material chemistry, holistic application of iron nanoparticles was assessed in relation to health. Iron nanoparticles are best approaches to apply as biological agents when compared to bulk materials because of its affordable, biocompatibity, biodegradability, simple approach to synthesis, ease of modification and non-toxic nature.\n\nKeywords: history of iron; chemistry of iron, uses of iron compounds, iron nanoparticles; biological screening techniques\n"
+        },
+        "funding-group": {}
+      },
+      "rev-group": {
+        "rev": [
+          {
+            "_attributes": {
+              "rev-type": "reviewer"
+            },
+            "name": {
+              "surname": {
+                "_text": "Mohammed"
+              },
+              "given-names": {
+                "_text": "Rizk"
+              },
+              "prefix": {
+                "_text": "dr"
+              }
+            },
+            "email": {
+              "_text": "mohammed.rizk@hindawi.com"
+            },
+            "xref": {
+              "_attributes": {
+                "ref-type": "aff",
+                "rid": "aff1"
+              }
+            },
+            "date": [
+              {
+                "_attributes": {
+                  "date-type": "assignment"
+                },
+                "day": {
+                  "_text": "24"
+                },
+                "month": {
+                  "_text": "10"
+                },
+                "year": {
+                  "_text": "2018"
+                }
+              },
+              {
+                "_attributes": {
+                  "date-type": "submission"
+                },
+                "day": {
+                  "_text": "24"
+                },
+                "month": {
+                  "_text": "10"
+                },
+                "year": {
+                  "_text": "2018"
+                }
+              }
+            ],
+            "comment": {
+              "_attributes": {
+                "comment-type": ""
+              },
+              "_text": "\n                This article is really great! well written and does not need any update. Please publish it as such\n        "
+            }
+          },
+          {
+            "_attributes": {
+              "rev-type": "editor"
+            },
+            "name": {
+              "surname": {
+                "_text": "Matt"
+              },
+              "given-names": {
+                "_text": "Green"
+              },
+              "prefix": {
+                "_text": "dr"
+              }
+            },
+            "email": {
+              "_text": "matt.green@hindawi.com"
+            },
+            "xref": {
+              "_attributes": {
+                "ref-type": "aff",
+                "rid": "aff1"
+              }
+            },
+            "date": [
+              {
+                "_attributes": {
+                  "date-type": "assignment"
+                },
+                "day": {
+                  "_text": "24"
+                },
+                "month": {
+                  "_text": "10"
+                },
+                "year": {
+                  "_text": "2018"
+                }
+              },
+              {
+                "_attributes": {
+                  "date-type": "submission"
+                },
+                "day": {
+                  "_text": "24"
+                },
+                "month": {
+                  "_text": "10"
+                },
+                "year": {
+                  "_text": "2018"
+                }
+              }
+            ],
+            "comment": [
+              {
+                "_attributes": {
+                  "comment-type": "comment"
+                },
+                "_text": "\n                  Public comment for the author.\n          "
+              },
+              {
+                "_attributes": {
+                  "comment-type": "Confidential"
+                },
+                "_text": "\n                  Internal staff comment.\n          "
+              }
+            ]
+          }
+        ],
+        "aff": {
+          "_attributes": {
+            "id": "aff1"
+          },
+          "country": {
+            "_text": "ZA"
+          },
+          "addr-line": {
+            "_text": "University of Fort Hare, Alice 5700, South Africa"
+          }
+        }
+      },
+      "files": {
+        "file": {
+          "item_type": {
+            "_text": "manuscripts"
+          },
+          "item_description": {
+            "_text": "23 2018.docx"
+          },
+          "item_name": {
+            "_text": "23 2018.docx"
+          }
+        }
+      },
+      "questions": {
+        "question": [
+          {
+            "_attributes": {
+              "type": "COI"
+            },
+            "answer": {
+              "_text": "No"
+            },
+            "statement": {}
+          },
+          {
+            "_attributes": {
+              "type": "DA"
+            },
+            "answer": {
+              "_text": "No"
+            },
+            "statement": {
+              "_text": "The asuthors for this paper did not provide a data availability statement"
+            }
+          },
+          {
+            "_attributes": {
+              "type": "Fund"
+            },
+            "answer": {
+              "_text": "Yes"
+            },
+            "statement": {}
+          }
+        ]
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/packages/component-mts-package/tests/sampleWithReviewers.xml b/packages/component-mts-package/tests/sampleWithReviewers.xml
new file mode 100644
index 0000000000000000000000000000000000000000..2f20d2d52f213c7c667012c07f4f26584d006f12
--- /dev/null
+++ b/packages/component-mts-package/tests/sampleWithReviewers.xml
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE article SYSTEM "JATS-archivearticle1-mathml3.dtd">
+<article dtd-version="1.1d1" article-type="Research Article">
+  <front>
+    <journal-meta>
+      <journal-id journal-id-type="publisher">BCA</journal-id>
+      <journal-id journal-id-type="email">bca.support@hindawi.com</journal-id>
+      <journal-title-group>
+        <journal-title>Bioinorganic Chemistry and Applications</journal-title>
+      </journal-title-group>
+      <issn pub-type="ppub">2474-7394</issn>
+      <issn pub-type="epub"></issn>
+    </journal-meta>
+    <article-meta>
+      <article-id pub-id-type="publisher-id">BCA-5402665</article-id>
+      <article-id pub-id-type="manuscript">BCA-5402665</article-id>
+      <article-categories>
+        <subj-group subj-group-type="Article Type">
+          <subject>Review Article</subject>
+        </subj-group>
+      </article-categories>
+      <title-group>
+        <article-title>Advances in iron compounds as biological agents</article-title>
+      </title-group>
+      <contrib-group>
+        <contrib contrib-type="author" corresp="Yes">
+          <role content-type="1"></role>
+          <name>
+            <surname>Ayodele</surname>
+            <given-names>Odularu</given-names>
+            <prefix>dr</prefix>
+          </name>
+          <email>201106223@ufh.ac.za</email>
+          <xref ref-type="aff" rid="aff1"></xref>
+        </contrib>
+        <aff id="aff1">
+          <country>ZA</country>
+          <addr-line>University of Fort Hare, Alice 5700, South Africa</addr-line>
+        </aff>
+      </contrib-group>
+      <history>
+        <date date-type="received">
+          <day>24</day>
+          <month>10</month>
+          <year>2018</year>
+        </date>
+      </history>
+      <abstract>
+        Abstract This mini review gives a report of the progresses in the use of iron compounds as biological agents. Review entails coordination of ligands in form of pharmaceutical drugs, reagents used directly as supplied, synthesized organic compounds and natural products from plants to iron(II) or iron(III) ions to yield compounds which were applied as antibacterial, iron natural product, antioxidant and anticancer agents. In addition, in the aspect of material chemistry, holistic application of iron nanoparticles was assessed in relation to health. Iron nanoparticles are best approaches to apply as biological agents when compared to bulk materials because of its affordable, biocompatibity, biodegradability, simple approach to synthesis, ease of modification and non-toxic nature. Keywords: history of iron; chemistry of iron, uses of iron compounds, iron nanoparticles; biological screening techniques
+      </abstract>
+      <funding-group></funding-group>
+    </article-meta>
+    <rev-group>
+        <rev rev-type="reviewer">
+
+          <name>
+            <surname>Mohammed</surname>
+            <given-names>Rizk</given-names>
+            <prefix>dr</prefix>
+          </name>
+          <email>mohammed.rizk@hindawi.com</email>
+          <xref ref-type="aff" rid="aff1"></xref>
+        <date date-type="assignment">
+          <day>24</day>
+          <month>10</month>
+          <year>2018</year>
+        </date>
+        <date date-type="submission">
+          <day>24</day>
+          <month>10</month>
+          <year>2018</year>
+        </date>
+        <comment comment-type="">
+                This article is really great! well written and does not need any update. Please publish it as such
+        </comment>
+        </rev>
+        <rev rev-type="editor">
+          <name>
+            <surname>Matt</surname>
+            <given-names>Green</given-names>
+            <prefix>dr</prefix>
+          </name>
+          <email>matt.green@hindawi.com</email>
+          <xref ref-type="aff" rid="aff1"></xref>
+          <date date-type="assignment">
+            <day>24</day>
+            <month>10</month>
+            <year>2018</year>
+          </date>
+          <date date-type="submission">
+            <day>24</day>
+            <month>10</month>
+            <year>2018</year>
+          </date>
+          <comment comment-type="comment">
+                  Public comment for the author.
+          </comment>
+          <comment comment-type="Confidential">
+                  Internal staff comment.
+          </comment>
+        </rev>
+        <aff id="aff1">
+          <country>ZA</country>
+          <addr-line>University of Fort Hare, Alice 5700, South Africa</addr-line>
+        </aff>
+      </rev-group>
+
+    <files>
+      <file>
+        <item_type>manuscripts</item_type>
+        <item_description>23 2018.docx</item_description>
+        <item_name>23 2018.docx</item_name>
+      </file>
+    </files>
+    <questions>
+      <question type="COI">
+        <answer>No</answer>
+        <statement></statement>
+      </question>
+      <question type="DA">
+        <answer>No</answer>
+        <statement>The authors for this paper did not provide a data availability statement</statement>
+      </question>
+      <question type="Fund">
+        <answer>Yes</answer>
+        <statement></statement>
+      </question>
+    </questions>
+  </front>
+</article>
\ No newline at end of file
diff --git a/packages/component-user-manager/src/routes/users/emails/notifications.js b/packages/component-user-manager/src/routes/users/emails/notifications.js
index b292e701971c0aa5098ad116a44a88cb8bcda44c..6c292ae2dcff7761c3146c157ec374923249bc74 100644
--- a/packages/component-user-manager/src/routes/users/emails/notifications.js
+++ b/packages/component-user-manager/src/routes/users/emails/notifications.js
@@ -10,39 +10,33 @@ const { name: journalName, staffEmail } = config.get('journal')
 const unsubscribeSlug = config.get('unsubscribe.url')
 
 module.exports = {
-  async sendNotifications({ user, baseUrl }) {
+  async sendForgotPasswordEmail({ user, baseUrl }) {
+    const { paragraph, ...bodyProps } = getEmailCopy({
+      emailType: 'user-forgot-password',
+    })
+
     const email = new Email({
       type: 'system',
+      toUser: {
+        email: user.email,
+      },
       fromEmail: `${journalName} <${staffEmail}>`,
       content: {
+        subject: 'Forgot Password',
         ctaLink: services.createUrl(baseUrl, forgotPath, {
           email: user.email,
           token: user.accessTokens.passwordReset,
         }),
         ctaText: 'RESET PASSWORD',
+        paragraph,
+        unsubscribeLink: services.createUrl(baseUrl, unsubscribeSlug, {
+          id: user.id,
+          token: user.accessTokens.unsubscribe,
+        }),
       },
+      bodyProps,
     })
 
-    sendForgotPasswordEmail({ email, baseUrl, user })
+    return email.sendEmail()
   },
 }
-
-const sendForgotPasswordEmail = ({ email, baseUrl, user }) => {
-  email.toUser = {
-    email: user.email,
-  }
-
-  email.content.subject = 'Forgot Password'
-  email.content.unsubscribeLink = services.createUrl(baseUrl, unsubscribeSlug, {
-    id: user.id,
-    token: user.accessTokens.unsubscribe,
-  })
-
-  const { html, text } = email.getNotificationBody({
-    emailBodyProps: getEmailCopy({
-      emailType: 'user-forgot-password',
-    }),
-  })
-
-  email.sendEmail({ html, text })
-}
diff --git a/packages/component-user-manager/src/routes/users/forgotPassword.js b/packages/component-user-manager/src/routes/users/forgotPassword.js
index 55b750e69bfaa886aaae329843c1967e8be6c634..23b80f6e2d723cf955a653f66d4f735a3c432318 100644
--- a/packages/component-user-manager/src/routes/users/forgotPassword.js
+++ b/packages/component-user-manager/src/routes/users/forgotPassword.js
@@ -36,7 +36,7 @@ module.exports = models => async (req, res) => {
     user.passwordResetTimestamp = Date.now()
     await user.save()
 
-    notifications.sendNotifications({
+    notifications.sendForgotPasswordEmail({
       user,
       baseUrl: services.getBaseUrl(req),
     })
diff --git a/packages/xpub-faraday/config/authsome-helpers.js b/packages/xpub-faraday/config/authsome-helpers.js
index 08e583c721fa6103de2f4729e0f2e64a348567a7..af24148066d5dc53764e440da68fb2c965436f2d 100644
--- a/packages/xpub-faraday/config/authsome-helpers.js
+++ b/packages/xpub-faraday/config/authsome-helpers.js
@@ -72,6 +72,34 @@ const filterAuthorRecommendations = (recommendations, status, isLast) => {
   return []
 }
 
+const filterRecommendationsFromLastVersion = (recommendations, user) =>
+  recommendations
+    .filter(
+      r =>
+        r.userId === user.id || r.recommendationType === 'editorRecommendation',
+    )
+    .map(r => ({
+      ...r,
+      comments: r.comments.filter(c => c.public === true),
+    }))
+
+const filterRecommendationsFromOlderVersions = (recommendations, user) => {
+  const ownRecommendation = recommendations.find(r => r.userId === user.id)
+  if (ownRecommendation) {
+    return recommendations
+      .filter(
+        r => r.submittedOn || r.recommendationType === 'editorRecommendation',
+      )
+      .map(
+        r =>
+          r.userId !== ownRecommendation.userId
+            ? { ...r, comments: r.comments.filter(c => c.public === true) }
+            : { ...r },
+      )
+  }
+  return []
+}
+
 const stripeCollectionByRole = ({ collection = {}, role = '' }) => {
   if (role === 'author') {
     const { handlingEditor } = collection
@@ -96,7 +124,8 @@ const stripeFragmentByRole = ({
   user = {},
   isLast = false,
 }) => {
-  const { recommendations, files, authors } = fragment
+  const { files, authors, recommendations = [] } = fragment
+  let recommendationsFromFragment = []
   switch (role) {
     case 'author':
       return {
@@ -106,22 +135,22 @@ const stripeFragmentByRole = ({
           : [],
       }
     case 'reviewer':
+      if (isLast) {
+        recommendationsFromFragment = filterRecommendationsFromLastVersion(
+          recommendations,
+          user,
+        )
+      } else {
+        recommendationsFromFragment = filterRecommendationsFromOlderVersions(
+          recommendations,
+          user,
+        )
+      }
       return {
         ...fragment,
         files: omit(files, ['coverLetter']),
         authors: authors.map(a => omit(a, ['email'])),
-        recommendations: recommendations
-          ? recommendations
-              .filter(
-                r =>
-                  r.userId === user.id ||
-                  r.recommendationType === 'editorRecommendation',
-              )
-              .map(r => ({
-                ...r,
-                comments: r.comments.filter(c => c.public === true),
-              }))
-          : [],
+        recommendations: recommendationsFromFragment,
       }
     case 'handlingEditor':
       return {
@@ -175,10 +204,13 @@ const getCollections = async ({ user, models }) => {
         } else {
           fragment = await models.Fragment.find(userPermission.objectId)
           collection = await models.Collection.find(fragment.collectionId)
+          const latestFragmentId =
+            collection.fragments[collection.fragments.length - 1]
           collection.currentVersion = stripeFragmentByRole({
             fragment,
             role: userPermission.role,
             user,
+            isLast: latestFragmentId === fragment.id,
           })
         }
       } catch (e) {
diff --git a/packages/xpub-faraday/tests/config/authsome-helpers.test.js b/packages/xpub-faraday/tests/config/authsome-helpers.test.js
index c5634168fdf6ab29134874c7c3fa9ee96183b2d0..de16758af67242c6ab707a10a6f0f31f2cb24876 100644
--- a/packages/xpub-faraday/tests/config/authsome-helpers.test.js
+++ b/packages/xpub-faraday/tests/config/authsome-helpers.test.js
@@ -116,7 +116,7 @@ describe('Authsome Helpers', () => {
       const { files = {} } = result
       expect(files.coverLetter).toBeFalsy()
     })
-    it('reviewer should not see private comments', () => {
+    it('reviewer should not see private comments on the last version of the manuscript', () => {
       const { fragment } = testFixtures.fragments
       fragment.recommendations = [
         {
@@ -132,13 +132,59 @@ describe('Authsome Helpers', () => {
           ],
         },
       ]
-      const result = ah.stripeFragmentByRole({ fragment, role: 'reviewer' })
+      const result = ah.stripeFragmentByRole({
+        fragment,
+        role: 'reviewer',
+        isLast: true,
+      })
       const { recommendations } = result
       expect(recommendations).toHaveLength(1)
       expect(recommendations[0].comments).toHaveLength(1)
       expect(recommendations[0].comments[0].public).toEqual(true)
     })
 
+    it('reviewer should see other reviewers recommendations on previous version if he submitted a review on that fragment', () => {
+      const { fragment } = testFixtures.fragments
+      const { answerReviewer } = testFixtures.users
+
+      const result = ah.stripeFragmentByRole({
+        fragment,
+        role: 'reviewer',
+        isLast: false,
+        user: answerReviewer,
+      })
+      const { recommendations } = result
+      expect(recommendations).toHaveLength(7)
+    })
+
+    it('reviewer should not see other reviewers recommendations on latest fragment', () => {
+      const { fragment } = testFixtures.fragments
+      const { answerReviewer } = testFixtures.users
+
+      const result = ah.stripeFragmentByRole({
+        fragment,
+        role: 'reviewer',
+        isLast: true,
+        user: answerReviewer,
+      })
+      const { recommendations } = result
+      expect(recommendations).toHaveLength(6)
+    })
+
+    it('reviewer should not see any reviewer recommendation on previous version if he did not submit a review on that fragment', () => {
+      const { fragment } = testFixtures.fragments
+      const { inactiveReviewer } = testFixtures.users
+
+      const result = ah.stripeFragmentByRole({
+        fragment,
+        role: 'reviewer',
+        isLast: false,
+        user: inactiveReviewer,
+      })
+      const { recommendations } = result
+      expect(recommendations).toHaveLength(0)
+    })
+
     it('author should not see recommendations if a decision has not been made', () => {
       const { fragment } = testFixtures.fragments
       fragment.recommendations = [
diff --git a/yarn.lock b/yarn.lock
index 1d0eed9742960517871deea463a9af4503a259f7..29f74163c850976f0e7fed488eb28e5b6feda5d5 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -6384,11 +6384,14 @@ https-browserify@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73"
   integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=
+<<<<<<< HEAD
 
 humps@^2.0.1:
   version "2.0.1"
   resolved "https://registry.yarnpkg.com/humps/-/humps-2.0.1.tgz#dd02ea6081bd0568dc5d073184463957ba9ef9aa"
   integrity sha1-3QLqYIG9BWjcXQcxhEY5V7qe+ao=
+=======
+>>>>>>> 7f82b580c1bba9cab8d4a7882d6667398002b88d
 
 husky@^0.14.3:
   version "0.14.3"