diff --git a/application/Espo/Core/Formula/Functions/RecordGroup/RelateType.php b/application/Espo/Core/Formula/Functions/RecordGroup/RelateType.php new file mode 100644 index 0000000000..62d56b471f --- /dev/null +++ b/application/Espo/Core/Formula/Functions/RecordGroup/RelateType.php @@ -0,0 +1,69 @@ +addDependency('entityManager'); + } + + public function process(\StdClass $item) + { + $args = $item->value ?? []; + + if (count($args) < 4) throw new Error("Formula: record\\relate: Not enough arguments."); + + $entityType = $this->evaluate($args[0]); + $id = $this->evaluate($args[1]); + $link = $this->evaluate($item->value[2]); + $foreignId = $this->evaluate($item->value[3]); + + if (!$entityType) throw new Error("Formula record\\relate: Empty entityType."); + if (!$id) return null; + if (!$link) throw new Error("Formula record\\relate: Empty link."); + if (!$foreignId) return null; + + $em = $this->getInjection('entityManager'); + + if (!$em->hasRepository($entityType)) throw new Error("Formula: record\\relate: Repository does not exist."); + + $entity = $em->getEntity($entityType, $id); + if (!$entity) return null; + + if ($em->getRepository($entityType)->isRelated($entity, $link, $foreignId)) + return true; + + return $em->getRepository($entityType)->relate($entity, $link, $foreignId); + } +} diff --git a/application/Espo/Core/Formula/Functions/RecordGroup/UnrelateType.php b/application/Espo/Core/Formula/Functions/RecordGroup/UnrelateType.php new file mode 100644 index 0000000000..08eb619589 --- /dev/null +++ b/application/Espo/Core/Formula/Functions/RecordGroup/UnrelateType.php @@ -0,0 +1,69 @@ +addDependency('entityManager'); + } + + public function process(\StdClass $item) + { + $args = $item->value ?? []; + + if (count($args) < 4) throw new Error("Formula: record\\unrelate: Not enough arguments."); + + $entityType = $this->evaluate($args[0]); + $id = $this->evaluate($args[1]); + $link = $this->evaluate($item->value[2]); + $foreignId = $this->evaluate($item->value[3]); + + if (!$entityType) throw new Error("Formula record\\unrelate: Empty entityType."); + if (!$id) return null; + if (!$link) throw new Error("Formula record\\unrelate: Empty link."); + if (!$foreignId) return null; + + $em = $this->getInjection('entityManager'); + + if (!$em->hasRepository($entityType)) throw new Error("Formula: record\\unrelate: Repository does not exist."); + + $entity = $em->getEntity($entityType, $id); + if (!$entity) return null; + + if (!$em->getRepository($entityType)->isRelated($entity, $link, $foreignId)) + return true; + + return $em->getRepository($entityType)->unrelate($entity, $link, $foreignId); + } +} diff --git a/application/Espo/Resources/metadata/app/currency.json b/application/Espo/Resources/metadata/app/currency.json index 544449ac68..f592f35441 100644 --- a/application/Espo/Resources/metadata/app/currency.json +++ b/application/Espo/Resources/metadata/app/currency.json @@ -163,5 +163,103 @@ "ZAR":"R", "ZWD":"Z$", "BTC":"฿" - } + }, + "list": [ + "AFN", + "AED", + "ALL", + "ANG", + "ARS", + "AUD", + "BAM", + "BGN", + "BHD", + "BND", + "BOB", + "BRL", + "BWP", + "CAD", + "CHF", + "CLP", + "CNY", + "COP", + "CRC", + "CZK", + "DKK", + "DOP", + "DZD", + "EEK", + "EGP", + "EUR", + "FJD", + "GBP", + "GNF", + "HKD", + "HNL", + "HRK", + "HUF", + "IDR", + "ILS", + "INR", + "IRR", + "JMD", + "JOD", + "JPY", + "KES", + "KRW", + "KWD", + "KYD", + "KZT", + "LBP", + "LKR", + "LTL", + "LVL", + "MAD", + "MDL", + "MKD", + "MMK", + "MUR", + "MXN", + "MYR", + "NAD", + "NGN", + "NIO", + "NOK", + "NPR", + "NZD", + "OMR", + "PEN", + "PGK", + "PHP", + "PKR", + "PLN", + "PYG", + "QAR", + "RON", + "RSD", + "RUB", + "SAR", + "SCR", + "SEK", + "SGD", + "SKK", + "SLL", + "SVC", + "THB", + "TND", + "TRY", + "TTD", + "TWD", + "TZS", + "UAH", + "UGX", + "USD", + "UYU", + "UZS", + "VND", + "YER", + "ZAR", + "ZMK", + "ZWD" + ] } \ No newline at end of file diff --git a/application/Espo/Resources/metadata/entityDefs/Settings.json b/application/Espo/Resources/metadata/entityDefs/Settings.json index fa4318b3c7..81338cf3b5 100644 --- a/application/Espo/Resources/metadata/entityDefs/Settings.json +++ b/application/Espo/Resources/metadata/entityDefs/Settings.json @@ -60,8 +60,8 @@ "currencyList": { "type": "multiEnum", "default": ["USD", "EUR"], - "options": ["AED","ANG","ARS","AUD","BAM", "BGN","BHD","BND","BOB","BRL","BWP","CAD","CHF","CLP","CNY","COP","CRC","CZK","DKK","DOP","DZD","EEK","EGP","EUR","FJD","GBP","GNF","HKD","HNL","HRK","HUF","IDR","ILS","INR","IRR","JMD","JOD","JPY","KES","KRW","KWD","KYD","KZT","LBP","LKR","LTL","LVL","MAD","MDL","MKD","MMK","MUR","MXN","MYR","NAD","NGN","NIO","NOK","NPR","NZD","OMR","PEN","PGK","PHP","PKR","PLN","PYG","QAR","RON","RSD","RUB","SAR","SCR","SEK","SGD","SKK","SLL","SVC","THB","TND","TRY","TTD","TWD","TZS","UAH","UGX","USD","UYU","UZS","VND","YER","ZAR","ZMK"], - "required": true + "required": true, + "view": "views/settings/fields/currency-list" }, "defaultCurrency": { "type": "enum", diff --git a/client/src/views/list-with-categories.js b/client/src/views/list-with-categories.js index 46d8bb7f36..48278aa719 100644 --- a/client/src/views/list-with-categories.js +++ b/client/src/views/list-with-categories.js @@ -26,7 +26,7 @@ * these Appropriate Legal Notices must retain the display of the "EspoCRM" word. ************************************************************************/ -Espo.define('views/list-with-categories', 'views/list', function (Dep) { +define('views/list-with-categories', 'views/list', function (Dep) { return Dep.extend({ @@ -124,6 +124,21 @@ Espo.define('views/list-with-categories', 'views/list', function (Dep) { } }, + hasTextFilter: function () { + if (this.collection.where) { + for (var i = 0; i < this.collection.where.length; i++) { + if (this.collection.where[i].type === 'textFilter') { + return true; + break; + } + } + } + if (this.collection.data && this.collection.data.textFilter) { + return true; + } + return false; + }, + hasIsExpandedStoredValue: function () { return this.getStorage().has('state', 'categories-expanded-' + this.scope); }, @@ -263,7 +278,12 @@ Espo.define('views/list-with-categories', 'views/list', function (Dep) { this.$listContainer.removeClass('hidden'); return; } - if (!this.collection.models.length && this.nestedCategoriesCollection && this.nestedCategoriesCollection.models.length) { + if ( + !this.collection.models.length && + this.nestedCategoriesCollection && + this.nestedCategoriesCollection.models.length && + !this.hasTextFilter() + ) { this.$listContainer.addClass('hidden'); } else { this.$listContainer.removeClass('hidden'); @@ -396,27 +416,14 @@ Espo.define('views/list-with-categories', 'views/list', function (Dep) { }, this); }, + applyCategoryToCollection: function () { this.collection.whereFunction = function () { var filter; var isExpanded = this.isExpanded; - var hasTextFilter = false; - if (this.collection.where) { - for (var i = 0; i < this.collection.where.length; i++) { - if (this.collection.where[i].type === 'textFilter') { - hasTextFilter = true; - break; - } - } - } - - if (this.collection.data && this.collection.data.textFilter) { - hasTextFilter = true; - } - - if (!isExpanded && !hasTextFilter) { + if (!isExpanded && !this.hasTextFilter()) { if (this.isCategoryMultiple()) { if (this.currentCategoryId) { filter = { @@ -491,7 +498,7 @@ Espo.define('views/list-with-categories', 'views/list', function (Dep) { actionManageCategories: function () { this.clearView('categories'); this.getRouter().navigate('#' + this.categoryScope, {trigger: true}); - } + }, }); }); diff --git a/client/src/views/settings/fields/currency-list.js b/client/src/views/settings/fields/currency-list.js new file mode 100644 index 0000000000..f39646a2fa --- /dev/null +++ b/client/src/views/settings/fields/currency-list.js @@ -0,0 +1,38 @@ +/************************************************************************ + * This file is part of EspoCRM. + * + * EspoCRM - Open Source CRM application. + * Copyright (C) 2014-2019 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('views/settings/fields/currency-list', 'views/fields/multi-enum', function (Dep) { + + return Dep.extend({ + + setupOptions: function () { + this.params.options = this.getMetadata().get(['app', 'currency', 'list']) || []; + }, + + }); +}); diff --git a/package.json b/package.json index 7d36d3a2e0..895ab05a54 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "espocrm", - "version": "5.7.7", + "version": "5.7.8", "description": "", "main": "index.php", "repository": { diff --git a/tests/integration/Core/BaseTestCase.php b/tests/integration/Core/BaseTestCase.php index e2eedc7c73..346645bebc 100644 --- a/tests/integration/Core/BaseTestCase.php +++ b/tests/integration/Core/BaseTestCase.php @@ -116,8 +116,6 @@ abstract class BaseTestCase extends \PHPUnit\Framework\TestCase protected function setUp() : void { - $this->beforeSetUp(); - $params = array( 'className' => get_class($this), 'dataFile' => $this->dataFile, @@ -126,6 +124,9 @@ abstract class BaseTestCase extends \PHPUnit\Framework\TestCase ); $this->espoTester = new Tester($params); + + $this->beforeSetUp(); + $this->espoTester->initialize(); $this->auth($this->userName, $this->password, null, $this->authenticationMethod); @@ -190,7 +191,7 @@ abstract class BaseTestCase extends \PHPUnit\Framework\TestCase $this->espoTester->setData($data); } - protected function enableFullReset() + protected function fullReset() { $this->espoTester->setParam('fullReset', true); } diff --git a/tests/integration/Core/Tester.php b/tests/integration/Core/Tester.php index 182d624348..f71c2de99b 100644 --- a/tests/integration/Core/Tester.php +++ b/tests/integration/Core/Tester.php @@ -251,15 +251,18 @@ class Tester $fullReset = false; $modifiedTime = filemtime($latestEspoDir . '/application'); - if (!isset($configData['lastModifiedTime']) || $configData['lastModifiedTime'] != $modifiedTime) { + if ($this->getParam('fullReset') || !isset($configData['lastModifiedTime']) || $configData['lastModifiedTime'] != $modifiedTime) { $fullReset = true; $this->saveTestConfigData('lastModifiedTime', $modifiedTime); } if ($fullReset) { Utils::dropTables($configData['database']); - $fileManager->removeInDir($this->installPath); - $fileManager->copy($latestEspoDir, $this->installPath, true); + + //$fileManager->removeInDir($this->installPath); + //$fileManager->copy($latestEspoDir, $this->installPath, true); + shell_exec('rm -rf "' . $this->installPath . '"'); + shell_exec('cp -r "' . $latestEspoDir . '" "' . $this->installPath . '"'); return true; } @@ -301,8 +304,8 @@ class Tester { $applyChanges = false; - if (!empty($this->params['pathToFiles'])) { - $this->getDataLoader()->loadFiles($this->params['pathToFiles']); + if (!empty($this->params['pathToFiles']) && file_exists($this->params['pathToFiles'])) { + $result = $this->getDataLoader()->loadFiles($this->params['pathToFiles']); $this->getApplication(true, true)->runRebuild(); } diff --git a/tests/integration/Espo/Core/Formula/FormulaTest.php b/tests/integration/Espo/Core/Formula/FormulaTest.php index d0d9de22bb..2e8c7983e0 100644 --- a/tests/integration/Espo/Core/Formula/FormulaTest.php +++ b/tests/integration/Espo/Core/Formula/FormulaTest.php @@ -377,4 +377,44 @@ class FormulaTest extends \tests\integration\Core\BaseTestCase $result = $fm->run($script, $lead); $this->assertFalse($result); } + + public function testRecordRelate() + { + $fm = $this->getContainer()->get('formulaManager'); + $em = $this->getContainer()->get('entityManager'); + + $a = $em->createEntity('Account', [ + 'name' => '1', + ]); + $o = $em->createEntity('Opportunity', [ + 'name' => '1', + ]); + + $script = "record\\relate('Account', '".$a->id."', 'opportunities', '".$o->id."')"; + $result = $fm->run($script, $contact); + + $this->assertTrue($result); + $this->assertTrue($em->getRepository('Account')->isRelated($a, 'opportunities', $o)); + } + + public function testRecordUnrelate() + { + $fm = $this->getContainer()->get('formulaManager'); + $em = $this->getContainer()->get('entityManager'); + + $a = $em->createEntity('Account', [ + 'name' => '1', + ]); + $o = $em->createEntity('Opportunity', [ + 'name' => '1', + ]); + + $em->getRepository('Account')->relate($a, 'opportunities', $o); + + $script = "record\\unrelate('Account', '".$a->id."', 'opportunities', '".$o->id."')"; + $result = $fm->run($script, $contact); + + $this->assertTrue($result); + $this->assertFalse($em->getRepository('Account')->isRelated($a, 'opportunities', $o)); + } } diff --git a/tests/integration/Espo/Extension/GeneralTest.php b/tests/integration/Espo/Extension/GeneralTest.php index 86453d5ea8..d9d3d33e39 100644 --- a/tests/integration/Espo/Extension/GeneralTest.php +++ b/tests/integration/Espo/Extension/GeneralTest.php @@ -38,6 +38,11 @@ class GeneralTest extends \tests\integration\Core\BaseTestCase protected $packagePath = 'Extension/General.zip'; + protected function beforeSetUp() + { + $this->fullReset(); + } + public function testUpload() { $fileData = file_get_contents($this->normalizePath($this->packagePath)); @@ -50,8 +55,6 @@ class GeneralTest extends \tests\integration\Core\BaseTestCase $this->assertFileExists('data/upload/extensions/' . $extensionId . 'z'); $this->assertFileExists('data/upload/extensions/' . $extensionId); //directory - $this->enableFullReset(); - return $extensionId; } @@ -75,8 +78,6 @@ class GeneralTest extends \tests\integration\Core\BaseTestCase $this->assertFileNotExists('extension.php'); $this->assertFileNotExists('upgrade.php'); - $this->enableFullReset(); - return $extensionId; } @@ -100,8 +101,6 @@ class GeneralTest extends \tests\integration\Core\BaseTestCase $this->assertFileExists('extension.php'); $this->assertFileExists('upgrade.php'); - $this->enableFullReset(); - return $extensionId; } @@ -124,7 +123,5 @@ class GeneralTest extends \tests\integration\Core\BaseTestCase $this->assertFileExists('vendor/zendframework'); //directory $this->assertFileExists('extension.php'); $this->assertFileExists('upgrade.php'); - - $this->enableFullReset(); } }