From 2b2777b3da65f85d1beeacfc099102496cd7702f Mon Sep 17 00:00:00 2001 From: Yuri Kuznetsov Date: Mon, 2 Mar 2020 13:19:42 +0200 Subject: [PATCH] sales pipeline: team filter --- .../Modules/Crm/Controllers/Opportunity.php | 3 +- .../Resources/i18n/en_US/DashletOptions.json | 1 + .../metadata/dashlets/SalesPipeline.json | 15 ++++++- .../Espo/Modules/Crm/Services/Opportunity.php | 14 ++++++- .../views/dashlets/options/sales-pipeline.js | 42 +++++++++++++++++++ .../options/sales-pipeline/fields/team.js | 40 ++++++++++++++++++ .../crm/src/views/dashlets/sales-pipeline.js | 4 ++ 7 files changed, 114 insertions(+), 5 deletions(-) create mode 100644 client/modules/crm/src/views/dashlets/options/sales-pipeline.js create mode 100644 client/modules/crm/src/views/dashlets/options/sales-pipeline/fields/team.js diff --git a/application/Espo/Modules/Crm/Controllers/Opportunity.php b/application/Espo/Modules/Crm/Controllers/Opportunity.php index 95921707e8..99bf87a35f 100644 --- a/application/Espo/Modules/Crm/Controllers/Opportunity.php +++ b/application/Espo/Modules/Crm/Controllers/Opportunity.php @@ -89,8 +89,9 @@ class Opportunity extends \Espo\Core\Controllers\Record $dateTo = $request->get('dateTo'); $dateFilter = $request->get('dateFilter'); $useLastStage = $request->get('useLastStage') === 'true'; + $teamId = $request->get('teamId') ?? null; - return $this->getService('Opportunity')->reportSalesPipeline($dateFilter, $dateFrom, $dateTo, $useLastStage); + return $this->getService('Opportunity')->reportSalesPipeline($dateFilter, $dateFrom, $dateTo, $useLastStage, $teamId); } public function getActionEmailAddressList($params, $data, $request) diff --git a/application/Espo/Modules/Crm/Resources/i18n/en_US/DashletOptions.json b/application/Espo/Modules/Crm/Resources/i18n/en_US/DashletOptions.json index 3277c22ccc..51c51adad2 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/en_US/DashletOptions.json +++ b/application/Espo/Modules/Crm/Resources/i18n/en_US/DashletOptions.json @@ -1,5 +1,6 @@ { "fields": { + "team": "Team", "futureDays": "Next X Days", "useLastStage": "Group by last reached stage" } diff --git a/application/Espo/Modules/Crm/Resources/metadata/dashlets/SalesPipeline.json b/application/Espo/Modules/Crm/Resources/metadata/dashlets/SalesPipeline.json index fdd8722bd5..337dfc4f66 100644 --- a/application/Espo/Modules/Crm/Resources/metadata/dashlets/SalesPipeline.json +++ b/application/Espo/Modules/Crm/Resources/metadata/dashlets/SalesPipeline.json @@ -2,7 +2,7 @@ "view":"crm:views/dashlets/sales-pipeline", "aclScope": "Opportunity", "options": { - "view": "crm:views/dashlets/options/chart", + "view": "crm:views/dashlets/options/sales-pipeline", "fields": { "title": { "type": "varchar", @@ -24,6 +24,11 @@ }, "useLastStage": { "type": "bool" + }, + "team": { + "type": "link", + "entity": "Team", + "view": "crm:views/dashlets/options/sales-pipeline/fields/team" } }, "layout": [ @@ -39,12 +44,18 @@ [ {"name": "dateFrom"}, {"name": "dateTo"} + ], + [ + {"name": "team"}, + false ] ] } ], "defaults": { - "dateFilter": "currentYear" + "dateFilter": "currentYear", + "teamId": null, + "teamName": null } } } diff --git a/application/Espo/Modules/Crm/Services/Opportunity.php b/application/Espo/Modules/Crm/Services/Opportunity.php index 260dbec75d..ccdb8e2c93 100644 --- a/application/Espo/Modules/Crm/Services/Opportunity.php +++ b/application/Espo/Modules/Crm/Services/Opportunity.php @@ -41,7 +41,7 @@ class Opportunity extends \Espo\Services\Record 'accountName' ]; - public function reportSalesPipeline($dateFilter, $dateFrom = null, $dateTo = null, $useLastStage = false) + public function reportSalesPipeline($dateFilter, $dateFrom = null, $dateTo = null, $useLastStage = false, $teamId = null) { if (in_array('amount', $this->getAcl()->getScopeForbiddenAttributeList('Opportunity'))) { throw new Forbidden(); @@ -76,13 +76,23 @@ class Opportunity extends \Espo\Services\Record ]; } + if ($teamId) { + $whereClause[] = [ + 'teamsFilter.id' => $teamId, + ]; + } + $selectParams = [ 'select' => [$stageField, ['SUM:amountConverted', 'amount']], 'whereClause' => $whereClause, 'orderBy' => 'LIST:'.$stageField.':' . implode(',', $options), - 'groupBy' => [$stageField] + 'groupBy' => [$stageField], ]; + if ($teamId) { + $selectManager->addJoin(['teams', 'teamsFilter'], $selectParams); + } + $selectManager->applyAccess($selectParams); $this->handleDistinctReportSelectParams($selectParams, $whereClause); diff --git a/client/modules/crm/src/views/dashlets/options/sales-pipeline.js b/client/modules/crm/src/views/dashlets/options/sales-pipeline.js new file mode 100644 index 0000000000..f402637501 --- /dev/null +++ b/client/modules/crm/src/views/dashlets/options/sales-pipeline.js @@ -0,0 +1,42 @@ +/************************************************************************ + * This file is part of EspoCRM. + * + * EspoCRM - Open Source CRM application. + * Copyright (C) 2014-2020 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko + * Website: https://www.espocrm.com + * + * EspoCRM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * EspoCRM 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with EspoCRM. If not, see http://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 General Public License version 3. + * + * In accordance with Section 7(b) of the GNU General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "EspoCRM" word. + ************************************************************************/ + +define('crm:views/dashlets/options/sales-pipeline', 'crm:views/dashlets/options/chart', function (Dep) { + + return Dep.extend({ + + setup: function () { + Dep.prototype.setup.call(this); + + if (this.getAcl().getLevel('Opportunity', 'read') === 'own') { + this.hideField('team'); + } + }, + + }); +}); diff --git a/client/modules/crm/src/views/dashlets/options/sales-pipeline/fields/team.js b/client/modules/crm/src/views/dashlets/options/sales-pipeline/fields/team.js new file mode 100644 index 0000000000..18b26419ef --- /dev/null +++ b/client/modules/crm/src/views/dashlets/options/sales-pipeline/fields/team.js @@ -0,0 +1,40 @@ +/************************************************************************ + * This file is part of EspoCRM. + * + * EspoCRM - Open Source CRM application. + * Copyright (C) 2014-2020 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko + * Website: https://www.espocrm.com + * + * EspoCRM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * EspoCRM 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with EspoCRM. If not, see http://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 General Public License version 3. + * + * In accordance with Section 7(b) of the GNU General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "EspoCRM" word. + ************************************************************************/ + +define('crm:views/dashlets/options/sales-pipeline/fields/team', 'views/fields/link', function (Dep) { + + return Dep.extend({ + + getSelectBoolFilterList: function () { + if (this.getAcl().getLevel('Opportunity', 'read') === 'team') { + return ['onlyMy']; + } + }, + }); + +}); diff --git a/client/modules/crm/src/views/dashlets/sales-pipeline.js b/client/modules/crm/src/views/dashlets/sales-pipeline.js index 3f64da33ae..79f79a5430 100644 --- a/client/modules/crm/src/views/dashlets/sales-pipeline.js +++ b/client/modules/crm/src/views/dashlets/sales-pipeline.js @@ -47,6 +47,10 @@ define('crm:views/dashlets/sales-pipeline', ['crm:views/dashlets/abstract/chart' if (this.getOption('useLastStage')) { url += '&useLastStage=true'; } + + if (this.getOption('teamId')) { + url += '&teamId=' + this.getOption('teamId'); + } return url; },