Skip to content

Commit

Permalink
Merge pull request #382 from systopia/bsh-status-model
Browse files Browse the repository at this point in the history
HiH: Add status model
  • Loading branch information
dontub authored Dec 12, 2024
2 parents 9032331 + 1d20014 commit a520828
Show file tree
Hide file tree
Showing 10 changed files with 365 additions and 119 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,14 @@

use Civi\Funding\ApplicationProcess\ActionStatusInfo\AbstractApplicationProcessActionStatusInfoDecorator;
use Civi\Funding\ApplicationProcess\ActionStatusInfo\DefaultApplicationProcessActionStatusInfo;
use Civi\Funding\ApplicationProcess\ActionStatusInfo\ReworkPossibleApplicationProcessActionStatusInfo;
use Civi\Funding\FundingCaseTypes\BSH\HiHAktion\Traits\HiHSupportedFundingCaseTypesTrait;

final class HiHApplicationActionStatusInfo extends AbstractApplicationProcessActionStatusInfoDecorator {

use HiHSupportedFundingCaseTypesTrait;

public function __construct() {
$info = new ReworkPossibleApplicationProcessActionStatusInfo(new DefaultApplicationProcessActionStatusInfo());
parent::__construct($info);
parent::__construct(new DefaultApplicationProcessActionStatusInfo());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,63 @@

namespace Civi\Funding\FundingCaseTypes\BSH\HiHAktion\Application\Actions;

use Civi\Funding\ApplicationProcess\ActionsDeterminer\AbstractApplicationActionsDeterminerDecorator;
use Civi\Funding\ApplicationProcess\ActionsDeterminer\DefaultApplicationProcessActionsDeterminer;
use Civi\Funding\ApplicationProcess\ActionsDeterminer\ReworkPossibleApplicationProcessActionsDeterminer;
use Civi\Funding\ApplicationProcess\ActionsDeterminer\AbstractApplicationProcessActionsDeterminer;
use Civi\Funding\Entity\ApplicationProcessEntityBundle;
use Civi\Funding\FundingCase\FundingCaseStatus;
use Civi\Funding\FundingCaseTypes\BSH\HiHAktion\Traits\HiHSupportedFundingCaseTypesTrait;

final class HiHApplicationActionsDeterminer extends AbstractApplicationActionsDeterminerDecorator {
final class HiHApplicationActionsDeterminer extends AbstractApplicationProcessActionsDeterminer {

use HiHSupportedFundingCaseTypesTrait;

private const FUNDING_CASE_FINAL_STATUS_LIST = [FundingCaseStatus::CLEARED];

private const STATUS_PERMISSION_ACTIONS_MAP = [
NULL => [
'application_create' => ['save'],
'application_apply' => ['apply'],
],
'new' => [
'application_modify' => ['save'],
'application_apply' => ['apply'],
'application_withdraw' => ['withdraw'],
],
'applied' => [
'application_modify' => ['modify'],
'application_withdraw' => ['withdraw'],
'review_application' => ['review', 'add-comment'],
],
'review' => [
'review_application' => ['request-change', 'update', 'reject', 'release', 'add-comment'],
],
'draft' => [
'application_modify' => ['save'],
'application_apply' => ['apply'],
'application_withdraw' => ['withdraw'],
'review_application' => ['add-comment'],
],
'advisory' => [
'advisor' => ['add-comment'],
'review_application' => ['update', 'reject', 'add-comment'],
],
'eligible' => [
'review_application' => ['add-comment'],
],
'complete' => [
'review_application' => ['add-comment'],
],
];

public function __construct() {
parent::__construct(
new ReworkPossibleApplicationProcessActionsDeterminer(new DefaultApplicationProcessActionsDeterminer())
);
parent::__construct(self::STATUS_PERMISSION_ACTIONS_MAP);
}

public function getActions(ApplicationProcessEntityBundle $applicationProcessBundle, array $statusList): array {
if ($applicationProcessBundle->getFundingCase()->isStatusIn(self::FUNDING_CASE_FINAL_STATUS_LIST)) {
return [];
}

return parent::getActions($applicationProcessBundle, $statusList);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,97 @@

namespace Civi\Funding\FundingCaseTypes\BSH\HiHAktion\Application\Actions;

use Civi\Funding\ApplicationProcess\StatusDeterminer\AbstractApplicationProcessStatusDeterminerDecorator;
use Civi\Funding\ApplicationProcess\StatusDeterminer\DefaultApplicationProcessStatusDeterminer;
use Civi\Funding\ApplicationProcess\StatusDeterminer\ReworkPossibleApplicationProcessStatusDeterminer;
use Civi\Funding\ApplicationProcess\StatusDeterminer\AbstractApplicationProcessStatusDeterminer;
use Civi\Funding\Entity\FullApplicationProcessStatus;
use Civi\Funding\FundingCaseTypes\BSH\HiHAktion\Traits\HiHSupportedFundingCaseTypesTrait;

final class HiHApplicationStatusDeterminer extends AbstractApplicationProcessStatusDeterminerDecorator {
final class HiHApplicationStatusDeterminer extends AbstractApplicationProcessStatusDeterminer {

use HiHSupportedFundingCaseTypesTrait;

private const STATUS_ACTION_STATUS_MAP = [
NULL => [
'save' => 'new',
'apply' => 'applied',
],
'new' => [
'save' => 'new',
'apply' => 'applied',
'withdraw' => 'withdrawn',
],
'applied' => [
'modify' => 'draft',
'withdraw' => 'withdrawn',
'review' => 'review',
'add-comment' => 'applied',
],
'review' => [
'request-change' => 'draft',
'release' => 'advisory',
'reject' => 'rejected',
'update' => 'review',
'add-comment' => 'review',
],
'draft' => [
'save' => 'draft',
'apply' => 'applied',
'withdraw' => 'withdrawn',
'add-comment' => 'draft',
],
'advisory' => [
'approve' => 'eligible',
'reject' => 'rejected',
'add-comment' => 'advisory',
],
'eligible' => [
'add-comment' => 'eligible',
],
'complete' => [],
];

public function __construct() {
parent::__construct(
new ReworkPossibleApplicationProcessStatusDeterminer(
new DefaultApplicationProcessStatusDeterminer()
)
parent::__construct(self::STATUS_ACTION_STATUS_MAP);
}

public function getStatusOnClearingProcessCreated(FullApplicationProcessStatus $currentStatus
): FullApplicationProcessStatus {
return new FullApplicationProcessStatus(
'complete',
$currentStatus->getIsReviewCalculative(),
$currentStatus->getIsReviewContent()
);
}

protected function getIsReviewCalculative(FullApplicationProcessStatus $currentStatus, string $action): ?bool {
if ('request-change' === $action) {
return NULL;
}

if ('release' === $action) {
return TRUE;
}

if ('reject' === $action) {
return $currentStatus->getIsReviewCalculative() ?? FALSE;
}

return $currentStatus->getIsReviewCalculative();
}

protected function getIsReviewContent(FullApplicationProcessStatus $currentStatus, string $action): ?bool {
if ('request-change' === $action) {
return NULL;
}

if ('release' === $action) {
return TRUE;
}

if ('reject' === $action) {
return $currentStatus->getIsReviewContent() ?? FALSE;
}

return $currentStatus->getIsReviewContent();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,33 @@

namespace Civi\Funding\FundingCaseTypes\BSH\HiHAktion\Application\Actions;

use Civi\Funding\ApplicationProcess\ActionsContainer\AbstractApplicationSubmitActionsContainerDecorator;
use Civi\Funding\ApplicationProcess\ActionsContainer\ReworkPossibleApplicationSubmitActionsContainerFactory;
use Civi\Funding\ApplicationProcess\ActionsContainer\AbstractApplicationSubmitActionsContainer;
use Civi\Funding\FundingCaseTypes\BSH\HiHAktion\Traits\HiHSupportedFundingCaseTypesTrait;
use CRM_Funding_ExtensionUtil as E;

/**
* @codeCoverageIgnore
*/
final class HiHApplicationSubmitActionsContainer extends AbstractApplicationSubmitActionsContainerDecorator {
final class HiHApplicationSubmitActionsContainer extends AbstractApplicationSubmitActionsContainer {

use HiHSupportedFundingCaseTypesTrait;

public function __construct() {
parent::__construct(ReworkPossibleApplicationSubmitActionsContainerFactory::create());
$this
// Applicant actions.
->add('save', E::ts('Save'))
->add('modify', E::ts('Modify'))
->add('apply', E::ts('Apply'))
->add('withdraw', E::ts('Withdraw'), E::ts('Do you really want to withdraw the application?'))
->add('delete', E::ts('Delete'), E::ts('Do you really want to delete the application?'))
// Reviewer actions.
->add('review', E::ts('Start Review'), NULL, ['needsFormData' => FALSE])
->add('release', 'Für Beirat freigeben', NULL, ['needsFormData' => FALSE])
->add('request-change', E::ts('Request Change'), NULL, ['needsFormData' => FALSE])
// Reviewer and advisor actions.
->add('reject', E::ts('Reject'), NULL, ['needsFormData' => FALSE])
// Advisor actions.
->add('approve', E::ts('Approve'), NULL, ['needsFormData' => FALSE]);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,128 @@
namespace Civi\Funding\FundingCaseTypes\BSH\HiHAktion\FundingCase\Actions;

use Civi\Funding\ClearingProcess\ClearingProcessManager;
use Civi\Funding\FundingCase\Actions\AbstractFundingCaseActionsDeterminerDecorator;
use Civi\Funding\FundingCase\Actions\DefaultFundingCaseActionsDeterminer;
use Civi\Funding\FundingCase\Actions\SetRecipientContactActionsDeterminer;
use Civi\Funding\ClearingProcess\ClearingProcessPermissions;
use Civi\Funding\FundingCase\Actions\FundingCaseActions as Actions;
use Civi\Funding\FundingCase\Actions\FundingCaseActionsDeterminer;
use Civi\Funding\FundingCase\FundingCaseStatus as Status;
use Civi\Funding\FundingCaseTypes\BSH\HiHAktion\Application\Actions\HiHApplicationActionStatusInfo;
use Civi\Funding\FundingCaseTypes\BSH\HiHAktion\Traits\HiHSupportedFundingCaseTypesTrait;

final class HiHCaseActionsDeterminer extends AbstractFundingCaseActionsDeterminerDecorator {
final class HiHCaseActionsDeterminer extends FundingCaseActionsDeterminer {

use HiHSupportedFundingCaseTypesTrait;

private const STATUS_PERMISSIONS_ACTION_MAP = [
Status::OPEN => [
'review_application' => [Actions::SET_RECIPIENT_CONTACT, Actions::SET_NOTIFICATION_CONTACTS],
ClearingProcessPermissions::REVIEW_CALCULATIVE => [Actions::SET_NOTIFICATION_CONTACTS],
ClearingProcessPermissions::REVIEW_CONTENT => [Actions::SET_NOTIFICATION_CONTACTS],
'review_drawdown' => [Actions::SET_NOTIFICATION_CONTACTS],
],
Status::ONGOING => [
'review_application' => [Actions::SET_NOTIFICATION_CONTACTS],
ClearingProcessPermissions::REVIEW_CALCULATIVE => [Actions::SET_NOTIFICATION_CONTACTS],
ClearingProcessPermissions::REVIEW_CONTENT => [Actions::SET_NOTIFICATION_CONTACTS],
'review_drawdown' => [Actions::SET_NOTIFICATION_CONTACTS],
],
Status::CLEARED => [
'review_application' => [Actions::SET_NOTIFICATION_CONTACTS],
ClearingProcessPermissions::REVIEW_CALCULATIVE => [Actions::SET_NOTIFICATION_CONTACTS],
ClearingProcessPermissions::REVIEW_CONTENT => [Actions::SET_NOTIFICATION_CONTACTS],
'review_drawdown' => [Actions::SET_NOTIFICATION_CONTACTS],
],
Status::REJECTED => [
'review_application' => [Actions::SET_NOTIFICATION_CONTACTS],
ClearingProcessPermissions::REVIEW_CALCULATIVE => [Actions::SET_NOTIFICATION_CONTACTS],
ClearingProcessPermissions::REVIEW_CONTENT => [Actions::SET_NOTIFICATION_CONTACTS],
'review_drawdown' => [Actions::SET_NOTIFICATION_CONTACTS],
],
Status::WITHDRAWN => [
'review_application' => [Actions::SET_NOTIFICATION_CONTACTS],
ClearingProcessPermissions::REVIEW_CALCULATIVE => [Actions::SET_NOTIFICATION_CONTACTS],
ClearingProcessPermissions::REVIEW_CONTENT => [Actions::SET_NOTIFICATION_CONTACTS],
'review_drawdown' => [Actions::SET_NOTIFICATION_CONTACTS],
],
];

private ClearingProcessManager $clearingProcessManager;

private HiHApplicationActionStatusInfo $statusInfo;

public function __construct(
ClearingProcessManager $clearingProcessManager,
HiHApplicationActionStatusInfo $statusInfo
) {
parent::__construct(new SetRecipientContactActionsDeterminer(
new DefaultFundingCaseActionsDeterminer($clearingProcessManager, $statusInfo))
parent::__construct(self::STATUS_PERMISSIONS_ACTION_MAP);
$this->statusInfo = $statusInfo;
$this->clearingProcessManager = $clearingProcessManager;
}

public function getActions(string $status, array $applicationProcessStatusList, array $permissions): array {
$actions = parent::getActions(
$status,
$applicationProcessStatusList,
$permissions
);

$posApprove = array_search(Actions::APPROVE, $actions, TRUE);
if (FALSE !== $posApprove && !$this->isApprovePossible($applicationProcessStatusList)) {
unset($actions[$posApprove]);
$actions = array_values($actions);
}

$posFinishClearing = array_search(Actions::FINISH_CLEARING, $actions, TRUE);
if (FALSE !== $posFinishClearing && !$this->isFinishClearingPossible($applicationProcessStatusList)) {
unset($actions[$posFinishClearing]);
$actions = array_values($actions);
}

return $actions;
}

/**
* @phpstan-param array<int, \Civi\Funding\Entity\FullApplicationProcessStatus> $applicationProcessStatusList
*
* @return bool
* TRUE If there's at least one eligible application and the eligibility of
* all applications is decided.
*/
private function isApprovePossible(array $applicationProcessStatusList): bool {
$eligibleCount = 0;
foreach ($applicationProcessStatusList as $applicationProcessStatus) {
$eligible = $this->statusInfo->isEligibleStatus($applicationProcessStatus->getStatus());
if (NULL === $eligible) {
return FALSE;
}

if ($eligible) {
++$eligibleCount;
}
}

return $eligibleCount > 0;
}

/**
* @phpstan-param array<int, \Civi\Funding\Entity\FullApplicationProcessStatus> $applicationProcessStatusList
*/
private function isFinishClearingPossible(array $applicationProcessStatusList): bool {
foreach ($applicationProcessStatusList as $applicationProcessId => $applicationProcessStatus) {
// Eligibility of all applications has to be decided.
if (NULL === $this->statusInfo->isEligibleStatus($applicationProcessStatus->getStatus())) {
return FALSE;
}

if (TRUE === $this->statusInfo->isEligibleStatus($applicationProcessStatus->getStatus())) {
// There has to be a clearing process for every eligible application that is either accepted or rejected.
$clearingProcess = $this->clearingProcessManager->getByApplicationProcessId($applicationProcessId);
if (NULL === $clearingProcess || !in_array($clearingProcess->getStatus(), ['accepted', 'rejected'], TRUE)) {
return FALSE;
}
}
}

return TRUE;
}

}
1 change: 1 addition & 0 deletions ang/crmFunding/application/applicationProcess.factory.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ fundingModule.factory('fundingApplicationProcessService', ['crmApi4', function(c

return {
get: (id) => crmApi4('FundingApplicationProcess', 'get', {
select: ['*', 'custom.*'],
where: [['id', '=', id]],
}).then(function (result) {
return result[0] || null;
Expand Down
Loading

0 comments on commit a520828

Please sign in to comment.