mirror of
https://github.com/espocrm/espocrm.git
synced 2026-03-04 16:47:01 +00:00
Compare commits
176 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
19f1ef75fd | ||
|
|
b29172ad18 | ||
|
|
8f201944a4 | ||
|
|
6c9a350e43 | ||
|
|
6f1be59b4c | ||
|
|
5a15fcbbb5 | ||
|
|
9084e6b679 | ||
|
|
ccb4fb13a9 | ||
|
|
b07c3b62cf | ||
|
|
d4805acef7 | ||
|
|
0637304a4f | ||
|
|
8f9089f0a3 | ||
|
|
83ccec26ee | ||
|
|
db427c0bf1 | ||
|
|
0785ab9ee1 | ||
|
|
767dcd1e9f | ||
|
|
7e997b224b | ||
|
|
1c11442aea | ||
|
|
7a08eea518 | ||
|
|
cb14ca4627 | ||
|
|
7a6a8bc707 | ||
|
|
cc3ba89ab3 | ||
|
|
88135f93fe | ||
|
|
1148e391a6 | ||
|
|
f7c5706004 | ||
|
|
3120afb55e | ||
|
|
e991241ad2 | ||
|
|
22e7756083 | ||
|
|
f2e48df7ea | ||
|
|
3b4dc45984 | ||
|
|
d9b1418f36 | ||
|
|
443016790a | ||
|
|
ca9253ecd5 | ||
|
|
395b11474e | ||
|
|
1c7fb79b33 | ||
|
|
c6c16cd488 | ||
|
|
a56502b814 | ||
|
|
24137df013 | ||
|
|
b945473422 | ||
|
|
ab7db9d084 | ||
|
|
c36007f216 | ||
|
|
1d8cc18411 | ||
|
|
723fc52d1c | ||
|
|
073aedc18b | ||
|
|
035abf03cb | ||
|
|
50dbc60a5c | ||
|
|
dbdc83c544 | ||
|
|
1d743afd2a | ||
|
|
094bf69fab | ||
|
|
706226298a | ||
|
|
322bbb5d95 | ||
|
|
5c12c6133f | ||
|
|
417367838c | ||
|
|
6f1cc78329 | ||
|
|
a2faab036c | ||
|
|
a32441543c | ||
|
|
f4497402ca | ||
|
|
ef6548bc82 | ||
|
|
f1bf0b3dee | ||
|
|
ec23cae38d | ||
|
|
771e3237cf | ||
|
|
ae72146d14 | ||
|
|
20d6865323 | ||
|
|
89e13b0bac | ||
|
|
8fa36ac14c | ||
|
|
e557782c64 | ||
|
|
7cc7f3fbcf | ||
|
|
3f293a6d23 | ||
|
|
309b09f6ce | ||
|
|
0b7e9f3d62 | ||
|
|
58c17ffd5c | ||
|
|
7d3ba23a9f | ||
|
|
ca2e4f5b37 | ||
|
|
d82174fec5 | ||
|
|
033c65b79b | ||
|
|
dbc8e5d9cc | ||
|
|
42407935d5 | ||
|
|
e7d558b0bf | ||
|
|
290b530b92 | ||
|
|
18726bdccd | ||
|
|
06b0498abb | ||
|
|
7a7627e931 | ||
|
|
c6038e9cee | ||
|
|
0e05596155 | ||
|
|
0ca212f911 | ||
|
|
94c2b9deda | ||
|
|
2016a1bb0d | ||
|
|
6841ba9c85 | ||
|
|
d5988f2c04 | ||
|
|
a56c9c3a46 | ||
|
|
9d0bbdcd4d | ||
|
|
4bfaac3414 | ||
|
|
d54c044fd9 | ||
|
|
1def66bb77 | ||
|
|
75041db2e9 | ||
|
|
356948cdf7 | ||
|
|
db92abf3ee | ||
|
|
d5d59abf13 | ||
|
|
69c1e3e8e0 | ||
|
|
963c4e3e2b | ||
|
|
cc4c735a27 | ||
|
|
175517a9dc | ||
|
|
9cb3548393 | ||
|
|
ac0dea317f | ||
|
|
839dfb9709 | ||
|
|
2c7a4098f3 | ||
|
|
0228396376 | ||
|
|
c5aa0eba48 | ||
|
|
ac4472975d | ||
|
|
379f5fbaaf | ||
|
|
af71408c52 | ||
|
|
b7a4fa1e7c | ||
|
|
92b6e45ef2 | ||
|
|
acf6f67627 | ||
|
|
017c34dcde | ||
|
|
f6e54918b2 | ||
|
|
75b3c33526 | ||
|
|
f784760735 | ||
|
|
a739b3a96e | ||
|
|
0a8e0f00c2 | ||
|
|
00c4cf4893 | ||
|
|
e8e9ea9e2f | ||
|
|
c9cdb6767b | ||
|
|
24f9c1c762 | ||
|
|
766a880799 | ||
|
|
07de0dbeb0 | ||
|
|
d1752f2ff0 | ||
|
|
ef27234ef8 | ||
|
|
685862f1de | ||
|
|
97621c45a8 | ||
|
|
b96d433796 | ||
|
|
03d784c284 | ||
|
|
02ef97724f | ||
|
|
93e2c65d30 | ||
|
|
d02bf65a55 | ||
|
|
fb2f566314 | ||
|
|
2227870854 | ||
|
|
b195509843 | ||
|
|
2100fa0606 | ||
|
|
3fe43bdfa3 | ||
|
|
26ad3d48af | ||
|
|
9c224fefb7 | ||
|
|
e4db873e43 | ||
|
|
f06d53b3d2 | ||
|
|
4ef706b716 | ||
|
|
b8be2c9e13 | ||
|
|
f05c763119 | ||
|
|
262b3bb3b3 | ||
|
|
d3ea71c726 | ||
|
|
62ccfaa9c0 | ||
|
|
c0b169f7dd | ||
|
|
3d68c77ed4 | ||
|
|
a2e241966e | ||
|
|
7bf7944360 | ||
|
|
9f72b074d5 | ||
|
|
59b7934aa2 | ||
|
|
a7a61a993c | ||
|
|
68d1c0854b | ||
|
|
fdd6f01415 | ||
|
|
54a045e25a | ||
|
|
862b76f165 | ||
|
|
5ed0b2ba6b | ||
|
|
bbe26618ac | ||
|
|
6f65d9e8d8 | ||
|
|
f1b0decbab | ||
|
|
c2b60698bc | ||
|
|
63ff4c1dca | ||
|
|
8987ec61fe | ||
|
|
a93627d274 | ||
|
|
90fe18b660 | ||
|
|
6182376d1f | ||
|
|
66235f7e77 | ||
|
|
49b61dab53 | ||
|
|
a10f2949a4 | ||
|
|
666d8ab5ad | ||
|
|
bbcf9e00fa |
78
application/Espo/Controllers/LabelManager.php
Normal file
78
application/Espo/Controllers/LabelManager.php
Normal file
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2017 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
|
||||
* Website: http://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\Controllers;
|
||||
|
||||
use Espo\Core\Utils as Utils;
|
||||
use \Espo\Core\Exceptions\NotFound;
|
||||
use \Espo\Core\Exceptions\Error;
|
||||
use \Espo\Core\Exceptions\Forbidden;
|
||||
use \Espo\Core\Exceptions\BadRequest;
|
||||
|
||||
class LabelManager extends \Espo\Core\Controllers\Base
|
||||
{
|
||||
protected function checkControllerAccess()
|
||||
{
|
||||
if (!$this->getUser()->isAdmin()) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
}
|
||||
|
||||
public function postActionGetScopeList($params)
|
||||
{
|
||||
$labelManager = $this->getContainer()->get('injectableFactory')->createByClassName('\\Espo\\Core\\Utils\\LabelManager');
|
||||
|
||||
return $labelManager->getScopeList();
|
||||
}
|
||||
|
||||
public function postActionGetScopeData($params, $data, $request)
|
||||
{
|
||||
if (empty($data['scope']) || empty($data['language'])) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
$labelManager = $this->getContainer()->get('injectableFactory')->createByClassName('\\Espo\\Core\\Utils\\LabelManager');
|
||||
return $labelManager->getScopeData($data['language'], $data['scope']);
|
||||
}
|
||||
|
||||
public function postActionSaveLabels($params, $data)
|
||||
{
|
||||
if (empty($data['scope']) || empty($data['language']) || !isset($data['labels'])) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
$labels = get_object_vars($data['labels']);
|
||||
|
||||
$labelManager = $this->getContainer()->get('injectableFactory')->createByClassName('\\Espo\\Core\\Utils\\LabelManager');
|
||||
$returnData = $labelManager->saveLabels($data['language'], $data['scope'], $labels);
|
||||
|
||||
$this->getContainer()->get('dataManager')->clearCache();
|
||||
|
||||
return $returnData;
|
||||
}
|
||||
}
|
||||
@@ -76,7 +76,11 @@ class Settings extends \Espo\Core\Controllers\Base
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
if (isset($data['useCache']) && $data['useCache'] != $this->getConfig()->get('useCache')) {
|
||||
if (
|
||||
(isset($data['useCache']) && $data['useCache'] != $this->getConfig()->get('useCache'))
|
||||
||
|
||||
(isset($data['aclStrictMode']) && $data['aclStrictMode'] !== $this->getConfig()->get('aclStrictMode'))
|
||||
) {
|
||||
$this->getContainer()->get('dataManager')->clearCache();
|
||||
}
|
||||
|
||||
|
||||
@@ -77,6 +77,8 @@ class Table
|
||||
|
||||
protected $forbiddenFieldsCache = array();
|
||||
|
||||
protected $isStrictMode = false;
|
||||
|
||||
public function __construct(User $user, Config $config = null, FileManager $fileManager = null, Metadata $metadata = null, FieldManagerUtil $fieldManager = null)
|
||||
{
|
||||
$this->data = (object) [
|
||||
@@ -85,6 +87,8 @@ class Table
|
||||
'fieldTableQuickAccess' => (object) [],
|
||||
];
|
||||
|
||||
$this->isStrictMode = $config->get('aclStrictMode', false);
|
||||
|
||||
$this->user = $user;
|
||||
|
||||
$this->metadata = $metadata;
|
||||
@@ -135,11 +139,6 @@ class Table
|
||||
return $this->fieldManager;
|
||||
}
|
||||
|
||||
protected function getConfig()
|
||||
{
|
||||
return $this->config;
|
||||
}
|
||||
|
||||
public function getMap()
|
||||
{
|
||||
return $this->data;
|
||||
@@ -454,7 +453,11 @@ class Table
|
||||
$aclType = $this->defaultAclType;
|
||||
}
|
||||
if (!empty($aclType)) {
|
||||
$defaultValue = $this->metadata->get('app.'.$this->type.'.scopeLevelTypesDefaults.' . $aclType, $this->metadata->get('app.'.$this->type.'.scopeLevelTypesDefaults.record'));
|
||||
$paramDefaultsName = 'scopeLevelTypesDefaults';
|
||||
if ($this->isStrictMode) {
|
||||
$paramDefaultsName = 'scopeLevelTypesStrictDefaults';
|
||||
}
|
||||
$defaultValue = $this->metadata->get(['app', $this->type, $paramDefaultsName, $aclType], $this->metadata->get(['app', $this->type, $paramDefaultsName, 'record']));
|
||||
if (is_array($defaultValue)) {
|
||||
$defaultValue = (object) $defaultValue;
|
||||
}
|
||||
|
||||
@@ -134,7 +134,7 @@ class Application
|
||||
public function runCron()
|
||||
{
|
||||
$auth = $this->createAuth();
|
||||
$auth->useNoAuth(true);
|
||||
$auth->useNoAuth();
|
||||
|
||||
$cronManager = new \Espo\Core\CronManager($this->container);
|
||||
$cronManager->run();
|
||||
@@ -327,6 +327,7 @@ class Application
|
||||
public function setupSystemUser()
|
||||
{
|
||||
$user = $this->getContainer()->get('entityManager')->getEntity('User', 'system');
|
||||
$user->set('isAdmin', true);
|
||||
$this->getContainer()->setUser($user);
|
||||
$this->getContainer()->get('entityManager')->setUser($user);
|
||||
}
|
||||
|
||||
@@ -93,6 +93,24 @@ class Container
|
||||
return $className;
|
||||
}
|
||||
|
||||
protected function loadContainer()
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function loadSlim()
|
||||
{
|
||||
return new \Espo\Core\Utils\Api\Slim();
|
||||
}
|
||||
|
||||
protected function loadFileStorageManager()
|
||||
{
|
||||
return new \Espo\Core\FileStorage\Manager(
|
||||
$this->get('metadata')->get(['app', 'fileStorage', 'implementationClassNameMap']),
|
||||
$this
|
||||
);
|
||||
}
|
||||
|
||||
protected function loadLog()
|
||||
{
|
||||
$config = $this->get('config');
|
||||
@@ -118,24 +136,6 @@ class Container
|
||||
return $log;
|
||||
}
|
||||
|
||||
protected function loadContainer()
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function loadSlim()
|
||||
{
|
||||
return new \Espo\Core\Utils\Api\Slim();
|
||||
}
|
||||
|
||||
protected function loadFileStorageManager()
|
||||
{
|
||||
return new \Espo\Core\FileStorage\Manager(
|
||||
$this->get('metadata')->get(['app', 'fileStorage', 'implementationClassNameMap']),
|
||||
$this
|
||||
);
|
||||
}
|
||||
|
||||
protected function loadFileManager()
|
||||
{
|
||||
return new \Espo\Core\Utils\File\Manager(
|
||||
|
||||
@@ -60,9 +60,9 @@ class ControllerManager
|
||||
|
||||
public function process($controllerName, $actionName, $params, $data, $request)
|
||||
{
|
||||
$customeClassName = '\\Espo\\Custom\\Controllers\\' . Util::normilizeClassName($controllerName);
|
||||
if (class_exists($customeClassName)) {
|
||||
$controllerClassName = $customeClassName;
|
||||
$customClassName = '\\Espo\\Custom\\Controllers\\' . Util::normilizeClassName($controllerName);
|
||||
if (class_exists($customClassName)) {
|
||||
$controllerClassName = $customClassName;
|
||||
} else {
|
||||
$moduleName = $this->metadata->getScopeModuleName($controllerName);
|
||||
if ($moduleName) {
|
||||
|
||||
@@ -283,24 +283,20 @@ class CronManager
|
||||
}
|
||||
|
||||
try {
|
||||
$previousDate = $cronExpression->getPreviousRunDate()->format('Y-m-d H:i:s');
|
||||
$nextDate = $cronExpression->getNextRunDate()->format('Y-m-d H:i:s');
|
||||
} catch (\Exception $e) {
|
||||
$GLOBALS['log']->error('CronManager (ScheduledJob ['.$scheduledJob['id'].']): Unsupported CRON expression ['.$scheduling.']');
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($cronExpression->isDue()) {
|
||||
$previousDate = date('Y-m-d H:i:s');
|
||||
}
|
||||
|
||||
$existingJob = $this->getCronJob()->getJobByScheduledJob($scheduledJob['id'], $previousDate);
|
||||
$existingJob = $this->getCronJob()->getJobByScheduledJob($scheduledJob['id'], $nextDate);
|
||||
if ($existingJob) continue;
|
||||
|
||||
$className = $this->getScheduledJobUtil()->get($scheduledJob['job']);
|
||||
if ($className) {
|
||||
if (method_exists($className, 'prepare')) {
|
||||
$implementation = new $className($this->container);
|
||||
$implementation->prepare($scheduledJob, $previousDate);
|
||||
$implementation->prepare($scheduledJob, $nextDate);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -314,7 +310,7 @@ class CronManager
|
||||
'name' => $scheduledJob['name'],
|
||||
'status' => self::PENDING,
|
||||
'scheduledJobId' => $scheduledJob['id'],
|
||||
'executeTime' => $previousDate,
|
||||
'executeTime' => $nextDate,
|
||||
'method' => $scheduledJob['job']
|
||||
));
|
||||
$this->getEntityManager()->saveEntity($jobEntity);
|
||||
|
||||
@@ -195,9 +195,9 @@ class Xlsx extends \Espo\Core\Injectable
|
||||
$label = $name;
|
||||
if (strpos($name, '_') !== false) {
|
||||
list($linkName, $foreignField) = explode('_', $name);
|
||||
$foreigScope = $this->getInjection('metadata')->get(['entityDefs', $entityType, 'links', $linkName, 'entity']);
|
||||
if ($foreigScope) {
|
||||
$label = $this->getInjection('language')->translate($linkName, 'links', $entityType) . '.' . $this->getInjection('language')->translate($foreignField, 'fields', $foreigScope);
|
||||
$foreignScope = $this->getInjection('metadata')->get(['entityDefs', $entityType, 'links', $linkName, 'entity']);
|
||||
if ($foreignScope) {
|
||||
$label = $this->getInjection('language')->translate($linkName, 'links', $entityType) . '.' . $this->getInjection('language')->translate($foreignField, 'fields', $foreignScope);
|
||||
}
|
||||
} else {
|
||||
$label = $this->getInjection('language')->translate($name, 'fields', $entityType);
|
||||
@@ -205,13 +205,7 @@ class Xlsx extends \Espo\Core\Injectable
|
||||
|
||||
$sheet->setCellValue($col . $rowNumber, $label);
|
||||
$sheet->getColumnDimension($col)->setAutoSize(true);
|
||||
if (
|
||||
$defs['type'] == 'phone'
|
||||
|| $defs['type'] == 'email'
|
||||
|| $defs['type'] == 'url'
|
||||
|| $defs['type'] == 'link'
|
||||
|| $defs['type'] == 'linkParent'
|
||||
) {
|
||||
if (in_array($defs['type'], ['phone', 'email', 'url', 'link', 'linkParent'])) {
|
||||
$linkColList[] = $col;
|
||||
} else if ($name == 'name') {
|
||||
$linkColList[] = $col;
|
||||
@@ -231,6 +225,8 @@ class Xlsx extends \Espo\Core\Injectable
|
||||
$sheet->getStyle("A$rowNumber:$col$rowNumber")->applyFromArray($headerStyle);
|
||||
$sheet->setAutoFilter("A$rowNumber:$col$rowNumber");
|
||||
|
||||
$typesCache = array();
|
||||
|
||||
$rowNumber++;
|
||||
foreach ($dataList as $row) {
|
||||
$i = 0;
|
||||
@@ -242,18 +238,31 @@ class Xlsx extends \Espo\Core\Injectable
|
||||
$defs = array();
|
||||
$defs['type'] = 'base';
|
||||
}
|
||||
|
||||
$type = $defs['type'];
|
||||
$foreignField = $name;
|
||||
$linkName = null;
|
||||
if (strpos($name, '_') !== false) {
|
||||
list($linkName, $foreignField) = explode('_', $name);
|
||||
$foreignScope = $this->getInjection('metadata')->get(['entityDefs', $entityType, 'links', $linkName, 'entity']);
|
||||
if ($foreignScope) {
|
||||
$type = $this->getInjection('metadata')->get(['entityDefs', $foreignScope, 'fields', $foreignField, 'type'], $type);
|
||||
}
|
||||
}
|
||||
$typesCache[$name] = $type;
|
||||
|
||||
$link = null;
|
||||
if ($defs['type'] == 'link') {
|
||||
if ($type == 'link') {
|
||||
if (array_key_exists($name.'Name', $row)) {
|
||||
$sheet->setCellValue("$col$rowNumber", $row[$name.'Name']);
|
||||
}
|
||||
} else if ($defs['type'] == 'linkParent') {
|
||||
} else if ($type == 'linkParent') {
|
||||
if (array_key_exists($name.'Name', $row)) {
|
||||
$sheet->setCellValue("$col$rowNumber", $row[$name.'Name']);
|
||||
}
|
||||
} else if ($defs['type'] == 'int') {
|
||||
} else if ($type == 'int') {
|
||||
$sheet->setCellValue("$col$rowNumber", $row[$name] ?: 0);
|
||||
} else if ($defs['type'] == 'currency') {
|
||||
} else if ($type == 'currency') {
|
||||
if (array_key_exists($name.'Currency', $row) && array_key_exists($name, $row)) {
|
||||
$sheet->setCellValue("$col$rowNumber", $row[$name] ? $row[$name] : '');
|
||||
$currency = $row[$name . 'Currency'];
|
||||
@@ -263,7 +272,7 @@ class Xlsx extends \Espo\Core\Injectable
|
||||
->getNumberFormat()
|
||||
->setFormatCode('[$'.$currencySymbol.'-409]#,##0.00;-[$'.$currencySymbol.'-409]#,##0.00');
|
||||
}
|
||||
} else if ($defs['type'] == 'currencyConverted') {
|
||||
} else if ($type == 'currencyConverted') {
|
||||
if (array_key_exists($name, $row)) {
|
||||
$currency = $this->getConfig()->get('baseCurrency');
|
||||
$currencySymbol = $this->getMetadata()->get(['app', 'currency', 'symbolMap', $currency], '');
|
||||
@@ -274,7 +283,7 @@ class Xlsx extends \Espo\Core\Injectable
|
||||
|
||||
$sheet->setCellValue("$col$rowNumber", $row[$name] ? $row[$name] : '');
|
||||
}
|
||||
} else if ($defs['type'] == 'personName') {
|
||||
} else if ($type == 'personName') {
|
||||
if (!empty($row['name'])) {
|
||||
$sheet->setCellValue("$col$rowNumber", $row['name']);
|
||||
} else {
|
||||
@@ -290,15 +299,15 @@ class Xlsx extends \Espo\Core\Injectable
|
||||
}
|
||||
$sheet->setCellValue("$col$rowNumber", $personName);
|
||||
}
|
||||
} else if ($defs['type'] == 'date') {
|
||||
} else if ($type == 'date') {
|
||||
if (isset($row[$name])) {
|
||||
$sheet->setCellValue("$col$rowNumber", \PHPExcel_Shared_Date::PHPToExcel(strtotime($row[$name])));
|
||||
}
|
||||
} else if ($defs['type'] == 'datetime' || $defs['type'] == 'datetimeOptional') {
|
||||
} else if ($type == 'datetime' || $type == 'datetimeOptional') {
|
||||
if (isset($row[$name])) {
|
||||
$sheet->setCellValue("$col$rowNumber", \PHPExcel_Shared_Date::PHPToExcel(strtotime($row[$name])));
|
||||
}
|
||||
} else if ($defs['type'] == 'image') {
|
||||
} else if ($type == 'image') {
|
||||
if (isset($row[$name . 'Id']) && $row[$name . 'Id']) {
|
||||
$attachment = $this->getEntityManager()->getEntity('Attachment', $row[$name . 'Id']);
|
||||
|
||||
@@ -316,13 +325,17 @@ class Xlsx extends \Espo\Core\Injectable
|
||||
}
|
||||
}
|
||||
|
||||
} else if ($defs['type'] == 'file') {
|
||||
} else if ($type == 'file') {
|
||||
if (array_key_exists($name.'Name', $row)) {
|
||||
$sheet->setCellValue("$col$rowNumber", $row[$name.'Name']);
|
||||
}
|
||||
} else if ($defs['type'] == 'enum') {
|
||||
} else if ($type == 'enum') {
|
||||
if (array_key_exists($name, $row)) {
|
||||
$value = $this->getInjection('language')->translateOption($row[$name], $name, $entityType);
|
||||
if ($linkName) {
|
||||
$value = $this->getInjection('language')->translateOption($row[$name], $foreignField, $foreignScope);
|
||||
} else {
|
||||
$value = $this->getInjection('language')->translateOption($row[$name], $name, $entityType);
|
||||
}
|
||||
$sheet->setCellValue("$col$rowNumber", $value);
|
||||
}
|
||||
} else {
|
||||
@@ -337,30 +350,30 @@ class Xlsx extends \Espo\Core\Injectable
|
||||
if (array_key_exists('id', $row)) {
|
||||
$link = $this->getConfig()->getSiteUrl() . "/#".$entityType . "/view/" . $row['id'];
|
||||
}
|
||||
} else if ($defs['type'] == 'url') {
|
||||
} else if ($type == 'url') {
|
||||
if (array_key_exists($name, $row) && filter_var($row[$name], FILTER_VALIDATE_URL)) {
|
||||
$link = $row[$name];
|
||||
}
|
||||
} else if ($defs['type'] == 'link') {
|
||||
} else if ($type == 'link') {
|
||||
if (array_key_exists($name.'Id', $row)) {
|
||||
$foreignEntity = $this->getMetadata()->get(['entityDefs', $entityType, 'links', $name, 'entity']);
|
||||
if ($foreignEntity) {
|
||||
$link = $this->getConfig()->getSiteUrl() . "/#" . $foreignEntity. "/view/". $row[$name.'Id'];
|
||||
}
|
||||
}
|
||||
} else if ($defs['type'] == 'file') {
|
||||
} else if ($type == 'file') {
|
||||
if (array_key_exists($name.'Id', $row)) {
|
||||
$link = $this->getConfig()->getSiteUrl() . "/?entryPoint=download&id=" . $row[$name.'Id'];
|
||||
}
|
||||
} else if ($defs['type'] == 'linkParent') {
|
||||
} else if ($type == 'linkParent') {
|
||||
if (array_key_exists($name.'Id', $row) && array_key_exists($name.'Type', $row)) {
|
||||
$link = $this->getConfig()->getSiteUrl() . "/#".$row[$name.'Type']."/view/". $row[$name.'Id'];
|
||||
}
|
||||
} else if ($defs['type'] == 'phone') {
|
||||
} else if ($type == 'phone') {
|
||||
if (array_key_exists($name, $row)) {
|
||||
$link = "tel:".$row[$name];
|
||||
}
|
||||
} else if ($defs['type'] == 'email' && array_key_exists($name, $row)) {
|
||||
} else if ($type == 'email' && array_key_exists($name, $row)) {
|
||||
if (array_key_exists($name, $row)) {
|
||||
$link = "mailto:".$row[$name];
|
||||
}
|
||||
@@ -373,52 +386,48 @@ class Xlsx extends \Espo\Core\Injectable
|
||||
$rowNumber++;
|
||||
}
|
||||
|
||||
$sheet->getStyle("A2:A$rowNumber")
|
||||
->getNumberFormat()
|
||||
->setFormatCode(\PHPExcel_Style_NumberFormat::FORMAT_TEXT);
|
||||
|
||||
$startingRowNumber = 4;
|
||||
|
||||
foreach ($fieldList as $i => $name) {
|
||||
$col = $azRange[$i];
|
||||
|
||||
$defs = $this->getInjection('metadata')->get(['entityDefs', $entityType, 'fields', $name]);
|
||||
if (!$defs) {
|
||||
$defs['type'] = 'base';
|
||||
}
|
||||
$type = $typesCache[$name];
|
||||
|
||||
if ($col == 'A') {
|
||||
$sheet->getStyle("A2:A$rowNumber")
|
||||
->getNumberFormat()
|
||||
->setFormatCode(\PHPExcel_Style_NumberFormat::FORMAT_TEXT);
|
||||
} else {
|
||||
switch($defs['type']) {
|
||||
case 'currency':
|
||||
case 'currencyConverted': {
|
||||
|
||||
} break;
|
||||
case 'int': {
|
||||
$sheet->getStyle($col.$startingRowNumber.':'.$col.$rowNumber)
|
||||
->getNumberFormat()
|
||||
->setFormatCode('0');
|
||||
} break;
|
||||
case 'date': {
|
||||
$sheet->getStyle($col.$startingRowNumber.':'.$col.$rowNumber)
|
||||
->getNumberFormat()
|
||||
->setFormatCode($this->getInjection('dateTime')->getDateFormat());
|
||||
} break;
|
||||
case 'datetime': {
|
||||
$sheet->getStyle($col.$startingRowNumber.':'.$col.$rowNumber)
|
||||
->getNumberFormat()
|
||||
->setFormatCode($this->getInjection('dateTime')->getDateTimeFormat());
|
||||
} break;
|
||||
case 'datetimeOptional': {
|
||||
$sheet->getStyle($col.$startingRowNumber.':'.$col.$rowNumber)
|
||||
->getNumberFormat()
|
||||
->setFormatCode($this->getInjection('dateTime')->getDateTimeFormat());
|
||||
} break;
|
||||
default: {
|
||||
$sheet->getStyle($col.$startingRowNumber.':'.$col.$rowNumber)
|
||||
->getNumberFormat()
|
||||
->setFormatCode('@');
|
||||
} break;
|
||||
}
|
||||
switch($type) {
|
||||
case 'currency':
|
||||
case 'currencyConverted': {
|
||||
|
||||
} break;
|
||||
case 'int': {
|
||||
$sheet->getStyle($col.$startingRowNumber.':'.$col.$rowNumber)
|
||||
->getNumberFormat()
|
||||
->setFormatCode('0');
|
||||
} break;
|
||||
case 'date': {
|
||||
$sheet->getStyle($col.$startingRowNumber.':'.$col.$rowNumber)
|
||||
->getNumberFormat()
|
||||
->setFormatCode($this->getInjection('dateTime')->getDateFormat());
|
||||
} break;
|
||||
case 'datetime': {
|
||||
$sheet->getStyle($col.$startingRowNumber.':'.$col.$rowNumber)
|
||||
->getNumberFormat()
|
||||
->setFormatCode($this->getInjection('dateTime')->getDateTimeFormat());
|
||||
} break;
|
||||
case 'datetimeOptional': {
|
||||
$sheet->getStyle($col.$startingRowNumber.':'.$col.$rowNumber)
|
||||
->getNumberFormat()
|
||||
->setFormatCode($this->getInjection('dateTime')->getDateTimeFormat());
|
||||
} break;
|
||||
default: {
|
||||
$sheet->getStyle($col.$startingRowNumber.':'.$col.$rowNumber)
|
||||
->getNumberFormat()
|
||||
->setFormatCode('@');
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,11 @@ class ExtensionManager extends Upgrades\Base
|
||||
'after' => 'AfterInstall',
|
||||
'beforeUninstall' => 'BeforeUninstall',
|
||||
'afterUninstall' => 'AfterUninstall',
|
||||
),
|
||||
|
||||
'customDirNames' => array(
|
||||
'before' => 'beforeInstallFiles',
|
||||
'after' => 'afterInstallFiles',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2017 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
|
||||
* Website: http://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\ArrayGroup;
|
||||
|
||||
use \Espo\Core\Exceptions\Error;
|
||||
|
||||
class LengthType extends \Espo\Core\Formula\Functions\Base
|
||||
{
|
||||
public function process(\StdClass $item)
|
||||
{
|
||||
if (!property_exists($item, 'value')) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
$list = $this->evaluate($item->value[0]);
|
||||
|
||||
if (!is_array($list)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return count($list);
|
||||
}
|
||||
}
|
||||
@@ -54,18 +54,15 @@ class DayOfWeekType extends \Espo\Core\Formula\Functions\Base
|
||||
|
||||
$value = $this->evaluate($item->value[0]);
|
||||
|
||||
if (empty($value)) return 0;
|
||||
if (empty($value)) return -1;
|
||||
|
||||
if (strlen($value) > 11) {
|
||||
$resultString = $this->getInjection('dateTime')->convertSystemDateTime($value, null, 'D');
|
||||
$resultString = $this->getInjection('dateTime')->convertSystemDateTime($value, null, 'e');
|
||||
} else {
|
||||
$resultString = $this->getInjection('dateTime')->convertSystemDate($value, 'D');
|
||||
$resultString = $this->getInjection('dateTime')->convertSystemDate($value, 'e');
|
||||
}
|
||||
|
||||
$result = intval($resultString) + 1;
|
||||
if ($result == 8) {
|
||||
$result = 1;
|
||||
}
|
||||
$result = intval($resultString);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
@@ -393,6 +393,9 @@ class Parser
|
||||
{
|
||||
$functionContent = trim($functionContent);
|
||||
|
||||
$isString = false;
|
||||
$isSingleQuote = false;
|
||||
|
||||
if ($functionContent === '') {
|
||||
return [];
|
||||
}
|
||||
@@ -400,13 +403,35 @@ class Parser
|
||||
$commaIndexList = [];
|
||||
$braceCounter = 0;
|
||||
for ($i = 0; $i < strlen($functionContent); $i++) {
|
||||
if ($functionContent[$i] === '(') {
|
||||
$braceCounter++;
|
||||
} else if ($functionContent[$i] === ')') {
|
||||
$braceCounter--;
|
||||
if ($functionContent[$i] === "'" && ($i === 0 || $functionContent[$i - 1] !== "\\")) {
|
||||
if (!$isString) {
|
||||
$isString = true;
|
||||
$isSingleQuote = true;
|
||||
} else {
|
||||
if ($isSingleQuote) {
|
||||
$isString = false;
|
||||
}
|
||||
}
|
||||
} else if ($functionContent[$i] === "\"" && ($i === 0 || $functionContent[$i - 1] !== "\\")) {
|
||||
if (!$isString) {
|
||||
$isString = true;
|
||||
$isSingleQuote = false;
|
||||
} else {
|
||||
if (!$isSingleQuote) {
|
||||
$isString = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($braceCounter === 0 && $functionContent[$i] === ',') {
|
||||
if (!$isString) {
|
||||
if ($functionContent[$i] === '(') {
|
||||
$braceCounter++;
|
||||
} else if ($functionContent[$i] === ')') {
|
||||
$braceCounter--;
|
||||
}
|
||||
}
|
||||
|
||||
if ($braceCounter === 0 && !$isString && $functionContent[$i] === ',') {
|
||||
$commaIndexList[] = $i;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,17 @@ abstract class Injectable implements \Espo\Core\Interfaces\Injectable
|
||||
{
|
||||
}
|
||||
|
||||
public function __call($methodName, $args)
|
||||
{
|
||||
if (strpos($methodName, 'get') === 0) {
|
||||
$injectionName = lcfirst(substr($methodName, 3));
|
||||
if (in_array($injectionName, $this->dependencyList)) {
|
||||
return $this->getInjection($injectionName);
|
||||
}
|
||||
}
|
||||
throw new \BadMethodCallException('Method ' . $methodName . ' does not exist');
|
||||
}
|
||||
|
||||
protected function getInjection($name)
|
||||
{
|
||||
return $this->injections[$name];
|
||||
|
||||
@@ -45,7 +45,12 @@ class EntityManager extends Base
|
||||
'metadata' => $this->getContainer()->get('ormMetadata')->getData(),
|
||||
'repositoryFactoryClassName' => '\\Espo\\Core\\ORM\\RepositoryFactory',
|
||||
'driver' => $config->get('database.driver'),
|
||||
'platform' => $config->get('database.platform')
|
||||
'platform' => $config->get('database.platform'),
|
||||
'sslCA' => $config->get('database.sslCA'),
|
||||
'sslCert' => $config->get('database.sslCert'),
|
||||
'sslKey' => $config->get('database.sslKey'),
|
||||
'sslCAPath' => $config->get('database.sslCAPath'),
|
||||
'sslCipher' => $config->get('database.sslCipher')
|
||||
);
|
||||
|
||||
$entityManager = new \Espo\Core\ORM\EntityManager($params);
|
||||
|
||||
@@ -203,8 +203,10 @@ class Importer
|
||||
} catch (\Exception $e) {}
|
||||
}
|
||||
|
||||
$inlineAttachmentList = [];
|
||||
|
||||
if (!$fetchOnlyHeader) {
|
||||
$parser->fetchContentParts($email, $message);
|
||||
$parser->fetchContentParts($email, $message, $inlineAttachmentList);
|
||||
|
||||
if ($this->getFiltersMatcher()->match($email, $filterList)) {
|
||||
return false;
|
||||
@@ -299,6 +301,14 @@ class Importer
|
||||
|
||||
$this->getEntityManager()->saveEntity($email);
|
||||
|
||||
foreach ($inlineAttachmentList as $attachment) {
|
||||
$attachment->set(array(
|
||||
'relatedId' => $email->id,
|
||||
'relatedType' => 'Email'
|
||||
));
|
||||
$this->getEntityManager()->saveEntity($attachment);
|
||||
}
|
||||
|
||||
return $email;
|
||||
}
|
||||
|
||||
@@ -314,11 +324,10 @@ class Importer
|
||||
$email->set('parentId', $contact->get('accountId'));
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
$email->set('parentType', 'Contact');
|
||||
$email->set('parentId', $contact->id);
|
||||
return true;
|
||||
}
|
||||
$email->set('parentType', 'Contact');
|
||||
$email->set('parentId', $contact->id);
|
||||
return true;
|
||||
} else {
|
||||
$account = $this->getEntityManager()->getRepository('Account')->where(array(
|
||||
'emailAddress' => $emailAddress
|
||||
|
||||
@@ -143,7 +143,7 @@ class MailMimeParser
|
||||
return $addressList;
|
||||
}
|
||||
|
||||
public function fetchContentParts(\Espo\Entities\Email $email, $message)
|
||||
public function fetchContentParts(\Espo\Entities\Email $email, $message, &$inlineAttachmentList = [])
|
||||
{
|
||||
$this->loadContent($message);
|
||||
|
||||
@@ -202,6 +202,7 @@ class MailMimeParser
|
||||
if ($contentId) {
|
||||
$inlineIds[$contentId] = $attachment->id;
|
||||
}
|
||||
$inlineAttachmentList[] = $attachment;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -133,7 +133,7 @@ class PhpMimeMailParser
|
||||
return $addressList;
|
||||
}
|
||||
|
||||
public function fetchContentParts(\Espo\Entities\Email $email, $message)
|
||||
public function fetchContentParts(\Espo\Entities\Email $email, $message, &$inlineAttachmentList = [])
|
||||
{
|
||||
$this->loadContent($message);
|
||||
|
||||
@@ -187,6 +187,7 @@ class PhpMimeMailParser
|
||||
if ($contentId) {
|
||||
$inlineIds[$contentId] = $attachment->id;
|
||||
}
|
||||
$inlineAttachmentList[] = $attachment;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -125,7 +125,7 @@ class ZendMail
|
||||
return $addressList;
|
||||
}
|
||||
|
||||
public function fetchContentParts(\Espo\Entities\Email $email, $message)
|
||||
public function fetchContentParts(\Espo\Entities\Email $email, $message, &$inlineAttachmentList = [])
|
||||
{
|
||||
$zendMessage = $message->getZendMessage();
|
||||
|
||||
@@ -133,10 +133,10 @@ class ZendMail
|
||||
|
||||
if ($zendMessage->isMultipart()) {
|
||||
foreach (new \RecursiveIteratorIterator($zendMessage) as $part) {
|
||||
$this->importPartDataToEmail($email, $part, $inlineIds);
|
||||
$this->importPartDataToEmail($email, $part, $inlineIds, null, $inlineAttachmentList);
|
||||
}
|
||||
} else {
|
||||
$this->importPartDataToEmail($email, $zendMessage, $inlineIds, 'text/plain');
|
||||
$this->importPartDataToEmail($email, $zendMessage, $inlineIds, 'text/plain', $inlineAttachmentList);
|
||||
}
|
||||
|
||||
if (!$email->get('body') && $email->get('bodyPlain')) {
|
||||
@@ -156,7 +156,7 @@ class ZendMail
|
||||
}
|
||||
}
|
||||
|
||||
protected function importPartDataToEmail(\Espo\Entities\Email $email, $part, &$inlineIds = array(), $defaultContentType = null)
|
||||
protected function importPartDataToEmail(\Espo\Entities\Email $email, $part, &$inlineIds = array(), $defaultContentType = null, &$inlineAttachmentList = [])
|
||||
{
|
||||
try {
|
||||
$type = null;
|
||||
@@ -275,6 +275,7 @@ class ZendMail
|
||||
}
|
||||
} else if ($disposition == 'inline') {
|
||||
$inlineIds[$contentId] = $attachment->id;
|
||||
$inlineAttachmentList[] = $attachment;
|
||||
}
|
||||
}
|
||||
} catch (\Exception $e) {}
|
||||
|
||||
@@ -47,6 +47,10 @@ class RDB extends \Espo\ORM\Repositories\RDB implements Injectable
|
||||
|
||||
private $restoreData = null;
|
||||
|
||||
protected $hooksDisabled = false;
|
||||
|
||||
protected $processFieldsAfterSaveDisabled = false;
|
||||
|
||||
protected function addDependency($name)
|
||||
{
|
||||
$this->dependencies[] = $name;
|
||||
@@ -172,7 +176,9 @@ class RDB extends \Espo\ORM\Repositories\RDB implements Injectable
|
||||
protected function beforeRemove(Entity $entity, array $options = array())
|
||||
{
|
||||
parent::beforeRemove($entity, $options);
|
||||
$this->getEntityManager()->getHookManager()->process($this->entityType, 'beforeRemove', $entity, $options);
|
||||
if (!$this->hooksDisabled) {
|
||||
$this->getEntityManager()->getHookManager()->process($this->entityType, 'beforeRemove', $entity, $options);
|
||||
}
|
||||
|
||||
$nowString = date('Y-m-d H:i:s', time());
|
||||
if ($entity->hasAttribute('modifiedAt')) {
|
||||
@@ -186,25 +192,25 @@ class RDB extends \Espo\ORM\Repositories\RDB implements Injectable
|
||||
protected function afterRemove(Entity $entity, array $options = array())
|
||||
{
|
||||
parent::afterRemove($entity, $options);
|
||||
$this->getEntityManager()->getHookManager()->process($this->entityType, 'afterRemove', $entity, $options);
|
||||
if (!$this->hooksDisabled) {
|
||||
$this->getEntityManager()->getHookManager()->process($this->entityType, 'afterRemove', $entity, $options);
|
||||
}
|
||||
}
|
||||
|
||||
protected function afterMassRelate(Entity $entity, $relationName, array $params = array(), array $options = array())
|
||||
{
|
||||
$hookData = array(
|
||||
'relationName' => $relationName,
|
||||
'relationParams' => $params
|
||||
);
|
||||
|
||||
$this->getEntityManager()->getHookManager()->process($this->entityType, 'afterMassRelate', $entity, $options, $hookData);
|
||||
if (!$this->hooksDisabled) {
|
||||
$hookData = array(
|
||||
'relationName' => $relationName,
|
||||
'relationParams' => $params
|
||||
);
|
||||
$this->getEntityManager()->getHookManager()->process($this->entityType, 'afterMassRelate', $entity, $options, $hookData);
|
||||
}
|
||||
}
|
||||
|
||||
public function remove(Entity $entity, array $options = array())
|
||||
{
|
||||
$result = parent::remove($entity, $options);
|
||||
if ($result) {
|
||||
$this->getEntityManager()->getHookManager()->process($this->entityType, 'afterRemove', $entity, $options);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
@@ -214,12 +220,14 @@ class RDB extends \Espo\ORM\Repositories\RDB implements Injectable
|
||||
|
||||
if ($foreign instanceof Entity) {
|
||||
$foreignEntity = $foreign;
|
||||
$hookData = array(
|
||||
'relationName' => $relationName,
|
||||
'relationData' => $data,
|
||||
'foreignEntity' => $foreignEntity
|
||||
);
|
||||
$this->getEntityManager()->getHookManager()->process($this->entityType, 'afterRelate', $entity, $options, $hookData);
|
||||
if (!$this->hooksDisabled) {
|
||||
$hookData = array(
|
||||
'relationName' => $relationName,
|
||||
'relationData' => $data,
|
||||
'foreignEntity' => $foreignEntity
|
||||
);
|
||||
$this->getEntityManager()->getHookManager()->process($this->entityType, 'afterRelate', $entity, $options, $hookData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,11 +237,13 @@ class RDB extends \Espo\ORM\Repositories\RDB implements Injectable
|
||||
|
||||
if ($foreign instanceof Entity) {
|
||||
$foreignEntity = $foreign;
|
||||
$hookData = array(
|
||||
'relationName' => $relationName,
|
||||
'foreignEntity' => $foreignEntity
|
||||
);
|
||||
$this->getEntityManager()->getHookManager()->process($this->entityType, 'afterUnrelate', $entity, $options, $hookData);
|
||||
if (!$this->hooksDisabled) {
|
||||
$hookData = array(
|
||||
'relationName' => $relationName,
|
||||
'foreignEntity' => $foreignEntity
|
||||
);
|
||||
$this->getEntityManager()->getHookManager()->process($this->entityType, 'afterUnrelate', $entity, $options, $hookData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,7 +251,9 @@ class RDB extends \Espo\ORM\Repositories\RDB implements Injectable
|
||||
{
|
||||
parent::beforeSave($entity, $options);
|
||||
|
||||
$this->getEntityManager()->getHookManager()->process($this->entityType, 'beforeSave', $entity, $options);
|
||||
if (!$this->hooksDisabled) {
|
||||
$this->getEntityManager()->getHookManager()->process($this->entityType, 'beforeSave', $entity, $options);
|
||||
}
|
||||
}
|
||||
|
||||
protected function afterSave(Entity $entity, array $options = array())
|
||||
@@ -252,12 +264,16 @@ class RDB extends \Espo\ORM\Repositories\RDB implements Injectable
|
||||
}
|
||||
parent::afterSave($entity, $options);
|
||||
|
||||
$this->processEmailAddressSave($entity);
|
||||
$this->processPhoneNumberSave($entity);
|
||||
$this->processSpecifiedRelationsSave($entity);
|
||||
$this->processFileFieldsSave($entity);
|
||||
if (!$this->processFieldsAfterSaveDisabled) {
|
||||
$this->processEmailAddressSave($entity);
|
||||
$this->processPhoneNumberSave($entity);
|
||||
$this->processSpecifiedRelationsSave($entity);
|
||||
$this->processFileFieldsSave($entity);
|
||||
}
|
||||
|
||||
$this->getEntityManager()->getHookManager()->process($this->entityType, 'afterSave', $entity, $options);
|
||||
if (!$this->hooksDisabled) {
|
||||
$this->getEntityManager()->getHookManager()->process($this->entityType, 'afterSave', $entity, $options);
|
||||
}
|
||||
}
|
||||
|
||||
public function save(Entity $entity, array $options = array())
|
||||
@@ -324,6 +340,24 @@ class RDB extends \Espo\ORM\Repositories\RDB implements Injectable
|
||||
));
|
||||
$this->getEntityManager()->saveEntity($attachment);
|
||||
}
|
||||
|
||||
if (!$entity->isNew()) {
|
||||
|
||||
foreach ($this->getMetadata()->get(['entityDefs', $entity->getEntityType(), 'fields']) as $name => $defs) {
|
||||
if (!empty($defs['type']) && in_array($defs['type'], ['file', 'image'])) {
|
||||
$attribute = $name . 'Id';
|
||||
if ($entity->isAttributeChanged($attribute)) {
|
||||
$previousAttachmentId = $entity->getFetched($attribute);
|
||||
if ($previousAttachmentId) {
|
||||
$attachment = $this->getEntityManager()->getEntity('Attachment', $previousAttachmentId);
|
||||
if ($attachment) {
|
||||
$this->getEntityManager()->removeEntity($attachment);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function processEmailAddressSave(Entity $entity)
|
||||
@@ -405,8 +439,16 @@ class RDB extends \Espo\ORM\Repositories\RDB implements Injectable
|
||||
} else {
|
||||
if (!empty($columns)) {
|
||||
foreach ($columns as $columnName => $columnField) {
|
||||
if (isset($columnData->$id)) {
|
||||
if ($columnData->$id->$columnName !== $existingColumnsData->$id->$columnName) {
|
||||
if (isset($columnData->$id) && is_object($columnData->$id)) {
|
||||
if (
|
||||
property_exists($columnData->$id, $columnName)
|
||||
&&
|
||||
(
|
||||
!property_exists($existingColumnsData->$id, $columnName)
|
||||
||
|
||||
$columnData->$id->$columnName !== $existingColumnsData->$id->$columnName
|
||||
)
|
||||
) {
|
||||
$toUpdateIds[] = $id;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,8 +36,20 @@ class Event extends \Espo\Core\ORM\Repositories\RDB
|
||||
{
|
||||
protected $reminderDateAttribute = 'dateStart';
|
||||
|
||||
protected $reminderSkippingStatusList = ['Held', 'Not Held'];
|
||||
|
||||
protected function beforeSave(Entity $entity, array $options = array())
|
||||
{
|
||||
if ($entity->isAttributeChanged('status') && in_array($entity->get('status'), $this->reminderSkippingStatusList)) {
|
||||
$entity->set('reminders', []);
|
||||
}
|
||||
parent::beforeSave($entity, $options);
|
||||
}
|
||||
|
||||
protected function afterRemove(Entity $entity, array $options = array())
|
||||
{
|
||||
parent::afterRemove($entity, $options);
|
||||
|
||||
$pdo = $this->getEntityManager()->getPDO();
|
||||
$sql = "
|
||||
DELETE FROM `reminder`
|
||||
|
||||
@@ -188,6 +188,8 @@ class Base
|
||||
|
||||
$whereClause = array();
|
||||
foreach ($where as $item) {
|
||||
if (!isset($item['type'])) continue;
|
||||
|
||||
if ($item['type'] == 'bool' && !empty($item['value']) && is_array($item['value'])) {
|
||||
foreach ($item['value'] as $filter) {
|
||||
$p = $this->getBoolFilterWhere($filter);
|
||||
@@ -210,6 +212,8 @@ class Base
|
||||
|
||||
$additionalFilters = array();
|
||||
foreach ($where as $item) {
|
||||
if (!isset($item['type'])) continue;
|
||||
|
||||
$type = $item['type'];
|
||||
if (!in_array($type, $ignoreTypeList)) {
|
||||
$part = $this->getWherePart($item, $result);
|
||||
@@ -817,7 +821,7 @@ class Base
|
||||
$dt->setTime(0, 0, 0);
|
||||
$dt->setTimezone(new \DateTimeZone('UTC'));
|
||||
$from = $dt->format($format);
|
||||
$dt->modify('+1 day');
|
||||
$dt->modify('+1 day -1 second');
|
||||
$to = $dt->format($format);
|
||||
$where['value'] = [$from, $to];
|
||||
break;
|
||||
@@ -907,8 +911,7 @@ class Base
|
||||
$dt = new \DateTime($value, new \DateTimeZone($timeZone));
|
||||
$dt->setTimezone(new \DateTimeZone('UTC'));
|
||||
$from = $dt->format($format);
|
||||
|
||||
$dt->modify('+1 day');
|
||||
$dt->modify('+1 day -1 second');
|
||||
$to = $dt->format($format);
|
||||
$where['value'] = [$from, $to];
|
||||
break;
|
||||
@@ -933,6 +936,7 @@ class Base
|
||||
|
||||
$dt = new \DateTime($value[1], new \DateTimeZone($timeZone));
|
||||
$dt->setTimezone(new \DateTimeZone('UTC'));
|
||||
$dt->modify('-1 second');
|
||||
$to = $dt->format($format);
|
||||
|
||||
$where['value'] = [$from, $to];
|
||||
@@ -1002,6 +1006,9 @@ class Base
|
||||
case 'like':
|
||||
$part[$attribute . '*'] = $item['value'];
|
||||
break;
|
||||
case 'notLike':
|
||||
$part[$attribute . '!*'] = $item['value'];
|
||||
break;
|
||||
case 'equals':
|
||||
case 'on':
|
||||
$part[$attribute . '='] = $item['value'];
|
||||
@@ -1015,6 +1022,9 @@ class Base
|
||||
case 'contains':
|
||||
$part[$attribute . '*'] = '%' . $item['value'] . '%';
|
||||
break;
|
||||
case 'notContains':
|
||||
$part[$attribute . '!*'] = '%' . $item['value'] . '%';
|
||||
break;
|
||||
case 'notEquals':
|
||||
case 'notOn':
|
||||
$part[$attribute . '!='] = $item['value'];
|
||||
@@ -1031,7 +1041,7 @@ class Base
|
||||
$part[$attribute . '>='] = $item['value'];
|
||||
break;
|
||||
case 'lessThanOrEquals':
|
||||
$part[$attribute . '<'] = $item['value'];
|
||||
$part[$attribute . '<='] = $item['value'];
|
||||
break;
|
||||
case 'in':
|
||||
$part[$attribute . '='] = $item['value'];
|
||||
@@ -1162,16 +1172,49 @@ class Base
|
||||
);
|
||||
}
|
||||
break;
|
||||
case 'columnLike':
|
||||
case 'columnIn':
|
||||
case 'columnIsNull':
|
||||
case 'columnNotIn':
|
||||
$link = $this->getMetadata()->get(['entityDefs', $this->entityType, 'fields', $attribute, 'link']);
|
||||
$column = $this->getMetadata()->get(['entityDefs', $this->entityType, 'fields', $attribute, 'column']);
|
||||
$alias = $link . 'Filter' . strval(rand(10000, 99999));
|
||||
$this->setDistinct(true, $result);
|
||||
$this->addLeftJoin([$link, $alias], $result);
|
||||
$value = $item['value'];
|
||||
$columnKey = $alias . 'Middle.' . $column;
|
||||
if ($item['type'] === 'columnIn') {
|
||||
$part[$columnKey] = $value;
|
||||
} else if ($item['type'] === 'columnNotIn') {
|
||||
$part[$columnKey . '!='] = $value;
|
||||
} else if ($item['type'] === 'columnIsNull') {
|
||||
$part[$columnKey] = null;
|
||||
} else if ($item['type'] === 'columnIsNotNull') {
|
||||
$part[$columnKey . '!='] = null;
|
||||
} else if ($item['type'] === 'columnLike') {
|
||||
$part[$columnKey . '*'] = $value;
|
||||
} else if ($item['type'] === 'columnStartsWith') {
|
||||
$part[$columnKey . '*'] = $value . '%';
|
||||
} else if ($item['type'] === 'columnEndsWith') {
|
||||
$part[$columnKey . '*'] = '%' . $value;
|
||||
} else if ($item['type'] === 'columnContains') {
|
||||
$part[$columnKey . '*'] = '%' . $value . '%';
|
||||
} else if ($item['type'] === 'columnEquals') {
|
||||
$part[$columnKey . '='] = $value;
|
||||
} else if ($item['type'] === 'columnNotEquals') {
|
||||
$part[$columnKey . '!='] = $value;
|
||||
}
|
||||
break;
|
||||
case 'isNotLinked':
|
||||
if (!$result) break;
|
||||
$alias = $attribute . 'IsNotLinkedFilter' . strval(rand(10000, 99999));;
|
||||
$alias = $attribute . 'IsNotLinkedFilter' . strval(rand(10000, 99999));
|
||||
$part[$alias . '.id'] = null;
|
||||
$this->setDistinct(true, $result);
|
||||
$this->addLeftJoin([$attribute, $alias], $result);
|
||||
break;
|
||||
case 'isLinked':
|
||||
if (!$result) break;
|
||||
$alias = $attribute . 'IsLinkedFilter' . strval(rand(10000, 99999));;
|
||||
$alias = $attribute . 'IsLinkedFilter' . strval(rand(10000, 99999));
|
||||
$part[$alias . '.id!='] = null;
|
||||
$this->setDistinct(true, $result);
|
||||
$this->addLeftJoin([$attribute, $alias], $result);
|
||||
|
||||
5
application/Espo/Core/Templates/i18n/en_GB/Base.json
Normal file
5
application/Espo/Core/Templates/i18n/en_GB/Base.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"labels": {
|
||||
"Create {entityType}": "Create {entityTypeTranslated}"
|
||||
}
|
||||
}
|
||||
10
application/Espo/Core/Templates/i18n/en_GB/BasePlus.json
Normal file
10
application/Espo/Core/Templates/i18n/en_GB/BasePlus.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"links": {
|
||||
"meetings": "Meetings",
|
||||
"calls": "Calls",
|
||||
"tasks": "Tasks"
|
||||
},
|
||||
"labels": {
|
||||
"Create {entityType}": "Create {entityTypeTranslated}"
|
||||
}
|
||||
}
|
||||
15
application/Espo/Core/Templates/i18n/en_GB/Company.json
Normal file
15
application/Espo/Core/Templates/i18n/en_GB/Company.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"fields": {
|
||||
"billingAddress": "Billing Address",
|
||||
"shippingAddress": "Shipping Address",
|
||||
"website": "Website"
|
||||
},
|
||||
"links": {
|
||||
"meetings": "Meetings",
|
||||
"calls": "Calls",
|
||||
"tasks": "Tasks"
|
||||
},
|
||||
"labels": {
|
||||
"Create {entityType}": "Create {entityTypeTranslated}"
|
||||
}
|
||||
}
|
||||
36
application/Espo/Core/Templates/i18n/en_GB/Event.json
Normal file
36
application/Espo/Core/Templates/i18n/en_GB/Event.json
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"fields": {
|
||||
"parent": "Parent",
|
||||
"dateStart": "Date Start",
|
||||
"dateEnd": "Date End",
|
||||
"duration": "Duration",
|
||||
"status": "Status",
|
||||
"reminders": "Reminders"
|
||||
},
|
||||
"links": {
|
||||
"parent": "Parent"
|
||||
},
|
||||
"options": {
|
||||
"status": {
|
||||
"Planned": "Planned",
|
||||
"Held": "Held",
|
||||
"Not Held": "Not Held"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
"Create {entityType}": "Create {entityTypeTranslated}",
|
||||
"Schedule {entityType}": "Schedule {entityTypeTranslated}",
|
||||
"Log {entityType}": "Log {entityTypeTranslated}",
|
||||
"Set Held": "Set Held",
|
||||
"Set Not Held": "Set Not Held"
|
||||
},
|
||||
"massActions": {
|
||||
"setHeld": "Set Held",
|
||||
"setNotHeld": "Set Not Held"
|
||||
},
|
||||
"presetFilters": {
|
||||
"planned": "Planned",
|
||||
"held": "Held",
|
||||
"todays": "Today's"
|
||||
}
|
||||
}
|
||||
13
application/Espo/Core/Templates/i18n/en_GB/Person.json
Normal file
13
application/Espo/Core/Templates/i18n/en_GB/Person.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"fields": {
|
||||
"address": "Address"
|
||||
},
|
||||
"links": {
|
||||
"meetings": "Meetings",
|
||||
"calls": "Calls",
|
||||
"tasks": "Tasks"
|
||||
},
|
||||
"labels": {
|
||||
"Create {entityType}": "Create {entityTypeTranslated}"
|
||||
}
|
||||
}
|
||||
5
application/Espo/Core/Templates/i18n/es_MX/Base.json
Normal file
5
application/Espo/Core/Templates/i18n/es_MX/Base.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"labels": {
|
||||
"Create {entityType}": "Crear {entityTypeTranslated}"
|
||||
}
|
||||
}
|
||||
10
application/Espo/Core/Templates/i18n/es_MX/BasePlus.json
Normal file
10
application/Espo/Core/Templates/i18n/es_MX/BasePlus.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"links": {
|
||||
"meetings": "Juntas",
|
||||
"calls": "Llamadas",
|
||||
"tasks": "Tareas"
|
||||
},
|
||||
"labels": {
|
||||
"Create {entityType}": "Crear {entityTypeTranslated}"
|
||||
}
|
||||
}
|
||||
15
application/Espo/Core/Templates/i18n/es_MX/Company.json
Normal file
15
application/Espo/Core/Templates/i18n/es_MX/Company.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"fields": {
|
||||
"billingAddress": "Dirección de Facturación",
|
||||
"shippingAddress": "Dirección de envio",
|
||||
"website": "Sitio Web"
|
||||
},
|
||||
"links": {
|
||||
"meetings": "reuniones",
|
||||
"calls": "Llamadas",
|
||||
"tasks": "Tareas"
|
||||
},
|
||||
"labels": {
|
||||
"Create {entityType}": "Crear {entityTypeTranslated}"
|
||||
}
|
||||
}
|
||||
36
application/Espo/Core/Templates/i18n/es_MX/Event.json
Normal file
36
application/Espo/Core/Templates/i18n/es_MX/Event.json
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"fields": {
|
||||
"parent": "Padre",
|
||||
"dateStart": "Fecha de incio",
|
||||
"dateEnd": "Fecha final",
|
||||
"duration": "Duracion",
|
||||
"status": "Estátus",
|
||||
"reminders": "Recordatorios"
|
||||
},
|
||||
"links": {
|
||||
"parent": "Padre"
|
||||
},
|
||||
"options": {
|
||||
"status": {
|
||||
"Planned": "Planeado",
|
||||
"Held": "Retenidas",
|
||||
"Not Held": "Pendientes"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
"Create {entityType}": "Creat",
|
||||
"Schedule {entityType}": "Agendar {entityTypeTranslated}",
|
||||
"Log {entityType}": "Registrar {entityTypeTranslated}",
|
||||
"Set Held": "Marcar como Retenida",
|
||||
"Set Not Held": "Marcar como Pendiente"
|
||||
},
|
||||
"massActions": {
|
||||
"setHeld": "Marcar como Retenida",
|
||||
"setNotHeld": "Marcar como Pendiente"
|
||||
},
|
||||
"presetFilters": {
|
||||
"planned": "Planeado",
|
||||
"held": "Retenida",
|
||||
"todays": "Hoy"
|
||||
}
|
||||
}
|
||||
13
application/Espo/Core/Templates/i18n/es_MX/Person.json
Normal file
13
application/Espo/Core/Templates/i18n/es_MX/Person.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"fields": {
|
||||
"address": "Dirección"
|
||||
},
|
||||
"links": {
|
||||
"meetings": "Reuniones",
|
||||
"calls": "Llamadas",
|
||||
"tasks": "Tareas"
|
||||
},
|
||||
"labels": {
|
||||
"Create {entityType}": "Crear {entityTypeTranslated}"
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"labels": {
|
||||
"Create {entityType}": "Crea {entityTypeTranslated}"
|
||||
}
|
||||
}
|
||||
"labels": {
|
||||
"Create {entityType}": "Crea {entityTypeTranslated}"
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,10 @@
|
||||
{
|
||||
"labels": {
|
||||
"Create {entityType}": "Crea {entityTypeTranslated}"
|
||||
}
|
||||
}
|
||||
"links": {
|
||||
"meetings": "Meeting",
|
||||
"calls": "Chiamate",
|
||||
"tasks": "Task"
|
||||
},
|
||||
"labels": {
|
||||
"Create {entityType}": "Crea {entityTypeTranslated}"
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,15 @@
|
||||
{
|
||||
"labels": {
|
||||
"Create {entityType}": "Crea {entityTypeTranslated}"
|
||||
}
|
||||
}
|
||||
"fields": {
|
||||
"billingAddress": "Indirizzo di Fatturazione",
|
||||
"shippingAddress": "Indirizzo di Spedizione",
|
||||
"website": "Website"
|
||||
},
|
||||
"links": {
|
||||
"meetings": "Meetings",
|
||||
"calls": "Chiamate",
|
||||
"tasks": "Tasks"
|
||||
},
|
||||
"labels": {
|
||||
"Create {entityType}": "Crea {entityTypeTranslated}"
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,36 @@
|
||||
{
|
||||
"labels": {
|
||||
"Create {entityType}": "Crea {entityTypeTranslated}"
|
||||
"fields": {
|
||||
"parent": "Parente",
|
||||
"dateStart": "Data Inizio",
|
||||
"dateEnd": "Data Termine",
|
||||
"duration": "Durata",
|
||||
"status": "Stato",
|
||||
"reminders": "Avvisi"
|
||||
},
|
||||
"links": {
|
||||
"parent": "Parente"
|
||||
},
|
||||
"options": {
|
||||
"status": {
|
||||
"Planned": "Pianificato",
|
||||
"Held": "Held",
|
||||
"Not Held": "Not Held"
|
||||
}
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
"Create {entityType}": "Crea {entityTypeTranslated}",
|
||||
"Schedule {entityType}": "Programma {entityTypeTranslated}",
|
||||
"Log {entityType}": "Log {entityTypeTranslated}",
|
||||
"Set Held": "Imposta Held",
|
||||
"Set Not Held": "Imposta Not Held"
|
||||
},
|
||||
"massActions": {
|
||||
"setHeld": "Set Held",
|
||||
"setNotHeld": "Imposta Not Held"
|
||||
},
|
||||
"presetFilters": {
|
||||
"planned": "Pianificato",
|
||||
"held": "Held",
|
||||
"todays": "Oggi"
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,13 @@
|
||||
{
|
||||
"labels": {
|
||||
"Create {entityType}": "Crea {entityTypeTranslated}"
|
||||
}
|
||||
}
|
||||
"fields": {
|
||||
"address": "Indirizzo"
|
||||
},
|
||||
"links": {
|
||||
"meetings": "Meetings",
|
||||
"calls": "Chiamate",
|
||||
"tasks": "Tasks"
|
||||
},
|
||||
"labels": {
|
||||
"Create {entityType}": "Crea {entityTypeTranslated}"
|
||||
}
|
||||
}
|
||||
5
application/Espo/Core/Templates/i18n/sr_RS/Base.json
Normal file
5
application/Espo/Core/Templates/i18n/sr_RS/Base.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"labels": {
|
||||
"Create {entityType}": "Napravi {entityTypeTranslated}"
|
||||
}
|
||||
}
|
||||
10
application/Espo/Core/Templates/i18n/sr_RS/BasePlus.json
Normal file
10
application/Espo/Core/Templates/i18n/sr_RS/BasePlus.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"links": {
|
||||
"meetings": "Ročišta",
|
||||
"calls": "Pozivi",
|
||||
"tasks": "Zadaci"
|
||||
},
|
||||
"labels": {
|
||||
"Create {entityType}": "Napravi {entityTypeTranslated}"
|
||||
}
|
||||
}
|
||||
15
application/Espo/Core/Templates/i18n/sr_RS/Company.json
Normal file
15
application/Espo/Core/Templates/i18n/sr_RS/Company.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"fields": {
|
||||
"billingAddress": "Adresa za naplatu",
|
||||
"shippingAddress": "Adresa za dostavu",
|
||||
"website": "Sajt"
|
||||
},
|
||||
"links": {
|
||||
"meetings": "Ročišta",
|
||||
"calls": "Pozivi",
|
||||
"tasks": "Zadaci"
|
||||
},
|
||||
"labels": {
|
||||
"Create {entityType}": "Napravi {entityTypeTranslated}"
|
||||
}
|
||||
}
|
||||
36
application/Espo/Core/Templates/i18n/sr_RS/Event.json
Normal file
36
application/Espo/Core/Templates/i18n/sr_RS/Event.json
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"fields": {
|
||||
"parent": "Roditelj",
|
||||
"dateStart": "Početni datum",
|
||||
"dateEnd": "Krajnji datum",
|
||||
"duration": "Trajanje",
|
||||
"status": "Status",
|
||||
"reminders": "Podsetnici"
|
||||
},
|
||||
"links": {
|
||||
"parent": "Roditelj"
|
||||
},
|
||||
"options": {
|
||||
"status": {
|
||||
"Planned": "Planiran",
|
||||
"Held": "Održan",
|
||||
"Not Held": "Nije održan"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
"Create {entityType}": "Napravi {entityTypeTranslated}",
|
||||
"Schedule {entityType}": "Zakaži {entityTypeTranslated}",
|
||||
"Log {entityType}": "Zabeleži {entitiTipeTranslated}",
|
||||
"Set Held": "Postavi kao održano",
|
||||
"Set Not Held": "Postavi kao nije održano"
|
||||
},
|
||||
"massActions": {
|
||||
"setHeld": "Postavi kao održano",
|
||||
"setNotHeld": "Postavi kao nije održano"
|
||||
},
|
||||
"presetFilters": {
|
||||
"planned": "Planiran",
|
||||
"held": "Održan",
|
||||
"todays": "Današnji"
|
||||
}
|
||||
}
|
||||
13
application/Espo/Core/Templates/i18n/sr_RS/Person.json
Normal file
13
application/Espo/Core/Templates/i18n/sr_RS/Person.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"fields": {
|
||||
"address": "Adresa"
|
||||
},
|
||||
"links": {
|
||||
"meetings": "Ročišta",
|
||||
"calls": "Pozivi",
|
||||
"tasks": "Zadaci"
|
||||
},
|
||||
"labels": {
|
||||
"Create {entityType}": "Napravi {entityTypeTranslated}"
|
||||
}
|
||||
}
|
||||
@@ -42,6 +42,11 @@ class UpgradeManager extends Upgrades\Base
|
||||
'scriptNames' => array(
|
||||
'before' => 'BeforeUpgrade',
|
||||
'after' => 'AfterUpgrade',
|
||||
),
|
||||
|
||||
'customDirNames' => array(
|
||||
'before' => 'beforeUpgradeFiles',
|
||||
'after' => 'afterUpgradeFiles',
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -389,9 +389,7 @@ abstract class Base
|
||||
{
|
||||
if (!isset($this->data['fileList'])) {
|
||||
$packagePath = $this->getPackagePath();
|
||||
$filesPath = Util::concatPath($packagePath, self::FILES);
|
||||
|
||||
$this->data['fileList'] = $this->getFileManager()->getFileList($filesPath, true, '', true, true);
|
||||
$this->data['fileList'] = $this->getFileList($packagePath);
|
||||
}
|
||||
|
||||
return $this->data['fileList'];
|
||||
@@ -401,14 +399,55 @@ abstract class Base
|
||||
{
|
||||
if (!isset($this->data['restoreFileList'])) {
|
||||
$backupPath = $this->getPath('backupPath');
|
||||
$backupFilePath = Util::concatPath($backupPath, self::FILES);
|
||||
|
||||
$this->data['restoreFileList'] = $this->getFileManager()->getFileList($backupFilePath, true, '', true, true);
|
||||
$this->data['restoreFileList'] = $this->getFileList($backupPath);
|
||||
}
|
||||
|
||||
return $this->data['restoreFileList'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file directories (files, beforeInstallFiles, afterInstallFiles)
|
||||
*
|
||||
* @param sting $parentDirPath
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getFileDirs($parentDirPath = null)
|
||||
{
|
||||
$dirNames = $this->getParams('customDirNames');
|
||||
$paths = array(self::FILES, $dirNames['before'], $dirNames['after']);
|
||||
|
||||
if (isset($parentDirPath)) {
|
||||
foreach ($paths as &$path) {
|
||||
$path = Util::concatPath($parentDirPath, $path);
|
||||
}
|
||||
}
|
||||
|
||||
return $paths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file list from directories: files, beforeUpgradeFiles, afterUpgradeFiles
|
||||
*
|
||||
* @param string $dirPath
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getFileList($dirPath)
|
||||
{
|
||||
$fileList = array();
|
||||
|
||||
$paths = $this->getFileDirs($dirPath);
|
||||
foreach ($paths as $filesPath) {
|
||||
if (file_exists($filesPath)) {
|
||||
$files = $this->getFileManager()->getFileList($filesPath, true, '', true, true);
|
||||
$fileList = array_merge($fileList, $files);
|
||||
}
|
||||
}
|
||||
|
||||
return $fileList;
|
||||
}
|
||||
|
||||
protected function copy($sourcePath, $destPath, $recursively = false, array $fileList = null, $copyOnlyFiles = false)
|
||||
{
|
||||
try {
|
||||
@@ -423,15 +462,32 @@ abstract class Base
|
||||
/**
|
||||
* Copy files from upgrade/extension package
|
||||
*
|
||||
* @param string $processId
|
||||
* @param string $type
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
protected function copyFiles()
|
||||
protected function copyFiles($type = null)
|
||||
{
|
||||
$packagePath = $this->getPackagePath();
|
||||
$filesPath = Util::concatPath($packagePath, self::FILES);
|
||||
switch ($type) {
|
||||
case 'before':
|
||||
case 'after':
|
||||
$dirNames = $this->getParams('customDirNames');
|
||||
$dirPath = $dirNames[$type];
|
||||
break;
|
||||
|
||||
return $this->copy($filesPath, '', true);
|
||||
default:
|
||||
$dirPath = self::FILES;
|
||||
break;
|
||||
}
|
||||
|
||||
$packagePath = $this->getPackagePath();
|
||||
$filesPath = Util::concatPath($packagePath, $dirPath);
|
||||
|
||||
if (file_exists($filesPath)) {
|
||||
return $this->copy($filesPath, '', true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getManifest()
|
||||
|
||||
@@ -67,6 +67,11 @@ class Install extends \Espo\Core\Upgrades\Actions\Base
|
||||
|
||||
$this->backupExistingFiles();
|
||||
|
||||
//beforeInstallFiles
|
||||
if (!$this->copyFiles('before')) {
|
||||
$this->throwErrorAndRemovePackage('Cannot copy beforeInstall files.');
|
||||
}
|
||||
|
||||
/* run before install script */
|
||||
$this->runScript('before');
|
||||
|
||||
@@ -85,6 +90,11 @@ class Install extends \Espo\Core\Upgrades\Actions\Base
|
||||
$this->throwErrorAndRemovePackage('Error occurred while EspoCRM rebuild.');
|
||||
}
|
||||
|
||||
//afterInstallFiles
|
||||
if (!$this->copyFiles('after')) {
|
||||
$this->throwErrorAndRemovePackage('Cannot copy afterInstall files.');
|
||||
}
|
||||
|
||||
/* run before install script */
|
||||
$this->runScript('after');
|
||||
|
||||
@@ -112,7 +122,9 @@ class Install extends \Espo\Core\Upgrades\Actions\Base
|
||||
$deleteFileList = array_diff($copyFileList, $backupFileList);
|
||||
|
||||
$res = $this->copy($backupFilePath, '', true);
|
||||
$res &= $this->getFileManager()->remove($deleteFileList, null, true);
|
||||
if (!empty($deleteFileList)) {
|
||||
$res &= $this->getFileManager()->remove($deleteFileList, null, true);
|
||||
}
|
||||
|
||||
if ($res) {
|
||||
$this->getFileManager()->removeInDir($backupPath, true);
|
||||
|
||||
@@ -95,15 +95,20 @@ class Uninstall extends \Espo\Core\Upgrades\Actions\Base
|
||||
protected function restoreFiles()
|
||||
{
|
||||
$packagePath = $this->getPath('packagePath');
|
||||
$filesPath = Util::concatPath($packagePath, self::FILES);
|
||||
|
||||
if (!file_exists($filesPath)) {
|
||||
$manifestPath = Util::concatPath($packagePath, $this->manifestName);
|
||||
if (!file_exists($manifestPath)) {
|
||||
$this->unzipArchive($packagePath);
|
||||
}
|
||||
|
||||
$res = $this->copy($filesPath, '', true);
|
||||
$fileDirs = $this->getFileDirs($packagePath);
|
||||
foreach ($fileDirs as $filesPath) {
|
||||
if (file_exists($filesPath)) {
|
||||
$res = $this->copy($filesPath, '', true);
|
||||
}
|
||||
}
|
||||
|
||||
$manifestJson = $this->getFileManager()->getContents(array($packagePath, $this->manifestName));
|
||||
$manifestJson = $this->getFileManager()->getContents($manifestPath);
|
||||
$manifest = Json::decode($manifestJson, true);
|
||||
if (!empty($manifest['delete'])) {
|
||||
$res &= $this->getFileManager()->remove($manifest['delete'], null, true);
|
||||
@@ -114,7 +119,7 @@ class Uninstall extends \Espo\Core\Upgrades\Actions\Base
|
||||
return $res;
|
||||
}
|
||||
|
||||
protected function copyFiles()
|
||||
protected function copyFiles($type = null)
|
||||
{
|
||||
$backupPath = $this->getPath('backupPath');
|
||||
$res = $this->copy(array($backupPath, self::FILES), '', true);
|
||||
|
||||
@@ -63,9 +63,8 @@ class Install extends \Espo\Core\Upgrades\Actions\Base\Install
|
||||
|
||||
/** copy scripts files */
|
||||
$packagePath = $this->getPackagePath();
|
||||
$res &= $this->copy(array($packagePath, self::SCRIPTS), array($backupPath, self::SCRIPTS), true);
|
||||
|
||||
return $res;
|
||||
return $this->copy(array($packagePath, self::SCRIPTS), array($backupPath, self::SCRIPTS), true);
|
||||
}
|
||||
|
||||
protected function isNew()
|
||||
|
||||
@@ -99,7 +99,7 @@ class Auth
|
||||
return $this->getContainer()->get('entityManager');
|
||||
}
|
||||
|
||||
public function useNoAuth($isAdmin = false)
|
||||
public function useNoAuth()
|
||||
{
|
||||
$entityManager = $this->getContainer()->get('entityManager');
|
||||
|
||||
@@ -108,7 +108,7 @@ class Auth
|
||||
throw new Error("System user is not found");
|
||||
}
|
||||
|
||||
$user->set('isAdmin', $isAdmin);
|
||||
$user->set('isAdmin', true);
|
||||
$user->set('ipAddress', $_SERVER['REMOTE_ADDR']);
|
||||
|
||||
$entityManager->setUser($user);
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Utils\Database\Orm;
|
||||
|
||||
use Espo\Core\Utils\Util;
|
||||
|
||||
class Base
|
||||
|
||||
@@ -190,8 +190,14 @@ class Converter
|
||||
|
||||
public function afterProcess(array $ormMeta)
|
||||
{
|
||||
foreach($ormMeta as $entityName => &$entityParams) {
|
||||
foreach($entityParams['fields'] as $fieldName => &$fieldParams) {
|
||||
foreach ($ormMeta as $entityName => &$entityParams) {
|
||||
foreach ($entityParams['fields'] as $fieldName => &$fieldParams) {
|
||||
|
||||
/* remove fields without type */
|
||||
if (!isset($fieldParams['type']) && (!isset($fieldParams['notStorable']) || $fieldParams['notStorable'] === false)) {
|
||||
unset($entityParams['fields'][$fieldName]);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch ($fieldParams['type']) {
|
||||
case 'id':
|
||||
@@ -240,16 +246,16 @@ class Converter
|
||||
$outputMeta = array(
|
||||
'id' => array(
|
||||
'type' => Entity::ID,
|
||||
'dbType' => 'varchar',
|
||||
'dbType' => 'varchar'
|
||||
),
|
||||
'name' => array(
|
||||
'type' => isset($entityMeta['fields']['name']['type']) ? $entityMeta['fields']['name']['type'] : Entity::VARCHAR,
|
||||
'notStorable' => true,
|
||||
'notStorable' => true
|
||||
),
|
||||
'deleted' => array(
|
||||
'type' => Entity::BOOL,
|
||||
'default' => false,
|
||||
),
|
||||
'default' => false
|
||||
)
|
||||
);
|
||||
|
||||
foreach($entityMeta['fields'] as $fieldName => $fieldParams) {
|
||||
@@ -307,14 +313,27 @@ class Converter
|
||||
|
||||
if (class_exists($className) && method_exists($className, 'load')) {
|
||||
$helperClass = new $className($this->metadata, $ormMeta, $entityDefs);
|
||||
$fieldResult = $helperClass->process( $fieldName, $entityName );
|
||||
$fieldResult = $helperClass->process($fieldName, $entityName);
|
||||
if (isset($fieldResult['unset'])) {
|
||||
$ormMeta = Util::unsetInArray($ormMeta, $fieldResult['unset']);
|
||||
unset($fieldResult['unset']);
|
||||
}
|
||||
|
||||
$ormMeta = Util::merge($ormMeta, $fieldResult);
|
||||
}
|
||||
|
||||
$defaultAttributes = $this->metadata->get(['entityDefs', $entityName, 'fields', $fieldName, 'defaultAttributes']);
|
||||
if ($defaultAttributes && array_key_exists($fieldName, $defaultAttributes)) {
|
||||
$defaultMetadataPart = array(
|
||||
$entityName => array(
|
||||
'fields' => array(
|
||||
$fieldName => array(
|
||||
'default' => $defaultAttributes[$fieldName]
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
$ormMeta = Util::merge($ormMeta, $defaultMetadataPart);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -387,6 +406,10 @@ class Converter
|
||||
$relationships = array();
|
||||
foreach ($entityMeta['links'] as $linkName => $linkParams) {
|
||||
|
||||
if (isset($linkParams['skipOrmDefs']) && $linkParams['skipOrmDefs'] === true) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$convertedLink = $this->getRelationManager()->convert($linkName, $linkParams, $entityName, $ormMeta);
|
||||
|
||||
if (isset($convertedLink)) {
|
||||
|
||||
82
application/Espo/Core/Utils/Database/Orm/Fields/File.php
Normal file
82
application/Espo/Core/Utils/Database/Orm/Fields/File.php
Normal file
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2017 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
|
||||
* Website: http://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\Utils\Database\Orm\Fields;
|
||||
|
||||
class File extends Base
|
||||
{
|
||||
protected function load($fieldName, $entityName)
|
||||
{
|
||||
$fieldParams = $this->getFieldParams();
|
||||
|
||||
$data = array(
|
||||
$entityName => array (
|
||||
'fields' => array(
|
||||
$fieldName.'Id' => array(
|
||||
'type' => 'foreignId',
|
||||
'index' => false
|
||||
),
|
||||
$fieldName.'Name' => array(
|
||||
'type' => 'foreign'
|
||||
)
|
||||
)
|
||||
),
|
||||
'unset' => array(
|
||||
$entityName => array(
|
||||
'fields.'.$fieldName
|
||||
)
|
||||
)
|
||||
);
|
||||
if (!empty($fieldParams['notStorable'])) {
|
||||
$data[$entityName]['fields'][$fieldName.'Id']['notStorable'] = true;
|
||||
$data[$entityName]['fields'][$fieldName.'Name']['type'] = 'varchar';
|
||||
}
|
||||
|
||||
if (!empty($fieldParams['defaultAttributes']) && array_key_exists($fieldName.'Id', $fieldParams['defaultAttributes'])) {
|
||||
$data[$entityName]['fields'][$fieldName.'Id']['default'] = $fieldParams['defaultAttributes'][$fieldName.'Id'];
|
||||
}
|
||||
|
||||
if (empty($fieldParams['notStorable'])) {
|
||||
$data[$entityName]['fields'][$fieldName . 'Name']['relation'] = $fieldName;
|
||||
$data[$entityName]['fields'][$fieldName . 'Name']['foreign'] = 'name';
|
||||
|
||||
$linkName = $fieldName;
|
||||
$data[$entityName]['relations'] = array();
|
||||
$data[$entityName]['relations'][$linkName] = array(
|
||||
'type' => 'belongsTo',
|
||||
'entity' => 'Attachment',
|
||||
'key' => $linkName.'Id',
|
||||
'foreignKey' => 'id',
|
||||
'foreign' => null
|
||||
);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
35
application/Espo/Core/Utils/Database/Orm/Fields/Image.php
Normal file
35
application/Espo/Core/Utils/Database/Orm/Fields/Image.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2017 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
|
||||
* Website: http://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\Utils\Database\Orm\Fields;
|
||||
|
||||
class Image extends File
|
||||
{
|
||||
|
||||
}
|
||||
@@ -40,24 +40,27 @@ class Link extends Base
|
||||
'fields' => array(
|
||||
$fieldName.'Id' => array(
|
||||
'type' => 'foreignId',
|
||||
'index' => $fieldName,
|
||||
'index' => $fieldName
|
||||
),
|
||||
$fieldName.'Name' => array(
|
||||
'type' => 'varchar',
|
||||
'notStorable' => true,
|
||||
),
|
||||
),
|
||||
'notStorable' => true
|
||||
)
|
||||
)
|
||||
),
|
||||
'unset' => array(
|
||||
$entityName => array(
|
||||
'fields.'.$fieldName,
|
||||
),
|
||||
),
|
||||
'fields.'.$fieldName
|
||||
)
|
||||
)
|
||||
);
|
||||
if (!empty($fieldParams['notStorable'])) {
|
||||
$data[$entityName]['fields'][$fieldName.'Id']['notStorable'] = true;
|
||||
}
|
||||
|
||||
if (!empty($fieldParams['defaultAttributes']) && array_key_exists($fieldName.'Id', $fieldParams['defaultAttributes'])) {
|
||||
$data[$entityName]['fields'][$fieldName.'Id']['default'] = $fieldParams['defaultAttributes'][$fieldName.'Id'];
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
@@ -33,31 +33,42 @@ class LinkParent extends Base
|
||||
{
|
||||
protected function load($fieldName, $entityName)
|
||||
{
|
||||
return array(
|
||||
$data = array(
|
||||
$entityName => array (
|
||||
'fields' => array(
|
||||
$fieldName.'Id' => array(
|
||||
'type' => 'foreignId',
|
||||
'index' => $fieldName,
|
||||
'index' => $fieldName
|
||||
),
|
||||
$fieldName.'Type' => array(
|
||||
'type' => 'foreignType',
|
||||
'notNull' => false,
|
||||
'index' => $fieldName,
|
||||
'index' => $fieldName
|
||||
),
|
||||
$fieldName.'Name' => array(
|
||||
'type' => 'varchar',
|
||||
'notStorable' => true,
|
||||
'relation' => $fieldName,
|
||||
'isParentName' => true
|
||||
),
|
||||
),
|
||||
)
|
||||
)
|
||||
),
|
||||
'unset' => array(
|
||||
$entityName => array(
|
||||
'fields.'.$fieldName,
|
||||
),
|
||||
),
|
||||
'fields.'.$fieldName
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$fieldParams = $this->getFieldParams();
|
||||
|
||||
if (!empty($fieldParams['defaultAttributes']) && array_key_exists($fieldName.'Id', $fieldParams['defaultAttributes'])) {
|
||||
$data[$entityName]['fields'][$fieldName.'Id']['default'] = $fieldParams['defaultAttributes'][$fieldName.'Id'];
|
||||
}
|
||||
if (!empty($fieldParams['defaultAttributes']) && array_key_exists($fieldName.'Type', $fieldParams['defaultAttributes'])) {
|
||||
$data[$entityName]['fields'][$fieldName.'Type']['default'] = $fieldParams['defaultAttributes'][$fieldName.'Type'];
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,10 @@ class BelongsTo extends Base
|
||||
$foreignEntityName = $this->getForeignEntityName();
|
||||
$foreignLinkName = $this->getForeignLinkName();
|
||||
|
||||
$index = true;
|
||||
if (!empty($linkParams['noIndex'])) {
|
||||
$index = false;
|
||||
}
|
||||
|
||||
$noForeignName = false;
|
||||
if (!empty($linkParams['noForeignName'])) {
|
||||
@@ -71,7 +75,7 @@ class BelongsTo extends Base
|
||||
'fields' => array(
|
||||
$linkName.'Id' => array(
|
||||
'type' => 'foreignId',
|
||||
'index' => true
|
||||
'index' => $index
|
||||
)
|
||||
),
|
||||
'relations' => array(
|
||||
|
||||
@@ -251,16 +251,11 @@ class Converter
|
||||
case 'manyMany':
|
||||
$tableName = $relationParams['relationName'];
|
||||
|
||||
//check for duplication tables
|
||||
//check for duplicate tables
|
||||
if (!isset($tables[$tableName])) { //no needs to create the table if it already exists
|
||||
$tables[$tableName] = $this->prepareManyMany($entityName, $relationParams, $tables);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'belongsTo':
|
||||
$columnName = Util::toUnderScore($relationParams['key']);
|
||||
$tables[$entityName]->addIndex(array($columnName));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -440,13 +435,13 @@ class Converter
|
||||
|
||||
$dependentEntities[] = $entityName;
|
||||
|
||||
foreach ($ormMeta[$entityName]['relations'] as $relationName => $relationParams) {
|
||||
|
||||
if (isset($relationParams['entity'])) {
|
||||
$relationEntity = $relationParams['entity'];
|
||||
|
||||
if (!in_array($relationEntity, $dependentEntities)) {
|
||||
$dependentEntities = $this->getDependentEntities($relationEntity, $ormMeta, $dependentEntities);
|
||||
if (array_key_exists('relations', $ormMeta[$entityName])) {
|
||||
foreach ($ormMeta[$entityName]['relations'] as $relationName => $relationParams) {
|
||||
if (isset($relationParams['entity'])) {
|
||||
$relationEntity = $relationParams['entity'];
|
||||
if (!in_array($relationEntity, $dependentEntities)) {
|
||||
$dependentEntities = $this->getDependentEntities($relationEntity, $ormMeta, $dependentEntities);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,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'];
|
||||
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'];
|
||||
|
||||
public function __construct(Metadata $metadata, Language $language, File\Manager $fileManager, Config $config, Container $container = null)
|
||||
{
|
||||
@@ -102,6 +102,26 @@ class EntityManager
|
||||
return $this->container->get('serviceFactory');
|
||||
}
|
||||
|
||||
protected function checkControllerExists($name)
|
||||
{
|
||||
$controllerClassName = '\\Espo\\Custom\\Controllers\\' . Util::normilizeClassName($name);
|
||||
if (class_exists($controllerClassName)) {
|
||||
return true;
|
||||
} else {
|
||||
foreach ($this->getMetadata()->getModuleList() as $moduleName) {
|
||||
$controllerClassName = '\\Espo\\Modules\\' . $moduleName . '\\Controllers\\' . Util::normilizeClassName($name);
|
||||
if (class_exists($controllerClassName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
$controllerClassName = '\\Espo\\Controllers\\' . Util::normilizeClassName($name);
|
||||
if (class_exists($controllerClassName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function create($name, $type, $params = array())
|
||||
{
|
||||
$name = ucfirst($name);
|
||||
@@ -114,6 +134,10 @@ class EntityManager
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
if ($this->checkControllerExists($name)) {
|
||||
throw new Conflict('Entity name \''.$name.'\' is not allowed.');
|
||||
}
|
||||
|
||||
$serviceFactory = $this->getServiceFactory();
|
||||
if ($serviceFactory && $serviceFactory->checKExists($name)) {
|
||||
throw new Conflict('Entity name \''.$name.'\' is not allowed.');
|
||||
|
||||
216
application/Espo/Core/Utils/LabelManager.php
Normal file
216
application/Espo/Core/Utils/LabelManager.php
Normal file
@@ -0,0 +1,216 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2017 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
|
||||
* Website: http://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\Utils;
|
||||
|
||||
use \Espo\Core\Utils\Util;
|
||||
use \Espo\Core\Exceptions\NotFound;
|
||||
use \Espo\Core\Exceptions\Error;
|
||||
|
||||
class LabelManager extends \Espo\Core\Injectable
|
||||
{
|
||||
protected $dependencyList = [
|
||||
'config',
|
||||
'fileManager',
|
||||
'metadata',
|
||||
'defaultLanguage'
|
||||
];
|
||||
|
||||
protected $ignoreList = [
|
||||
'Global.sets'
|
||||
];
|
||||
|
||||
public function getScopeList()
|
||||
{
|
||||
$scopeList = [];
|
||||
|
||||
$languageObj = $this->getDefaultLanguage();
|
||||
|
||||
$data = $languageObj->getAll();
|
||||
foreach (array_keys($data) as $scope) {
|
||||
if (!in_array($scope, $scopeList)) {
|
||||
$scopeList[] = $scope;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->getMetadata()->get('scopes') as $scope => $data) {
|
||||
if (!in_array($scope, $scopeList)) {
|
||||
$scopeList[] = $scope;
|
||||
}
|
||||
}
|
||||
|
||||
return $scopeList;
|
||||
}
|
||||
|
||||
public function getScopeData($language, $scope)
|
||||
{
|
||||
$languageObj = new Language($language, $this->getFileManager(), $this->getMetadata());
|
||||
|
||||
$data = $languageObj->get($scope);
|
||||
|
||||
if (empty($data)) {
|
||||
return (object) [];
|
||||
}
|
||||
|
||||
if ($this->getMetadata()->get(['scopes', $scope, 'entity'])) {
|
||||
|
||||
if (empty($data['fields'])) {
|
||||
$data['fields'] = array();
|
||||
}
|
||||
foreach ($this->getMetadata()->get(['entityDefs', $scope, 'fields']) as $field => $item) {
|
||||
if (!array_key_exists($field, $data['fields'])) {
|
||||
$data['fields'][$field] = $languageObj->get('Global.fields.' . $field);
|
||||
if (is_null($data['fields'][$field])) {
|
||||
$data['fields'][$field] = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
if (empty($data['links'])) {
|
||||
$data['links'] = array();
|
||||
}
|
||||
foreach ($this->getMetadata()->get(['entityDefs', $scope, 'links']) as $link => $item) {
|
||||
if (!array_key_exists($link, $data['links'])) {
|
||||
$data['links'][$link] = $languageObj->get('Global.links.' . $link);
|
||||
if (is_null($data['links'][$link])) {
|
||||
$data['links'][$link] = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($data['labels'])) {
|
||||
$data['labels'] = array();
|
||||
}
|
||||
if (!array_key_exists('Create ' . $scope, $data['labels'])) {
|
||||
$data['labels']['Create ' . $scope] = '';
|
||||
}
|
||||
}
|
||||
|
||||
if ($scope === 'Global') {
|
||||
if (empty($data['scopeNames'])) {
|
||||
$data['scopeNames'] = array();
|
||||
}
|
||||
if (empty($data['scopeNamesPlural'])) {
|
||||
$data['scopeNamesPlural'] = array();
|
||||
}
|
||||
foreach ($this->getMetadata()->get(['scopes']) as $scopeKey => $item) {
|
||||
if (!empty($item['entity'])) {
|
||||
if (empty($data['scopeNamesPlural'][$scopeKey])) {
|
||||
$data['scopeNamesPlural'][$scopeKey] = '';
|
||||
}
|
||||
}
|
||||
if (empty($data['scopeNames'][$scopeKey])) {
|
||||
$data['scopeNames'][$scopeKey] = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($data as $key => $value) {
|
||||
if (empty($value)) {
|
||||
unset($data[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
$finalData = array();
|
||||
|
||||
foreach ($data as $category => $item) {
|
||||
if (in_array($scope . '.' . $category, $this->ignoreList)) continue;
|
||||
foreach ($item as $key => $categoryItem) {
|
||||
if (is_array($categoryItem)) {
|
||||
foreach ($categoryItem as $subKey => $subItem) {
|
||||
$finalData[$category][$category .'[.]' . $key .'[.]' . $subKey] = $subItem;
|
||||
}
|
||||
} else {
|
||||
$finalData[$category][$category .'[.]' . $key] = $categoryItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $finalData;
|
||||
}
|
||||
|
||||
public function saveLabels($language, $scope, $labels)
|
||||
{
|
||||
$languageObj = new Language($language, $this->getFileManager(), $this->getMetadata());
|
||||
$languageOriginalObj = new Language($language, $this->getFileManager(), $this->getMetadata(), false, true);
|
||||
|
||||
$returnDataHash = array();
|
||||
|
||||
foreach ($labels as $key => $value) {
|
||||
$arr = explode('[.]', $key);
|
||||
$category = $arr[0];
|
||||
$name = $arr[1];
|
||||
|
||||
$setPath = [$scope, $category, $name];
|
||||
|
||||
$setValue = null;
|
||||
|
||||
if (count($arr) == 2) {
|
||||
if ($value !== '') {
|
||||
$languageObj->set($scope, $category, $name, $value);
|
||||
$setValue = $value;
|
||||
} else {
|
||||
$setValue = $languageOriginalObj->get(implode('.', [$scope, $category, $name]));
|
||||
if (is_null($setValue) && $scope !== 'Global') {
|
||||
$setValue = $languageOriginalObj->get(implode('.', ['Global', $category, $name]));
|
||||
}
|
||||
$languageObj->delete($scope, $category, $name);
|
||||
}
|
||||
} else if (count($arr) == 3) {
|
||||
$name = $arr[1];
|
||||
$attribute = $arr[2];
|
||||
$data = $languageObj->get($scope . '.' . $category . '.' . $name);
|
||||
|
||||
$setPath[] = $attribute;
|
||||
|
||||
if (is_array($data)) {
|
||||
if ($value !== '') {
|
||||
$data[$attribute] = $value;
|
||||
$setValue = $value;
|
||||
} else {
|
||||
$dataOriginal = $languageOriginalObj->get($scope . '.' . $category . '.' . $name);
|
||||
if (is_array($dataOriginal) && isset($dataOriginal[$attribute])) {
|
||||
$data[$attribute] = $dataOriginal[$attribute];
|
||||
$setValue = $dataOriginal[$attribute];
|
||||
}
|
||||
}
|
||||
$languageObj->set($scope, $category, $name, $data);
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_null($setValue)) {
|
||||
$frontKey = implode('[.]', $setPath);
|
||||
$returnDataHash[$frontKey] = $setValue;
|
||||
}
|
||||
}
|
||||
|
||||
$languageObj->save();
|
||||
|
||||
return $returnDataHash;
|
||||
}
|
||||
}
|
||||
@@ -61,13 +61,15 @@ class Language
|
||||
|
||||
protected $useCache = false;
|
||||
|
||||
protected $noCustom = false;
|
||||
|
||||
private $paths = array(
|
||||
'corePath' => 'application/Espo/Resources/i18n',
|
||||
'modulePath' => 'application/Espo/Modules/{*}/Resources/i18n',
|
||||
'customPath' => 'custom/Espo/Custom/Resources/i18n',
|
||||
);
|
||||
|
||||
public function __construct($language = null, File\Manager $fileManager, Metadata $metadata, $useCache = false)
|
||||
public function __construct($language = null, File\Manager $fileManager, Metadata $metadata, $useCache = false, $noCustom = false)
|
||||
{
|
||||
if ($language) {
|
||||
$this->currentLanguage = $language;
|
||||
@@ -79,6 +81,7 @@ class Language
|
||||
$this->metadata = $metadata;
|
||||
|
||||
$this->useCache = $useCache;
|
||||
$this->noCustom = $noCustom;
|
||||
|
||||
$this->unifier = new \Espo\Core\Utils\File\Unifier($this->fileManager, $this->metadata);
|
||||
}
|
||||
@@ -345,7 +348,13 @@ class Language
|
||||
protected function init($reload = false)
|
||||
{
|
||||
if ($reload || !file_exists($this->getLangCacheFile()) || !$this->useCache) {
|
||||
$fullData = $this->getUnifier()->unify($this->name, $this->paths, true);
|
||||
|
||||
$paths = $this->paths;
|
||||
if ($this->noCustom) {
|
||||
unset($paths['customPath']);
|
||||
}
|
||||
|
||||
$fullData = $this->getUnifier()->unify($this->name, $paths, true);
|
||||
|
||||
$result = true;
|
||||
foreach ($fullData as $i18nName => $i18nData) {
|
||||
|
||||
@@ -602,5 +602,18 @@ class Util
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Array keys exists
|
||||
*
|
||||
* @param array $keys
|
||||
* @param array $array
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
static public function arrayKeysExists(array $keys, array $array)
|
||||
{
|
||||
return !array_diff_key(array_flip($keys), $array);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -63,7 +63,9 @@ return array (
|
||||
'smtpUsername' => '',
|
||||
'smtpPassword' => '',
|
||||
'languageList' => [
|
||||
'en_GB',
|
||||
'en_US',
|
||||
'es_MX',
|
||||
'cs_CZ',
|
||||
'da_DK',
|
||||
'de_DE',
|
||||
@@ -74,6 +76,7 @@ return array (
|
||||
'nb_NO',
|
||||
'nl_NL',
|
||||
'tr_TR',
|
||||
'sr_RS',
|
||||
'ro_RO',
|
||||
'ru_RU',
|
||||
'pl_PL',
|
||||
@@ -162,6 +165,7 @@ return array (
|
||||
'cleanupAuthTokenPeriod' => '1 month',
|
||||
'currencyFormat' => 1,
|
||||
'currencyDecimalPlaces' => null,
|
||||
'aclStrictMode' => false,
|
||||
'isInstalled' => false
|
||||
);
|
||||
|
||||
|
||||
@@ -115,6 +115,7 @@ return array ( 'defaultPermissions' =>
|
||||
'smtpPassword',
|
||||
'cron',
|
||||
'authenticationMethod',
|
||||
'adminPanelIframeUrl',
|
||||
'ldapHost',
|
||||
'ldapPort',
|
||||
'ldapSecurity',
|
||||
|
||||
@@ -124,7 +124,7 @@ class Email extends \Espo\Core\ORM\Entity
|
||||
|
||||
public function getToList()
|
||||
{
|
||||
$value = $email->get('to');
|
||||
$value = $this->get('to');
|
||||
if ($value) {
|
||||
$arr = explode(';', $value);
|
||||
if (is_array($arr)) {
|
||||
@@ -136,7 +136,7 @@ class Email extends \Espo\Core\ORM\Entity
|
||||
|
||||
public function getCcList()
|
||||
{
|
||||
$value = $email->get('cc');
|
||||
$value = $this->get('cc');
|
||||
if ($value) {
|
||||
$arr = explode(';', $value);
|
||||
if (is_array($arr)) {
|
||||
@@ -148,7 +148,7 @@ class Email extends \Espo\Core\ORM\Entity
|
||||
|
||||
public function getBccList()
|
||||
{
|
||||
$value = $email->get('bcc');
|
||||
$value = $this->get('bcc');
|
||||
if ($value) {
|
||||
$arr = explode(';', $value);
|
||||
if (is_array($arr)) {
|
||||
@@ -160,7 +160,7 @@ class Email extends \Espo\Core\ORM\Entity
|
||||
|
||||
public function getReplyToList()
|
||||
{
|
||||
$value = $email->get('replyTo');
|
||||
$value = $this->get('replyTo');
|
||||
if ($value) {
|
||||
$arr = explode(';', $value);
|
||||
if (is_array($arr)) {
|
||||
|
||||
@@ -36,7 +36,7 @@ use \Espo\Core\Exceptions\Error;
|
||||
|
||||
class Avatar extends Image
|
||||
{
|
||||
public static $authRequired = false;
|
||||
public static $authRequired = true;
|
||||
|
||||
public static $notStrictAuth = true;
|
||||
|
||||
@@ -88,14 +88,7 @@ class Avatar extends Image
|
||||
exit;
|
||||
}
|
||||
|
||||
if (isset($_GET['attachmentId'])) {
|
||||
$id = $_GET['attachmentId'];
|
||||
if ($id == 'false') {
|
||||
$id = false;
|
||||
}
|
||||
} else {
|
||||
$id = $user->get('avatarId');
|
||||
}
|
||||
$id = $user->get('avatarId');
|
||||
|
||||
$size = null;
|
||||
if (!empty($_GET['size'])) {
|
||||
|
||||
@@ -75,7 +75,10 @@ class NextNumber extends \Espo\Core\Hooks\Base
|
||||
'fieldName' => $fieldName,
|
||||
'entityType' => $entity->getEntityType()
|
||||
))->findOne();
|
||||
if (!$nextNumber) continue;
|
||||
if (!$nextNumber) {
|
||||
$this->getEntityManager()->getPdo()->query('UNLOCK TABLES');
|
||||
continue;
|
||||
}
|
||||
$entity->set($fieldName, $this->composeNumberAttribute($nextNumber));
|
||||
|
||||
$value = $nextNumber->get('value');
|
||||
|
||||
@@ -45,6 +45,10 @@ class Cleanup extends \Espo\Core\Jobs\Base
|
||||
|
||||
protected $cleanupAttachmentsPeriod = '1 month';
|
||||
|
||||
protected $cleanupAttachmentsFromPeriod = '3 months';
|
||||
|
||||
protected $cleanupRemindersPeriod = '15 days';
|
||||
|
||||
public function run()
|
||||
{
|
||||
$this->cleanupJobs();
|
||||
@@ -103,6 +107,19 @@ class Cleanup extends \Espo\Core\Jobs\Base
|
||||
$sth->execute();
|
||||
}
|
||||
|
||||
protected function cleanupReminders()
|
||||
{
|
||||
$period = '-' . $this->getConfig()->get('cleanupRemindersPeriod', $this->cleanupRemindersPeriod);
|
||||
$datetime = new \DateTime();
|
||||
$datetime->modify($period);
|
||||
|
||||
$query = "DELETE FROM `reminder` WHERE DATE(remind_at) < '" . $datetime->format('Y-m-d') . "'";
|
||||
|
||||
$pdo = $this->getEntityManager()->getPDO();
|
||||
$sth = $pdo->prepare($query);
|
||||
$sth->execute();
|
||||
}
|
||||
|
||||
protected function cleanupAuthToken()
|
||||
{
|
||||
$period = '-' . $this->getConfig()->get('cleanupAuthTokenPeriod', $this->cleanupAuthTokenPeriod);
|
||||
@@ -171,6 +188,57 @@ class Cleanup extends \Espo\Core\Jobs\Base
|
||||
}
|
||||
}
|
||||
|
||||
$fromPeriod = '-' . $this->getConfig()->get('cleanupAttachmentsFromPeriod', $this->cleanupAttachmentsFromPeriod);
|
||||
$datetimeFrom = new \DateTime();
|
||||
$datetimeFrom->modify($fromPeriod);
|
||||
|
||||
$scopeList = array_keys($this->getMetadata()->get(['scopes']));
|
||||
foreach ($scopeList as $scope) {
|
||||
if (!$this->getMetadata()->get(['scopes', $scope, 'entity'])) continue;
|
||||
if (!$this->getMetadata()->get(['scopes', $scope, 'object']) && $scope !== 'Note') continue;
|
||||
if (!$this->getMetadata()->get(['entityDefs', $scope, 'fields', 'modifiedAt'])) continue;
|
||||
|
||||
$hasAttachmentField = false;
|
||||
if ($scope === 'Note') {
|
||||
$hasAttachmentField = true;
|
||||
}
|
||||
if (!$hasAttachmentField) {
|
||||
foreach ($this->getMetadata()->get(['entityDefs', $scope, 'fields']) as $field => $defs) {
|
||||
if (empty($defs['type'])) continue;
|
||||
if (in_array($defs['type'], ['file', 'image', 'attachmentMultiple'])) {
|
||||
$hasAttachmentField = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!$hasAttachmentField) continue;
|
||||
|
||||
$deletedEntityList = $this->getEntityManager()->getRepository($scope)->where([
|
||||
'deleted' => 1,
|
||||
'modifiedAt<' => $datetime->format('Y-m-d H:i:s'),
|
||||
'modifiedAt>' => $datetimeFrom->format('Y-m-d H:i:s'),
|
||||
|
||||
])->find(['withDeleted' => true]);
|
||||
foreach ($deletedEntityList as $deletedEntity) {
|
||||
$attachmentToRemoveList = $this->getEntityManager()->getRepository('Attachment')->where(array(
|
||||
'OR' => array(
|
||||
array(
|
||||
'relatedType' => $scope,
|
||||
'relatedId' => $deletedEntity->id
|
||||
),
|
||||
array(
|
||||
'parentType' => $scope,
|
||||
'parentId' => $deletedEntity->id
|
||||
)
|
||||
)
|
||||
))->find();
|
||||
|
||||
foreach ($attachmentToRemoveList as $attachmentToRemove) {
|
||||
$this->getEntityManager()->removeEntity($attachmentToRemove);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$sql = "DELETE FROM attachment WHERE deleted = 1 AND created_at < ".$pdo->quote($datetime->format('Y-m-d H:i:s'));
|
||||
$sth = $pdo->query($sql);
|
||||
}
|
||||
|
||||
@@ -66,12 +66,20 @@ class CheckEmailAccounts extends \Espo\Core\Jobs\Base
|
||||
foreach ($collection as $entity) {
|
||||
$running = $this->getEntityManager()->getRepository('Job')->where(array(
|
||||
'scheduledJobId' => $data['id'],
|
||||
'status' => ['Running', 'Pending'],
|
||||
'status' => 'Running',
|
||||
'targetType' => 'EmailAccount',
|
||||
'targetId' => $entity->id
|
||||
))->findOne();
|
||||
if ($running) continue;
|
||||
|
||||
$countPending = $this->getEntityManager()->getRepository('Job')->where(array(
|
||||
'scheduledJobId' => $data['id'],
|
||||
'status' => 'Pending',
|
||||
'targetType' => 'EmailAccount',
|
||||
'targetId' => $entity->id
|
||||
))->count();
|
||||
if ($countPending > 1) continue;
|
||||
|
||||
$job = $this->getEntityManager()->getEntity('Job');
|
||||
|
||||
$jobEntity = $this->getEntityManager()->getEntity('Job');
|
||||
|
||||
@@ -36,8 +36,6 @@ class Meeting extends \Espo\Core\Repositories\Event
|
||||
{
|
||||
protected function beforeSave(Entity $entity, array $options = array())
|
||||
{
|
||||
parent::beforeSave($entity, $options);
|
||||
|
||||
$parentId = $entity->get('parentId');
|
||||
$parentType = $entity->get('parentType');
|
||||
if (!empty($parentId) || !empty($parentType)) {
|
||||
@@ -61,6 +59,27 @@ class Meeting extends \Espo\Core\Repositories\Event
|
||||
}
|
||||
}
|
||||
|
||||
if (!$entity->isNew()) {
|
||||
if ($entity->isFieldChanged('dateStart') && $entity->isFieldChanged('dateStart') && !$entity->isFieldChanged('dateEnd')) {
|
||||
$dateEndPrevious = $entity->getFetched('dateEnd');
|
||||
$dateStartPrevious = $entity->getFetched('dateStart');
|
||||
if ($dateStartPrevious && $dateEndPrevious) {
|
||||
$dtStart = new \DateTime($dateStartPrevious);
|
||||
$dtEnd = new \DateTime($dateEndPrevious);
|
||||
$dt = new \DateTime($entity->get('dateStart'));
|
||||
|
||||
if ($dtStart && $dtEnd && $dt) {
|
||||
$duration = ($dtEnd->getTimestamp() - $dtStart->getTimestamp());
|
||||
$dt->modify('+' . $duration . ' seconds');
|
||||
$dateEnd = $dt->format('Y-m-d H:i:s');
|
||||
$entity->set('dateEnd', $dateEnd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parent::beforeSave($entity, $options);
|
||||
|
||||
$assignedUserId = $entity->get('assignedUserId');
|
||||
if ($assignedUserId) {
|
||||
if ($entity->has('usersIds')) {
|
||||
@@ -98,24 +117,5 @@ class Meeting extends \Espo\Core\Repositories\Event
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$entity->isNew()) {
|
||||
if ($entity->isFieldChanged('dateStart') && $entity->isFieldChanged('dateStart') && !$entity->isFieldChanged('dateEnd')) {
|
||||
$dateEndPrevious = $entity->getFetched('dateEnd');
|
||||
$dateStartPrevious = $entity->getFetched('dateStart');
|
||||
if ($dateStartPrevious && $dateEndPrevious) {
|
||||
$dtStart = new \DateTime($dateStartPrevious);
|
||||
$dtEnd = new \DateTime($dateEndPrevious);
|
||||
$dt = new \DateTime($entity->get('dateStart'));
|
||||
|
||||
if ($dtStart && $dtEnd && $dt) {
|
||||
$duration = ($dtEnd->getTimestamp() - $dtStart->getTimestamp());
|
||||
$dt->modify('+' . $duration . ' seconds');
|
||||
$dateEnd = $dt->format('Y-m-d H:i:s');
|
||||
$entity->set('dateEnd', $dateEnd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,14 +35,13 @@ class Opportunity extends \Espo\Core\ORM\Repositories\RDB
|
||||
{
|
||||
public function beforeSave(Entity $entity, array $options = array())
|
||||
{
|
||||
parent::beforeSave($entity, $options);
|
||||
|
||||
if ($entity->isNew()) {
|
||||
if (!$entity->has('probability') && $entity->get('stage')) {
|
||||
$probability = $this->getMetadata()->get('entityDefs.Opportunity.probabilityMap.' . $entity->get('stage'), 0);
|
||||
$entity->set('probability', $probability);
|
||||
}
|
||||
}
|
||||
|
||||
parent::beforeSave($entity, $options);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,8 @@ class Task extends \Espo\Core\Repositories\Event
|
||||
{
|
||||
protected $reminderDateAttribute = 'dateEnd';
|
||||
|
||||
protected $reminderSkippingStatusList = ['Completed', 'Canceled'];
|
||||
|
||||
protected function init()
|
||||
{
|
||||
parent::init();
|
||||
@@ -69,8 +71,6 @@ class Task extends \Espo\Core\Repositories\Event
|
||||
|
||||
protected function beforeSave(Entity $entity, array $options = array())
|
||||
{
|
||||
parent::beforeSave($entity, $options);
|
||||
|
||||
if ($entity->isFieldChanged('status')) {
|
||||
if ($entity->get('status') == 'Completed') {
|
||||
$entity->set('dateCompleted', date('Y-m-d H:i:s'));
|
||||
@@ -125,5 +125,7 @@ class Task extends \Espo\Core\Repositories\Event
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parent::beforeSave($entity, $options);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Název",
|
||||
"emailAddress": "Email",
|
||||
"title": "Pozice",
|
||||
"website": "Web",
|
||||
"accountName": "Jméno organizace",
|
||||
"phoneNumber": "Telefon",
|
||||
"doNotCall": "Nevolat",
|
||||
"address": "Adresa",
|
||||
"description": "Popis"
|
||||
},
|
||||
"links": {
|
||||
},
|
||||
"labels": {
|
||||
"Create Target": "Vytvořit cíl",
|
||||
"Convert to Lead": "Konvertovat na stopu"
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,8 @@
|
||||
"targetLists": "Kontaktlister",
|
||||
"targetList": "Kontaktliste",
|
||||
"portalUser": "Portalbruger",
|
||||
"originalLead": "Oprindelig Lead"
|
||||
"originalLead": "Oprindelig Lead",
|
||||
"acceptanceStatus": "Acceptance Status"
|
||||
},
|
||||
"links": {
|
||||
"opportunities": "Muligheder",
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
"Create Lead": "Opret Lead",
|
||||
"Create Contact": "Opret Kontakt",
|
||||
"Create Task": "Opret Opgave",
|
||||
"Create Case": "Opret Sag"
|
||||
"Create Case": "Opret Sag",
|
||||
"Add to Contact": "Add to Contact",
|
||||
"Add to Lead": "Add to Lead"
|
||||
}
|
||||
}
|
||||
@@ -78,12 +78,12 @@
|
||||
"labels": {
|
||||
"Create InboundEmail": "Opret Indkommende Email",
|
||||
"Activities": "Aktiviteter",
|
||||
"History": "Forløb",
|
||||
"History": "Historik",
|
||||
"Attendees": "Deltagere",
|
||||
"Schedule Meeting": "Planlæg Møde",
|
||||
"Schedule Call": "Planlæg Opkald",
|
||||
"Compose Email": "Skriv Email",
|
||||
"Log Meeting": "Logge Møde",
|
||||
"Log Meeting": "Log møde",
|
||||
"Log Call": "Logge Opkald",
|
||||
"Archive Email": "Arkiver Email",
|
||||
"Create Task": "Opret Opgave",
|
||||
|
||||
@@ -38,9 +38,10 @@
|
||||
"Article": "Artikel"
|
||||
}
|
||||
},
|
||||
"tooltips": {
|
||||
},
|
||||
"presetFilters": {
|
||||
"published": "Publiseret"
|
||||
},
|
||||
"tooltips": {
|
||||
"portals": "Article will be available only in specified portals."
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
"Converted To": "Konverteret Til",
|
||||
"Create Lead": "Opret Lead",
|
||||
"Convert": "Konverter",
|
||||
"convert": "konverter"
|
||||
"convert": "convert"
|
||||
},
|
||||
"fields": {
|
||||
"name": " Navn",
|
||||
@@ -25,7 +25,9 @@
|
||||
"campaign": "Kampagne",
|
||||
"targetLists": "Kontaktlister",
|
||||
"targetList": "Kontaktliste",
|
||||
"industry": "Industri"
|
||||
"industry": "Industri",
|
||||
"acceptanceStatus": "Acceptance Status",
|
||||
"opportunityAmountCurrency": "Opportunity Amount Currency"
|
||||
},
|
||||
"links": {
|
||||
"targetLists": "Kontaktlister",
|
||||
|
||||
@@ -13,7 +13,8 @@
|
||||
"amountConverted": "Beløb (konverteret)",
|
||||
"amountWeightedConverted": "Beløb Vægtet",
|
||||
"campaign": "Kampagne",
|
||||
"originalLead": "Oprindelig Lead"
|
||||
"originalLead": "Oprindelig Lead",
|
||||
"amountCurrency": "Amount Currency"
|
||||
},
|
||||
"links": {
|
||||
"contacts": "Kontakter",
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Navn",
|
||||
"emailAddress": "Email",
|
||||
"title": "Titel",
|
||||
"website": "Webside",
|
||||
"accountName": "Kontonavn",
|
||||
"phoneNumber": "Telefon",
|
||||
"doNotCall": "Ring Ikke!",
|
||||
"address": "Adresse",
|
||||
"description": "Beskrivelse"
|
||||
},
|
||||
"labels": {
|
||||
"Create Target": "Opret Mål",
|
||||
"Convert to Lead": "Konverter til Lead"
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,8 @@
|
||||
{
|
||||
"links": {
|
||||
"targetLists": "Kontaktlister"
|
||||
},
|
||||
"fields": {
|
||||
"acceptanceStatus": "Acceptance Status"
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Name",
|
||||
"emailAddress": "E-Mail",
|
||||
"title": "Funktion",
|
||||
"website": "Webseite",
|
||||
"accountName": "Firmenname",
|
||||
"phoneNumber": "Telefon",
|
||||
"doNotCall": "Anrufe unerwünscht",
|
||||
"address": "Adresse",
|
||||
"description": "Beschreibung"
|
||||
},
|
||||
"labels": {
|
||||
"Create Target": "Zielkontakt erstellen",
|
||||
"Convert to Lead": "Zu Interessent umwandeln"
|
||||
}
|
||||
}
|
||||
103
application/Espo/Modules/Crm/Resources/i18n/en_GB/Account.json
Normal file
103
application/Espo/Modules/Crm/Resources/i18n/en_GB/Account.json
Normal file
@@ -0,0 +1,103 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Name",
|
||||
"emailAddress": "Email",
|
||||
"website": "Website",
|
||||
"phoneNumber": "Phone",
|
||||
"billingAddress": "Billing Address",
|
||||
"shippingAddress": "Shipping Address",
|
||||
"description": "Description",
|
||||
"sicCode": "Sic Code",
|
||||
"industry": "Industry",
|
||||
"type": "Type",
|
||||
"contactRole": "Title",
|
||||
"campaign": "Campaign",
|
||||
"targetLists": "Target Lists",
|
||||
"targetList": "Target List",
|
||||
"originalLead": "Original Lead"
|
||||
},
|
||||
"links": {
|
||||
"contacts": "Contacts",
|
||||
"opportunities": "Opportunities",
|
||||
"cases": "Cases",
|
||||
"documents": "Documents",
|
||||
"meetingsPrimary": "Meetings (expanded)",
|
||||
"callsPrimary": "Calls (expanded)",
|
||||
"tasksPrimary": "Tasks (expanded)",
|
||||
"emailsPrimary": "Emails (expanded)",
|
||||
"targetLists": "Target Lists",
|
||||
"campaignLogRecords": "Campaign Log",
|
||||
"campaign": "Campaign",
|
||||
"portalUsers": "Portal Users",
|
||||
"originalLead": "Original Lead"
|
||||
},
|
||||
"options": {
|
||||
"type": {
|
||||
"Customer": "Customer",
|
||||
"Investor": "Investor",
|
||||
"Partner": "Partner",
|
||||
"Reseller": "Reseller"
|
||||
},
|
||||
"industry": {
|
||||
"Agriculture": "Agriculture",
|
||||
"Advertising": "Advertising",
|
||||
"Apparel & Accessories": "Apparel & Accessories",
|
||||
"Automotive": "Automotive",
|
||||
"Banking": "Banking",
|
||||
"Biotechnology": "Biotechnology",
|
||||
"Building Materials & Equipment": "Building Materials & Equipment",
|
||||
"Chemical": "Chemical",
|
||||
"Computer": "Computer",
|
||||
"Education": "Education",
|
||||
"Electronics": "Electronics",
|
||||
"Energy": "Energy",
|
||||
"Entertainment & Leisure": "Entertainment & Leisure",
|
||||
"Finance": "Finance",
|
||||
"Food & Beverage": "Food & Beverage",
|
||||
"Grocery": "Grocery",
|
||||
"Healthcare": "Healthcare",
|
||||
"Insurance": "Insurance",
|
||||
"Legal": "Legal",
|
||||
"Manufacturing": "Manufacturing",
|
||||
"Publishing": "Publishing",
|
||||
"Real Estate": "Real Estate",
|
||||
"Service": "Service",
|
||||
"Sports": "Sports",
|
||||
"Software": "Software",
|
||||
"Technology": "Technology",
|
||||
"Telecommunications": "Telecommunications",
|
||||
"Television": "Television",
|
||||
"Transportation": "Transportation",
|
||||
"Venture Capital": "Venture Capital",
|
||||
"Aerospace": "Aerospace",
|
||||
"Architecture": "Architecture",
|
||||
"Construction": "Construction",
|
||||
"Defense": "Defense",
|
||||
"Creative": "Creative",
|
||||
"Culture": "Culture",
|
||||
"Consulting": "Consulting",
|
||||
"Electric Power": "Electric Power",
|
||||
"Hospitality": "Hospitality",
|
||||
"Mass Media": "Mass Media",
|
||||
"Mining": "Mining",
|
||||
"Music": "Music",
|
||||
"Marketing": "Marketing",
|
||||
"Petroleum": "Petroleum",
|
||||
"Retail": "Retail",
|
||||
"Shipping": "Shipping",
|
||||
"Support": "Support",
|
||||
"Testing, Inspection & Certification": "Testing, Inspection & Certification",
|
||||
"Wholesale": "Wholesale",
|
||||
"Water": "Water"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
"Create Account": "Create Account",
|
||||
"Copy Billing": "Copy Billing"
|
||||
},
|
||||
"presetFilters": {
|
||||
"customers": "Customers",
|
||||
"partners": "Partners",
|
||||
"recentlyCreated": "Recently Created"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"layouts": {
|
||||
"detailConvert": "Convert Lead",
|
||||
"listForAccount": "List (for Account)"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"modes": {
|
||||
"month": "Month",
|
||||
"week": "Week",
|
||||
"agendaWeek": "Week",
|
||||
"day": "Day",
|
||||
"agendaDay": "Day",
|
||||
"timeline": "Timeline"
|
||||
},
|
||||
"labels": {
|
||||
"Today": "Today",
|
||||
"Create": "Create",
|
||||
"Shared": "Shared",
|
||||
"Add User": "Add User",
|
||||
"current": "current",
|
||||
"time": "time",
|
||||
"User List": "User List",
|
||||
"Manage Users": "Manage Users"
|
||||
}
|
||||
}
|
||||
50
application/Espo/Modules/Crm/Resources/i18n/en_GB/Call.json
Normal file
50
application/Espo/Modules/Crm/Resources/i18n/en_GB/Call.json
Normal file
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Name",
|
||||
"parent": "Parent",
|
||||
"status": "Status",
|
||||
"dateStart": "Date Start",
|
||||
"dateEnd": "Date End",
|
||||
"direction": "Direction",
|
||||
"duration": "Duration",
|
||||
"description": "Description",
|
||||
"users": "Users",
|
||||
"contacts": "Contacts",
|
||||
"leads": "Leads",
|
||||
"reminders": "Reminders",
|
||||
"account": "Account",
|
||||
"acceptanceStatus": "Acceptance Status"
|
||||
},
|
||||
"options": {
|
||||
"status": {
|
||||
"Planned": "Planned",
|
||||
"Held": "Held",
|
||||
"Not Held": "Not Held"
|
||||
},
|
||||
"direction": {
|
||||
"Outbound": "Outbound",
|
||||
"Inbound": "Inbound"
|
||||
},
|
||||
"acceptanceStatus": {
|
||||
"None": "None",
|
||||
"Accepted": "Accepted",
|
||||
"Declined": "Declined",
|
||||
"Tentative": "Tentative"
|
||||
}
|
||||
},
|
||||
"massActions": {
|
||||
"setHeld": "Set Held",
|
||||
"setNotHeld": "Set Not Held"
|
||||
},
|
||||
"labels": {
|
||||
"Create Call": "Create Call",
|
||||
"Set Held": "Set Held",
|
||||
"Set Not Held": "Set Not Held",
|
||||
"Send Invitations": "Send Invitations"
|
||||
},
|
||||
"presetFilters": {
|
||||
"planned": "Planned",
|
||||
"held": "Held",
|
||||
"todays": "Today's"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Name",
|
||||
"description": "Description",
|
||||
"status": "Status",
|
||||
"type": "Type",
|
||||
"startDate": "Start Date",
|
||||
"endDate": "End Date",
|
||||
"targetLists": "Target Lists",
|
||||
"excludingTargetLists": "Excluding Target Lists",
|
||||
"sentCount": "Sent",
|
||||
"openedCount": "Opened",
|
||||
"clickedCount": "Clicked",
|
||||
"optedOutCount": "Opted Out",
|
||||
"bouncedCount": "Bounced",
|
||||
"hardBouncedCount": "Hard Bounced",
|
||||
"softBouncedCount": "Soft Bounced",
|
||||
"leadCreatedCount": "Leads Created",
|
||||
"revenue": "Revenue",
|
||||
"revenueConverted": "Revenue (converted)",
|
||||
"budget": "Budget",
|
||||
"budgetConverted": "Budget (converted)"
|
||||
},
|
||||
"links": {
|
||||
"targetLists": "Target Lists",
|
||||
"excludingTargetLists": "Excluding Target Lists",
|
||||
"accounts": "Accounts",
|
||||
"contacts": "Contacts",
|
||||
"leads": "Leads",
|
||||
"opportunities": "Opportunities",
|
||||
"campaignLogRecords": "Log",
|
||||
"massEmails": "Mass Emails",
|
||||
"trackingUrls": "Tracking URLs"
|
||||
},
|
||||
"options": {
|
||||
"type": {
|
||||
"Email": "Email",
|
||||
"Web": "Web",
|
||||
"Television": "Television",
|
||||
"Radio": "Radio",
|
||||
"Newsletter": "Newsletter",
|
||||
"Mail": "Mail"
|
||||
},
|
||||
"status": {
|
||||
"Planning": "Planning",
|
||||
"Active": "Active",
|
||||
"Inactive": "Inactive",
|
||||
"Complete": "Complete"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
"Create Campaign": "Create Campaign",
|
||||
"Target Lists": "Target Lists",
|
||||
"Statistics": "Statistics",
|
||||
"hard": "hard",
|
||||
"soft": "soft",
|
||||
"Unsubscribe": "Unsubscribe",
|
||||
"Mass Emails": "Mass Emails",
|
||||
"Email Templates": "Email Templates",
|
||||
"Unsubscribe again": "Unsubscribe again",
|
||||
"Subscribe again": "Subscribe again",
|
||||
"Create Target List": "Create Target List"
|
||||
},
|
||||
"presetFilters": {
|
||||
"active": "Active"
|
||||
},
|
||||
"messages": {
|
||||
"unsubscribed": "You have been unsubscribed from our mailing list.",
|
||||
"subscribedAgain": "You are subscribed again."
|
||||
},
|
||||
"tooltips": {
|
||||
"targetLists": "Targets that should receive messages.",
|
||||
"excludingTargetLists": "Targets that should not receive messages."
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"fields": {
|
||||
"action": "Action",
|
||||
"actionDate": "Date",
|
||||
"data": "Data",
|
||||
"campaign": "Campaign",
|
||||
"parent": "Target",
|
||||
"object": "Object",
|
||||
"application": "Application",
|
||||
"queueItem": "Queue Item",
|
||||
"stringData": "String Data",
|
||||
"stringAdditionalData": "String Additional Data"
|
||||
},
|
||||
"links": {
|
||||
"queueItem": "Queue Item",
|
||||
"parent": "Parent",
|
||||
"object": "Object"
|
||||
},
|
||||
"options": {
|
||||
"action": {
|
||||
"Sent": "Sent",
|
||||
"Opened": "Opened",
|
||||
"Opted Out": "Opted Out",
|
||||
"Bounced": "Bounced",
|
||||
"Clicked": "Clicked",
|
||||
"Lead Created": "Lead Created"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
"All": "All"
|
||||
},
|
||||
"presetFilters": {
|
||||
"sent": "Sent",
|
||||
"opened": "Opened",
|
||||
"optedOut": "Opted Out",
|
||||
"bounced": "Bounced",
|
||||
"clicked": "Clicked",
|
||||
"leadCreated": "Lead Created"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"fields": {
|
||||
"url": "URL",
|
||||
"urlToUse": "Code to insert instead of URL",
|
||||
"campaign": "Campaign"
|
||||
},
|
||||
"links": {
|
||||
"campaign": "Campaign"
|
||||
},
|
||||
"labels": {
|
||||
"Create CampaignTrackingUrl": "Create Tracking URL"
|
||||
}
|
||||
}
|
||||
59
application/Espo/Modules/Crm/Resources/i18n/en_GB/Case.json
Normal file
59
application/Espo/Modules/Crm/Resources/i18n/en_GB/Case.json
Normal file
@@ -0,0 +1,59 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Name",
|
||||
"number": "Number",
|
||||
"status": "Status",
|
||||
"account": "Account",
|
||||
"contact": "Contact",
|
||||
"contacts": "Contacts",
|
||||
"priority": "Priority",
|
||||
"type": "Type",
|
||||
"description": "Description",
|
||||
"inboundEmail": "Inbound Email",
|
||||
"lead": "Lead"
|
||||
},
|
||||
"links": {
|
||||
"inboundEmail": "Inbound Email",
|
||||
"account": "Account",
|
||||
"contact": "Contact (Primary)",
|
||||
"Contacts": "Contacts",
|
||||
"meetings": "Meetings",
|
||||
"calls": "Calls",
|
||||
"tasks": "Tasks",
|
||||
"emails": "Emails",
|
||||
"articles": "Knowledge Base Articles",
|
||||
"lead": "Lead"
|
||||
},
|
||||
"options": {
|
||||
"status": {
|
||||
"New": "New",
|
||||
"Assigned": "Assigned",
|
||||
"Pending": "Pending",
|
||||
"Closed": "Closed",
|
||||
"Rejected": "Rejected",
|
||||
"Duplicate": "Duplicate"
|
||||
},
|
||||
"priority": {
|
||||
"Low": "Low",
|
||||
"Normal": "Normal",
|
||||
"High": "High",
|
||||
"Urgent": "Urgent"
|
||||
},
|
||||
"type": {
|
||||
"Question": "Question",
|
||||
"Incident": "Incident",
|
||||
"Problem": "Problem"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
"Create Case": "Create Case",
|
||||
"Close": "Close",
|
||||
"Reject": "Reject",
|
||||
"Closed": "Closed",
|
||||
"Rejected": "Rejected"
|
||||
},
|
||||
"presetFilters": {
|
||||
"open": "Open",
|
||||
"closed": "Closed"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Name",
|
||||
"emailAddress": "Email",
|
||||
"title": "Title",
|
||||
"accountRole": "Title",
|
||||
"account": "Account",
|
||||
"accounts": "Accounts",
|
||||
"phoneNumber": "Phone",
|
||||
"accountType": "Account Type",
|
||||
"doNotCall": "Do Not Call",
|
||||
"address": "Address",
|
||||
"opportunityRole": "Opportunity Role",
|
||||
"description": "Description",
|
||||
"campaign": "Campaign",
|
||||
"targetLists": "Target Lists",
|
||||
"targetList": "Target List",
|
||||
"portalUser": "Portal User",
|
||||
"originalLead": "Original Lead",
|
||||
"acceptanceStatus": "Acceptance Status"
|
||||
},
|
||||
"links": {
|
||||
"opportunities": "Opportunities",
|
||||
"cases": "Cases",
|
||||
"targetLists": "Target Lists",
|
||||
"campaignLogRecords": "Campaign Log",
|
||||
"campaign": "Campaign",
|
||||
"account": "Account (Primary)",
|
||||
"accounts": "Accounts",
|
||||
"casesPrimary": "Cases (Primary)",
|
||||
"portalUser": "Portal User",
|
||||
"originalLead": "Original Lead",
|
||||
"documents": "Documents"
|
||||
},
|
||||
"labels": {
|
||||
"Create Contact": "Create Contact"
|
||||
},
|
||||
"options": {
|
||||
"opportunityRole": {
|
||||
"": "--None--",
|
||||
"Decision Maker": "Decision Maker",
|
||||
"Evaluator": "Evaluator",
|
||||
"Influencer": "Influencer"
|
||||
}
|
||||
},
|
||||
"presetFilters": {
|
||||
"portalUsers": "Portal Users",
|
||||
"notPortalUsers": "Not Portal Users"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"labels": {
|
||||
"Create Document": "Create Document",
|
||||
"Details": "Details"
|
||||
},
|
||||
"fields": {
|
||||
"name": "Name",
|
||||
"status": "Status",
|
||||
"file": "File",
|
||||
"type": "Type",
|
||||
"publishDate": "Publish Date",
|
||||
"expirationDate": "Expiration Date",
|
||||
"description": "Description",
|
||||
"accounts": "Accounts",
|
||||
"folder": "Folder"
|
||||
},
|
||||
"links": {
|
||||
"accounts": "Accounts",
|
||||
"opportunities": "Opportunities",
|
||||
"folder": "Folder",
|
||||
"leads": "Leads",
|
||||
"contacts": "Contacts"
|
||||
},
|
||||
"options": {
|
||||
"status": {
|
||||
"Active": "Active",
|
||||
"Draft": "Draft",
|
||||
"Expired": "Expired",
|
||||
"Canceled": "Cancelled"
|
||||
},
|
||||
"type": {
|
||||
"": "None",
|
||||
"Contract": "Contract",
|
||||
"NDA": "NDA",
|
||||
"EULA": "EULA",
|
||||
"License Agreement": "License Agreement"
|
||||
}
|
||||
},
|
||||
"presetFilters": {
|
||||
"active": "Active",
|
||||
"draft": "Draft"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"labels": {
|
||||
"Create DocumentFolder": "Create Document Folder",
|
||||
"Manage Categories": "Manage Folders",
|
||||
"Documents": "Documents"
|
||||
},
|
||||
"links": {
|
||||
"documents": "Documents"
|
||||
}
|
||||
}
|
||||
10
application/Espo/Modules/Crm/Resources/i18n/en_GB/Email.json
Normal file
10
application/Espo/Modules/Crm/Resources/i18n/en_GB/Email.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"labels": {
|
||||
"Create Lead": "Create Lead",
|
||||
"Create Contact": "Create Contact",
|
||||
"Create Task": "Create Task",
|
||||
"Create Case": "Create Case",
|
||||
"Add to Contact": "Add to Contact",
|
||||
"Add to Lead": "Add to Lead"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Name",
|
||||
"status": "Status",
|
||||
"target": "Target",
|
||||
"sentAt": "Date Sent",
|
||||
"attemptCount": "Attempts",
|
||||
"emailAddress": "Email Address",
|
||||
"massEmail": "Mass Email",
|
||||
"isTest": "Is Test"
|
||||
},
|
||||
"links": {
|
||||
"target": "Target",
|
||||
"massEmail": "Mass Email"
|
||||
},
|
||||
"options": {
|
||||
"status": {
|
||||
"Pending": "Pending",
|
||||
"Sent": "Sent",
|
||||
"Failed": "Failed",
|
||||
"Sending": "Sending"
|
||||
}
|
||||
},
|
||||
"presetFilters": {
|
||||
"pending": "Pending",
|
||||
"sent": "Sent",
|
||||
"failed": "Failed"
|
||||
}
|
||||
}
|
||||
118
application/Espo/Modules/Crm/Resources/i18n/en_GB/Global.json
Normal file
118
application/Espo/Modules/Crm/Resources/i18n/en_GB/Global.json
Normal file
@@ -0,0 +1,118 @@
|
||||
{
|
||||
"links": {
|
||||
"parent": "Parent",
|
||||
"contacts": "Contacts",
|
||||
"opportunities": "Opportunities",
|
||||
"leads": "Leads",
|
||||
"meetings": "Meetings",
|
||||
"calls": "Calls",
|
||||
"tasks": "Tasks",
|
||||
"emails": "Emails",
|
||||
"accounts": "Accounts",
|
||||
"cases": "Cases",
|
||||
"documents": "Documents",
|
||||
"account": "Account",
|
||||
"opportunity": "Opportunity",
|
||||
"contact": "Contact"
|
||||
},
|
||||
"scopeNames": {
|
||||
"Account": "Account",
|
||||
"Contact": "Contact",
|
||||
"Lead": "Lead",
|
||||
"Target": "Target",
|
||||
"Opportunity": "Opportunity",
|
||||
"Meeting": "Meeting",
|
||||
"Calendar": "Calendar",
|
||||
"Call": "Call",
|
||||
"Task": "Task",
|
||||
"Case": "Case",
|
||||
"Document": "Document",
|
||||
"DocumentFolder": "Document Folder",
|
||||
"Campaign": "Campaign",
|
||||
"TargetList": "Target List",
|
||||
"MassEmail": "Mass Email",
|
||||
"EmailQueueItem": "Email Queue Item",
|
||||
"CampaignTrackingUrl": "Tracking URL",
|
||||
"Activities": "Activities",
|
||||
"KnowledgeBaseArticle": "Knowledge Base Article",
|
||||
"KnowledgeBaseCategory": "Knowledge Base Category",
|
||||
"CampaignLogRecord": "Campaign Log Record"
|
||||
},
|
||||
"scopeNamesPlural": {
|
||||
"Account": "Accounts",
|
||||
"Contact": "Contacts",
|
||||
"Lead": "Leads",
|
||||
"Target": "Targets",
|
||||
"Opportunity": "Opportunities",
|
||||
"Meeting": "Meetings",
|
||||
"Calendar": "Calendar",
|
||||
"Call": "Calls",
|
||||
"Task": "Tasks",
|
||||
"Case": "Cases",
|
||||
"Document": "Documents",
|
||||
"DocumentFolder": "Document Folders",
|
||||
"Campaign": "Campaigns",
|
||||
"TargetList": "Target Lists",
|
||||
"MassEmail": "Mass Emails",
|
||||
"EmailQueueItem": "Email Queue Items",
|
||||
"CampaignTrackingUrl": "Tracking URLs",
|
||||
"Activities": "Activities",
|
||||
"KnowledgeBaseArticle": "Knowledge Base",
|
||||
"KnowledgeBaseCategory": "Knowledge Base Categories",
|
||||
"CampaignLogRecord": "Campaign Log Records"
|
||||
},
|
||||
"dashlets": {
|
||||
"Leads": "My Leads",
|
||||
"Opportunities": "My Opportunities",
|
||||
"Tasks": "My Tasks",
|
||||
"Cases": "My Cases",
|
||||
"Calendar": "Calendar",
|
||||
"Calls": "My Calls",
|
||||
"Meetings": "My Meetings",
|
||||
"OpportunitiesByStage": "Opportunities by Stage",
|
||||
"OpportunitiesByLeadSource": "Opportunities by Lead Source",
|
||||
"SalesByMonth": "Sales by Month",
|
||||
"SalesPipeline": "Sales Pipeline",
|
||||
"Activities": "My Activities"
|
||||
},
|
||||
"labels": {
|
||||
"Create InboundEmail": "Create Inbound Email",
|
||||
"Activities": "Activities",
|
||||
"History": "History",
|
||||
"Attendees": "Attendees",
|
||||
"Schedule Meeting": "Schedule Meeting",
|
||||
"Schedule Call": "Schedule Call",
|
||||
"Compose Email": "Compose Email",
|
||||
"Log Meeting": "Log Meeting",
|
||||
"Log Call": "Log Call",
|
||||
"Archive Email": "Archive Email",
|
||||
"Create Task": "Create Task",
|
||||
"Tasks": "Tasks"
|
||||
},
|
||||
"fields": {
|
||||
"billingAddressCity": "City",
|
||||
"addressCity": "City",
|
||||
"billingAddressCountry": "Country",
|
||||
"addressCountry": "Country",
|
||||
"billingAddressPostalCode": "Postal Code",
|
||||
"addressPostalCode": "Postal Code",
|
||||
"billingAddressState": "County",
|
||||
"addressState": "County",
|
||||
"billingAddressStreet": "Street",
|
||||
"addressStreet": "Street",
|
||||
"billingAddressMap": "Map",
|
||||
"addressMap": "Map",
|
||||
"shippingAddressCity": "City (Shipping)",
|
||||
"shippingAddressStreet": "Street (Shipping)",
|
||||
"shippingAddressCountry": "Country (Shipping)",
|
||||
"shippingAddressState": "County (Shipping)",
|
||||
"shippingAddressPostalCode": "Postal Code (Shipping)",
|
||||
"shippingAddressMap": "Map (Shipping)"
|
||||
},
|
||||
"options": {
|
||||
"reminderTypes": {
|
||||
"Popup": "Popup",
|
||||
"Email": "Email"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"labels": {
|
||||
"Create KnowledgeBaseArticle": "Create Article",
|
||||
"Any": "Any",
|
||||
"Send in Email": "Send in Email",
|
||||
"Move Up": "Move Up",
|
||||
"Move Down": "Move Down",
|
||||
"Move to Top": "Move to Top",
|
||||
"Move to Bottom": "Move to Bottom"
|
||||
},
|
||||
"fields": {
|
||||
"name": "Name",
|
||||
"status": "Status",
|
||||
"type": "Type",
|
||||
"attachments": "Attachments",
|
||||
"publishDate": "Publish Date",
|
||||
"expirationDate": "Expiration Date",
|
||||
"description": "Description",
|
||||
"body": "Body",
|
||||
"categories": "Categories",
|
||||
"language": "Language",
|
||||
"portals": "Portals"
|
||||
},
|
||||
"links": {
|
||||
"cases": "Cases",
|
||||
"opportunities": "Opportunities",
|
||||
"categories": "Categories",
|
||||
"portals": "Portals"
|
||||
},
|
||||
"options": {
|
||||
"status": {
|
||||
"In Review": "In Review",
|
||||
"Draft": "Draft",
|
||||
"Archived": "Archived",
|
||||
"Published": "Published"
|
||||
},
|
||||
"type": {
|
||||
"Article": "Article"
|
||||
}
|
||||
},
|
||||
"presetFilters": {
|
||||
"published": "Published"
|
||||
},
|
||||
"tooltips": {
|
||||
"portals": "Article will be available only in specified portals."
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"labels": {
|
||||
"Create KnowledgeBaseCategory": "Create Category",
|
||||
"Manage Categories": "Manage Categories",
|
||||
"Articles": "Articles"
|
||||
},
|
||||
"links": {
|
||||
"articles": "Articles"
|
||||
}
|
||||
}
|
||||
68
application/Espo/Modules/Crm/Resources/i18n/en_GB/Lead.json
Normal file
68
application/Espo/Modules/Crm/Resources/i18n/en_GB/Lead.json
Normal file
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"labels": {
|
||||
"Converted To": "Converted To",
|
||||
"Create Lead": "Create Lead",
|
||||
"Convert": "Convert",
|
||||
"convert": "convert"
|
||||
},
|
||||
"fields": {
|
||||
"name": "Name",
|
||||
"emailAddress": "Email",
|
||||
"title": "Title",
|
||||
"website": "Website",
|
||||
"phoneNumber": "Phone",
|
||||
"accountName": "Account Name",
|
||||
"doNotCall": "Do Not Call",
|
||||
"address": "Address",
|
||||
"status": "Status",
|
||||
"source": "Source",
|
||||
"opportunityAmount": "Opportunity Amount",
|
||||
"opportunityAmountConverted": "Opportunity Amount (converted)",
|
||||
"description": "Description",
|
||||
"createdAccount": "Account",
|
||||
"createdContact": "Contact",
|
||||
"createdOpportunity": "Opportunity",
|
||||
"campaign": "Campaign",
|
||||
"targetLists": "Target Lists",
|
||||
"targetList": "Target List",
|
||||
"industry": "Industry",
|
||||
"acceptanceStatus": "Acceptance Status",
|
||||
"opportunityAmountCurrency": "Opportunity Amount Currency"
|
||||
},
|
||||
"links": {
|
||||
"targetLists": "Target Lists",
|
||||
"campaignLogRecords": "Campaign Log",
|
||||
"campaign": "Campaign",
|
||||
"createdAccount": "Account",
|
||||
"createdContact": "Contact",
|
||||
"createdOpportunity": "Opportunity",
|
||||
"cases": "Cases",
|
||||
"documents": "Documents"
|
||||
},
|
||||
"options": {
|
||||
"status": {
|
||||
"New": "New",
|
||||
"Assigned": "Assigned",
|
||||
"In Process": "In Process",
|
||||
"Converted": "Converted",
|
||||
"Recycled": "Recycled",
|
||||
"Dead": "Dead"
|
||||
},
|
||||
"source": {
|
||||
"": "None",
|
||||
"Call": "Call",
|
||||
"Email": "Email",
|
||||
"Existing Customer": "Existing Customer",
|
||||
"Partner": "Partner",
|
||||
"Public Relations": "Public Relations",
|
||||
"Web Site": "Web Site",
|
||||
"Campaign": "Campaign",
|
||||
"Other": "Other"
|
||||
}
|
||||
},
|
||||
"presetFilters": {
|
||||
"active": "Active",
|
||||
"actual": "Actual",
|
||||
"converted": "Converted"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Name",
|
||||
"status": "Status",
|
||||
"storeSentEmails": "Store Sent Emails",
|
||||
"startAt": "Date Start",
|
||||
"fromAddress": "From Address",
|
||||
"fromName": "From Name",
|
||||
"replyToAddress": "Reply-to Address",
|
||||
"replyToName": "Reply-to Name",
|
||||
"campaign": "Campaign",
|
||||
"emailTemplate": "Email Template",
|
||||
"inboundEmail": "Email Account",
|
||||
"targetLists": "Target Lists",
|
||||
"excludingTargetLists": "Excluding Target Lists",
|
||||
"optOutEntirely": "Opt-Out Entirely"
|
||||
},
|
||||
"links": {
|
||||
"targetLists": "Target Lists",
|
||||
"excludingTargetLists": "Excluding Target Lists",
|
||||
"queueItems": "Queue Items",
|
||||
"campaign": "Campaign",
|
||||
"emailTemplate": "Email Template",
|
||||
"inboundEmail": "Email Account"
|
||||
},
|
||||
"options": {
|
||||
"status": {
|
||||
"Draft": "Draft",
|
||||
"Pending": "Pending",
|
||||
"In Process": "In Process",
|
||||
"Complete": "Complete",
|
||||
"Canceled": "Cancelled",
|
||||
"Failed": "Failed"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
"Create MassEmail": "Create Mass Email",
|
||||
"Send Test": "Send Test"
|
||||
},
|
||||
"messages": {
|
||||
"selectAtLeastOneTarget": "Select at least one target.",
|
||||
"testSent": "Test email(s) supposed to be sent"
|
||||
},
|
||||
"tooltips": {
|
||||
"optOutEntirely": "Email addresses of recipients that unsubscribed will be marked as opted out and they will not receive any mass emails anymore.",
|
||||
"targetLists": "Targets that should receive messages.",
|
||||
"excludingTargetLists": "Targets that should not receive messages."
|
||||
},
|
||||
"presetFilters": {
|
||||
"actual": "Actual",
|
||||
"complete": "Complete"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Name",
|
||||
"parent": "Parent",
|
||||
"status": "Status",
|
||||
"dateStart": "Date Start",
|
||||
"dateEnd": "Date End",
|
||||
"duration": "Duration",
|
||||
"description": "Description",
|
||||
"users": "Users",
|
||||
"contacts": "Contacts",
|
||||
"leads": "Leads",
|
||||
"reminders": "Reminders",
|
||||
"account": "Account",
|
||||
"acceptanceStatus": "Acceptance Status"
|
||||
},
|
||||
"options": {
|
||||
"status": {
|
||||
"Planned": "Planned",
|
||||
"Held": "Held",
|
||||
"Not Held": "Not Held"
|
||||
},
|
||||
"acceptanceStatus": {
|
||||
"None": "None",
|
||||
"Accepted": "Accepted",
|
||||
"Declined": "Declined",
|
||||
"Tentative": "Tentative"
|
||||
}
|
||||
},
|
||||
"massActions": {
|
||||
"setHeld": "Set Held",
|
||||
"setNotHeld": "Set Not Held"
|
||||
},
|
||||
"labels": {
|
||||
"Create Meeting": "Create Meeting",
|
||||
"Set Held": "Set Held",
|
||||
"Set Not Held": "Set Not Held",
|
||||
"Send Invitations": "Send Invitations",
|
||||
"on time": "on time",
|
||||
"before": "before"
|
||||
},
|
||||
"presetFilters": {
|
||||
"planned": "Planned",
|
||||
"held": "Held",
|
||||
"todays": "Today's"
|
||||
},
|
||||
"messages": {
|
||||
"nothingHasBeenSent": "Nothing were sent"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Name",
|
||||
"account": "Account",
|
||||
"stage": "Stage",
|
||||
"amount": "Amount",
|
||||
"probability": "Probability, %",
|
||||
"leadSource": "Lead Source",
|
||||
"doNotCall": "Do Not Call",
|
||||
"closeDate": "Close Date",
|
||||
"contacts": "Contacts",
|
||||
"description": "Description",
|
||||
"amountConverted": "Amount (converted)",
|
||||
"amountWeightedConverted": "Amount Weighted",
|
||||
"campaign": "Campaign",
|
||||
"originalLead": "Original Lead",
|
||||
"amountCurrency": "Amount Currency"
|
||||
},
|
||||
"links": {
|
||||
"contacts": "Contacts",
|
||||
"documents": "Documents",
|
||||
"campaign": "Campaign",
|
||||
"originalLead": "Original Lead"
|
||||
},
|
||||
"options": {
|
||||
"stage": {
|
||||
"Prospecting": "Prospecting",
|
||||
"Qualification": "Qualification",
|
||||
"Needs Analysis": "Needs Analysis",
|
||||
"Value Proposition": "Value Proposition",
|
||||
"Id. Decision Makers": "Id. Decision Makers",
|
||||
"Perception Analysis": "Perception Analysis",
|
||||
"Proposal/Price Quote": "Proposal/Price Quote",
|
||||
"Negotiation/Review": "Negotiation/Review",
|
||||
"Closed Won": "Closed Won",
|
||||
"Closed Lost": "Closed Lost"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
"Create Opportunity": "Create Opportunity"
|
||||
},
|
||||
"presetFilters": {
|
||||
"open": "Open",
|
||||
"won": "Won",
|
||||
"lost": "Lost"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"links": {
|
||||
"articles": "Knowledge Base Articles"
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user