updated advanced pack to 3.12.0:

Reports:

    Non-aggregated columns in Grid report export.
    Normalized table mode for 2-dimensional Grid reports.
    Ability to create internal reports via the UI.
    Ability to show/hide and resize columns in the list report result view.
This commit is contained in:
2026-02-07 16:09:20 +01:00
parent 26db904407
commit f95246f99f
384 changed files with 6184 additions and 3643 deletions

View File

@@ -11,7 +11,7 @@
* usage to the software or any modified version or derivative work of the software
* created by or for you.
*
* Copyright (C) 2015-2025 EspoCRM, Inc.
* Copyright (C) 2015-2026 EspoCRM, Inc.
*
* License ID: 19bc86a68a7bb01f458cb391d43a9212
************************************************************************************/
@@ -21,10 +21,12 @@ namespace Espo\Modules\Advanced\Tools\Report;
use Espo\Core\Acl;
use Espo\Core\Acl\Table as AclTable;
use Espo\Core\Exceptions\BadRequest;
use Espo\Core\Exceptions\Error\Body;
use Espo\Core\Exceptions\Forbidden;
use Espo\Core\Record\ServiceContainer;
use Espo\Entities\User;
use Espo\Modules\Advanced\Entities\Report;
use Espo\Modules\Advanced\Tools\Report\Internal\InternalReportHelper;
use Espo\ORM\EntityManager;
use stdClass;
@@ -37,6 +39,7 @@ class PreviewReportProvider
private ServiceContainer $serviceContainer,
private User $user,
private ReportHelper $reportHelper,
private InternalReportHelper $internalReportHelper,
) {}
/**
@@ -45,9 +48,57 @@ class PreviewReportProvider
*/
public function get(stdClass $data): Report
{
$report = $this->entityManager->getRDBRepositoryByClass(Report::class)->getNew();
$report = $this->prepareReport($data);
unset($data->isInternal);
foreach ($report->getJoinedReportIdList() as $subReportId) {
$subReport = $this->entityManager->getRDBRepositoryByClass(Report::class)->getById($subReportId);
if (!$subReport) {
continue;
}
$this->reportHelper->checkReportCanBeRun($subReport);
if (!$this->acl->checkEntityRead($subReport)) {
throw new Forbidden("No access to sub-report.");
}
}
$this->reportHelper->checkReportCanBeRun($report);
$this->accessCheck($report);
return $report;
}
/**
* @throws Forbidden
*/
private function accessCheck(Report $report): void
{
if (
!$this->user->isAdmin() &&
($report->isInternal() || $report->getInternalClassName())
) {
throw Forbidden::createWithBody('onlyAdminCanPreviewInternalReports',
Body::create()->withMessageTranslation('onlyAdminCanPreviewInternalReports', Report::ENTITY_TYPE)
);
}
if (
$report->getTargetEntityType() &&
!$this->acl->checkScope($report->getTargetEntityType(), AclTable::ACTION_READ)
) {
throw new Forbidden("No 'read' access to target entity.");
}
}
/**
* @throws BadRequest
*/
private function prepareReport(stdClass $data): Report
{
$report = $this->entityManager->getRDBRepositoryByClass(Report::class)->getNew();
$attributeList = [
'entityType',
@@ -70,6 +121,9 @@ class PreviewReportProvider
'joinedReports',
'joinedReportLabel',
'joinedReportDataList',
'isInternal',
'internalClassName',
'internalParams',
];
foreach (array_keys(get_object_vars($data)) as $attribute) {
@@ -77,36 +131,19 @@ class PreviewReportProvider
unset($data->$attribute);
}
}
$report->setMultiple($data);
$report->setApplyAcl();
$report->setName('Unnamed');
$report
->setApplyAcl()
->setName('Unnamed');
if ($report->getInternalClassName()) {
$this->internalReportHelper->populateFields($report);
}
$this->serviceContainer->getByClass(Report::class)->processValidation($report, $data);
foreach ($report->getJoinedReportIdList() as $subReportId) {
$subReport = $this->entityManager->getRDBRepositoryByClass(Report::class)->getById($subReportId);
if (!$subReport) {
continue;
}
$this->reportHelper->checkReportCanBeRun($subReport);
if (!$this->acl->checkEntityRead($subReport)) {
throw new Forbidden("No access to sub-report.");
}
}
$this->reportHelper->checkReportCanBeRun($report);
if (
$report->getTargetEntityType() &&
!$this->acl->checkScope($report->getTargetEntityType(), AclTable::ACTION_READ)
) {
throw new Forbidden("No 'read' access to target entity.");
}
return $report;
}
}