From 8350bebb50a2da7f07c09bb6adfafac856c3fc3c Mon Sep 17 00:00:00 2001 From: Yuri Kuznetsov Date: Mon, 24 Feb 2025 13:43:08 +0200 Subject: [PATCH] opportunity probability allow empty --- .../MassAction/Opportunity/MassUpdate.php | 17 ++---- .../RecordHooks/Opportunity/BeforeUpdate.php | 6 +- .../Opportunity/PrimaryFilters/Lost.php | 4 +- .../Opportunity/PrimaryFilters/Open.php | 4 +- .../Select/Opportunity/PrimaryFilters/Won.php | 4 +- ...eListPoriver.php => StageListProvider.php} | 59 +++++++++++-------- .../Espo/Modules/Crm/Entities/Opportunity.php | 5 ++ .../Crm/Hooks/Opportunity/LastStage.php | 43 ++++++++++---- .../Crm/Hooks/Opportunity/Probability.php | 2 +- 9 files changed, 89 insertions(+), 55 deletions(-) rename application/Espo/Modules/Crm/Classes/Select/Opportunity/Utils/{StageListPoriver.php => StageListProvider.php} (60%) diff --git a/application/Espo/Modules/Crm/Classes/MassAction/Opportunity/MassUpdate.php b/application/Espo/Modules/Crm/Classes/MassAction/Opportunity/MassUpdate.php index a0bce363e4..b1d9f5350d 100644 --- a/application/Espo/Modules/Crm/Classes/MassAction/Opportunity/MassUpdate.php +++ b/application/Espo/Modules/Crm/Classes/MassAction/Opportunity/MassUpdate.php @@ -34,22 +34,16 @@ use Espo\Core\MassAction\Params; use Espo\Core\MassAction\Result; use Espo\Core\MassAction\Data; use Espo\Core\MassAction\MassAction; - use Espo\Tools\MassUpdate\Data as MassUpdateData; - use Espo\Core\Utils\Metadata; class MassUpdate implements MassAction { - private MassUpdateOriginal $massUpdateOriginal; - private Metadata $metadata; - - public function __construct(MassUpdateOriginal $massUpdateOriginal, Metadata $metadata) - { - $this->massUpdateOriginal = $massUpdateOriginal; - $this->metadata = $metadata; - } + public function __construct( + private MassUpdateOriginal $massUpdateOriginal, + private Metadata $metadata + ) {} public function process(Params $params, Data $data): Result { @@ -60,8 +54,7 @@ class MassUpdate implements MassAction $stage = $massUpdateData->getValue('stage'); if ($stage && !$massUpdateData->has('probability')) { - $probability = $this->metadata - ->get(['entityDefs', 'Opportunity', 'fields', 'stage', 'probabilityMap', $stage]); + $probability = $this->metadata->get("entityDefs.Opportunity.fields.stage.probabilityMap.$stage"); } if ($probability !== null) { diff --git a/application/Espo/Modules/Crm/Classes/RecordHooks/Opportunity/BeforeUpdate.php b/application/Espo/Modules/Crm/Classes/RecordHooks/Opportunity/BeforeUpdate.php index d2fbf7ffcf..60d02b3fe9 100644 --- a/application/Espo/Modules/Crm/Classes/RecordHooks/Opportunity/BeforeUpdate.php +++ b/application/Espo/Modules/Crm/Classes/RecordHooks/Opportunity/BeforeUpdate.php @@ -56,7 +56,11 @@ class BeforeUpdate implements SaveHook $stage = $entity->getStage(); - $probability = $this->metadata->get("entityDefs.Opportunity.fields.stage.probabilityMap.$stage") ?? 0; + $probability = $this->metadata->get("entityDefs.Opportunity.fields.stage.probabilityMap.$stage"); + + if ($probability === null) { + return; + } $entity->setProbability($probability); } diff --git a/application/Espo/Modules/Crm/Classes/Select/Opportunity/PrimaryFilters/Lost.php b/application/Espo/Modules/Crm/Classes/Select/Opportunity/PrimaryFilters/Lost.php index 351b2c402b..f406195221 100644 --- a/application/Espo/Modules/Crm/Classes/Select/Opportunity/PrimaryFilters/Lost.php +++ b/application/Espo/Modules/Crm/Classes/Select/Opportunity/PrimaryFilters/Lost.php @@ -33,13 +33,13 @@ use Espo\Core\Select\Primary\Filter; use Espo\ORM\Query\SelectBuilder; use Espo\ORM\Query\Part\Condition as Cond; -use Espo\Modules\Crm\Classes\Select\Opportunity\Utils\StageListPoriver; +use Espo\Modules\Crm\Classes\Select\Opportunity\Utils\StageListProvider; class Lost implements Filter { private $stageListPoriver; - public function __construct(StageListPoriver $stageListPoriver) + public function __construct(StageListProvider $stageListPoriver) { $this->stageListPoriver = $stageListPoriver; } diff --git a/application/Espo/Modules/Crm/Classes/Select/Opportunity/PrimaryFilters/Open.php b/application/Espo/Modules/Crm/Classes/Select/Opportunity/PrimaryFilters/Open.php index 15766af43b..0475157ca7 100644 --- a/application/Espo/Modules/Crm/Classes/Select/Opportunity/PrimaryFilters/Open.php +++ b/application/Espo/Modules/Crm/Classes/Select/Opportunity/PrimaryFilters/Open.php @@ -33,13 +33,13 @@ use Espo\Core\Select\Primary\Filter; use Espo\ORM\Query\SelectBuilder; use Espo\ORM\Query\Part\Condition as Cond; -use Espo\Modules\Crm\Classes\Select\Opportunity\Utils\StageListPoriver; +use Espo\Modules\Crm\Classes\Select\Opportunity\Utils\StageListProvider; class Open implements Filter { private $stageListPoriver; - public function __construct(StageListPoriver $stageListPoriver) + public function __construct(StageListProvider $stageListPoriver) { $this->stageListPoriver = $stageListPoriver; } diff --git a/application/Espo/Modules/Crm/Classes/Select/Opportunity/PrimaryFilters/Won.php b/application/Espo/Modules/Crm/Classes/Select/Opportunity/PrimaryFilters/Won.php index 42806b00aa..0a99f1a0f0 100644 --- a/application/Espo/Modules/Crm/Classes/Select/Opportunity/PrimaryFilters/Won.php +++ b/application/Espo/Modules/Crm/Classes/Select/Opportunity/PrimaryFilters/Won.php @@ -33,13 +33,13 @@ use Espo\Core\Select\Primary\Filter; use Espo\ORM\Query\SelectBuilder; use Espo\ORM\Query\Part\Condition as Cond; -use Espo\Modules\Crm\Classes\Select\Opportunity\Utils\StageListPoriver; +use Espo\Modules\Crm\Classes\Select\Opportunity\Utils\StageListProvider; class Won implements Filter { private $stageListPoriver; - public function __construct(StageListPoriver $stageListPoriver) + public function __construct(StageListProvider $stageListPoriver) { $this->stageListPoriver = $stageListPoriver; } diff --git a/application/Espo/Modules/Crm/Classes/Select/Opportunity/Utils/StageListPoriver.php b/application/Espo/Modules/Crm/Classes/Select/Opportunity/Utils/StageListProvider.php similarity index 60% rename from application/Espo/Modules/Crm/Classes/Select/Opportunity/Utils/StageListPoriver.php rename to application/Espo/Modules/Crm/Classes/Select/Opportunity/Utils/StageListProvider.php index 40270e6469..94c5bfa90c 100644 --- a/application/Espo/Modules/Crm/Classes/Select/Opportunity/Utils/StageListPoriver.php +++ b/application/Espo/Modules/Crm/Classes/Select/Opportunity/Utils/StageListProvider.php @@ -31,34 +31,29 @@ namespace Espo\Modules\Crm\Classes\Select\Opportunity\Utils; use Espo\Core\Utils\Metadata; -class StageListPoriver +class StageListProvider { - private $metadata; - - public function __construct(Metadata $metadata) - { - $this->metadata = $metadata; - } + public function __construct(private Metadata $metadata) + {} /** * @return string[] */ public function getLost(): array { - $lostStageList = []; + $output = []; - $probabilityMap = $this->metadata - ->get(['entityDefs', 'Opportunity', 'fields', 'stage', 'probabilityMap']) ?? []; + $probabilityMap = $this->getProbabilityMap(); - $stageList = $this->metadata->get('entityDefs.Opportunity.fields.stage.options') ?? []; + foreach ($this->getStageList() as $stage) { + $value = $probabilityMap[$stage] ?? null; - foreach ($stageList as $stage) { - if (empty($probabilityMap[$stage])) { - $lostStageList[] = $stage; + if ($value === 0 || $value === 0.0) { + $output[] = $stage; } } - return $lostStageList; + return $output; } /** @@ -66,19 +61,37 @@ class StageListPoriver */ public function getWon(): array { - $wonStageList = []; + $output = []; - $probabilityMap = $this->metadata - ->get(['entityDefs', 'Opportunity', 'fields', 'stage', 'probabilityMap']) ?? []; + $probabilityMap = $this->getProbabilityMap(); - $stageList = $this->metadata->get('entityDefs.Opportunity.fields.stage.options') ?? []; + foreach ($this->getStageList() as $stage) { + $value = $probabilityMap[$stage] ?? null; - foreach ($stageList as $stage) { - if (!empty($probabilityMap[$stage]) && $probabilityMap[$stage] == 100) { - $wonStageList[] = $stage; + if ($value == 100) { + $output[] = $stage; } } - return $wonStageList; + return $output; + } + + /** + * @return array + */ + private function getProbabilityMap(): array + { + /** @var array $probabilityMap */ + $probabilityMap = $this->metadata->get('entityDefs.Opportunity.fields.stage.probabilityMap') ?? []; + + return $probabilityMap; + } + + /** + * @return string[] + */ + private function getStageList(): array + { + return $this->metadata->get('entityDefs.Opportunity.fields.stage.options') ?? []; } } diff --git a/application/Espo/Modules/Crm/Entities/Opportunity.php b/application/Espo/Modules/Crm/Entities/Opportunity.php index 3653cf39ae..c704842c00 100644 --- a/application/Espo/Modules/Crm/Entities/Opportunity.php +++ b/application/Espo/Modules/Crm/Entities/Opportunity.php @@ -107,6 +107,11 @@ class Opportunity extends Entity return $this->get('lastStage'); } + public function setLastStage(?string $lastStage): void + { + $this->set('lastStage', $lastStage); + } + public function getProbability(): ?int { return $this->get('probability'); diff --git a/application/Espo/Modules/Crm/Hooks/Opportunity/LastStage.php b/application/Espo/Modules/Crm/Hooks/Opportunity/LastStage.php index 88f2d00702..16a4803f8d 100644 --- a/application/Espo/Modules/Crm/Hooks/Opportunity/LastStage.php +++ b/application/Espo/Modules/Crm/Hooks/Opportunity/LastStage.php @@ -56,19 +56,20 @@ class LastStage implements BeforeSave return; } - $probability = $this->metadata - ->get(['entityDefs', 'Opportunity', 'fields', 'stage', 'probabilityMap', $entity->getStage() ?? '']) ?? 0; + $stage = $entity->getStage(); - if ($probability) { - $entity->set('lastStage', $entity->getStage()); + $probability = $this->metadata->get("entityDefs.Opportunity.fields.stage.probabilityMap.$stage"); + + if ($probability !== 0) { + $entity->setLastStage($entity->getStage()); return; } - $probabilityMap = $this->metadata - ->get(['entityDefs', 'Opportunity', 'fields', 'stage', 'probabilityMap']) ?? []; + // Lost. - $stageList = $this->metadata->get(['entityDefs', 'Opportunity', 'fields', 'stage', 'options']) ?? []; + $probabilityMap = $this->getProbabilityMap(); + $stageList = $this->getStageList(); if (!count($stageList)) { return; @@ -85,7 +86,7 @@ class LastStage implements BeforeSave if ( $itemProbability === null || - $itemProbability === 100 || + $itemProbability == 100 || $itemProbability === 0 || $itemProbability >= $min ) { @@ -100,7 +101,7 @@ class LastStage implements BeforeSave return; } - $entity->set('lastStage', $minStage); + $entity->setLastStage($minStage); return; } @@ -111,8 +112,7 @@ class LastStage implements BeforeSave return; } - $lastStageProbability = $this->metadata - ->get(['entityDefs', 'Opportunity', 'fields', 'stage', 'probabilityMap', $entity->getLastStage()]) ?? 0; + $lastStageProbability = $probabilityMap[$entity->getLastStage()] ?? null; if ($lastStageProbability !== 100) { return; @@ -141,6 +141,25 @@ class LastStage implements BeforeSave return; } - $entity->set('lastStage', $maxStage); + $entity->setLastStage($maxStage); + } + + /** + * @return array + */ + private function getProbabilityMap(): array + { + /** @var array $probabilityMap */ + $probabilityMap = $this->metadata->get('entityDefs.Opportunity.fields.stage.probabilityMap') ?? []; + + return $probabilityMap; + } + + /** + * @return string[] + */ + private function getStageList(): array + { + return $this->metadata->get('entityDefs.Opportunity.fields.stage.options') ?? []; } } diff --git a/application/Espo/Modules/Crm/Hooks/Opportunity/Probability.php b/application/Espo/Modules/Crm/Hooks/Opportunity/Probability.php index 0e9632f5f7..be48fd53ae 100644 --- a/application/Espo/Modules/Crm/Hooks/Opportunity/Probability.php +++ b/application/Espo/Modules/Crm/Hooks/Opportunity/Probability.php @@ -53,7 +53,7 @@ class Probability implements BeforeSave return; } - if ($entity->get('probability') !== null) { + if ($entity->getProbability() !== null) { return; }