mirror of
https://github.com/espocrm/espocrm.git
synced 2026-03-06 13:37:02 +00:00
Compare commits
49 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8199692df7 | ||
|
|
1d3a340d3a | ||
|
|
d664f29388 | ||
|
|
4d0e1af000 | ||
|
|
97ea0c71e1 | ||
|
|
d9fbcda231 | ||
|
|
f4b5cfa5b6 | ||
|
|
4391c7a7ac | ||
|
|
6c14f390f6 | ||
|
|
4a6829cf10 | ||
|
|
2b6c493be5 | ||
|
|
597406f70d | ||
|
|
110e2fbc37 | ||
|
|
3e1fab487a | ||
|
|
c76e34fe81 | ||
|
|
eb922103a8 | ||
|
|
9b946c6a1f | ||
|
|
e2df819e57 | ||
|
|
9b00d50079 | ||
|
|
814f79d53b | ||
|
|
0d6482374e | ||
|
|
427e3d466a | ||
|
|
ae72768f8c | ||
|
|
bd4e92d892 | ||
|
|
afc17ac54c | ||
|
|
52dda066cd | ||
|
|
29bec8fcd6 | ||
|
|
5c4fd344e4 | ||
|
|
e936ad907b | ||
|
|
bc59dab9ec | ||
|
|
48652e35ee | ||
|
|
381a51b836 | ||
|
|
a9f36a352d | ||
|
|
6c8a0bbb66 | ||
|
|
b21b69eed5 | ||
|
|
ef0d3febd8 | ||
|
|
2d6db7570c | ||
|
|
a7804742e7 | ||
|
|
09301e9d7c | ||
|
|
5d10da3b78 | ||
|
|
dcc4cce872 | ||
|
|
02fbc20838 | ||
|
|
6641075043 | ||
|
|
6624b178c0 | ||
|
|
4ec6708cb4 | ||
|
|
f9752eab02 | ||
|
|
3de816e03a | ||
|
|
b854ebab43 | ||
|
|
ffab7c3e6b |
@@ -181,7 +181,7 @@ class Application
|
||||
}
|
||||
}
|
||||
$processList = array_values($processList);
|
||||
if (count($runningCount) >= $maxProcessNumber) {
|
||||
if ($runningCount >= $maxProcessNumber) {
|
||||
$toSkip = true;
|
||||
}
|
||||
if (!$toSkip) {
|
||||
|
||||
@@ -69,7 +69,13 @@ class ClientManager
|
||||
$externalAccountEntity = $this->clientMap[$hash]['externalAccountEntity'];
|
||||
$externalAccountEntity->set('accessToken', $data['accessToken']);
|
||||
$externalAccountEntity->set('tokenType', $data['tokenType']);
|
||||
$this->getEntityManager()->saveEntity($externalAccountEntity, ['isTokenRenewal' => true]);
|
||||
|
||||
$copy = $this->getEntityManager()->getEntity('ExternalAccount', $externalAccountEntity->id);
|
||||
if ($copy) {
|
||||
$copy->set('accessToken', $data['accessToken']);
|
||||
$copy->set('tokenType', $data['tokenType']);
|
||||
$this->getEntityManager()->saveEntity($copy, ['isTokenRenewal' => true]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Formula\Functions\EntityGroup;
|
||||
|
||||
use \Espo\ORM\Entity;
|
||||
use \Espo\Core\Exceptions\Error;
|
||||
|
||||
class GetLinkColumnType extends \Espo\Core\Formula\Functions\Base
|
||||
{
|
||||
protected function init()
|
||||
{
|
||||
$this->addDependency('entityManager');
|
||||
}
|
||||
|
||||
public function process(\StdClass $item)
|
||||
{
|
||||
$args = $item->value ?? [];
|
||||
|
||||
if (!is_array($args)) throw new Error();
|
||||
if (count($args) < 3) throw new Error("Formula: entity\\isRelated: no argument.");
|
||||
|
||||
$link = $this->evaluate($args[0]);
|
||||
$id = $this->evaluate($args[1]);
|
||||
$column = $this->evaluate($args[2]);
|
||||
|
||||
$entityType = $this->getEntity()->getEntityType($entityType);
|
||||
$repository = $this->getInjection('entityManager')->getRepository($entityType);
|
||||
|
||||
return $repository->getRelationColumn($this->getEntity(), $link, $id, $column);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Formula\Functions\StringGroup;
|
||||
|
||||
use \Espo\Core\Exceptions\Error;
|
||||
|
||||
class PosType extends \Espo\Core\Formula\Functions\Base
|
||||
{
|
||||
public function process(\StdClass $item)
|
||||
{
|
||||
$args = $item->value ?? [];
|
||||
|
||||
if (count($args) < 2) throw new Error("Bad arguments passed to function string\\pos.");
|
||||
|
||||
$string = $this->evaluate($args[0]);
|
||||
$needle = $this->evaluate($args[1]);
|
||||
|
||||
if (!is_string($string)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return mb_strpos($string, $needle);
|
||||
}
|
||||
}
|
||||
@@ -300,7 +300,19 @@ class Htmlizer
|
||||
} else {
|
||||
return $context['inverse'] ? $context['inverse']() : '';
|
||||
}
|
||||
}
|
||||
},
|
||||
'ifInArray' => function () {
|
||||
$args = func_get_args();
|
||||
$context = $args[count($args) - 1];
|
||||
|
||||
$array = $args[1] ?? [];
|
||||
|
||||
if (in_array($args[0], $array)) {
|
||||
return $context['fn']();
|
||||
} else {
|
||||
return $context['inverse'] ? $context['inverse']() : '';
|
||||
}
|
||||
},
|
||||
]
|
||||
]);
|
||||
|
||||
|
||||
@@ -356,12 +356,16 @@ class Base
|
||||
if ($relationType == 'belongsTo') {
|
||||
$key = $seed->getRelationParam($link, 'key');
|
||||
|
||||
$aliasName = 'usersTeams' . ucfirst($link);
|
||||
$aliasName = 'usersTeams' . ucfirst($link) . strval(rand(10000, 99999));
|
||||
|
||||
$result['customJoin'] .= "
|
||||
JOIN team_user AS {$aliasName}Middle ON {$aliasName}Middle.user_id = ".$query->toDb($seed->getEntityType()).".".$query->toDb($key)." AND {$aliasName}Middle.deleted = 0
|
||||
JOIN team AS {$aliasName} ON {$aliasName}.deleted = 0 AND {$aliasName}Middle.team_id = {$aliasName}.id
|
||||
";
|
||||
$this->addLeftJoin([
|
||||
'TeamUser',
|
||||
$aliasName . 'Middle',
|
||||
[
|
||||
$aliasName . 'Middle.userId:' => $key,
|
||||
$aliasName . 'Middle.deleted' => false,
|
||||
]
|
||||
], $result);
|
||||
|
||||
$result['whereClause'][] = [
|
||||
$aliasName . 'Middle.teamId' => $idsValue
|
||||
@@ -819,14 +823,23 @@ class Base
|
||||
|
||||
$this->applyAdditional($params, $result);
|
||||
|
||||
if (empty($result['orderBy'])) {
|
||||
$result['orderBy'] = $this->getMetadata()->get(['entityDefs', $this->entityType, 'collection', 'orderBy']);
|
||||
if (empty($result['order']) && !is_array($result['orderBy'])) {
|
||||
$result['order'] = $this->getMetadata()->get(['entityDefs', $this->entityType, 'collection', 'order']) ?? null;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function applyDefaultOrder(array &$result)
|
||||
{
|
||||
$orderBy = $this->getMetadata()->get(['entityDefs', $this->entityType, 'collection', 'orderBy']);
|
||||
$order = $result['order'] ?? null;
|
||||
|
||||
if (!$order && !is_array($orderBy)) {
|
||||
$order = $this->getMetadata()->get(['entityDefs', $this->entityType, 'collection', 'order']) ?? null;
|
||||
}
|
||||
|
||||
return $result;
|
||||
if ($orderBy) {
|
||||
$this->applyOrder($orderBy, $order, $result);
|
||||
} else {
|
||||
$result['order'] = $order;
|
||||
}
|
||||
}
|
||||
|
||||
public function checkWhere(array $where, bool $checkWherePermission = true, bool $forbidComplexExpressions = false)
|
||||
@@ -1624,11 +1637,12 @@ class Base
|
||||
break;
|
||||
|
||||
case 'isNotLinked':
|
||||
if (!$result) break;
|
||||
$alias = $attribute . 'IsNotLinkedFilter' . strval(rand(10000, 99999));
|
||||
$part[$alias . '.id'] = null;
|
||||
$this->setDistinct(true, $result);
|
||||
$this->addLeftJoin([$attribute, $alias], $result);
|
||||
$part['id!=s'] = [
|
||||
'selectParams' => [
|
||||
'select' => ['id'],
|
||||
'joins' => [$attribute],
|
||||
]
|
||||
];
|
||||
break;
|
||||
|
||||
case 'isLinked':
|
||||
@@ -1718,6 +1732,8 @@ class Base
|
||||
case 'arrayNoneOf':
|
||||
case 'arrayIsEmpty':
|
||||
case 'arrayIsNotEmpty':
|
||||
if (!$result) break;
|
||||
|
||||
$arrayValueAlias = 'arrayFilter' . strval(rand(10000, 99999));
|
||||
$arrayAttribute = $attribute;
|
||||
$arrayEntityType = $this->getEntityType();
|
||||
@@ -1727,7 +1743,16 @@ class Base
|
||||
list($arrayAttributeLink, $arrayAttribute) = explode('.', $attribute);
|
||||
$seed = $this->getSeed();
|
||||
$arrayEntityType = $seed->getRelationParam($arrayAttributeLink, 'entity');
|
||||
$idPart = $arrayAttributeLink . '.id';
|
||||
|
||||
$arrayLinkAlias = $arrayAttributeLink . 'Filter' . strval(rand(10000, 99999));
|
||||
$idPart = $arrayLinkAlias . '.id';
|
||||
|
||||
$this->addLeftJoin([$arrayAttributeLink, $arrayLinkAlias], $result);
|
||||
|
||||
$relationType = $seed->getRelationType($arrayAttributeLink);
|
||||
if ($relationType === 'manyMany' || $relationType === 'hasMany') {
|
||||
$this->setDistinct(true, $result);
|
||||
}
|
||||
}
|
||||
|
||||
if ($type === 'arrayAnyOf') {
|
||||
|
||||
@@ -71,7 +71,7 @@ class Output
|
||||
echo $data;
|
||||
}
|
||||
|
||||
public function processError(string $message = 'Error', int $statusCode = 500, bool $toPrint = false, $exception = null)
|
||||
public function processError(string $message = 'Error', $statusCode = 500, bool $toPrint = false, $exception = null)
|
||||
{
|
||||
$currentRoute = $this->getSlim()->router()->getCurrentRoute();
|
||||
|
||||
@@ -99,7 +99,7 @@ class Output
|
||||
$this->displayError($message, $statusCode, $toPrint, $exception);
|
||||
}
|
||||
|
||||
public function displayError(string $text, int $statusCode = 500, bool $toPrint = false, $exception = null)
|
||||
public function displayError(string $text, $statusCode = 500, bool $toPrint = false, $exception = null)
|
||||
{
|
||||
$logLevel = 'error';
|
||||
$messageLineFile = null;
|
||||
|
||||
@@ -560,14 +560,23 @@ class Converter
|
||||
|
||||
protected function applyIndexes(&$ormMetadata, $entityType)
|
||||
{
|
||||
if (!isset($ormMetadata[$entityType]['indexes'])) {
|
||||
return;
|
||||
if (isset($ormMetadata[$entityType]['indexes'])) {
|
||||
foreach ($ormMetadata[$entityType]['indexes'] as $indexName => &$indexData) {
|
||||
if (!isset($indexData['key'])) {
|
||||
$indexType = SchemaUtils::getIndexTypeByIndexDefs($indexData);
|
||||
$indexData['key'] = SchemaUtils::generateIndexName($indexName, $indexType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($ormMetadata[$entityType]['indexes'] as $indexName => &$indexData) {
|
||||
if (!isset($indexData['key'])) {
|
||||
$indexType = SchemaUtils::getIndexTypeByIndexDefs($indexData);
|
||||
$indexData['key'] = SchemaUtils::generateIndexName($indexName, $indexType);
|
||||
if (isset($ormMetadata[$entityType]['relations'])) {
|
||||
foreach ($ormMetadata[$entityType]['relations'] as $relationName => &$relationData) {
|
||||
if (isset($relationData['indexes'])) {
|
||||
foreach ($relationData['indexes'] as $indexName => &$indexData) {
|
||||
$indexType = SchemaUtils::getIndexTypeByIndexDefs($indexData);
|
||||
$indexData['key'] = SchemaUtils::generateIndexName($indexName, $indexType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,13 +31,13 @@ namespace Espo\Core\Utils\Database\Orm\Relations;
|
||||
|
||||
class EntityTeam extends Base
|
||||
{
|
||||
protected function load($linkName, $entityName)
|
||||
protected function load($linkName, $entityType)
|
||||
{
|
||||
$linkParams = $this->getLinkParams();
|
||||
$foreignEntityName = $this->getForeignEntityName();
|
||||
|
||||
return [
|
||||
$entityName => [
|
||||
$entityType => [
|
||||
'relations' => [
|
||||
$linkName => [
|
||||
'type' => 'manyMany',
|
||||
@@ -45,21 +45,21 @@ class EntityTeam extends Base
|
||||
'relationName' => lcfirst($linkParams['relationName']),
|
||||
'midKeys' => [
|
||||
'entityId',
|
||||
'teamId'
|
||||
'teamId',
|
||||
],
|
||||
'conditions' => [
|
||||
'entityType' => $entityName
|
||||
'entityType' => $entityType,
|
||||
],
|
||||
'additionalColumns' => [
|
||||
'entityType' => [
|
||||
'type' => 'varchar',
|
||||
'len' => 100
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
'len' => 100,
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -340,7 +340,8 @@ class Converter
|
||||
}
|
||||
|
||||
if (!empty($uniqueIndex)) {
|
||||
$table->addUniqueIndex($uniqueIndex, SchemaUtils::generateIndexName($columnName, 'unique'));
|
||||
$uniqueIndexName = implode('_', $uniqueIndex);
|
||||
$table->addUniqueIndex($uniqueIndex, SchemaUtils::generateIndexName($uniqueIndexName, 'unique'));
|
||||
}
|
||||
//END: add unique indexes
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ class Utils
|
||||
if (isset($entityParams['indexes']) && is_array($entityParams['indexes'])) {
|
||||
foreach ($entityParams['indexes'] as $indexName => $indexParams) {
|
||||
$indexType = static::getIndexTypeByIndexDefs($indexParams);
|
||||
$tableIndexName = static::generateIndexName($indexName, $indexType);
|
||||
$tableIndexName = isset($indexParams['key']) ? $indexParams['key'] : static::generateIndexName($indexName, $indexType);
|
||||
|
||||
if (isset($indexParams['flags']) && is_array($indexParams['flags'])) {
|
||||
$skipIndex = false;
|
||||
|
||||
@@ -50,7 +50,7 @@ class EntityManager
|
||||
|
||||
private $container;
|
||||
|
||||
private $reservedWordList = ['__halt_compiler', 'abstract', 'and', 'array', 'as', 'break', 'callable', 'case', 'catch', 'class', 'clone', 'const', 'continue', 'declare', 'default', 'die', 'do', 'echo', 'else', 'elseif', 'empty', 'enddeclare', 'endfor', 'endforeach', 'endif', 'endswitch', 'endwhile', 'eval', 'exit', 'extends', 'final', 'for', 'foreach', 'function', 'global', 'goto', 'if', 'implements', 'include', 'include_once', 'instanceof', 'insteadof', 'interface', 'isset', 'list', 'namespace', 'new', 'or', 'print', 'private', 'protected', 'public', 'require', 'require_once', 'return', 'static', 'switch', 'throw', 'trait', 'try', 'unset', 'use', 'var', 'while', 'xor', 'common'];
|
||||
private $reservedWordList = ['__halt_compiler', 'abstract', 'and', 'array', 'as', 'break', 'callable', 'case', 'catch', 'class', 'clone', 'const', 'continue', 'declare', 'default', 'die', 'do', 'echo', 'else', 'elseif', 'empty', 'enddeclare', 'endfor', 'endforeach', 'endif', 'endswitch', 'endwhile', 'eval', 'exit', 'extends', 'final', 'for', 'foreach', 'function', 'global', 'goto', 'if', 'implements', 'include', 'include_once', 'instanceof', 'insteadof', 'interface', 'isset', 'list', 'namespace', 'new', 'or', 'print', 'private', 'protected', 'public', 'require', 'require_once', 'return', 'static', 'switch', 'throw', 'trait', 'try', 'unset', 'use', 'var', 'while', 'xor', 'common', 'fn'];
|
||||
|
||||
private $linkForbiddenNameList = ['posts', 'stream', 'subscription', 'followers', 'action', 'null', 'false', 'true'];
|
||||
|
||||
|
||||
@@ -57,9 +57,9 @@ return [
|
||||
'outboundEmailFromName' => 'EspoCRM',
|
||||
'outboundEmailFromAddress' => '',
|
||||
'smtpServer' => '',
|
||||
'smtpPort' => 25,
|
||||
'smtpPort' => 587,
|
||||
'smtpAuth' => true,
|
||||
'smtpSecurity' => '',
|
||||
'smtpSecurity' => 'TLS',
|
||||
'smtpUsername' => '',
|
||||
'smtpPassword' => '',
|
||||
'languageList' => [
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace Espo\Entities;
|
||||
|
||||
class Integration extends \Espo\Core\ORM\Entity
|
||||
{
|
||||
public function get($name, $params = array())
|
||||
public function get($name, $params = [])
|
||||
{
|
||||
if ($name == 'id') {
|
||||
return $this->id;
|
||||
@@ -100,6 +100,13 @@ class Integration extends \Espo\Core\ORM\Entity
|
||||
}
|
||||
}
|
||||
|
||||
public function isAttributeChanged($name)
|
||||
{
|
||||
if ($name === 'data') return true;
|
||||
|
||||
return parent::isAttributeChanged($name);
|
||||
}
|
||||
|
||||
public function populateFromArray(array $arr, $onlyAccessible = true, $reset = false)
|
||||
{
|
||||
if ($reset) {
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
"dateEnd": {
|
||||
"type": "datetime",
|
||||
"required": true,
|
||||
"view": "crm:views/call/fields/date-end",
|
||||
"after": "dateStart"
|
||||
},
|
||||
"duration": {
|
||||
|
||||
@@ -438,6 +438,59 @@ abstract class Mapper implements IMapper
|
||||
}
|
||||
}
|
||||
|
||||
public function getRelationColumn(IEntity $entity, string $relationName, string $id, string $column)
|
||||
{
|
||||
$type = $entity->getRelationType($entityType, $relationName);
|
||||
|
||||
if (!$type === IEntity::MANY_MANY) return null;
|
||||
|
||||
$relDefs = $entity->relations[$relationName];
|
||||
|
||||
$relTable = $this->toDb($relDefs['relationName']);
|
||||
|
||||
$keySet = $this->query->getKeys($entity, $relationName);
|
||||
$key = $keySet['key'];
|
||||
$foreignKey = $keySet['foreignKey'];
|
||||
$nearKey = $keySet['nearKey'];
|
||||
$distantKey = $keySet['distantKey'];
|
||||
|
||||
$additionalColumns = $entity->getRelationParam($relationName, 'additionalColumns') ?? [];
|
||||
|
||||
if (!isset($additionalColumns[$column])) return null;
|
||||
|
||||
$columnType = $additionalColumns[$column]['type'] ?? 'string';
|
||||
|
||||
$columnAlias = $this->query->sanitizeSelectAlias($column);
|
||||
|
||||
$sql =
|
||||
"SELECT " . $this->toDb($this->query->sanitize($column)) . " AS `{$columnAlias}` FROM `{$relTable}` " .
|
||||
"WHERE ";
|
||||
|
||||
$wherePart =
|
||||
$this->toDb($nearKey) . " = " . $this->pdo->quote($entity->id) . " ".
|
||||
"AND " . $this->toDb($distantKey) . " = " . $this->pdo->quote($id) . " AND deleted = 0";
|
||||
|
||||
$sql .= $wherePart;
|
||||
|
||||
$ps = $this->pdo->query($sql);
|
||||
if ($ps) {
|
||||
foreach ($ps as $row) {
|
||||
$value = $row[$columnAlias];
|
||||
if ($columnType == 'bool') {
|
||||
$value = boolval($value);
|
||||
} else if ($columnType == 'int') {
|
||||
$value = intval($value);
|
||||
} else if ($columnType == 'float') {
|
||||
$value = floatval($value);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function massRelate(IEntity $entity, $relationName, array $params = [])
|
||||
{
|
||||
if (!$entity) {
|
||||
|
||||
@@ -57,7 +57,7 @@ abstract class Base
|
||||
'customHaving',
|
||||
'skipTextColumns',
|
||||
'maxTextColumnsLength',
|
||||
'useIndexList',
|
||||
'useIndex',
|
||||
];
|
||||
|
||||
protected static $sqlOperators = [
|
||||
@@ -310,13 +310,15 @@ abstract class Base
|
||||
|
||||
if (!empty($params['additionalColumns']) && is_array($params['additionalColumns']) && !empty($params['relationName'])) {
|
||||
foreach ($params['additionalColumns'] as $column => $field) {
|
||||
$selectPart .= ", `" . $this->toDb($this->sanitize($params['relationName'])) . "`." . $this->toDb($this->sanitize($column)) . " AS `{$field}`";
|
||||
$itemAlias = $this->sanitizeSelectAlias($field);
|
||||
$selectPart .= ", `" . $this->toDb($this->sanitize($params['relationName'])) . "`." . $this->toDb($this->sanitize($column)) . " AS `{$itemAlias}`";
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($params['additionalSelectColumns']) && is_array($params['additionalSelectColumns'])) {
|
||||
foreach ($params['additionalSelectColumns'] as $column => $field) {
|
||||
$selectPart .= ", " . $column . " AS `{$field}`";
|
||||
$itemAlias = $this->sanitizeSelectAlias($field);
|
||||
$selectPart .= ", " . $column . " AS `{$itemAlias}`";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -384,9 +386,14 @@ abstract class Base
|
||||
}
|
||||
|
||||
$indexKeyList = null;
|
||||
if (!empty($params['useIndexList']) && $this->metadata) {
|
||||
$indexList = $params['useIndex'] ?? null;
|
||||
|
||||
if (!empty($indexList) && $this->metadata) {
|
||||
$indexKeyList = [];
|
||||
foreach ($params['useIndexList'] as $indexName) {
|
||||
if (is_string($indexList)) {
|
||||
$indexList = [$indexList];
|
||||
}
|
||||
foreach ($indexList as $indexName) {
|
||||
$indexKey = $this->metadata->get($entityType, ['indexes', $indexName, 'key']);
|
||||
if ($indexKey) {
|
||||
$indexKeyList[] = $indexKey;
|
||||
@@ -864,7 +871,7 @@ abstract class Base
|
||||
$part = str_replace('{alias}', $alias, $part);
|
||||
}
|
||||
} else {
|
||||
$part = $this->toDb($entity->getEntityType()) . '.' . $this->toDb($attribute);
|
||||
$part = $this->toDb($entity->getEntityType()) . '.' . $this->toDb($this->sanitize($attribute));
|
||||
if ($type === 'orderBy') {
|
||||
$part .= ' {direction}';
|
||||
}
|
||||
@@ -1019,6 +1026,8 @@ abstract class Base
|
||||
|
||||
if (!$alias) {
|
||||
$alias = $this->getAlias($entity, $relationName);
|
||||
} else {
|
||||
$alias = $this->sanitizeSelectAlias($alias);
|
||||
}
|
||||
|
||||
if ($alias) {
|
||||
@@ -1613,14 +1622,19 @@ abstract class Base
|
||||
protected function getJoins(IEntity $entity, array $joins, $isLeft = false, $joinConditions = [])
|
||||
{
|
||||
$joinSqlList = [];
|
||||
|
||||
foreach ($joins as $item) {
|
||||
$itemConditions = [];
|
||||
$params = [];
|
||||
if (is_array($item)) {
|
||||
$relationName = $item[0];
|
||||
if (count($item) > 1) {
|
||||
$alias = $item[1];
|
||||
$alias = $item[1] ?? $relationName;
|
||||
if (count($item) > 2) {
|
||||
$itemConditions = $item[2];
|
||||
$itemConditions = $item[2] ?? [];
|
||||
}
|
||||
if (count($item) > 3) {
|
||||
$params = $item[3] ?? [];
|
||||
}
|
||||
} else {
|
||||
$alias = $relationName;
|
||||
@@ -1636,7 +1650,7 @@ abstract class Base
|
||||
foreach ($itemConditions as $left => $right) {
|
||||
$conditions[$left] = $right;
|
||||
}
|
||||
if ($sql = $this->getJoin($entity, $relationName, $isLeft, $conditions, $alias)) {
|
||||
if ($sql = $this->getJoin($entity, $relationName, $isLeft, $conditions, $alias, $params)) {
|
||||
$joinSqlList[] = $sql;
|
||||
}
|
||||
}
|
||||
@@ -1752,13 +1766,15 @@ abstract class Base
|
||||
}
|
||||
}
|
||||
|
||||
protected function getJoin(IEntity $entity, $name, $isLeft = false, $conditions = [], $alias = null)
|
||||
protected function getJoin(IEntity $entity, $name, $isLeft = false, $conditions = [], $alias = null, array $params = [])
|
||||
{
|
||||
$prefix = ($isLeft) ? 'LEFT ' : '';
|
||||
|
||||
if (!$entity->hasRelation($name)) {
|
||||
if (!$alias) {
|
||||
$alias = $this->sanitize($name);
|
||||
} else {
|
||||
$alias = $this->sanitizeSelectAlias($alias);
|
||||
}
|
||||
$table = $this->toDb($this->sanitize($name));
|
||||
|
||||
@@ -1808,8 +1824,34 @@ abstract class Base
|
||||
|
||||
$midAlias = $alias . 'Middle';
|
||||
|
||||
$indexKeyList = null;
|
||||
$indexList = $params['useIndex'] ?? null;
|
||||
|
||||
if ($indexList && $this->metadata) {
|
||||
$indexKeyList = [];
|
||||
if (is_string($indexList)) {
|
||||
$indexList = [$indexList];
|
||||
}
|
||||
foreach ($indexList as $indexName) {
|
||||
$indexKey = $this->metadata->get($entity->getEntityType(), ['relations', $relationName, 'indexes', $indexName, 'key']);
|
||||
if ($indexKey) {
|
||||
$indexKeyList[] = $indexKey;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$indexPart = '';
|
||||
|
||||
if ($indexKeyList && count($indexKeyList)) {
|
||||
$sanitizedIndexList = [];
|
||||
foreach ($indexKeyList as $indexKey) {
|
||||
$sanitizedIndexList[] = '`' . $this->sanitizeIndexName($indexKey) . '`';
|
||||
}
|
||||
$indexPart = " USE INDEX (".implode(', ', $sanitizedIndexList).")";
|
||||
}
|
||||
|
||||
$sql =
|
||||
"{$prefix}JOIN `{$relTable}` AS `{$midAlias}` ON {$this->toDb($entity->getEntityType())}." . $this->toDb($key) . " = {$midAlias}." . $this->toDb($nearKey)
|
||||
"{$prefix}JOIN `{$relTable}` AS `{$midAlias}`{$indexPart} ON {$this->toDb($entity->getEntityType())}." . $this->toDb($key) . " = {$midAlias}." . $this->toDb($nearKey)
|
||||
. " AND "
|
||||
. "{$midAlias}.deleted = " . $this->pdo->quote(0);
|
||||
|
||||
@@ -1821,9 +1863,13 @@ abstract class Base
|
||||
$sql .= " AND " . implode(" AND ", $joinSqlList);
|
||||
}
|
||||
|
||||
$sql .= " {$prefix}JOIN `{$distantTable}` AS `{$alias}` ON {$alias}." . $this->toDb($foreignKey) . " = {$midAlias}." . $this->toDb($distantKey)
|
||||
. " AND "
|
||||
. "{$alias}.deleted = " . $this->pdo->quote(0) . "";
|
||||
$onlyMiddle = $params['onlyMiddle'] ?? false;
|
||||
|
||||
if (!$onlyMiddle) {
|
||||
$sql .= " {$prefix}JOIN `{$distantTable}` AS `{$alias}` ON {$alias}." . $this->toDb($foreignKey) . " = {$midAlias}." . $this->toDb($distantKey)
|
||||
. " AND "
|
||||
. "{$alias}.deleted = " . $this->pdo->quote(0) . "";
|
||||
}
|
||||
|
||||
return $sql;
|
||||
|
||||
|
||||
@@ -396,6 +396,11 @@ class RDB extends \Espo\ORM\Repository
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getRelationColumn(Entity $entity, string $relationName, string $foreignId, string $column)
|
||||
{
|
||||
return $this->getMapper()->getRelationColumn($entity, $relationName, $foreignId, $column);
|
||||
}
|
||||
|
||||
protected function beforeRelate(Entity $entity, $relationName, $foreign, $data = null, array $options = [])
|
||||
{
|
||||
}
|
||||
|
||||
@@ -188,6 +188,7 @@
|
||||
"inlineEditDisabled": "Disable Inline Edit",
|
||||
"allowCustomOptions": "Allow Custom Options",
|
||||
"displayAsLabel": "Display as Label",
|
||||
"displayAsList": "Display as List",
|
||||
"maxCount": "Max Item Count",
|
||||
"accept": "Accept",
|
||||
"displayRawText": "Display raw text (no markdown)"
|
||||
|
||||
@@ -56,7 +56,20 @@
|
||||
"Portal Users": "Usuarios del portal",
|
||||
"Action History": "Histórico",
|
||||
"Label Manager": "Etiquetas",
|
||||
"Permissions": "Permisos"
|
||||
"Auth Log": "Registros de autenticación",
|
||||
"Lead Capture": "Captura de Posible cliente",
|
||||
"Attachments": "Adjuntos",
|
||||
"API Users": "Usuarios de API",
|
||||
"Template Manager": "Gestor de plantillas",
|
||||
"System Requirements": "Requerimientos del sistema",
|
||||
"PHP Settings": "Configuraciones PHP",
|
||||
"Database Settings": "Configuraciones de la Base de Datos",
|
||||
"Permissions": "Permisos",
|
||||
"Success": "Éxito",
|
||||
"Fail": "Falló",
|
||||
"is recommended": "es recomendado",
|
||||
"extension is missing": "no se encuentra la extensión",
|
||||
"PDF Templates": "Plantillas PDF"
|
||||
},
|
||||
"layouts": {
|
||||
"list": "Lista",
|
||||
@@ -159,8 +172,7 @@
|
||||
"installExtension": "La extensión {name} {version} está lista para ser instalada.",
|
||||
"upgradeBackup": "Recomendamos hacer una copia de seguridad de los archivos y datos de EspoCRM antes de actualizar.",
|
||||
"thousandSeparatorEqualsDecimalMark": "El símbolo de separador de miles no puede ser el mismo que el de punto decimal.",
|
||||
"userHasNoEmailAddress": "El usuario no tiene dirección de correo electrónico.",
|
||||
"newVersionIsAvailable": "La nueva versión de EspoCRM {latestVersion} está disponible."
|
||||
"userHasNoEmailAddress": "El usuario no tiene dirección de correo electrónico."
|
||||
},
|
||||
"descriptions": {
|
||||
"settings": "Ajustes generales del sistema.",
|
||||
@@ -191,7 +203,17 @@
|
||||
"entityManager": "Crear y editar entidades personalizadas. Administrar campos y relaciones.",
|
||||
"emailFilters": "Filtros para los correos entrantes.",
|
||||
"actionHistory": "Registro de las acciones del usuario.",
|
||||
"labelManager": "Personaliza las etiquetas de las aplicaciones."
|
||||
"labelManager": "Personaliza las etiquetas de las aplicaciones.",
|
||||
"authLog": "Historial de acceso.",
|
||||
"leadCapture": "Puntos de acceso al API para Web-to-Lead.",
|
||||
"attachments": "Todos los archivos adjuntos almacenados en el sistema.",
|
||||
"templateManager": "Personalice las plantillas de mensajes.",
|
||||
"systemRequirements": "Requerimientos del sistema para EspoCRM.",
|
||||
"apiUsers": "Usuarios separados para propósitos de integraciones.",
|
||||
"jobs": "Los trabajos que ejecutan tareas en segundo plano.",
|
||||
"pdfTemplates": "Plantillas para impresión en PDF.",
|
||||
"webhooks": "Administre webhooks.",
|
||||
"dashboardTemplates": "Implemente paneles para los usuarios."
|
||||
},
|
||||
"options": {
|
||||
"previewSize": {
|
||||
|
||||
@@ -328,14 +328,14 @@
|
||||
},
|
||||
"notificationMessages": {
|
||||
"assign": "{entityType} {entity} ha sido asignado a usted",
|
||||
"emailReceived": "Correo recibido de: <strong>{from}</strong>.",
|
||||
"entityRemoved": "{user} ha eliminado: <strong>[{entityType}]</strong> {entity}"
|
||||
"emailReceived": "Correo recibido de: {from}",
|
||||
"entityRemoved": "{user} ha eliminado: {entityType} {entity}"
|
||||
},
|
||||
"streamMessages": {
|
||||
"post": "{user} ha publicado en: <strong>[{entityType}]</strong> {entity}",
|
||||
"attach": "{user} ha añadido un archivo adjunto en: <strong>[{entityType}]</strong> {entity}",
|
||||
"status": "{user} ha actualizado el campo <strong>{field}</strong> en: <strong>[{entityType}]</strong> {entity}",
|
||||
"update": "{user} ha actualizado: <strong>[{entityType}]</strong> {entity}",
|
||||
"post": "{user} ha publicado en: {entityType} {entity}",
|
||||
"attach": "{user} ha añadido un archivo adjunto en: {entityType} {entity}",
|
||||
"status": "{user} ha actualizado el campo {field} en: {entityType} {entity}",
|
||||
"update": "{user} ha actualizado: {entityType} {entity}",
|
||||
"postTargetTeam": "{user} ha publicado en el equipo {target}",
|
||||
"postTargetTeams": "{user} ha publicado en los equipos {target}",
|
||||
"postTargetPortal": "{user} ha publicado en el portal {target}",
|
||||
@@ -344,47 +344,47 @@
|
||||
"postTargetYou": "{user} ha publicado pora usted",
|
||||
"postTargetYouAndOthers": "{user} ha publicado para {target} y para usted",
|
||||
"postTargetAll": "{user} ha publicado para todos",
|
||||
"mentionInPost": "{user} ha mencionado a {mentioned} en: <strong>[{entityType}]</strong> {entity}",
|
||||
"mentionYouInPost": "{user} te ha mencionado en: <strong>[{entityType}]</strong> {entity}",
|
||||
"mentionInPost": "{user} ha mencionado a {mentioned} en: {entityType} {entity}",
|
||||
"mentionYouInPost": "{user} te ha mencionado en: {entityType} {entity}",
|
||||
"mentionInPostTarget": "{user} ha mencionado a {mentioned} en la publicación",
|
||||
"mentionYouInPostTarget": "{user} te ha mencionado en la publicación para {target}",
|
||||
"mentionYouInPostTargetAll": "{user} te ha mencionado en una publicación para todos",
|
||||
"mentionYouInPostTargetNoTarget": "{user} te ha mencionado en una publicación",
|
||||
"create": "{user} ha creado: <strong>[{entityType}]</strong> {entity}",
|
||||
"createThis": "{user} ha creado: <strong>{entityType}</strong>",
|
||||
"create": "{user} ha creado: {entityType} {entity}",
|
||||
"createThis": "{user} ha creado: {entityType}",
|
||||
"createAssignedThis": "{user} ha creado y se lo ha asignado a {assignee}: {entityType}",
|
||||
"createAssigned": "{user} ha creado y se lo ha asignado a {assignee}: <strong>[{entityType}]</strong> {entity}",
|
||||
"assign": "{user} ha asignado: <strong>[{entityType}]</strong> {entity} a {assignee}",
|
||||
"createAssigned": "{user} ha creado y se lo ha asignado a {assignee}: {entityType} {entity}",
|
||||
"assign": "{user} ha asignado: {entityType} {entity} a {assignee}",
|
||||
"assignThis": "{user} ha asignado {entityType} a {assignee}",
|
||||
"postThis": "{user} ha publicado",
|
||||
"attachThis": "{user} ha adjuntado",
|
||||
"statusThis": "{user} ha actualizado el campo <strong>{field}</strong>",
|
||||
"statusThis": "{user} ha actualizado el campo {field}",
|
||||
"updateThis": "{user} ha actualizado: {entityType}",
|
||||
"createRelatedThis": "{user} ha creado: <strong>[{relatedEntityType}]</strong> {relatedEntity}, enlazado a {entityType}",
|
||||
"createRelated": "{user} ha creado: <strong>[{relatedEntityType}]</strong> {relatedEntity} enlazado a <strong>[{entityType}]</strong> {entity}",
|
||||
"relate": "{user} ha enlazado <strong>[{relatedEntityType}]</strong> {relatedEntity} a <strong>[{entityType}] {entity}",
|
||||
"createRelatedThis": "{user} ha creado: {relatedEntityType} {relatedEntity}, enlazado a {entityType}",
|
||||
"createRelated": "{user} ha creado: {relatedEntityType} {relatedEntity} enlazado a {entityType} {entity}",
|
||||
"relate": "{user} ha enlazado {relatedEntityType} {relatedEntity} a {entityType} {entity}",
|
||||
"relateThis": "{user} vinculado {relatedEntityType} {relatedEntity} con este {entityType}",
|
||||
"emailReceivedFromThis": "Correo recibido de: <strong>{from}</strong>.",
|
||||
"emailReceivedFromThis": "Correo recibido de: {from}",
|
||||
"emailReceivedInitialFromThis": "Correo recibido de {from}, se ha creado: {entityType}",
|
||||
"emailReceivedThis": "Correo recibido",
|
||||
"emailReceivedInitialThis": "Correo recibido, se ha creado: {entityType}",
|
||||
"emailReceivedFrom": "Correo recibido de {from}, relacionado a: <strong>[{entityType}]</strong> {entity}",
|
||||
"emailReceivedFromInitial": "Correo recibido de {from}, se ha creado: <strong>[{entityType}]<strong>\n {entityType}",
|
||||
"emailReceivedInitialFrom": "Correo recibido de {from}, se ha creado: <strong>[{entityType}]<strong>\n {entityType}",
|
||||
"emailReceivedFrom": "Correo recibido de {from}, relacionado a: {entityType} {entity}",
|
||||
"emailReceivedFromInitial": "Correo recibido de {from}, se ha creado: {entityType} {entityType}",
|
||||
"emailReceivedInitialFrom": "Correo recibido de {from}, se ha creado: {entityType} {entityType}",
|
||||
"emailReceived": "El correo {email} ha sido recibido para el {entityType} {entity}",
|
||||
"emailReceivedInitial": "Correo recibido, se ha creado: <strong>[{entityType}]<strong>\n {entityType}",
|
||||
"emailSent": "{by} ha enviado un correo relacionado a: <strong>[{entityType}]</strong> {entity}",
|
||||
"emailReceivedInitial": "Correo recibido, se ha creado: {entityType} {entityType}",
|
||||
"emailSent": "{by} ha enviado un correo relacionado a: {entityType} {entity}",
|
||||
"emailSentThis": "{by} ha enviado un correo",
|
||||
"postTargetSelf": "{user} se ha enviado un mensaje a sí mismo",
|
||||
"postTargetSelfAndOthers": "{user} ha publicado para {target} y para sí mismo",
|
||||
"createAssignedYou": "{user} ha creado y te lo ha asignado: <strong>[{entityType}]</strong> {entity}",
|
||||
"createAssignedYou": "{user} ha creado y te lo ha asignado: {entityType} {entity}",
|
||||
"createAssignedThisSelf": "{user} ha creado y se ha asignado a sí mismo: {entityType}",
|
||||
"createAssignedSelf": "{user} ha creado y se ha asignado a sí mismo: <strong>[{entityType}]</strong> {entity}",
|
||||
"assignYou": "{user} te ha asignado <strong>[{entityType}]<strong> {entity} a ti",
|
||||
"createAssignedSelf": "{user} ha creado y se ha asignado a sí mismo: {entityType} {entity}",
|
||||
"assignYou": "{user} te ha asignado {entityType} {entity} a ti",
|
||||
"assignThisVoid": "{user} ha desasignado: {entityType}",
|
||||
"assignVoid": "{user} ha desasignado: <strong>[{entityType}]</strong> {entity}",
|
||||
"assignVoid": "{user} ha desasignado: {entityType} {entity}",
|
||||
"assignThisSelf": "{user} se ha asignado así mismo: {entityType}",
|
||||
"assignSelf": "{user} se ha asignado así mismo: <strong>[{entityType}]</strong> {entity}"
|
||||
"assignSelf": "{user} se ha asignado así mismo: {entityType} {entity}"
|
||||
},
|
||||
"lists": {
|
||||
"monthNames": [
|
||||
|
||||
@@ -147,7 +147,6 @@
|
||||
"upgradeBackup": "We adviseren om eerst een backup te maken van uw EspoCRM bestanden en data, alvorens te upgraden.",
|
||||
"thousandSeparatorEqualsDecimalMark": "Het duizendtal scheidingsteken mag niet hetzelfde zijn als het decimaalteken.",
|
||||
"userHasNoEmailAddress": "Gebruiker heeft geen emailadres.",
|
||||
"newVersionIsAvailable": "Nieuwe EspoCRM-versie {latestVersion} is beschikbaar.",
|
||||
"uninstallConfirmation": "Weet je zeker dat je de extensie wilt verwijderen?",
|
||||
"cronIsNotConfigured": "Geplande taken zijn niet actief. Vandaar dat inkomende e-mails, meldingen en herinneringen niet werken. Volg de [instructies] (https://www.espocrm.com/documentation/administration/server-configuration/#user-content-setup-a-crontab) om cron-taak in te stellen.",
|
||||
"newExtensionVersionIsAvailable": "Nieuwe versie {extensionName} {latestVersion} is beschikbaar.",
|
||||
|
||||
@@ -184,10 +184,9 @@
|
||||
"upgradeBackup": "Перед обновлением рекомендуется сделать резервную копию ваших файлов и данных EspoCRM.",
|
||||
"thousandSeparatorEqualsDecimalMark": "Разделитель тысячных не может быть таким же, как разделитель десятичных.",
|
||||
"userHasNoEmailAddress": "У пользователя нет адреса эл. почты.",
|
||||
"newVersionIsAvailable": "Новая версия EspoCRM {latestVersion} доступна.",
|
||||
"uninstallConfirmation": "Вы действительно хотите удалить расширение?",
|
||||
"cronIsNotConfigured": "Запланированные задания не выполняются. Следовательно, входящие письма, уведомления и напоминания не работают. Пожалуйста, следуйте инструкциям [https://www.espocrm.com/documentation/administration/server-configuration/#user-content-setup-a-crontab) для установки cron job.",
|
||||
"newExtensionVersionIsAvailable": "Новая {extensionName} версия {lastVersion} доступна."
|
||||
"newExtensionVersionIsAvailable": "Новая {extensionName} версия {latestVersion} доступна."
|
||||
},
|
||||
"descriptions": {
|
||||
"settings": "Системные настройки.",
|
||||
|
||||
@@ -1,18 +1,21 @@
|
||||
[
|
||||
{
|
||||
"label":"",
|
||||
"rows":[
|
||||
"columns": [
|
||||
[
|
||||
{
|
||||
"name":"from",
|
||||
"view": "views/email/fields/compose-from-address"
|
||||
},
|
||||
{"name":"cc"}
|
||||
{"name":"to"}
|
||||
],
|
||||
[
|
||||
{"name":"to"},
|
||||
{"name":"cc"},
|
||||
{"name":"bcc"}
|
||||
],
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"rows": [
|
||||
[
|
||||
{
|
||||
"name": "parent"
|
||||
@@ -22,9 +25,9 @@
|
||||
"view":"views/email/fields/select-template"
|
||||
}
|
||||
],
|
||||
[{"name":"subject","fullWidth":true}],
|
||||
[{"name":"body","fullWidth":true}],
|
||||
[{"name":"attachments"},{"name":"isHtml"}]
|
||||
[{"name":"subject","fullWidth": true}],
|
||||
[{"name":"body","fullWidth": true}],
|
||||
[{"name":"attachments"}, {"name":"isHtml"} ]
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -92,7 +92,7 @@
|
||||
"type": "int",
|
||||
"min": 0,
|
||||
"max": 9999,
|
||||
"default": 25
|
||||
"default": 587
|
||||
},
|
||||
"smtpAuth": {
|
||||
"type": "bool",
|
||||
@@ -100,6 +100,7 @@
|
||||
},
|
||||
"smtpSecurity": {
|
||||
"type": "enum",
|
||||
"default": "TLS",
|
||||
"options": ["", "SSL", "TLS"]
|
||||
},
|
||||
"smtpUsername": {
|
||||
|
||||
@@ -100,7 +100,7 @@
|
||||
"type": "int",
|
||||
"min": 0,
|
||||
"max": 9999,
|
||||
"default": 25
|
||||
"default": 587
|
||||
},
|
||||
"smtpAuth": {
|
||||
"type": "bool",
|
||||
@@ -108,6 +108,7 @@
|
||||
},
|
||||
"smtpSecurity": {
|
||||
"type": "enum",
|
||||
"default": "TLS",
|
||||
"options": ["", "SSL", "TLS"]
|
||||
},
|
||||
"smtpUsername": {
|
||||
|
||||
@@ -101,7 +101,8 @@
|
||||
"type": "int",
|
||||
"min": 0,
|
||||
"max": 9999,
|
||||
"default": 25
|
||||
"required": true,
|
||||
"default": 587
|
||||
},
|
||||
"smtpAuth": {
|
||||
"type": "bool",
|
||||
@@ -109,6 +110,7 @@
|
||||
},
|
||||
"smtpSecurity": {
|
||||
"type": "enum",
|
||||
"default": "TLS",
|
||||
"options": ["", "SSL", "TLS"]
|
||||
},
|
||||
"smtpUsername": {
|
||||
|
||||
@@ -37,6 +37,10 @@
|
||||
"name":"displayAsLabel",
|
||||
"type":"bool"
|
||||
},
|
||||
{
|
||||
"name": "displayAsList",
|
||||
"type":"bool"
|
||||
},
|
||||
{
|
||||
"name":"audited",
|
||||
"type":"bool"
|
||||
|
||||
@@ -71,12 +71,12 @@ class Email extends \Espo\Core\SelectManagers\Base
|
||||
$skipIndex = true;
|
||||
}
|
||||
if (!$skipIndex) {
|
||||
$result['useIndexList'] = ['dateSent'];
|
||||
$result['useIndex'] = 'dateSent';
|
||||
}
|
||||
}
|
||||
|
||||
if ($folderId === 'drafts') {
|
||||
$result['useIndexList'] = ['createdById'];
|
||||
$result['useIndex'] = 'createdById';
|
||||
}
|
||||
|
||||
if ($folderId !== 'drafts') {
|
||||
|
||||
@@ -253,7 +253,7 @@ class Email extends Record
|
||||
}
|
||||
}
|
||||
|
||||
$message = null;
|
||||
$message = new \Zend\Mail\Message();
|
||||
|
||||
$this->validateEmailAddresses($entity);
|
||||
|
||||
|
||||
@@ -97,6 +97,14 @@ class GlobalSearch extends \Espo\Core\Services\Base
|
||||
$selectParams['orderBy'] = [['name']];
|
||||
}
|
||||
|
||||
if ($this->getMetadata()->get(['entityDefs', $entityType, 'fields', 'name', 'type']) === 'personName') {
|
||||
$selectParams['select'][] = 'firstName';
|
||||
$selectParams['select'][] = 'lastName';
|
||||
} else {
|
||||
$selectParams['select'][] = ['VALUE:', 'firstName'];
|
||||
$selectParams['select'][] = ['VALUE:', 'lastName'];
|
||||
}
|
||||
|
||||
$selectParams['offset'] = 0;
|
||||
$selectParams['limit'] = $offset + $maxSize + 1;
|
||||
|
||||
|
||||
@@ -102,6 +102,8 @@ class Language extends \Espo\Core\Services\Base
|
||||
unset($data['Global']['scopeNames'][$scope]);
|
||||
unset($data['Global']['scopeNamesPlural'][$scope]);
|
||||
} else {
|
||||
if (in_array($scope, ['EmailAccount', 'InboundEmail'])) continue;
|
||||
|
||||
foreach ($this->getAcl()->getScopeForbiddenFieldList($scope) as $field) {
|
||||
if (isset($data[$scope]['fields'])) unset($data[$scope]['fields'][$field]);
|
||||
if (isset($data[$scope]['options'])) unset($data[$scope]['options'][$field]);
|
||||
|
||||
@@ -327,12 +327,16 @@ class LeadCapture extends Record
|
||||
}
|
||||
}
|
||||
|
||||
$isContactOptedIn = false;
|
||||
|
||||
if ($leadCapture->get('subscribeToTargetList') && $leadCapture->get('targetListId')) {
|
||||
$isAlreadyOptedIn = false;
|
||||
|
||||
if ($contact) {
|
||||
if ($leadCapture->get('subscribeContactToTargetList')) {
|
||||
$isAlreadyOptedIn = $this->isTargetOptedIn($contact, $leadCapture->get('targetListId'));
|
||||
$isContactOptedIn = $isAlreadyOptedIn;
|
||||
|
||||
if (!$isAlreadyOptedIn) {
|
||||
$this->getEntityManager()->getRepository('Contact')->relate($contact, 'targetLists', $leadCapture->get('targetListId'), [
|
||||
'optedOut' => false,
|
||||
@@ -351,15 +355,6 @@ class LeadCapture extends Record
|
||||
'leadCaptureId' => $leadCapture->id,
|
||||
]);
|
||||
}
|
||||
|
||||
$this->getInjection('hookManager')->process('LeadCapture', 'afterLeadCapture', $leadCapture, [], [
|
||||
'targetId' => $contact->id,
|
||||
'targetType' => 'Contact',
|
||||
]);
|
||||
|
||||
$this->getInjection('hookManager')->process('Contact', 'afterLeadCapture', $contact, [], [
|
||||
'leadCaptureId' => $leadCapture->id,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -376,6 +371,16 @@ class LeadCapture extends Record
|
||||
}
|
||||
}
|
||||
|
||||
if ($contact && (!$isContactOptedIn || !$leadCapture->get('subscribeToTargetList'))) {
|
||||
$this->getInjection('hookManager')->process('LeadCapture', 'afterLeadCapture', $leadCapture, [], [
|
||||
'targetId' => $contact->id,
|
||||
'targetType' => 'Contact',
|
||||
]);
|
||||
$this->getInjection('hookManager')->process('Contact', 'afterLeadCapture', $contact, [], [
|
||||
'leadCaptureId' => $leadCapture->id,
|
||||
]);
|
||||
}
|
||||
|
||||
$isNew = !$duplicate && !$contact;
|
||||
|
||||
if (!$contact || !$leadCapture->get('subscribeContactToTargetList')) {
|
||||
@@ -408,12 +413,13 @@ class LeadCapture extends Record
|
||||
'leadCaptureId' => $leadCapture->id,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
if ($toRelateLead || !$leadCapture->get('subscribeToTargetList')) {
|
||||
$this->getInjection('hookManager')->process('LeadCapture', 'afterLeadCapture', $leadCapture, [], [
|
||||
'targetId' => $targetLead->id,
|
||||
'targetType' => 'Lead',
|
||||
]);
|
||||
|
||||
$this->getInjection('hookManager')->process('Lead', 'afterLeadCapture', $targetLead, [], [
|
||||
'leadCaptureId' => $leadCapture->id,
|
||||
]);
|
||||
|
||||
@@ -64,6 +64,7 @@ class Metadata extends \Espo\Core\Services\Base
|
||||
if (!$this->getUser()->isAdmin()) {
|
||||
$scopeList = array_keys($this->getMetadata()->get(['scopes'], []));
|
||||
foreach ($scopeList as $scope) {
|
||||
if (in_array($scope, ['Reminder'])) continue;
|
||||
if (!$this->getAcl()->check($scope)) {
|
||||
unset($data->entityDefs->$scope);
|
||||
unset($data->clientDefs->$scope);
|
||||
|
||||
@@ -1064,7 +1064,13 @@ class Record extends \Espo\Core\Services\Base
|
||||
|
||||
protected function getSelectParams($params)
|
||||
{
|
||||
$selectParams = $this->getSelectManager($this->entityType)->getSelectParams($params, true, true, true);
|
||||
$selectManager = $this->getSelectManager($this->entityType);
|
||||
|
||||
$selectParams = $selectManager->getSelectParams($params, true, true, true);
|
||||
|
||||
if (empty($selectParams['orderBy'])) {
|
||||
$selectManager->applyDefaultOrder($selectParams);
|
||||
}
|
||||
|
||||
return $selectParams;
|
||||
}
|
||||
@@ -1345,7 +1351,13 @@ class Record extends \Espo\Core\Services\Base
|
||||
}
|
||||
}
|
||||
|
||||
$selectParams = $this->getSelectManager($foreignEntityType)->getSelectParams($params, !$skipAcl, true);
|
||||
$selectManager = $this->getSelectManager($foreignEntityType);
|
||||
|
||||
$selectParams = $selectManager->getSelectParams($params, !$skipAcl, true);
|
||||
|
||||
if (empty($selectParams['orderBy'])) {
|
||||
$selectManager->applyDefaultOrder($selectParams);
|
||||
}
|
||||
|
||||
if (array_key_exists($link, $this->linkSelectParams)) {
|
||||
$selectParams = array_merge($selectParams, $this->linkSelectParams[$link]);
|
||||
|
||||
@@ -194,9 +194,7 @@ class RecordTree extends Record
|
||||
public function getLastChildrenIdList($parentId = null)
|
||||
{
|
||||
$selectParams = $this->getSelectManager($this->entityType)->getSelectParams([], true, true);
|
||||
$selectParams['whereClause'][] = array(
|
||||
'parentId' => $parentId
|
||||
);
|
||||
$selectParams['whereClause'][] = ['parentId' => $parentId];
|
||||
|
||||
$idList = [];
|
||||
|
||||
@@ -205,12 +203,12 @@ class RecordTree extends Record
|
||||
$includingRecords = true;
|
||||
}
|
||||
|
||||
$collection = $this->getRepository()->find($selectParams);
|
||||
$collection = $this->getRepository()->select(['id'])->find($selectParams);
|
||||
|
||||
foreach ($collection as $entity) {
|
||||
$selectParams2 = $this->getSelectManager($this->entityType)->getSelectParams([], true, true);
|
||||
$selectParams2['whereClause'][] = array(
|
||||
'parentId' => $entity->id
|
||||
);
|
||||
$selectParams2['whereClause'][] = ['parentId' => $entity->id];
|
||||
|
||||
if (!$this->getRepository()->count($selectParams2)) {
|
||||
$idList[] = $entity->id;
|
||||
} else {
|
||||
|
||||
@@ -386,7 +386,7 @@ class Stream extends \Espo\Core\Services\Base
|
||||
'orderBy' => 'number',
|
||||
'order' => 'DESC',
|
||||
'limit' => $sqLimit,
|
||||
'useIndexList' => ['createdByNumber'],
|
||||
'useIndex' => 'createdByNumber',
|
||||
];
|
||||
|
||||
if ($user->isPortal()) {
|
||||
@@ -484,7 +484,7 @@ class Stream extends \Espo\Core\Services\Base
|
||||
'orderBy' => 'number',
|
||||
'order' => 'DESC',
|
||||
'limit' => $sqLimit,
|
||||
'useIndexList' => ['createdByNumber'],
|
||||
'useIndex' => 'createdByNumber',
|
||||
];
|
||||
|
||||
if ($user->isPortal()) {
|
||||
|
||||
@@ -3,18 +3,20 @@
|
||||
|
||||
{{#if header}}
|
||||
<div class="row button-container">
|
||||
<div class="col-sm-4 col-xs-6">
|
||||
<div class="col-sm-4 col-xs-5">
|
||||
<div class="btn-group range-switch-group">
|
||||
<button class="btn btn-text btn-icon" data-action="prev"><span class="fas fa-chevron-left"></span></button>
|
||||
<button class="btn btn-text btn-icon" data-action="next"><span class="fas fa-chevron-right"></span></button>
|
||||
</div>
|
||||
<button class="btn btn-text strong" data-action="today">{{translate 'Today' scope='Calendar'}}</button>
|
||||
<button class="btn btn-text strong" data-action="today" title="{{todayLabel}}">
|
||||
<span class="hidden-sm hidden-xs">{{todayLabel}}</span><span class="visible-sm visible-xs">{{todayLabelShort}}</span>
|
||||
</button>
|
||||
|
||||
<button class="btn btn-text{{#unless isCustomView}} hidden{{/unless}} btn-icon" data-action="editCustomView" title="{{translate 'Edit'}}"><span class="fas fa-pencil-alt fa-sm"></span></button>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="date-title col-sm-4 col-xs-6"><h4><span style="cursor: pointer;" data-action="refresh" title="{{translate 'Refresh'}}"></span></h4></div>
|
||||
<div class="date-title col-sm-4 col-xs-7"><h4><span style="cursor: pointer;" data-action="refresh" title="{{translate 'Refresh'}}"></span></h4></div>
|
||||
|
||||
<div class="col-sm-4 col-xs-12">
|
||||
<div class="btn-group pull-right mode-buttons">
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
Espo.define('crm:views/calendar/calendar', ['view', 'lib!full-calendar'], function (Dep, FullCalendar) {
|
||||
define('crm:views/calendar/calendar', ['view', 'lib!full-calendar'], function (Dep, FullCalendar) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
@@ -56,7 +56,7 @@ Espo.define('crm:views/calendar/calendar', ['view', 'lib!full-calendar'], functi
|
||||
|
||||
titleFormat: {
|
||||
month: 'MMMM YYYY',
|
||||
week: 'MMMM D, YYYY',
|
||||
week: 'MMMM YYYY',
|
||||
day: 'dddd, MMMM D, YYYY'
|
||||
},
|
||||
|
||||
@@ -66,6 +66,8 @@ Espo.define('crm:views/calendar/calendar', ['view', 'lib!full-calendar'], functi
|
||||
header: this.header,
|
||||
isCustomViewAvailable: this.isCustomViewAvailable,
|
||||
isCustomView: this.isCustomView,
|
||||
todayLabel: this.translate('Today', 'labels', 'Calendar'),
|
||||
todayLabelShort: this.translate('Today', 'labels', 'Calendar').substr(0, 2),
|
||||
};
|
||||
},
|
||||
|
||||
@@ -286,7 +288,7 @@ Espo.define('crm:views/calendar/calendar', ['view', 'lib!full-calendar'], functi
|
||||
var title;
|
||||
|
||||
if (viewName == 'week') {
|
||||
title = $.fullCalendar.formatRange(view.start, view.end, this.titleFormat[viewName], ' - ');
|
||||
title = $.fullCalendar.formatRange(view.start, view.end, this.titleFormat[viewName], ' – ');
|
||||
} else {
|
||||
title = view.intervalStart.format(this.titleFormat[viewName]);
|
||||
}
|
||||
|
||||
50
client/modules/crm/src/views/call/fields/date-end.js
Normal file
50
client/modules/crm/src/views/call/fields/date-end.js
Normal file
@@ -0,0 +1,50 @@
|
||||
/************************************************************************
|
||||
* 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('crm:views/call/fields/date-end', 'views/fields/datetime', function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
validateAfter: function () {
|
||||
var field = this.model.getFieldParam(this.name, 'after');
|
||||
if (field) {
|
||||
var value = this.model.get(this.name);
|
||||
var otherValue = this.model.get(field);
|
||||
if (value && otherValue) {
|
||||
if (moment(value).unix() < moment(otherValue).unix()) {
|
||||
var msg = this.translate('fieldShouldAfter', 'messages').replace('{field}', this.getLabelText())
|
||||
.replace('{otherField}', this.translate(field, 'fields', this.model.name));
|
||||
|
||||
this.showValidationMessage(msg);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
});
|
||||
@@ -26,7 +26,7 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
Espo.define('crm:views/meeting/fields/reminders', 'views/fields/base', function (Dep) {
|
||||
define('crm:views/meeting/fields/reminders', 'views/fields/base', function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
@@ -76,8 +76,8 @@ Espo.define('crm:views/meeting/fields/reminders', 'views/fields/base', function
|
||||
this.reminderList = this.model.get(this.name) || [];
|
||||
}, this);
|
||||
|
||||
this.typeList = this.getMetadata().get('entityDefs.Reminder.fields.type.options');
|
||||
this.secondsList = this.getMetadata().get('entityDefs.Reminder.fields.seconds.options');
|
||||
this.typeList = this.getMetadata().get('entityDefs.Reminder.fields.type.options') || [];
|
||||
this.secondsList = this.getMetadata().get('entityDefs.Reminder.fields.seconds.options') || [];
|
||||
},
|
||||
|
||||
afterRender: function () {
|
||||
|
||||
@@ -16,7 +16,11 @@
|
||||
<div class="panel-heading"><h4 class="panel-title"><%= panelLabelString %></h4></div>
|
||||
<% } %>
|
||||
<div class="panel-body panel-body-form">
|
||||
<% _.each(panel.rows, function (row, rowNumber) { %>
|
||||
|
||||
<% var rows = panel.rows || [] %>
|
||||
<% var columns = panel.columns || [] %>
|
||||
|
||||
<% _.each(rows, function (row, rowNumber) { %>
|
||||
<div class="row">
|
||||
<% var columnCount = row.length; %>
|
||||
<% _.each(row, function (cell, cellNumber) { %>
|
||||
@@ -90,6 +94,78 @@
|
||||
<% }); %>
|
||||
</div>
|
||||
<% }); %>
|
||||
|
||||
<%
|
||||
var columnCount = columns.length;
|
||||
if (columnCount) {
|
||||
%>
|
||||
<div class="row">
|
||||
<%
|
||||
}
|
||||
%>
|
||||
<% _.each(columns, function (column, columnNumber) { %>
|
||||
<%
|
||||
var spanClass;
|
||||
if (!columnCount) return;
|
||||
|
||||
if (columnCount === 1 || column.fullWidth) {
|
||||
spanClass = 'col-sm-12';
|
||||
} else if (columnCount === 2) {
|
||||
if (column.span === 2) {
|
||||
spanClass = 'col-sm-12';
|
||||
} else {
|
||||
spanClass = 'col-sm-6';
|
||||
}
|
||||
} else if (columnCount === 3) {
|
||||
if (column.span === 2) {
|
||||
spanClass = 'col-sm-8';
|
||||
} else if (column.span === 3) {
|
||||
spanClass = 'col-sm-12';
|
||||
} else {
|
||||
spanClass = 'col-sm-4';
|
||||
}
|
||||
} else if (columnCount === 4) {
|
||||
if (column.span === 2) {
|
||||
spanClass = 'col-sm-6';
|
||||
} else if (column.span === 3) {
|
||||
spanClass = 'col-sm-9';
|
||||
} else if (column.span === 4) {
|
||||
spanClass = 'col-sm-12';
|
||||
} else {
|
||||
spanClass = 'col-md-3 col-sm-6';
|
||||
}
|
||||
} else {
|
||||
spanClass = 'col-sm-12';
|
||||
}
|
||||
%>
|
||||
<div class="column <%= spanClass %>">
|
||||
<% _.each(column, function (cell, cellNumber) { %>
|
||||
<div class="cell form-group<% if (cell.field) { %>{{#if hiddenFields.<%= cell.field %>}} hidden-cell{{/if}}<% } %>" data-name="<%= cell.field %>">
|
||||
<% if (!cell.noLabel) { %><label class="control-label<% if (cell.field) { %>{{#if hiddenFields.<%= cell.field %>}} hidden{{/if}}<% } %>" data-name="<%= cell.field %>"><span class="label-text"><%
|
||||
if ('customLabel' in cell) {
|
||||
print (cell.customLabel);
|
||||
} else {
|
||||
print ("{{translate \""+cell.field+"\" scope=\""+model.name+"\" category='fields'}}");
|
||||
}
|
||||
%></span></label><% } %>
|
||||
<div class="field<% if (cell.field) { %>{{#if hiddenFields.<%= cell.field %>}} hidden{{/if}}<% } %>" data-name="<%= cell.field %>"><%
|
||||
if ('customCode' in cell) {
|
||||
print (cell.customCode);
|
||||
} else {
|
||||
print ("{{{this."+cell.name+"}}}");
|
||||
}
|
||||
%></div>
|
||||
</div>
|
||||
<% }); %>
|
||||
</div>
|
||||
<% }); %>
|
||||
<%
|
||||
if (columnCount) {
|
||||
%>
|
||||
</div>
|
||||
<%
|
||||
}
|
||||
%>
|
||||
</div>
|
||||
</div>
|
||||
<% }); %>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<div class="input-group input-group-link-parent">
|
||||
{{#if foreignScopeList.length}}
|
||||
<span class="input-group-btn">
|
||||
<select class="form-control" data-name="{{typeName}}">
|
||||
{{options foreignScopeList foreignScope category='scopeNames'}}
|
||||
@@ -9,5 +10,8 @@
|
||||
<button data-action="selectLink" class="btn btn-default btn-icon" type="button" tabindex="-1" title="{{translate 'Select'}}"><i class="fas fa-angle-up"></i></button>
|
||||
<button data-action="clearLink" class="btn btn-default btn-icon" type="button" tabindex="-1"><i class="fas fa-times"></i></button>
|
||||
</span>
|
||||
{{else}}
|
||||
{{translate 'None'}}
|
||||
{{/if}}
|
||||
</div>
|
||||
<input type="hidden" data-name="{{idName}}" value="{{idValue}}">
|
||||
|
||||
@@ -58,7 +58,15 @@ define('utils', [], function () {
|
||||
if ($dropdown.length) {
|
||||
var $dropdownToggle = $dropdown.parent().find('[data-toggle="dropdown"]');
|
||||
if ($dropdownToggle.length) {
|
||||
var isDisabled = false;
|
||||
if ($dropdownToggle.attr('disabled')) {
|
||||
isDisabled = true;
|
||||
$dropdownToggle.removeAttr('disabled').removeClass('disabled');
|
||||
}
|
||||
$dropdownToggle.dropdown('toggle');
|
||||
if (isDisabled) {
|
||||
$dropdownToggle.attr('disabled', 'disabled').addClass('disabled');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,29 +26,73 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
Espo.define('views/admin/outbound-emails', 'views/settings/record/edit', function (Dep) {
|
||||
define('views/admin/outbound-emails', 'views/settings/record/edit', function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
layoutName: 'outboundEmails',
|
||||
|
||||
dependencyDefs: {
|
||||
'smtpAuth': {
|
||||
map: {
|
||||
true: [
|
||||
{
|
||||
action: 'show',
|
||||
fields: ['smtpUsername', 'smtpPassword']
|
||||
}
|
||||
]
|
||||
},
|
||||
default: [
|
||||
{
|
||||
action: 'hide',
|
||||
fields: ['smtpUsername', 'smtpPassword']
|
||||
dynamicLogicDefs: {
|
||||
fields: {
|
||||
smtpUsername: {
|
||||
visible: {
|
||||
conditionGroup: [
|
||||
{
|
||||
type: 'isNotEmpty',
|
||||
attribute: 'smtpServer',
|
||||
},
|
||||
{
|
||||
type: 'isTrue',
|
||||
attribute: 'smtpAuth',
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
smtpPassword: {
|
||||
visible: {
|
||||
conditionGroup: [
|
||||
{
|
||||
type: 'isNotEmpty',
|
||||
attribute: 'smtpServer',
|
||||
},
|
||||
{
|
||||
type: 'isTrue',
|
||||
attribute: 'smtpAuth',
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
smtpPort: {
|
||||
visible: {
|
||||
conditionGroup: [
|
||||
{
|
||||
type: 'isNotEmpty',
|
||||
attribute: 'smtpServer',
|
||||
},
|
||||
]
|
||||
}
|
||||
},
|
||||
smtpSecurity: {
|
||||
visible: {
|
||||
conditionGroup: [
|
||||
{
|
||||
type: 'isNotEmpty',
|
||||
attribute: 'smtpServer',
|
||||
},
|
||||
]
|
||||
}
|
||||
},
|
||||
smtpAuth: {
|
||||
visible: {
|
||||
conditionGroup: [
|
||||
{
|
||||
type: 'isNotEmpty',
|
||||
attribute: 'smtpServer',
|
||||
},
|
||||
]
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
setup: function () {
|
||||
|
||||
@@ -136,36 +136,29 @@ define('views/detail', 'views/main', function (Dep) {
|
||||
},
|
||||
|
||||
actionFollow: function () {
|
||||
$el = this.$el.find('[data-action="follow"]');
|
||||
$el.addClass('disabled');
|
||||
$.ajax({
|
||||
url: this.model.name + '/' + this.model.id + '/subscription',
|
||||
type: 'PUT',
|
||||
success: function () {
|
||||
$el.remove();
|
||||
this.disableMenuItem('follow');
|
||||
|
||||
Espo.Ajax.putRequest(this.model.name + '/' + this.model.id + '/subscription')
|
||||
.then(function () {
|
||||
this.removeMenuItem('follow', true);
|
||||
this.model.set('isFollowed', true);
|
||||
}.bind(this),
|
||||
error: function () {
|
||||
$el.removeClass('disabled');
|
||||
}.bind(this)
|
||||
});
|
||||
}.bind(this))
|
||||
.fail(function () {
|
||||
this.enableMenuItem('follow');
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
actionUnfollow: function () {
|
||||
$el = this.$el.find('[data-action="unfollow"]');
|
||||
$el.addClass('disabled');
|
||||
$.ajax({
|
||||
url: this.model.name + '/' + this.model.id + '/subscription',
|
||||
type: 'DELETE',
|
||||
success: function () {
|
||||
$el.remove();
|
||||
this.model.set('isFollowed', false);
|
||||
}.bind(this),
|
||||
error: function () {
|
||||
$el.removeClass('disabled');
|
||||
}.bind(this)
|
||||
});
|
||||
this.disableMenuItem('unfollow');
|
||||
|
||||
Espo.Ajax.deleteRequest(this.model.name + '/' + this.model.id + '/subscription')
|
||||
.then(function () {
|
||||
this.removeMenuItem('unfollow', true);
|
||||
this.model.set('isFollowed', false);
|
||||
}.bind(this))
|
||||
.fail(function () {
|
||||
this.enableMenuItem('unfollow');
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
getHeader: function () {
|
||||
@@ -352,11 +345,10 @@ define('views/detail', 'views/main', function (Dep) {
|
||||
|
||||
this.getRouter().dispatch(this.scope, 'create', {
|
||||
attributes: attributes,
|
||||
returnUrl: this.getRouter().getCurrentUrl(),
|
||||
});
|
||||
this.getRouter().navigate(url, {trigger: false});
|
||||
}.bind(this));
|
||||
|
||||
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
@@ -395,7 +395,12 @@ define('views/fields/array', ['views/fields/base', 'lib!Selectize'], function (D
|
||||
|
||||
if (this.displayAsList) {
|
||||
if (!list.length) return '';
|
||||
return '<div>' + list.join('</div><div>') + '</div>';
|
||||
var itemClassName = 'multi-enum-item-container';
|
||||
if (this.displayAsLabel) {
|
||||
itemClassName += ' multi-enum-item-label-container';
|
||||
}
|
||||
return '<div class="'+itemClassName+'">' +
|
||||
list.join('</div><div class="'+itemClassName+'">') + '</div>';
|
||||
} else if (this.displayAsLabel) {
|
||||
return list.join(' ');
|
||||
} else {
|
||||
|
||||
@@ -25,7 +25,8 @@
|
||||
* 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.
|
||||
************************************************************************/
|
||||
Espo.define('views/fields/duration', 'views/fields/enum', function (Dep) {
|
||||
|
||||
define('views/fields/duration', 'views/fields/enum', function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
@@ -111,7 +112,7 @@ Espo.define('views/fields/duration', 'views/fields/enum', function (Dep) {
|
||||
|
||||
stringifyDuration: function (seconds) {
|
||||
if (!seconds) {
|
||||
return '';
|
||||
return '0';
|
||||
}
|
||||
var d = seconds;
|
||||
var days = Math.floor(d / (86400));
|
||||
@@ -242,7 +243,7 @@ Espo.define('views/fields/duration', 'views/fields/enum', function (Dep) {
|
||||
updateDuration: function () {
|
||||
var seconds = this.seconds;
|
||||
|
||||
if (seconds <= 0) {
|
||||
if (seconds < 0) {
|
||||
if (this.mode == 'edit') {
|
||||
this.$duration.val('');
|
||||
} else {
|
||||
|
||||
@@ -110,7 +110,7 @@ define('views/fields/enum', ['views/fields/base', 'lib!Selectize'], function (De
|
||||
}
|
||||
|
||||
if (this.params.isSorted && this.translatedOptions) {
|
||||
this.params.options = Espo.Utils.clone(this.params.options);
|
||||
this.params.options = Espo.Utils.clone(this.params.options) || [];
|
||||
this.params.options = this.params.options.sort(function (v1, v2) {
|
||||
return (this.translatedOptions[v1] || v1).localeCompare(this.translatedOptions[v2] || v2);
|
||||
}.bind(this));
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
Espo.define('views/fields/link-parent', 'views/fields/base', function (Dep) {
|
||||
define('views/fields/link-parent', 'views/fields/base', function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
@@ -65,6 +65,7 @@ Espo.define('views/fields/link-parent', 'views/fields/base', function (Dep) {
|
||||
if ((this.mode == 'detail' || this.mode == 'list' && this.displayScopeColorInListMode) && this.foreignScope) {
|
||||
iconHtml = this.getHelper().getScopeColorIconHtml(this.foreignScope);
|
||||
}
|
||||
|
||||
return _.extend({
|
||||
idName: this.idName,
|
||||
nameName: this.nameName,
|
||||
@@ -103,11 +104,6 @@ Espo.define('views/fields/link-parent', 'views/fields/base', function (Dep) {
|
||||
if (!this.getMetadata().get(['scopes', item, 'disabled'])) return true;
|
||||
}, this);
|
||||
|
||||
|
||||
if (this.mode == 'edit' && this.foreignScopeList.length == 0) {
|
||||
throw new Error('Bad parent link defenition. Model list is empty.');
|
||||
}
|
||||
|
||||
this.foreignScope = this.model.get(this.typeName) || this.foreignScopeList[0];
|
||||
|
||||
this.listenTo(this.model, 'change:' + this.typeName, function () {
|
||||
|
||||
@@ -191,6 +191,10 @@ define('views/main', 'view', function (Dep) {
|
||||
if (!doNotReRender && this.isRendered()) {
|
||||
this.getView('header').reRender();
|
||||
}
|
||||
|
||||
if (doNotReRender && this.isRendered()) {
|
||||
this.$el.find('.header .header-buttons [data-name="'+name+'"]').remove();
|
||||
}
|
||||
},
|
||||
|
||||
disableMenuItem: function (name) {
|
||||
|
||||
@@ -394,14 +394,13 @@ Espo.define('views/modals/detail', 'views/modal', function (Dep) {
|
||||
} else {
|
||||
var initialCount = collection.length;
|
||||
|
||||
this.listenToOnce(collection, 'sync', function () {
|
||||
var model = collection.at(indexOfRecord);
|
||||
this.switchToModelByIndex(indexOfRecord);
|
||||
}, this);
|
||||
collection.fetch({
|
||||
more: true,
|
||||
remove: false,
|
||||
});
|
||||
}).then(function () {
|
||||
var model = collection.at(indexOfRecord);
|
||||
this.switchToModelByIndex(indexOfRecord);
|
||||
}.bind(this));
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -118,6 +118,8 @@ define('views/record/detail', ['views/record/base', 'view-record-helper'], funct
|
||||
|
||||
convertCurrencyAction: true,
|
||||
|
||||
saveAndContinueEditingAction: false,
|
||||
|
||||
events: {
|
||||
'click .button-container .action': function (e) {
|
||||
Espo.Utils.handleAction(this, e);
|
||||
@@ -163,6 +165,10 @@ define('views/record/detail', ['views/record/base', 'view-record-helper'], funct
|
||||
$(window).scrollTop(0);
|
||||
},
|
||||
|
||||
actionSaveAndContinueEditing: function () {
|
||||
this.save(null, true);
|
||||
},
|
||||
|
||||
actionSelfAssign: function () {
|
||||
var attributes = {
|
||||
assignedUserId: this.getUser().id,
|
||||
@@ -348,6 +354,13 @@ define('views/record/detail', ['views/record/base', 'view-record-helper'], funct
|
||||
}, this);
|
||||
}, this);
|
||||
}
|
||||
|
||||
if (this.saveAndContinueEditingAction) {
|
||||
this.dropdownEditItemList.push({
|
||||
name: 'saveAndContinueEditing',
|
||||
label: 'Save & Continue Editing',
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -975,6 +988,8 @@ define('views/record/detail', ['views/record/base', 'view-record-helper'], funct
|
||||
},
|
||||
|
||||
actionPrevious: function () {
|
||||
this.model.abortLastFetch();
|
||||
|
||||
var collection;
|
||||
if (!this.model.collection) {
|
||||
collection = this.collection;
|
||||
@@ -992,6 +1007,8 @@ define('views/record/detail', ['views/record/base', 'view-record-helper'], funct
|
||||
},
|
||||
|
||||
actionNext: function () {
|
||||
this.model.abortLastFetch();
|
||||
|
||||
var collection;
|
||||
if (!this.model.collection) {
|
||||
collection = this.collection;
|
||||
@@ -1011,14 +1028,13 @@ define('views/record/detail', ['views/record/base', 'view-record-helper'], funct
|
||||
} else {
|
||||
var initialCount = collection.length;
|
||||
|
||||
this.listenToOnce(collection, 'sync', function () {
|
||||
var model = collection.at(indexOfRecord);
|
||||
this.switchToModelByIndex(indexOfRecord);
|
||||
}, this);
|
||||
collection.fetch({
|
||||
more: true,
|
||||
remove: false,
|
||||
});
|
||||
}).then(function () {
|
||||
var model = collection.at(indexOfRecord);
|
||||
this.switchToModelByIndex(indexOfRecord);
|
||||
}.bind(this));
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1350,11 +1366,18 @@ define('views/record/detail', ['views/record/base', 'view-record-helper'], funct
|
||||
}
|
||||
}
|
||||
|
||||
for (var i in simplifiedLayout[p].rows) {
|
||||
var lType = 'rows';
|
||||
if (simplifiedLayout[p].columns) {
|
||||
lType = 'columns';
|
||||
panel.columns = [];
|
||||
}
|
||||
|
||||
|
||||
for (var i in simplifiedLayout[p][lType]) {
|
||||
var row = [];
|
||||
|
||||
for (var j in simplifiedLayout[p].rows[i]) {
|
||||
var cellDefs = simplifiedLayout[p].rows[i][j];
|
||||
for (var j in simplifiedLayout[p][lType][i]) {
|
||||
var cellDefs = simplifiedLayout[p][lType][i][j];
|
||||
|
||||
if (cellDefs == false) {
|
||||
row.push(false);
|
||||
@@ -1398,7 +1421,7 @@ define('views/record/detail', ['views/record/base', 'view-record-helper'], funct
|
||||
|
||||
var fullWidth = cellDefs.fullWidth || false;
|
||||
if (!fullWidth) {
|
||||
if (simplifiedLayout[p].rows[i].length == 1) {
|
||||
if (simplifiedLayout[p][lType][i].length == 1) {
|
||||
fullWidth = true;
|
||||
}
|
||||
}
|
||||
@@ -1452,7 +1475,7 @@ define('views/record/detail', ['views/record/base', 'view-record-helper'], funct
|
||||
row.push(cell);
|
||||
}
|
||||
|
||||
panel.rows.push(row);
|
||||
panel[lType].push(row);
|
||||
}
|
||||
layout.push(panel);
|
||||
}
|
||||
|
||||
@@ -81,7 +81,18 @@ define('views/record/edit', 'views/record/detail', function (Dep) {
|
||||
this.populateDefaults();
|
||||
}
|
||||
Dep.prototype.setupBeforeFinal.call(this);
|
||||
}
|
||||
},
|
||||
|
||||
setupActionItems: function () {
|
||||
Dep.prototype.setupActionItems.call(this);
|
||||
|
||||
if (this.saveAndContinueEditingAction) {
|
||||
this.dropdownItemList.push({
|
||||
name: 'saveAndContinueEditing',
|
||||
label: 'Save & Continue Editing',
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1041,6 +1041,13 @@ ul.dropdown-menu > li.checkbox:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.multi-enum-item-label-container {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.multi-enum-item-label-container:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.filter > .form-group .field {
|
||||
@@ -3167,7 +3174,10 @@ table.table-admin-panel {
|
||||
margin-top: 6px;
|
||||
h4 {
|
||||
margin-top: 0;
|
||||
font-size: 15px;
|
||||
}
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -99,7 +99,7 @@
|
||||
"modRewriteInstruction": {
|
||||
"apache": {
|
||||
"windows": "<br> <pre>1. Encontrar el archivo httpd.conf (generalmente lo encontrará en una carpeta llamada conf, config o o algo similar a esas líneas)<br>\n2. Dentro del archivo httpd.conf descomentamos la línea LoadModule rewrite_module modules/mod_rewrite.so (eliminar el '#' que está al comienzo de la línea)<br>\n3. También encuentre que la línea ClearModuleList no esté comentada después busque y asegurese que la línea AddModule mod_rewrite.c no está comentada tampoco.\n</pre>",
|
||||
"linux": "<br> <br>1. Habilita \"mod_rewrite\". Para hacerlo, ejecute esos comandos en un Terminal: <pre>{APACHE1}</pre><br> 2. Habilita el soporte de .htaccess. Agregue/edite los ajustes de configuración del Servidor (/etc/apache/apache2.conf, /etc/httpd/conf/httpd.conf): <pre>{APACHE2}</pre>\nLuego ejecuta este comando en un Terminal: <pre>{APACHE3}</pre> <br>3. Intente agregar la ruta RewriteBase, abra un archivo {API_PATH} .htaccess y reemplace la siguiente línea: <pre>{APACHE4}</ pre> a <pre>{APACHE5}</ pre> <br> Para obtener más información, visite la guía <a href=\"https://www.espocrm.com/documentation/administration/apache-server-configuration/\" target=\"_blank\"> configuración del servidor Apache para EspoCRM </a>. <br> <br>"
|
||||
"linux": "<br> <br>1. Habilita \"mod_rewrite\". Para hacerlo, ejecute esos comandos en un Terminal: <pre>{APACHE1}</pre><br> 2. Habilita el soporte de .htaccess. Agregue/edite los ajustes de configuración del Servidor (/etc/apache/apache2.conf, /etc/httpd/conf/httpd.conf): <pre>{APACHE2}</pre>\nLuego ejecuta este comando en un Terminal: <pre>{APACHE3}</pre> <br>3. Intente agregar la ruta RewriteBase, abra un archivo {API_PATH} .htaccess y reemplace la siguiente línea: <pre>{APACHE4}</pre> a <pre>{APACHE5}</pre> <br> Para obtener más información, visite la guía <a href=\"https://www.espocrm.com/documentation/administration/apache-server-configuration/\" target=\"_blank\"> configuración del servidor Apache para EspoCRM </a>. <br> <br>"
|
||||
},
|
||||
"nginx": {
|
||||
"linux": "<br>\n<pre>\n{NGINX}\n</pre> <br> Para obtener más información, visite la guía <a href=\"https://www.espocrm.com/documentation/administration/nginx-server-configuration/\" target=\"_blank\"> configuración del servidor Nginx para EspoCRM </a>. <br> <br> <br>",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "espocrm",
|
||||
"version": "5.7.0",
|
||||
"version": "5.7.3",
|
||||
"description": "",
|
||||
"main": "index.php",
|
||||
"repository": {
|
||||
|
||||
@@ -320,4 +320,30 @@ class FormulaTest extends \tests\integration\Core\BaseTestCase
|
||||
|
||||
$this->assertTrue($result1 !== $result);
|
||||
}
|
||||
|
||||
public function testEntityGetLinkColumn()
|
||||
{
|
||||
$fm = $this->getContainer()->get('formulaManager');
|
||||
$em = $this->getContainer()->get('entityManager');
|
||||
|
||||
$lead = $em->createEntity('Lead', []);
|
||||
$targetList = $em->createEntity('TargetList', []);
|
||||
|
||||
$em->getRepository('Lead')->relate($lead, 'targetLists', $targetList->id, [
|
||||
'optedOut' => true,
|
||||
]);
|
||||
|
||||
$script = "entity\\getLinkColumn('targetLists', '{$targetList->id}', 'optedOut')";
|
||||
|
||||
$result = $fm->run($script, $lead);
|
||||
$this->assertTrue($result);
|
||||
|
||||
|
||||
$em->getRepository('Lead')->relate($lead, 'targetLists', $targetList->id, [
|
||||
'optedOut' => false,
|
||||
]);
|
||||
|
||||
$result = $fm->run($script, $lead);
|
||||
$this->assertFalse($result);
|
||||
}
|
||||
}
|
||||
|
||||
93
tests/integration/Espo/GlobalSearch/GlobalSearchTest.php
Normal file
93
tests/integration/Espo/GlobalSearch/GlobalSearchTest.php
Normal file
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
namespace tests\integration\Espo\GlobalSearch;
|
||||
|
||||
class GlobalSearchTest extends \tests\integration\Core\BaseTestCase
|
||||
{
|
||||
public function testSearch1()
|
||||
{
|
||||
$app = $this->createApplication();
|
||||
|
||||
$em = $app->getContainer()->get('entityManager');
|
||||
|
||||
$team = $em->createEntity('Team', [
|
||||
'name' => 'test',
|
||||
]);
|
||||
|
||||
$contact = $em->createEntity('Contact', [
|
||||
'lastName' => '1',
|
||||
'teamsIds' => [$team->id],
|
||||
]);
|
||||
|
||||
$account = $em->createEntity('Account', [
|
||||
'name' => '1',
|
||||
'teamsIds' => [$team->id],
|
||||
]);
|
||||
$account = $em->createEntity('Account', [
|
||||
'name' => '2',
|
||||
'teamsIds' => [$team->id],
|
||||
]);
|
||||
$account = $em->createEntity('Account', [
|
||||
'name' => '1',
|
||||
]);
|
||||
|
||||
$this->createUser([
|
||||
'userName' => 'tester',
|
||||
'teamsIds' => [$team->id],
|
||||
], [
|
||||
'data' => [
|
||||
'Account' => [
|
||||
'create' => 'no',
|
||||
'read' => 'team',
|
||||
'edit' => 'no',
|
||||
'delete' => 'no',
|
||||
'stream' => 'no',
|
||||
],
|
||||
'Contact' => [
|
||||
'create' => 'no',
|
||||
'read' => 'team',
|
||||
'edit' => 'no',
|
||||
'delete' => 'no',
|
||||
'stream' => 'no',
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
$this->auth('tester');
|
||||
|
||||
$app = $this->createApplication(true);
|
||||
|
||||
$service = $app->getContainer()->get('serviceFactory')->create('GlobalSearch');
|
||||
|
||||
$result = $service->find('1', 0, 10);
|
||||
|
||||
$this->assertEquals(2, count($result['list']));
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,7 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace tests\integration\Espo\Attachment;
|
||||
namespace tests\integration\Espo\LeadCapture;
|
||||
|
||||
class LeadCaptureTest extends \tests\integration\Core\BaseTestCase
|
||||
{
|
||||
|
||||
@@ -2816,6 +2816,47 @@ class FormulaTest extends \PHPUnit\Framework\TestCase
|
||||
$this->assertEquals('12', $actual);
|
||||
}
|
||||
|
||||
function testPos()
|
||||
{
|
||||
$item = json_decode('
|
||||
{
|
||||
"type": "string\\\\pos",
|
||||
"value": [
|
||||
{
|
||||
"type": "value",
|
||||
"value": "1234"
|
||||
},
|
||||
{
|
||||
"type": "value",
|
||||
"value": 23
|
||||
}
|
||||
]
|
||||
}
|
||||
');
|
||||
|
||||
$actual = $this->formula->process($item, $this->entity);
|
||||
$this->assertEquals(1, $actual);
|
||||
|
||||
$item = json_decode('
|
||||
{
|
||||
"type": "string\\\\pos",
|
||||
"value": [
|
||||
{
|
||||
"type": "value",
|
||||
"value": "1234"
|
||||
},
|
||||
{
|
||||
"type": "value",
|
||||
"value": 54
|
||||
}
|
||||
]
|
||||
}
|
||||
');
|
||||
|
||||
$actual = $this->formula->process($item, $this->entity);
|
||||
$this->assertFalse($actual);
|
||||
}
|
||||
|
||||
function testBundle()
|
||||
{
|
||||
$item = json_decode('
|
||||
|
||||
@@ -308,6 +308,22 @@ class QueryTest extends \PHPUnit\Framework\TestCase
|
||||
$this->assertEquals($expectedSql, $sql);
|
||||
}
|
||||
|
||||
|
||||
public function testJoinOnlyMiddle()
|
||||
{
|
||||
$sql = $this->query->createSelectQuery('Post', [
|
||||
'select' => ['id'],
|
||||
'leftJoins' => [['tags', null, null, ['onlyMiddle' => true]]]
|
||||
]);
|
||||
|
||||
$expectedSql =
|
||||
"SELECT post.id AS `id` FROM `post` " .
|
||||
"LEFT JOIN `post_tag` AS `tagsMiddle` ON post.id = tagsMiddle.post_id AND tagsMiddle.deleted = '0' " .
|
||||
"WHERE post.deleted = '0'";
|
||||
|
||||
$this->assertEquals($expectedSql, $sql);
|
||||
}
|
||||
|
||||
public function testWhereNotValue1()
|
||||
{
|
||||
$sql = $this->query->createSelectQuery('Post', [
|
||||
|
||||
Reference in New Issue
Block a user