snapshot of https://github.com/espocrm/espocrm.git (master, 2026-09-18; blobs > 131072B omitted)
Some checks failed
Test / Test on PHP 8.3 (push) Failing after 5s
Test / Test on PHP 8.4 (push) Failing after 4s
Test / Test on PHP 8.5 (push) Failing after 3s
TypeScript static analysis / TypeScript check (push) Failing after 14s
Test Integration on MySQL / Test on PHP 8.3 (push) Failing after 2s
Test Integration on MySQL / Test on PHP 8.5 (push) Failing after 0s
Test Integration on PostgreSQL / Test on PHP 8.4 fix (push) Failing after 1s
Test Integration on PostgreSQL / Test on PHP 8.4 master (push) Failing after 1s

This commit is contained in:
upstream-mirror
2026-09-18 04:19:15 +05:00
commit 7cc7e6b4f3
10077 changed files with 900756 additions and 0 deletions

View File

@@ -0,0 +1,237 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM – Open Source CRM application.
* Copyright (C) 2014-2026 EspoCRM, Inc.
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace tests\integration\Espo\Tools\Pipeline;
use Espo\Classes\AppParams\Pipelines;
use Espo\Core\Acl\Table;
use Espo\Core\AclManager;
use Espo\Core\Exceptions\BadRequest;
use Espo\Core\Field\Date;
use Espo\Core\Name\Field;
use Espo\Core\Record\CreateParams;
use Espo\Core\Record\DeleteParams;
use Espo\Core\Record\ServiceContainer;
use Espo\Core\Record\UpdateParams;
use Espo\Entities\Pipeline;
use Espo\Entities\PipelineStage;
use Espo\Entities\Role;
use Espo\Entities\Team;
use Espo\Modules\Crm\Entities\Opportunity;
use Espo\Tools\EntityManager\EntityManager as EntityManagerTool;
use integration\Core\NoTransaction;
use tests\integration\Core\BaseTestCase;
#[NoTransaction]
class PipelineTest extends BaseTestCase
{
/**
* @noinspection PhpUnhandledExceptionInspection
*/
public function testPipeline1(): void
{
$this->initPipeline(Opportunity::ENTITY_TYPE);
$em = $this->getEntityManager();
$role = $em->getRDBRepositoryByClass(Role::class)->getNew();
$role
->set(Field::NAME, 'Test')
->setRawData([
Opportunity::ENTITY_TYPE => [
Table::ACTION_EDIT => Table::LEVEL_TEAM,
],
]);
$em->saveEntity($role);
$team = $em->createEntity(Team::ENTITY_TYPE, [
Field::NAME => 'Test',
'rolesIds' => [$role->getId()],
]);
$user1 = $this->createUser([
'userName' => 'test-1',
'teamsIds' => [$team->getId()],
]);
$pipelineService = $this->getContainer()
->getByClass(ServiceContainer::class)
->getByClass(Pipeline::class);
$pipelineStageService = $this->getContainer()
->getByClass(ServiceContainer::class)
->getByClass(PipelineStage::class);
$oppService = $this->getContainer()
->getByClass(ServiceContainer::class)
->getByClass(Opportunity::class);
//
$pipeline1 = $pipelineService->create((object) [
Field::NAME => 'Test 1',
Pipeline::FIELD_ENTITY_TYPE => Opportunity::ENTITY_TYPE,
Pipeline::FIELD_IS_AVAILABLE_FOR_ALL => false,
], CreateParams::create())->getEntity();
$this->assertCount(6, $pipeline1->getStages());
//
$pipeline2 = $pipelineService->create((object) [
Field::NAME => 'Test 2',
Pipeline::FIELD_ENTITY_TYPE => Opportunity::ENTITY_TYPE,
Pipeline::FIELD_IS_AVAILABLE_FOR_ALL => false,
Field::TEAMS . 'Ids' => [$team->getId()],
], CreateParams::create())->getEntity();
foreach ($pipeline2->getStages() as $stage) {
$pipelineStageService->delete($stage->getId(), DeleteParams::create());
}
$stage2_1 = $pipelineStageService->create((object) [
Field::NAME => 'Open',
PipelineStage::ATTR_PIPELINE_ID => $pipeline2->getId(),
PipelineStage::FIELD_MAPPED_STATUS => 'Prospecting',
], CreateParams::create())->getEntity();
$pipelineStageService->create((object) [
Field::NAME => 'Closed Won',
PipelineStage::ATTR_PIPELINE_ID => $pipeline2->getId(),
PipelineStage::FIELD_MAPPED_STATUS => Opportunity::STAGE_CLOSED_WON,
], CreateParams::create());
$pipelineStageService->create((object) [
Field::NAME => 'Closed Lost',
PipelineStage::ATTR_PIPELINE_ID => $pipeline2->getId(),
PipelineStage::FIELD_MAPPED_STATUS => Opportunity::STAGE_CLOSED_LOST,
], CreateParams::create());
$thrown = false;
try {
// Non-existing status.
$pipelineStageService->create((object) [
Field::NAME => 'Test',
PipelineStage::ATTR_PIPELINE_ID => $pipeline2->getId(),
PipelineStage::FIELD_MAPPED_STATUS => 'Test',
], CreateParams::create());
} catch (BadRequest) {
$thrown = true;
}
$this->assertTrue($thrown);
$em->refreshEntity($pipeline2);
$this->assertCount(3, $pipeline2->getStages());
//
$opp = $oppService->create((object) [
Field::NAME => 'Opp 1',
Field::PIPELINE . 'Id' => $pipeline1->getId(),
Field::PIPELINE_STAGE . 'Id' => $pipeline1->getStages()[0]->getId(),
Opportunity::FIELD_CLOSE_DATE => Date::fromString('2026-01-01')->toString(),
Opportunity::FIELD_AMOUNT => 1000,
], CreateParams::create())->getEntity();
$opp = $oppService->update($opp->getId(), (object) [
Field::PIPELINE . 'Id' => $pipeline2->getId(),
Field::PIPELINE_STAGE . 'Id' => $pipeline2->getStages()[0]->getId(),
], UpdateParams::create())->getEntity();
$this->assertEquals('Prospecting', $opp->getStage());
//
$opp = $oppService->create((object) [
Field::NAME => 'Opp 2',
Field::PIPELINE . 'Id' => $pipeline1->getId(),
Field::PIPELINE_STAGE . 'Id' => $pipeline1->getStages()[4]->getId(),
Opportunity::FIELD_CLOSE_DATE => Date::fromString('2026-01-01')->toString(),
Opportunity::FIELD_AMOUNT => 1000,
], CreateParams::create())->getEntity();
$this->assertEquals(Opportunity::STAGE_CLOSED_WON, $opp->getStage());
//
$opp = $oppService->create((object) [
Field::NAME => 'Opp 3',
Opportunity::FIELD_CLOSE_DATE => Date::fromString('2026-01-01')->toString(),
Opportunity::FIELD_AMOUNT => 1000,
], CreateParams::create());
$this->assertEquals($pipeline1->getId(), $opp->getEntity()->get(Field::PIPELINE . 'Id'));
$this->assertEquals($pipeline1->getStages()[0]->getId(), $opp->getEntity()->get(Field::PIPELINE_STAGE . 'Id'));
//
$pipelinesParam = $this->getInjectableFactory()->create(Pipelines::class);
$pipelines = $pipelinesParam->get();
$this->assertCount(2, $pipelines[Opportunity::ENTITY_TYPE]);
//
$this->auth($user1->getUserName());
$this->reCreateApplication(reuse: true);
$pipelinesParam = $this->getInjectableFactory()->create(Pipelines::class);
$pipelines = $pipelinesParam->get();
$this->assertCount(1, $pipelines[Opportunity::ENTITY_TYPE]);
//
$aclManager = $this->getContainer()->getByClass(AclManager::class);
$this->assertFalse($aclManager->checkEntityRead($user1, $pipeline1));
$this->assertTrue($aclManager->checkEntityRead($user1, $pipeline2));
$this->assertTrue($aclManager->checkEntityRead($user1, $stage2_1));
}
/**
* @noinspection PhpUnhandledExceptionInspection
* @noinspection PhpArrayKeyDoesNotMatchArrayShapeInspection
* @noinspection PhpSameParameterValueInspection
*/
private function initPipeline(string $entityType): void
{
$entityManager = $this->getInjectableFactory()->create(EntityManagerTool::class);
$entityManager->update($entityType, [
'pipelines' => true
]);
}
}