Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HiH: Add status model #382

Merged
merged 7 commits into from
Dec 12, 2024
Merged
Show file tree
Hide file tree
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 @@ -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
Loading