Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,6 @@ public function getDecisionMappings(): array
'updated_value' => 2,
],

// \PKP\decision\Decision::EXTERNAL_REVIEW
[
'stage_id' => [WORKFLOW_STAGE_ID_SUBMISSION],
'current_value' => 8,
'updated_value' => 3,
],

// \PKP\decision\Decision::SKIP_EXTERNAL_REVIEW
[
'stage_id' => [WORKFLOW_STAGE_ID_SUBMISSION],
Expand Down Expand Up @@ -127,6 +120,62 @@ public function up(): void
])
);

// \PKP\decision\Decision::EXTERNAL_REVIEW (8→3) — special handling
//
// After the buggy I7725 ran, both stranded EXTERNAL_REVIEW rows and
// correctly-migrated INITIAL_DECLINE rows share decision=8, stage_id=1.
// They are indistinguishable from edit_decisions alone.
//
// Two-layer disambiguation:
// 1. whereExists(review_rounds at EXTERNAL_REVIEW stage) — the submission
// must have actually reached external review
// 2. whereNotExists(later decision=8 at same submission/stage) — only
// the MOST RECENT decision=8 per submission is the EXTERNAL_REVIEW;
// all earlier ones were INITIAL_DECLINE
//
// Why "most recent" instead of checking for REVERT_INITIAL_DECLINE:
// OJS 3.3 had a loose workflow that allowed editors to decline a submission
// and then send it to review WITHOUT recording a REVERT_INITIAL_DECLINE.
// The "most recent" check handles ALL cases: with revert, without revert,
// and multiple decline cycles.

// Collect the IDs of the MOST RECENT decision=8 per submission
// (the EXTERNAL_REVIEW row). Done as a separate SELECT because MySQL
// does not allow referencing the target table in an UPDATE subquery.
$externalReviewIds = DB::table('edit_decisions')
->where('edit_decisions.stage_id', WORKFLOW_STAGE_ID_SUBMISSION)
->where('edit_decisions.decision', 8)
->whereNull('edit_decisions.updated_at')
->where('edit_decisions.date_decided', '<', $firstVersionOf34->date_installed)
->whereExists(function ($query) {
$query->select(DB::raw(1))
->from('review_rounds')
->whereColumn('review_rounds.submission_id', 'edit_decisions.submission_id')
->where('review_rounds.stage_id', WORKFLOW_STAGE_ID_EXTERNAL_REVIEW);
})
->whereNotExists(function ($query) use ($firstVersionOf34) {
// If a LATER decision=8 at stage_id=1 exists for the same submission,
// then this row was an earlier INITIAL_DECLINE — not the final
// EXTERNAL_REVIEW that triggered the review
$query->select(DB::raw(1))
->from('edit_decisions as later_ed')
->whereColumn('later_ed.submission_id', 'edit_decisions.submission_id')
->where('later_ed.decision', 8)
->where('later_ed.stage_id', WORKFLOW_STAGE_ID_SUBMISSION)
->whereColumn('later_ed.date_decided', '>', 'edit_decisions.date_decided')
->where('later_ed.date_decided', '<', $firstVersionOf34->date_installed);
})
->pluck('edit_decision_id');

if ($externalReviewIds->isNotEmpty()) {
DB::table('edit_decisions')
->whereIn('edit_decision_id', $externalReviewIds)
->update([
'decision' => 3,
'updated_at' => Carbon::now(),
]);
}

$this->removeUpdatedAtColumn();
}

Expand Down
Loading