JFIFICC_PROFILElcmsmntrRGB XYZ  acspMSFTsawsctrl-hand=@=@t," desc_cprt wtptrXYZ,gXYZ@bXYZTrTRCh`gTRCh`bTRCh`descuRGBtextCC0XYZ TXYZ o8XYZ bXYZ $curv*|uN  bj. C$)j.~39?FWM6Tv\dluV~,6۾ewC    #%$""!&+7/&)4)!"0A149;>>>%.DIC;C  ;("(;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?|WH?cS?Ne.r˿ޱ5\YYhFOejT7PZ[qs2c/$Ep[Gqo(Nù=QHci;OipX=Ģ8d^mQeӴm1OsL/x2];i6p!zU -/uX!=<-}JFIFICC_PROFILElcmsmntrRGB XYZ  acspMSFTsawsctrl-hand=@=@t," desc_cprt wtptrXYZ,gXYZ@bXYZTrTRCh`gTRCh`bTRCh`descuRGBtextCC0XYZ TXYZ o8XYZ bXYZ $curv*|uN  bj. C$)j.~39?FWM6Tv\dluV~,6۾ewC    #%$""!&+7/&)4)!"0A149;>>>%.DIC;C  ;("(;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?|WH?cS?Ne.r˿ޱ5\YYhFOejT7PZ[qs2c/$Ep[Gqo(Nù=QHci;OipX=Ģ8d^mQeӴm1OsL/x2];i6p!zU -/uX!=<-}JFIFICC_PROFILElcmsmntrRGB XYZ  acspMSFTsawsctrl-hand=@=@t," desc_cprt wtptrXYZ,gXYZ@bXYZTrTRCh`gTRCh`bTRCh`descuRGBtextCC0XYZ TXYZ o8XYZ bXYZ $curv*|uN  bj. C$)j.~39?FWM6Tv\dluV~,6۾ewC    #%$""!&+7/&)4)!"0A149;>>>%.DIC;C  ;("(;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?|WH?cS?Ne.r˿ޱ5\YYhFOejT7PZ[qs2c/$Ep[Gqo(Nù=QHci;OipX=Ģ8d^mQeӴm1OsL/x2];i6p!zU -/uX!=<-}JFIFICC_PROFILElcmsmntrRGB XYZ  acspMSFTsawsctrl-hand=@=@t," desc_cprt wtptrXYZ,gXYZ@bXYZTrTRCh`gTRCh`bTRCh`descuRGBtextCC0XYZ TXYZ o8XYZ bXYZ $curv*|uN  bj. C$)j.~39?FWM6Tv\dluV~,6۾ewC    #%$""!&+7/&)4)!"0A149;>>>%.DIC;C  ;("(;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?|WH?cS?Ne.r˿ޱ5\YYhFOejT7PZ[qs2c/$Ep[Gqo(Nù=QHci;OipX=Ģ8d^mQeӴm1OsL/x2];i6p!zU -/uX!=<-}JFIFICC_PROFILElcmsmntrRGB XYZ  acspMSFTsawsctrl-hand=@=@t," desc_cprt wtptrXYZ,gXYZ@bXYZTrTRCh`gTRCh`bTRCh`descuRGBtextCC0XYZ TXYZ o8XYZ bXYZ $curv*|uN  bj. C$)j.~39?FWM6Tv\dluV~,6۾ewC    #%$""!&+7/&)4)!"0A149;>>>%.DIC;C  ;("(;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?|WH?cS?Ne.r˿ޱ5\YYhFOejT7PZ[qs2c/$Ep[Gqo(Nù=QHci;OipX=Ģ8d^mQeӴm1OsL/x2];i6p!zU -/uX!=<-}JFIFICC_PROFILElcmsmntrRGB XYZ  acspMSFTsawsctrl-hand=@=@t," desc_cprt wtptrXYZ,gXYZ@bXYZTrTRCh`gTRCh`bTRCh`descuRGBtextCC0XYZ TXYZ o8XYZ bXYZ $curv*|uN  bj. C$)j.~39?FWM6Tv\dluV~,6۾ewC    #%$""!&+7/&)4)!"0A149;>>>%.DIC;C  ;("(;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?|WH?cS?Ne.r˿ޱ5\YYhFOejT7PZ[qs2c/$Ep[Gqo(Nù=QHci;OipX=Ģ8d^mQeӴm1OsL/x2];i6p!zU -/uX!=<-}JFIFICC_PROFILElcmsmntrRGB XYZ  acspMSFTsawsctrl-hand=@=@t," desc_cprt wtptrXYZ,gXYZ@bXYZTrTRCh`gTRCh`bTRCh`descuRGBtextCC0XYZ TXYZ o8XYZ bXYZ $curv*|uN  bj. C$)j.~39?FWM6Tv\dluV~,6۾ewC    #%$""!&+7/&)4)!"0A149;>>>%.DIC;C  ;("(;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?|WH?cS?Ne.r˿ޱ5\YYhFOejT7PZ[qs2c/$Ep[Gqo(Nù=QHci;OipX=Ģ8d^mQeӴm1OsL/x2];i6p!zU -/uX!=<-}JFIFICC_PROFILElcmsmntrRGB XYZ  acspMSFTsawsctrl-hand=@=@t," desc_cprt wtptrXYZ,gXYZ@bXYZTrTRCh`gTRCh`bTRCh`descuRGBtextCC0XYZ TXYZ o8XYZ bXYZ $curv*|uN  bj. C$)j.~39?FWM6Tv\dluV~,6۾ewC    #%$""!&+7/&)4)!"0A149;>>>%.DIC;C  ;("(;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?|WH?cS?Ne.r˿ޱ5\YYhFOejT7PZ[qs2c/$Ep[Gqo(Nù=QHci;OipX=Ģ8d^mQeӴm1OsL/x2];i6p!zU -/uX!=<-}JFIFICC_PROFILElcmsmntrRGB XYZ  acspMSFTsawsctrl-hand=@=@t," desc_cprt wtptrXYZ,gXYZ@bXYZTrTRCh`gTRCh`bTRCh`descuRGBtextCC0XYZ TXYZ o8XYZ bXYZ $curv*|uN  bj. C$)j.~39?FWM6Tv\dluV~,6۾ewC    #%$""!&+7/&)4)!"0A149;>>>%.DIC;C  ;("(;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?|WH?cS?Ne.r˿ޱ5\YYhFOejT7PZ[qs2c/$Ep[Gqo(Nù=QHci;OipX=Ģ8d^mQeӴm1OsL/x2];i6p!zU -/uX!=<-}JFIFICC_PROFILElcmsmntrRGB XYZ  acspMSFTsawsctrl-hand=@=@t," desc_cprt wtptrXYZ,gXYZ@bXYZTrTRCh`gTRCh`bTRCh`descuRGBtextCC0XYZ TXYZ o8XYZ bXYZ $curv*|uN  bj. C$)j.~39?FWM6Tv\dluV~,6۾ewC    #%$""!&+7/&)4)!"0A149;>>>%.DIC;C  ;("(;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?|WH?cS?Ne.r˿ޱ5\YYhFOejT7PZ[qs2c/$Ep[Gqo(Nù=QHci;OipX=Ģ8d^mQeӴm1OsL/x2];i6p!zU -/uX!=<-}JFIFICC_PROFILElcmsmntrRGB XYZ  acspMSFTsawsctrl-hand=@=@t," desc_cprt wtptrXYZ,gXYZ@bXYZTrTRCh`gTRCh`bTRCh`descuRGBtextCC0XYZ TXYZ o8XYZ bXYZ $curv*|uN  bj. C$)j.~39?FWM6Tv\dluV~,6۾ewC    #%$""!&+7/&)4)!"0A149;>>>%.DIC;C  ;("(;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?|WH?cS?Ne.r˿ޱ5\YYhFOejT7PZ[qs2c/$Ep[Gqo(Nù=QHci;OipX=Ģ8d^mQeӴm1OsL/x2];i6p!zU -/uX!=<-}JFIFICC_PROFILElcmsmntrRGB XYZ  acspMSFTsawsctrl-hand=@=@t," desc_cprt wtptrXYZ,gXYZ@bXYZTrTRCh`gTRCh`bTRCh`descuRGBtextCC0XYZ TXYZ o8XYZ bXYZ $curv*|uN  bj. C$)j.~39?FWM6Tv\dluV~,6۾ewC    #%$""!&+7/&)4)!"0A149;>>>%.DIC;C  ;("(;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?|WH?cS?Ne.r˿ޱ5\YYhFOejT7PZ[qs2c/$Ep[Gqo(Nù=QHci;OipX=Ģ8d^mQeӴm1OsL/x2];i6p!zU -/uX!=<-}JFIFICC_PROFILElcmsmntrRGB XYZ  acspMSFTsawsctrl-hand=@=@t," desc_cprt wtptrXYZ,gXYZ@bXYZTrTRCh`gTRCh`bTRCh`descuRGBtextCC0XYZ TXYZ o8XYZ bXYZ $curv*|uN  bj. C$)j.~39?FWM6Tv\dluV~,6۾ewC    #%$""!&+7/&)4)!"0A149;>>>%.DIC;C  ;("(;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?|WH?cS?Ne.r˿ޱ5\YYhFOejT7PZ[qs2c/$Ep[Gqo(Nù=QHci;OipX=Ģ8d^mQeӴm1OsL/x2];i6p!zU -/uX!=<-}JFIFICC_PROFILElcmsmntrRGB XYZ  acspMSFTsawsctrl-hand=@=@t," desc_cprt wtptrXYZ,gXYZ@bXYZTrTRCh`gTRCh`bTRCh`descuRGBtextCC0XYZ TXYZ o8XYZ bXYZ $curv*|uN  bj. C$)j.~39?FWM6Tv\dluV~,6۾ewC    #%$""!&+7/&)4)!"0A149;>>>%.DIC;C  ;("(;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?|WH?cS?Ne.r˿ޱ5\YYhFOejT7PZ[qs2c/$Ep[Gqo(Nù=QHci;OipX=Ģ8d^mQeӴm1OsL/x2];i6p!zU -/uX!=<-} .
LIBYA CYBER ARMY
Logo of a company Instagram@3g86    Server : Apache
System : Linux uta-edu.server.ly 4.18.0-513.11.1.el8_9.x86_64 #1 SMP Wed Jan 17 02:00:40 EST 2024 x86_64
User : utripoli ( 1001)
PHP Version : 7.4.33
Disable Function : NONE
Directory :  /home/utripoli/public_html/journalDEL/lib/pkp/classes/services/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : /home/utripoli/public_html/journalDEL/lib/pkp/classes/services/PKPStatsEditorialService.php
<?php

/**
 * @file classes/services/PKPStatsEditorialService.php
 *
 * Copyright (c) 2014-2021 Simon Fraser University
 * Copyright (c) 2000-2021 John Willinsky
 * Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
 *
 * @class PKPStatsEditorialService
 *
 * @ingroup services
 *
 * @brief Helper class that encapsulates business logic for getting
 *   editorial stats
 */

namespace PKP\services;

use APP\decision\Decision;
use PKP\plugins\Hook;

class PKPStatsEditorialService
{
    /**
     * Get overview of key editorial stats
     *
     * @param array $args See self::getQueryBuilder()
     *
     * @return array
     */
    public function getOverview($args = [])
    {
        $received = $this->countSubmissionsReceived($args);
        $accepted = $this->countByDecisions(Decision::ACCEPT, $args);
        $submissionsPublished = $this->countSubmissionsPublished($args);
        $submissionsInProgress = $this->countSubmissionsInProgress($args);
        $submissionsImported = $this->countSubmissionsImported($args);
        $submissionsSkipped = $submissionsInProgress + $submissionsImported;
        $declinedDesk = $this->countByDecisions(Decision::INITIAL_DECLINE, $args);
        $declinedReview = $this->countByDecisions(Decision::DECLINE, $args);
        $declined = $declinedDesk + $declinedReview;

        // Calculate the acceptance/decline rates
        if (!$received) {
            // Never divide by 0
            $acceptanceRate = 0;
            $declineRate = 0;
            $declinedDeskRate = 0;
            $declinedReviewRate = 0;
        } elseif (empty($args['dateStart']) && empty($args['dateEnd'])) {
            $acceptanceRate = $accepted / $received;
            $declineRate = $declined / $received;
            $declinedDeskRate = $declinedDesk / $received;
            $declinedReviewRate = $declinedReview / $received;
        } else {
            // To calculate the acceptance/decline rates within a date range
            // we must collect the total number of all submissions made within
            // that date range which have received a decision. The acceptance
            // rate is the number of submissions made within the date range
            // that were accepted divided by the number of submissions made
            // within the date range that were accepted or declined. This
            // excludes submissions that were made within the date range but
            // have not yet been accepted or declined.
            $acceptedForSubmissionDate = $this->countByDecisionsForSubmittedDate(Decision::ACCEPT, $args);
            $declinedDeskForSubmissionDate = $this->countByDecisionsForSubmittedDate(Decision::INITIAL_DECLINE, $args);
            $declinedReviewForSubmissionDate = $this->countByDecisionsForSubmittedDate(Decision::DECLINE, $args);
            $totalDecidedForSubmissionDate = $acceptedForSubmissionDate + $declinedDeskForSubmissionDate + $declinedReviewForSubmissionDate;

            // Never divide by 0
            if (!$totalDecidedForSubmissionDate) {
                $acceptanceRate = 0;
                $declineRate = 0;
                $declinedDeskRate = 0;
                $declinedReviewRate = 0;
            } else {
                $acceptanceRate = $acceptedForSubmissionDate / $totalDecidedForSubmissionDate;
                $declineRate = ($declinedDeskForSubmissionDate + $declinedReviewForSubmissionDate) / $totalDecidedForSubmissionDate;
                $declinedDeskRate = $declinedDeskForSubmissionDate / $totalDecidedForSubmissionDate;
                $declinedReviewRate = $declinedReviewForSubmissionDate / $totalDecidedForSubmissionDate;
            }
        }

        // Calculate the number of days it took for most submissions to
        // receive decisions
        $firstDecisionDays = $this->getDaysToDecisions([], $args);
        $acceptDecisionDays = $this->getDaysToDecisions($this->getAcceptedDecisions(), $args);
        $declineDecisionDays = $this->getDaysToDecisions($this->getDeclinedDecisions(), $args);
        $firstDecisionDaysRate = empty($firstDecisionDays) ? 0 : $this->calculateDaysToDecisionRate($firstDecisionDays, 0.8);
        $acceptDecisionDaysRate = empty($acceptDecisionDays) ? 0 : $this->calculateDaysToDecisionRate($acceptDecisionDays, 0.8);
        $declineDecisionDaysRate = empty($declineDecisionDays) ? 0 : $this->calculateDaysToDecisionRate($declineDecisionDays, 0.8);

        $overview = [
            [
                'key' => 'submissionsReceived',
                'name' => 'stats.name.submissionsReceived',
                'value' => $received,
            ],
            [
                'key' => 'submissionsAccepted',
                'name' => 'stats.name.submissionsAccepted',
                'value' => $accepted,
            ],
            [
                'key' => 'submissionsDeclined',
                'name' => 'stats.name.submissionsDeclined',
                'value' => $declined,
            ],
            [
                'key' => 'submissionsDeclinedDeskReject',
                'name' => 'stats.name.submissionsDeclinedDeskReject',
                'value' => $declinedDesk,
            ],
            [
                'key' => 'submissionsDeclinedPostReview',
                'name' => 'stats.name.submissionsDeclinedPostReview',
                'value' => $declinedReview,
            ],
            [
                'key' => 'submissionsPublished',
                'name' => 'stats.name.submissionsPublished',
                'value' => $submissionsPublished,
            ],
            [
                'key' => 'submissionsSkipped',
                'name' => 'stats.name.submissionsSkipped',
                'value' => $submissionsSkipped,
            ],
            [
                'key' => 'submissionsInProgress',
                'name' => 'stats.name.submissionsInProgress',
                'value' => $submissionsInProgress,
            ],
            [
                'key' => 'submissionsImported',
                'name' => 'stats.name.submissionsImported',
                'value' => $submissionsImported,
            ],
            [
                'key' => 'daysToDecision',
                'name' => 'stats.name.daysToDecision',
                'value' => $firstDecisionDaysRate,
            ],
            [
                'key' => 'daysToAccept',
                'name' => 'stats.name.daysToAccept',
                'value' => $acceptDecisionDaysRate,
            ],
            [
                'key' => 'daysToReject',
                'name' => 'stats.name.daysToReject',
                'value' => $declineDecisionDaysRate,
            ],
            [
                'key' => 'acceptanceRate',
                'name' => 'stats.name.acceptanceRate',
                'value' => round($acceptanceRate, 2),
            ],
            [
                'key' => 'declineRate',
                'name' => 'stats.name.declineRate',
                'value' => round($declineRate, 2),
            ],
            [
                'key' => 'declinedDeskRate',
                'name' => 'stats.name.declinedDeskRate',
                'value' => round($declinedDeskRate, 2),
            ],
            [
                'key' => 'declinedReviewRate',
                'name' => 'stats.name.declinedReviewRate',
                'value' => round($declinedReviewRate, 2),
            ],
        ];

        Hook::call('EditorialStats::overview', [&$overview, $args]);

        return $overview;
    }

    /**
     * Get the yearly averages of key editorial stats
     *
     * Averages are calculated over full years. If no dateStart and
     * dateEnd are passed, it will determine the first and last
     * full years during which the activity occurred. This means that
     * if the first submission was received in October 2017 and the
     * last submission was received in the current calendar year, only
     * submissions from 2018 up until the end of the previous calendar
     * year will be used to calculate the average.
     *
     * This method does not yet support getting averages for date ranges.
     *
     * @see https://github.com/pkp/pkp-lib/issues/4844#issuecomment-554011922
     *
     * @param array $args See self::getQueryBuilder(). No date range supported
     *
     * @return array
     */
    public function getAverages($args = [])
    {
        unset($args['dateStart']);
        unset($args['dateEnd']);

        // Submissions received
        $received = -1;
        $receivedDates = $this->getQueryBuilder($args)->getSubmissionsReceivedDates();
        if (empty($receivedDates[0])) {
            $received = 0;
        } else {
            $yearStart = ((int) substr($receivedDates[0], 0, 4)) + 1;
            $yearEnd = (int) substr($receivedDates[1], 0, 4);
            if ($yearEnd >= date('Y')) {
                $yearEnd--;
            }
            $years = ($yearEnd - $yearStart) + 1;
            if ($years) {
                $argsReceived = array_merge(
                    $args,
                    [
                        'dateStart' => sprintf('%s-01-01', $yearStart),
                        'dateEnd' => sprintf('%s-12-31', $yearEnd),
                    ]
                );
                $received = round($this->countSubmissionsReceived($argsReceived) / $years);
            }
        }

        // Editorial decisions (accepted and declined)
        $decisionsList = [
            'submissionsAccepted' => [Decision::ACCEPT],
            'submissionsDeclined' => [Decision::INITIAL_DECLINE, Decision::DECLINE],
            'submissionsDeclinedDeskReject' => [Decision::INITIAL_DECLINE],
            'submissionsDeclinedPostReview' => [Decision::DECLINE],
        ];
        $yearlyDecisions = [];
        foreach ($decisionsList as $key => $decisions) {
            $yearly = -1;
            $dates = $this->getQueryBuilder($args)->getDecisionsDates($decisions);
            if (empty($dates[0])) {
                $yearly = 0;
            } else {
                $yearStart = ((int) substr($dates[0], 0, 4)) + 1;
                $yearEnd = (int) substr($dates[1], 0, 4);
                if ($yearEnd >= date('Y')) {
                    $yearEnd--;
                }
                $years = ($yearEnd - $yearStart) + 1;
                if ($years) {
                    $argsYearly = array_merge(
                        $args,
                        [
                            'dateStart' => sprintf('%s-01-01', $yearStart),
                            'dateEnd' => sprintf('%s-12-31', $yearEnd),
                        ]
                    );
                    $yearly = round($this->countByDecisions($decisions, $argsYearly) / $years);
                }
            }
            $yearlyDecisions[$key] = $yearly;
        }

        // Submissions published
        $published = -1;
        $publishedDates = $this->getQueryBuilder($args)->getPublishedDates();
        if (empty($publishedDates[0])) {
            $published = 0;
        } else {
            $yearStart = ((int) substr($publishedDates[0], 0, 4)) + 1;
            $yearEnd = (int) substr($publishedDates[1], 0, 4);
            if ($yearEnd >= date('Y')) {
                $yearEnd--;
            }
            $years = ($yearEnd - $yearStart) + 1;
            if ($years) {
                $argsPublished = array_merge(
                    $args,
                    [
                        'dateStart' => sprintf('%s-01-01', $yearStart),
                        'dateEnd' => sprintf('%s-12-31', $yearEnd),
                    ]
                );
                $published = round($this->countSubmissionsPublished($argsPublished) / $years);
            }
        }

        $averages = array_merge(
            ['submissionsReceived' => $received],
            $yearlyDecisions,
            ['submissionsPublished' => $published]
        );

        Hook::call('EditorialStats::averages', [&$averages, $args]);

        return $averages;
    }

    /**
     * Get a count of the number of submissions that have been received
     *
     * Any date restrictions will be applied to the submission date, so it
     * will only count submissions completed within the date range.
     *
     * @param array $args See self::getQueryBuilder()
     *
     * @return int
     */
    public function countSubmissionsReceived($args = [])
    {
        return $this->getQueryBuilder($args)->countSubmissionsReceived();
    }


    /**
     * Get a count of the number of submissions that have been published
     *
     * Any date restrictions will be applied to the initial publication date,
     * so it will only count submissions published within the date range.
     *
     * @param array $args See self::getQueryBuilder()
     *
     * @return int
     */
    public function countSubmissionsPublished($args = [])
    {
        return $this->getQueryBuilder($args)->countPublished();
    }

    /**
     * Get a count of the submissions receiving one or more editorial decisions
     *
     * Any date restrictions will be applied to the decision, so it will only
     * count decisions that occurred within the date range.
     *
     * @param int|array $decisions One or more Decision::*
     * @param array $args See self::getQueryBuilder()
     *
     * @return int
     */
    public function countByDecisions($decisions, $args = [])
    {
        return $this->getQueryBuilder($args)->countByDecisions((array) $decisions);
    }

    /**
     * Get a count of the submissions receiving one or more editorial decisions
     *
     * Any date restrictions will be applied to the submission date, so it will
     * only count submissions made within the date range which eventually received
     * one of the decisions.
     *
     * @param int|array $decisions One or more Decision::*
     * @param array $args See self::getQueryBuilder()
     *
     * @return int
     */
    public function countByDecisionsForSubmittedDate($decisions, $args = [])
    {
        return $this->getQueryBuilder($args)->countByDecisions((array) $decisions, true);
    }

    /**
     * Get a count of the submissions with one or more statuses
     *
     * Date restrictions will not be applied. It will return the count of
     * all submissions with the passed statuses.
     *
     * @param int|array $statuses One or more PKPSubmission::STATUS_*
     * @param array $args See self::getQueryBuilder()
     *
     * @return int
     */
    public function countByStatus($statuses, $args = [])
    {
        return $this->getQueryBuilder($args)->countByStatus((array) $statuses);
    }

    /**
     * Get a count of the submissions which are skipped by the other statistics
     *
     * Date restrictions will not be applied. It will return the count of
     * all skipped submissions.
     *
     * @param array $args See self::getQueryBuilder()
     */
    public function countSubmissionsSkipped(array $args = []): int
    {
        return $this->getQueryBuilder($args)->countSkipped();
    }

    /**
     * Get a count of the submissions which are incomplete
     *
     * Date restrictions will not be applied. It will return the count of
     * all incomplete submissions.
     *
     * @param array $args See self::getQueryBuilder()
     *
     * @return int
     */
    public function countSubmissionsInProgress($args = [])
    {
        return $this->getQueryBuilder($args)->countInProgress();
    }

    /**
     * Get a count of the submissions which are imported
     *
     * Date restrictions will not be applied. It will return the count of
     * all imported submissions.
     *
     * @param array $args See self::getQueryBuilder()
     *
     * @return int
     */
    public function countSubmissionsImported($args = [])
    {
        return $this->getQueryBuilder($args)->countImported();
    }

    /**
     * Get a count of the active submissions in one or more stages
     *
     * Date restrictions will not be applied. It will return the count of
     * all submissions with the passed statuses.
     *
     * @param int|array $stages One or more WORKFLOW_STAGE_ID_*
     * @param array $args See self::getQueryBuilder()
     *
     * @return int
     */
    public function countActiveByStages($stages, $args = [])
    {
        return $this->getQueryBuilder($args)->countActiveByStages((array) $stages);
    }

    /**
     * Get the number of days it took for each submission to reach
     * one or more editorial decisions
     *
     * Any date restrictions will be applied to the submission date, so it will
     * only return the days to a decision for submissions that were made within
     * the selected date range.
     *
     * @param int|array $decisions One or more Decision::*
     * @param array $args See self::getQueryBuilder()
     *
     * @return array
     */
    public function getDaysToDecisions($decisions, $args = [])
    {
        return $this->getQueryBuilder($args)->getDaysToDecisions((array) $decisions);
    }

    /**
     * Get the average number of days to reach one or more editorial decisions
     *
     * Any date restrictions will be applied to the submission date, so it will
     * only average the days to a decision for submissions that were made within
     * the selected date range.
     *
     * @param int|array $decisions One or more Decision::*
     * @param array $args See self::getQueryBuilder()
     *
     * @return int
     */
    public function getAverageDaysToDecisions($decisions, $args = [])
    {
        return ceil($this->getQueryBuilder($args)->getAverageDaysToDecisions((array) $decisions));
    }

    /**
     * A helper function to calculate the number of days it took reach an
     * editorial decision on a given portion of submission decisions
     *
     * This can be used to answer questions like how many days it took for
     * a decision to be reached in 80% of submissions.
     *
     * For example, if passed an array of [5, 8, 10, 20] and a percentage of
     * .75, it would return 10 since 75% of the array values are 10 or less.
     *
     * @param array $days An array of integers representing the dataset of
     *  days to reach a decision.
     * @param float $percentage The percentage of the dataset that must be
     *  included in the rate. 75% = 0.75
     *
     * @return int The number of days X% of submissions received the decision
     */
    public function calculateDaysToDecisionRate($days, $percentage)
    {
        sort($days);
        $arrayPart = array_slice($days, 0, ceil(count($days) * $percentage));
        return end($arrayPart) ?? 0;
    }

    /**
     * Get a QueryBuilder object with the passed args
     *
     * @param array{dateStart:string,dateEnd:string,contextIds:array|int,sectionIds:array|int $args
     */
    protected function getQueryBuilder($args = [])
    {
        $qb = new \APP\services\queryBuilders\StatsEditorialQueryBuilder();

        if (!empty($args['dateStart'])) {
            $qb->after($args['dateStart']);
        }
        if (!empty($args['dateEnd'])) {
            $qb->before($args['dateEnd']);
        }
        if (!empty($args['contextIds'])) {
            $qb->filterByContexts($args['contextIds']);
        }

        Hook::call('Stats::editorial::queryBuilder', [&$qb, $args]);

        return $qb;
    }

    /**
     * Get the decisions that indicate a submission has been accepted
     *
     * Decision::SEND_TO_PRODUCTION is included
     * in order to catch submissions that do not have an accept decision recorded, but have
     * still made it to the production stage. Once a SEND_TO_PRODUCTION decision has been
     * recorded, we assume the submission has been accepted for the purposes of statistics.
     *
     * This list only applies to editorial statistics. This method should not be used to
     * identify acceptance decisions for any other purpose.
     *
     * @return int[] Decision::* constants
     */
    protected function getAcceptedDecisions(): array
    {
        return [
            Decision::ACCEPT,
            Decision::SKIP_EXTERNAL_REVIEW,
            Decision::SEND_TO_PRODUCTION,
        ];
    }

    /**
     * Get the decisions that indicate a submission has been declined
     *
     * This distinction only applies to editorial statistics. This method should not be used to
     * identify declined decisions for any other purpose.
     *
     * @return int[] Decision::* constants
     */
    protected function getDeclinedDecisions(): array
    {
        return [
            Decision::DECLINE,
            Decision::INITIAL_DECLINE,
        ];
    }
}

3g86 2022