Compare commits
159 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 56a04336fe | |||
| 1814529d3e | |||
| 1dbe2d9eac | |||
| 4ca099afc4 | |||
| 7ca09bc893 | |||
| 0a4a8c956a | |||
| 6f2a7ae08f | |||
| 45a9dd1226 | |||
| 9d904171c9 | |||
| 53abea7cdd | |||
| 6427604724 | |||
| 0d72dc7c2f | |||
| 9ee5a98ff4 | |||
| 3f0c92744c | |||
| 7a87749c4c | |||
| 0eaab6b7ee | |||
| b52722565a | |||
| 80fd2a2006 | |||
| 1c1fdffb7d | |||
| 53481890db | |||
| b82a3d0f31 | |||
| 1700b27501 | |||
| 635064e116 | |||
| f6e45d8a68 | |||
| ee0cf4bca5 | |||
| ae98290721 | |||
| 24bbcf0e0a | |||
| 23b1945a3e | |||
| e1fe3c03dd | |||
| 7e0034f674 | |||
| d73cfbca53 | |||
| 3eec2b2a33 | |||
| d60dc744e6 | |||
| bd66211c3c | |||
| 2f341c8967 | |||
| 5c7612c9cf | |||
| b41c0f34aa | |||
| 14eebc7392 | |||
| 5a86d0e396 | |||
| a4e0c8107d | |||
| 1652de16a7 | |||
| ad539e19a2 | |||
| 592f073bf9 | |||
| d5c1d1b86e | |||
| bd70e2424c | |||
| 06d6299d7f | |||
| d00d2bdb0f | |||
| 9f481f6887 | |||
| 47d0501828 | |||
| a4cd8dccfe | |||
| eee0f0eb13 | |||
| 67b9600341 | |||
| 4c0329e6be | |||
| ff6cd18411 | |||
| 8d4219802b | |||
| 07e7374a18 | |||
| 060f517591 | |||
| 1af5e93bd3 | |||
| 38df3162b3 | |||
| e03298b041 | |||
| 80278b7213 | |||
| a701905e9c | |||
| 59b896e594 | |||
| ba4c8e0afd | |||
| 9175d8c7ce | |||
| 052fee6ba2 | |||
| aae3afc895 | |||
| 1892ff6cae | |||
| aa3e9fd8b0 | |||
| 2863092911 | |||
| 1c36421157 | |||
| 77f7da0ba5 | |||
| a5f858dda2 | |||
| a5b7bfc00e | |||
| 4d2cb6c38e | |||
| b6bd70d47c | |||
| ef3ed38b97 | |||
| a38b86b2c6 | |||
| a87044623c | |||
| 44a96ddece | |||
| b0e911870b | |||
| 96bb421b0a | |||
| c281d7b2d9 | |||
| dc5766088f | |||
| fe69f97b1e | |||
| b7bc1e3622 | |||
| b3c4123669 | |||
| 0795f6f6f2 | |||
| c3cd909063 | |||
| 0e37c26b9f | |||
| 80937f8d09 | |||
| 380cdeba35 | |||
| 1eabce0d2e | |||
| 3cd5f801a5 | |||
| c1cfd75bd6 | |||
| dd5fabdfa4 | |||
| 3e9c7056b0 | |||
| 26188879b6 | |||
| 488717c6a1 | |||
| b8476d7335 | |||
| 1cfad615c0 | |||
| e3a3547a54 | |||
| e6948aba2e | |||
| d4943e4d1c | |||
| af5e7d99b2 | |||
| 667a46f141 | |||
| 67f65492de | |||
| b6a98e7121 | |||
| 9669ff91bb | |||
| acb6e245a2 | |||
| b5e015e9c9 | |||
| 70d2e311e5 | |||
| 6c7e5c0d02 | |||
| d4558d73b3 | |||
| e2257f6cfd | |||
| 149fa41e2b | |||
| 71e4c2fca0 | |||
| 5a4613617c | |||
| cbf9dd458e | |||
| 08553bdf9d | |||
| d0b61b42e0 | |||
| 3e3348c4a7 | |||
| c32b0f365b | |||
| 8fd0554714 | |||
| 982f0e1f62 | |||
| c87f5dfab3 | |||
| b335462aa4 | |||
| 97c951484d | |||
| 2215f15aaf | |||
| 65f38a4906 | |||
| 6429823cc3 | |||
| 2a71bb2ea1 | |||
| 1674c2221e | |||
| e3b448f520 | |||
| a04c973817 | |||
| 01c9939215 | |||
| 2d57824cb0 | |||
| 878385f14b | |||
| 8b82058d06 | |||
| 68e05f0935 | |||
| cb7492c042 | |||
| beb811755f | |||
| 7c7fc4ee0f | |||
| aeef25f7ec | |||
| 6856ff97b1 | |||
| 10f6f7600c | |||
| a0b678a3d9 | |||
| f78e558a33 | |||
| e205ef3370 | |||
| 8b6e4d469e | |||
| a63ec2710b | |||
| 6895fac58c | |||
| ea3c8f2d35 | |||
| 0f2c050537 | |||
| 2cd8866c73 | |||
| 217d0f6540 | |||
| f0e7a8f029 | |||
| d2954483d9 | |||
| 999b88cba1 |
@@ -15,3 +15,4 @@
|
||||
/client
|
||||
/test.php
|
||||
/main.html
|
||||
/tests/testData/Utils/Config/config.php
|
||||
|
||||
@@ -1,10 +1,23 @@
|
||||
DirectoryIndex index.php index.html
|
||||
|
||||
RedirectMatch 403 \.config$
|
||||
# PROTECTED DIRECTORIES
|
||||
<IfModule mod_rewrite.c>
|
||||
RewriteEngine On
|
||||
RewriteCond %{REQUEST_FILENAME} -d
|
||||
RewriteRule (?i)(data|api) - [F]
|
||||
</IfModule>
|
||||
RedirectMatch 403 (?i)/data/config\.php$
|
||||
RedirectMatch 403 (?i)/data/logs
|
||||
RedirectMatch 403 (?i)/data/cache
|
||||
RedirectMatch 403 (?i)/data/upload
|
||||
RedirectMatch 403 (?i)/application
|
||||
RedirectMatch 403 (?i)/custom
|
||||
RedirectMatch 403 (?i)/vendor
|
||||
#END PROTECTED DIRECTORIES
|
||||
|
||||
<IfModule mod_rewrite.c>
|
||||
RewriteEngine On
|
||||
RewriteRule .* - [E=HTTP_ESPO_CGI_AUTH:%{HTTP:Authorization}]
|
||||
RewriteEngine On
|
||||
RewriteRule .* - [E=HTTP_ESPO_CGI_AUTH:%{HTTP:Authorization}]
|
||||
|
||||
RewriteRule reset/?$ reset.html [QSA,L]
|
||||
RewriteRule reset/?$ reset.html [QSA,L]
|
||||
</IfModule>
|
||||
+50
-51
@@ -1,4 +1,50 @@
|
||||
module.exports = function (grunt) {
|
||||
|
||||
var jsFilesToMinify = [
|
||||
'client/lib/jquery-2.0.2.min.js',
|
||||
'client/lib/underscore-min.js',
|
||||
'client/lib/backbone-min.js',
|
||||
'client/lib/handlebars.js',
|
||||
'client/lib/base64.js',
|
||||
'client/lib/jquery-ui.min.js',
|
||||
'client/lib/moment.min.js',
|
||||
'client/lib/moment-timezone-with-data.min.js',
|
||||
'client/lib/jquery.timepicker.min.js',
|
||||
'client/lib/jquery.autocomplete.js',
|
||||
'client/lib/bootstrap.min.js',
|
||||
'client/lib/bootstrap-datepicker.js',
|
||||
'client/lib/bull.min.js',
|
||||
'client/src/namespace.js',
|
||||
'client/src/exceptions.js',
|
||||
'client/src/app.js',
|
||||
'client/src/utils.js',
|
||||
'client/src/storage.js',
|
||||
'client/src/loader.js',
|
||||
'client/src/pre-loader.js',
|
||||
'client/src/ui.js',
|
||||
'client/src/acl.js',
|
||||
'client/src/model.js',
|
||||
'client/src/model-offline.js',
|
||||
'client/src/metadata.js',
|
||||
'client/src/language.js',
|
||||
'client/src/cache.js',
|
||||
'client/src/controller.js',
|
||||
'client/src/router.js',
|
||||
'client/src/date-time.js',
|
||||
'client/src/field-manager.js',
|
||||
'client/src/search-manager.js',
|
||||
'client/src/collection.js',
|
||||
'client/src/multi-collection.js',
|
||||
'client/src/view-helper.js',
|
||||
'client/src/layout-manager.js',
|
||||
'client/src/model-factory.js',
|
||||
'client/src/collection-factory.js',
|
||||
'client/src/models/settings.js',
|
||||
'client/src/models/user.js',
|
||||
'client/src/models/preferences.js',
|
||||
'client/src/controllers/base.js',
|
||||
'client/src/view.js',
|
||||
];
|
||||
|
||||
grunt.initConfig({
|
||||
pkg: grunt.file.readJSON('package.json'),
|
||||
@@ -44,56 +90,9 @@ module.exports = function (grunt) {
|
||||
mangle: false,
|
||||
banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n',
|
||||
},
|
||||
'build/tmp/client/espo.min.js': [
|
||||
'frontend/client/lib/jquery-2.0.2.min.js',
|
||||
'frontend/client/lib/underscore-min.js',
|
||||
'frontend/client/lib/backbone-min.js',
|
||||
'frontend/client/lib/handlebars.js',
|
||||
'frontend/client/lib/base64.js',
|
||||
'frontend/client/lib/jquery-ui.min.js',
|
||||
'frontend/client/lib/moment.min.js',
|
||||
'frontend/client/lib/moment-timezone-with-data.min.js',
|
||||
'frontend/client/lib/jquery.timepicker.min.js',
|
||||
'frontend/client/lib/jquery.autocomplete.js',
|
||||
'frontend/client/lib/bootstrap.min.js',
|
||||
'frontend/client/lib/bootstrap-datepicker.js',
|
||||
'frontend/client/lib/bull.min.js',
|
||||
'frontend/client/src/namespace.js',
|
||||
'frontend/client/src/exceptions.js',
|
||||
'frontend/client/src/app.js',
|
||||
'frontend/client/src/utils.js',
|
||||
'frontend/client/src/storage.js',
|
||||
'frontend/client/src/loader.js',
|
||||
'frontend/client/src/pre-loader.js',
|
||||
'frontend/client/src/ui.js',
|
||||
'frontend/client/src/acl.js',
|
||||
'frontend/client/src/model.js',
|
||||
'frontend/client/src/model-offline.js',
|
||||
'frontend/client/src/metadata.js',
|
||||
'frontend/client/src/language.js',
|
||||
'frontend/client/src/cache.js',
|
||||
'frontend/client/src/controller.js',
|
||||
'frontend/client/src/router.js',
|
||||
'frontend/client/src/date-time.js',
|
||||
'frontend/client/src/field-manager.js',
|
||||
'frontend/client/src/search-manager.js',
|
||||
'frontend/client/src/collection.js',
|
||||
'frontend/client/src/multi-collection.js',
|
||||
'frontend/client/src/view-helper.js',
|
||||
'frontend/client/src/layout-manager.js',
|
||||
'frontend/client/src/model-factory.js',
|
||||
'frontend/client/src/collection-factory.js',
|
||||
'frontend/client/src/models/settings.js',
|
||||
'frontend/client/src/models/user.js',
|
||||
'frontend/client/src/models/preferences.js',
|
||||
'frontend/client/src/controllers/base.js',
|
||||
'frontend/client/src/controllers/record.js',
|
||||
'frontend/client/src/controllers/role.js',
|
||||
'frontend/client/src/controllers/admin.js',
|
||||
'frontend/client/src/view.js',
|
||||
'frontend/client/src/views/base.js',
|
||||
'frontend/client/src/views/login.js',
|
||||
]
|
||||
'build/tmp/client/espo.min.js': jsFilesToMinify.map(function (item) {
|
||||
return 'frontend/' + item;
|
||||
})
|
||||
},
|
||||
copy: {
|
||||
frontendFolders: {
|
||||
@@ -137,7 +136,7 @@ module.exports = function (grunt) {
|
||||
'index.php',
|
||||
'LICENSE.txt',
|
||||
'.htaccess',
|
||||
'Web.config',
|
||||
'web.config',
|
||||
],
|
||||
dest: 'build/tmp/',
|
||||
},
|
||||
|
||||
-22
@@ -1,22 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
|
||||
<system.webServer>
|
||||
<rewrite>
|
||||
<rules>
|
||||
<rule name="rule 1X" stopProcessing="true">
|
||||
<match url="reset/?$" />
|
||||
<action type="Rewrite" url="reset.html" appendQueryString="true" />
|
||||
</rule>
|
||||
</rules>
|
||||
</rewrite>
|
||||
|
||||
<defaultDocument>
|
||||
<files>
|
||||
<clear />
|
||||
<add value="index.php" />
|
||||
</files>
|
||||
</defaultDocument>
|
||||
</system.webServer>
|
||||
|
||||
</configuration>
|
||||
@@ -1,2 +0,0 @@
|
||||
Order Deny,Allow
|
||||
Deny from all
|
||||
@@ -25,6 +25,7 @@ namespace Espo\Controllers;
|
||||
use Espo\Core\Utils as Utils;
|
||||
use \Espo\Core\Exceptions\NotFound;
|
||||
use \Espo\Core\Exceptions\Error;
|
||||
use \Espo\Core\Exceptions\Forbidden;
|
||||
|
||||
class Layout extends \Espo\Core\Controllers\Base
|
||||
{
|
||||
@@ -39,6 +40,10 @@ class Layout extends \Espo\Core\Controllers\Base
|
||||
|
||||
public function actionUpdate($params, $data)
|
||||
{
|
||||
if (!$this->getUser()->isAdmin()) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
$result = $this->getContainer()->get('layout')->set($data, $params['scope'], $params['name']);
|
||||
|
||||
if ($result === false) {
|
||||
|
||||
@@ -54,7 +54,13 @@ class Notification extends \Espo\Core\Controllers\Base
|
||||
public function actionNotReadCount()
|
||||
{
|
||||
$userId = $this->getUser()->id;
|
||||
return $this->getService('Notification')->getNotReadCount($userId);
|
||||
return $this->getService('Notification')->getNotReadCount($userId);
|
||||
}
|
||||
|
||||
public function actionMarkAllRead($params, $data, $request)
|
||||
{
|
||||
$userId = $this->getUser()->id;
|
||||
return $this->getService('Notification')->markAllRead($userId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -63,6 +63,12 @@ class Settings extends \Espo\Core\Controllers\Base
|
||||
throw new Error('Cannot save settings');
|
||||
}
|
||||
|
||||
/** Rebuild for Currency Settings */
|
||||
if (isset($data['baseCurrency']) || isset($data['currencyRates'])) {
|
||||
$this->getContainer()->get('dataManager')->rebuildDatabase(array());
|
||||
}
|
||||
/** END Rebuild for Currency Settings */
|
||||
|
||||
return $this->getConfigData();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ class ControllerManager
|
||||
throw new NotFound("Controller '$controllerName' is not found");
|
||||
}
|
||||
|
||||
$controller = new $controllerClassName($this->container);
|
||||
$controller = new $controllerClassName($this->container, $request->getMethod());
|
||||
|
||||
if ($actionName == 'index') {
|
||||
$actionName = $controllerClassName::$defaultAction;
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Controllers;
|
||||
|
||||
@@ -29,15 +29,21 @@ use \Espo\Core\Utils\Util;
|
||||
abstract class Base
|
||||
{
|
||||
protected $name;
|
||||
|
||||
|
||||
private $container;
|
||||
|
||||
|
||||
private $requestMethod;
|
||||
|
||||
public static $defaultAction = 'index';
|
||||
|
||||
public function __construct(Container $container)
|
||||
public function __construct(Container $container, $requestMethod = null)
|
||||
{
|
||||
$this->container = $container;
|
||||
|
||||
|
||||
if (isset($requestMethod)) {
|
||||
$this->setRequestMethod($requestMethod);
|
||||
}
|
||||
|
||||
if (empty($this->name)) {
|
||||
$name = get_class($this);
|
||||
if (preg_match('@\\\\([\w]+)$@', $name, $matches)) {
|
||||
@@ -45,40 +51,55 @@ abstract class Base
|
||||
}
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
|
||||
$this->checkControllerAccess();
|
||||
}
|
||||
|
||||
|
||||
protected function checkControllerAccess()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
protected function getContainer()
|
||||
{
|
||||
return $this->container;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get request method name (Uppercase)
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getRequestMethod()
|
||||
{
|
||||
return $this->requestMethod;
|
||||
}
|
||||
|
||||
protected function setRequestMethod($requestMethod)
|
||||
{
|
||||
$this->requestMethod = strtoupper($requestMethod);
|
||||
}
|
||||
|
||||
protected function getUser()
|
||||
{
|
||||
return $this->container->get('user');
|
||||
}
|
||||
|
||||
|
||||
protected function getAcl()
|
||||
{
|
||||
return $this->container->get('acl');
|
||||
}
|
||||
|
||||
|
||||
protected function getConfig()
|
||||
{
|
||||
return $this->container->get('config');
|
||||
}
|
||||
|
||||
|
||||
protected function getPreferences()
|
||||
{
|
||||
return $this->container->get('preferences');
|
||||
}
|
||||
|
||||
|
||||
protected function getMetadata()
|
||||
{
|
||||
return $this->container->get('metadata');
|
||||
@@ -88,7 +109,7 @@ abstract class Base
|
||||
{
|
||||
return $this->container->get('serviceFactory');
|
||||
}
|
||||
|
||||
|
||||
protected function getService($name)
|
||||
{
|
||||
return $this->getServiceFactory()->create($name);
|
||||
|
||||
@@ -182,8 +182,10 @@ class Record extends Base
|
||||
}
|
||||
|
||||
public function actionExport($params, $data, $request)
|
||||
{
|
||||
// TODO move to service
|
||||
{
|
||||
if ($this->getConfig()->get('disableExport') && !$this->getUser()->isAdmin()) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
if (!$this->getAcl()->check($this->name, 'read')) {
|
||||
throw new Forbidden();
|
||||
|
||||
@@ -124,23 +124,25 @@ class Sender
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function send(Email $email)
|
||||
public function send(Email $email, $params = array())
|
||||
{
|
||||
$message = new Message();
|
||||
|
||||
$config = $this->config;
|
||||
|
||||
$params = $this->params + $params;
|
||||
|
||||
if ($email->get('from')) {
|
||||
$fromName = null;
|
||||
if (!empty($this->params['fromName'])) {
|
||||
$fromName = $this->params['fromName'];
|
||||
if (!empty($params['fromName'])) {
|
||||
$fromName = $params['fromName'];
|
||||
} else {
|
||||
$fromName = $config->get('outboundEmailFromName');
|
||||
}
|
||||
$message->addFrom(trim($email->get('from')), $fromName);
|
||||
} else {
|
||||
if (!empty($this->params['fromAddress'])) {
|
||||
$fromAddress = $this->params['fromAddress'];
|
||||
if (!empty($params['fromAddress'])) {
|
||||
$fromAddress = $params['fromAddress'];
|
||||
} else {
|
||||
if (!$config->get('outboundEmailFromAddress')) {
|
||||
throw new Error('outboundEmailFromAddress is not specified in config.');
|
||||
@@ -148,14 +150,22 @@ class Sender
|
||||
$fromAddress = $config->get('outboundEmailFromAddress');
|
||||
}
|
||||
|
||||
if (!empty($this->params['fromName'])) {
|
||||
$fromName = $this->params['fromName'];
|
||||
if (!empty($params['fromName'])) {
|
||||
$fromName = $params['fromName'];
|
||||
} else {
|
||||
$fromName = $config->get('outboundEmailFromName');
|
||||
}
|
||||
|
||||
$message->addFrom($fromAddress, $fromName);
|
||||
}
|
||||
|
||||
if (!empty($params['replyToAddress'])) {
|
||||
$replyToName = null;
|
||||
if (!empty($params['replyToName'])) {
|
||||
$replyToName = $params['replyToName'];
|
||||
}
|
||||
$message->setReplyTo($params['replyToAddress'], $replyToName);
|
||||
}
|
||||
|
||||
$value = $email->get('to');
|
||||
if ($value) {
|
||||
|
||||
@@ -56,7 +56,12 @@ class EntityManager extends \Espo\ORM\EntityManager
|
||||
public function getUser()
|
||||
{
|
||||
return $this->user;
|
||||
}
|
||||
}
|
||||
|
||||
public function getEspoMetadata()
|
||||
{
|
||||
return $this->espoMetadata;
|
||||
}
|
||||
|
||||
public function setEspoMetadata($espoMetadata)
|
||||
{
|
||||
|
||||
@@ -82,6 +82,11 @@ class Base
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function getTextFilterFields()
|
||||
{
|
||||
return $this->metadata->get("entityDefs.{$this->entityName}.collection.textFilterFields", array('name'));
|
||||
}
|
||||
|
||||
protected function where($params, &$result)
|
||||
{
|
||||
@@ -96,6 +101,18 @@ class Base
|
||||
$params['where'][] = $p;
|
||||
}
|
||||
}
|
||||
} else if ($item['type'] == 'textFilter' && !empty($item['value'])) {
|
||||
if (!empty($item['value'])) {
|
||||
if (empty($result['whereClause'])) {
|
||||
$result['whereClause'] = array();
|
||||
}
|
||||
$fieldList = $this->getTextFilterFields();
|
||||
$d = array();
|
||||
foreach ($fieldList as $field) {
|
||||
$d[$field . '*'] = $item['value'] . '%';
|
||||
}
|
||||
$where['OR'] = $d;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,18 +176,23 @@ class Base
|
||||
}
|
||||
$result['whereClause']['assignedUserId'] = $this->user->id;
|
||||
}
|
||||
if ($this->acl->checkReadOnlyTeam($this->entityName)) {
|
||||
if (!$this->user->isAdmin() && $this->acl->checkReadOnlyTeam($this->entityName)) {
|
||||
if (!array_key_exists('whereClause', $result)) {
|
||||
$result['whereClause'] = array();
|
||||
}
|
||||
$result['distinct'] = true;
|
||||
if (!array_key_exists('joins', $result)) {
|
||||
$result['joins'] = array();
|
||||
}
|
||||
if (!in_array('teams', $result['joins'])) {
|
||||
$result['joins'][] = 'teams';
|
||||
$result['leftJoins'][] = 'teams';
|
||||
}
|
||||
|
||||
$result['whereClause']['Team.id'] = $this->user->get('teamsIds');
|
||||
$result['whereClause']['OR'] = array(
|
||||
'Team.id' => $this->user->get('teamsIds'),
|
||||
'assignedUserId' => $this->user->id
|
||||
);
|
||||
//$result['whereClause']['Team.id'] = $this->user->get('teamsIds');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -255,6 +277,15 @@ class Base
|
||||
case 'isFalse':
|
||||
$part[$item['field'] . '='] = false;
|
||||
break;
|
||||
case 'today':
|
||||
$part[$item['field'] . '='] = date('Y-m-d');
|
||||
break;
|
||||
case 'past':
|
||||
$part[$item['field'] . '<'] = date('Y-m-d');
|
||||
break;
|
||||
case 'future':
|
||||
$part[$item['field'] . '>'] = date('Y-m-d');
|
||||
break;
|
||||
case 'between':
|
||||
if (is_array($item['value'])) {
|
||||
$part['AND'] = array(
|
||||
|
||||
@@ -26,7 +26,11 @@ use \Espo\Core\Interfaces\Injectable;
|
||||
|
||||
abstract class Base implements Injectable
|
||||
{
|
||||
protected $dependencies = array();
|
||||
protected $dependencies = array(
|
||||
'config',
|
||||
'entityManager',
|
||||
'user',
|
||||
);
|
||||
|
||||
protected $injections = array();
|
||||
|
||||
@@ -53,5 +57,20 @@ abstract class Base implements Injectable
|
||||
{
|
||||
return $this->dependencies;
|
||||
}
|
||||
|
||||
protected function getEntityManager()
|
||||
{
|
||||
return $this->getInjection('entityManager');
|
||||
}
|
||||
|
||||
protected function getConfig()
|
||||
{
|
||||
return $this->getInjection('config');
|
||||
}
|
||||
|
||||
protected function getUser()
|
||||
{
|
||||
return $this->getInjection('user');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,11 +51,12 @@ class Auth
|
||||
$entityManager = $this->container->get('entityManager');
|
||||
|
||||
$user = $entityManager->getRepository('User')->get('system');
|
||||
$user->set('isAdmin', $isAdmin);
|
||||
if (!$user) {
|
||||
throw new Error('System user is not found');
|
||||
}
|
||||
|
||||
$user->set('isAdmin', $isAdmin);
|
||||
|
||||
$entityManager->setUser($user);
|
||||
$this->container->setUser($user);
|
||||
}
|
||||
|
||||
@@ -56,6 +56,7 @@ class Config
|
||||
private $data;
|
||||
|
||||
private $changedData = array();
|
||||
private $removeData = array();
|
||||
|
||||
private $fileManager;
|
||||
|
||||
@@ -112,11 +113,33 @@ class Config
|
||||
}
|
||||
|
||||
foreach ($name as $key => $value) {
|
||||
|
||||
if (is_object($value)) {
|
||||
$value = (array) $value;
|
||||
}
|
||||
|
||||
$this->data[$key] = $value;
|
||||
$this->changedData[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an option in config
|
||||
*
|
||||
* @param string $name
|
||||
* @return bool | null - null if an option doesn't exist
|
||||
*/
|
||||
public function remove($name)
|
||||
{
|
||||
if (array_key_exists($name, $this->data)) {
|
||||
unset($this->data[$name]);
|
||||
$this->removeData[] = $name;
|
||||
return true;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function save()
|
||||
{
|
||||
$values = $this->changedData;
|
||||
@@ -125,9 +148,12 @@ class Config
|
||||
$values = array_merge($this->updateCacheTimestamp(true), $values);
|
||||
}
|
||||
|
||||
$result = $this->getFileManager()->mergeContentsPHP($this->configPath, $values, true);
|
||||
$removeData = empty($this->removeData) ? null : $this->removeData;
|
||||
|
||||
$result = $this->getFileManager()->mergeContentsPHP($this->configPath, $values, 1, $removeData);
|
||||
if ($result) {
|
||||
$this->changedData = array();
|
||||
$this->removeData = array();
|
||||
$this->loadConfig(true);
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ class Email extends \Espo\Core\Utils\Database\Orm\Base
|
||||
JOIN email_address ON email_address.id = entity_email_address.email_address_id
|
||||
WHERE
|
||||
entity_email_address.deleted = 0 AND entity_email_address.entity_type = '{$entityName}' AND
|
||||
email_address.deleted = 0 AND email_address.name LIKE '{text}'
|
||||
email_address.deleted = 0 AND email_address.name LIKE {value}
|
||||
)",
|
||||
'=' => \Espo\Core\Utils\Util::toUnderScore($entityName) . ".id IN (
|
||||
SELECT entity_id
|
||||
@@ -47,7 +47,7 @@ class Email extends \Espo\Core\Utils\Database\Orm\Base
|
||||
JOIN email_address ON email_address.id = entity_email_address.email_address_id
|
||||
WHERE
|
||||
entity_email_address.deleted = 0 AND entity_email_address.entity_type = '{$entityName}' AND
|
||||
email_address.deleted = 0 AND email_address.name = '{text}'
|
||||
email_address.deleted = 0 AND email_address.name = {value}
|
||||
)"
|
||||
),
|
||||
'orderBy' => 'email_address.name {direction}',
|
||||
|
||||
@@ -44,8 +44,8 @@ class PersonName extends \Espo\Core\Utils\Database\Orm\Base
|
||||
$columnName = $tableName.'.'.Util::toUnderScore($fieldNameTrimmed);
|
||||
|
||||
$fullList[] = $fieldList[] = $columnName;
|
||||
$like[] = $columnName." LIKE '{text}'";
|
||||
$equal[] = $columnName." = '{text}'";
|
||||
$like[] = $columnName." LIKE {value}";
|
||||
$equal[] = $columnName." = {value}";
|
||||
} else {
|
||||
$fullList[] = "'".$foreignFieldName."'";
|
||||
}
|
||||
@@ -60,8 +60,8 @@ class PersonName extends \Espo\Core\Utils\Database\Orm\Base
|
||||
'type' => 'varchar',
|
||||
'select' => $this->getSelect($fullList),
|
||||
'where' => array(
|
||||
'LIKE' => "(".implode(" OR ", $like)." OR CONCAT(".implode(", ", $fullList).") LIKE '{text}' OR CONCAT(".implode(", ", $fullListReverse).") LIKE '{text}')",
|
||||
'=' => "(".implode(" OR ", $equal)." OR CONCAT(".implode(", ", $fullList).") = '{text}' OR CONCAT(".implode(", ", $fullListReverse).") = '{text}')",
|
||||
'LIKE' => "(".implode(" OR ", $like)." OR CONCAT(".implode(", ", $fullList).") LIKE {value} OR CONCAT(".implode(", ", $fullListReverse).") LIKE {value})",
|
||||
'=' => "(".implode(" OR ", $equal)." OR CONCAT(".implode(", ", $fullList).") = {value} OR CONCAT(".implode(", ", $fullListReverse).") = {value})",
|
||||
),
|
||||
'orderBy' => implode(", ", array_map(function ($item) {return $item . ' {direction}';}, $fieldList)),
|
||||
),
|
||||
@@ -86,4 +86,4 @@ class PersonName extends \Espo\Core\Utils\Database\Orm\Base
|
||||
return $select;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ class Phone extends \Espo\Core\Utils\Database\Orm\Base
|
||||
JOIN phone_number ON phone_number.id = entity_phone_number.phone_number_id
|
||||
WHERE
|
||||
entity_phone_number.deleted = 0 AND entity_phone_number.entity_type = '{$entityName}' AND
|
||||
phone_number.deleted = 0 AND phone_number.name LIKE '{text}'
|
||||
phone_number.deleted = 0 AND phone_number.name LIKE {value}
|
||||
)",
|
||||
'=' => \Espo\Core\Utils\Util::toUnderScore($entityName) . ".id IN (
|
||||
SELECT entity_id
|
||||
@@ -47,7 +47,7 @@ class Phone extends \Espo\Core\Utils\Database\Orm\Base
|
||||
JOIN phone_number ON phone_number.id = entity_phone_number.phone_number_id
|
||||
WHERE
|
||||
entity_phone_number.deleted = 0 AND entity_phone_number.entity_type = '{$entityName}' AND
|
||||
phone_number.deleted = 0 AND phone_number.name = '{text}'
|
||||
phone_number.deleted = 0 AND phone_number.name = {value}
|
||||
)"
|
||||
),
|
||||
'orderBy' => 'phone_number.name {direction}',
|
||||
|
||||
@@ -276,7 +276,8 @@ class Converter
|
||||
case 'array':
|
||||
case 'jsonArray':
|
||||
case 'text':
|
||||
$dbFieldParams['default'] = ''; //for db type TEXT can't be defined a default value
|
||||
case 'longtext':
|
||||
unset($dbFieldParams['default']); //for db type TEXT can't be defined a default value
|
||||
break;
|
||||
|
||||
case 'bool':
|
||||
|
||||
@@ -18,24 +18,32 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Utils\Database\Schema\rebuildActions;
|
||||
|
||||
class Currency extends \Espo\Core\Utils\Database\Schema\BaseRebuildActions
|
||||
{
|
||||
|
||||
public function afterRebuild()
|
||||
{
|
||||
$currencyConfig = $this->getConfig()->get('currency');
|
||||
$currencyConfig['rate'][ $currencyConfig['base'] ] = '1.00';
|
||||
|
||||
$pdo = $this->getEntityManager()->getPDO();
|
||||
public function afterRebuild()
|
||||
{
|
||||
$defaultCurrency = $this->getConfig()->get('defaultCurrency');
|
||||
|
||||
$baseCurrency = $this->getConfig()->get('baseCurrency');
|
||||
$currencyRates = $this->getConfig()->get('currencyRates');
|
||||
|
||||
if ($defaultCurrency != $baseCurrency) {
|
||||
$currencyRates = $this->exchangeRates($baseCurrency, $defaultCurrency, $currencyRates);
|
||||
}
|
||||
|
||||
$currencyRates[$defaultCurrency] = '1.00';
|
||||
|
||||
$pdo = $this->getEntityManager()->getPDO();
|
||||
|
||||
$sql = "TRUNCATE `currency`";
|
||||
$pdo->prepare($sql)->execute();
|
||||
|
||||
foreach ($currencyConfig['rate'] as $currencyName => $rate) {
|
||||
foreach ($currencyRates as $currencyName => $rate) {
|
||||
|
||||
$sql = "
|
||||
INSERT INTO `currency`
|
||||
@@ -43,9 +51,34 @@ class Currency extends \Espo\Core\Utils\Database\Schema\BaseRebuildActions
|
||||
VALUES
|
||||
(".$pdo->quote($currencyName) . ", " . $pdo->quote($rate) . ")
|
||||
";
|
||||
$pdo->prepare($sql)->execute();
|
||||
}
|
||||
}
|
||||
|
||||
$pdo->prepare($sql)->execute();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate exchange rates if defaultCurrency doesn't equals baseCurrency
|
||||
*
|
||||
* @param string $baseCurrency
|
||||
* @param string $defaultCurrency
|
||||
* @param array $currencyRates [description]
|
||||
* @return array - List of new currency rates
|
||||
*/
|
||||
protected function exchangeRates($baseCurrency, $defaultCurrency, array $currencyRates)
|
||||
{
|
||||
$precision = 5;
|
||||
$defaultCurrencyRate = round(1 / $currencyRates[$defaultCurrency], $precision);
|
||||
|
||||
$exchangedRates = array();
|
||||
$exchangedRates[$baseCurrency] = $defaultCurrencyRate;
|
||||
|
||||
unset($currencyRates[$baseCurrency], $currencyRates[$defaultCurrency]);
|
||||
|
||||
foreach ($currencyRates as $currencyName => $rate) {
|
||||
$exchangedRates[$currencyName] = round($rate * $defaultCurrencyRate, $precision);
|
||||
}
|
||||
|
||||
return $exchangedRates;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -225,22 +225,33 @@ class Manager
|
||||
* @param string | array $path
|
||||
* @param string $content JSON string
|
||||
* @param bool $isJSON
|
||||
* @param array $mergeOptions
|
||||
* @param string | array $mergeOptions
|
||||
* @param string | array $removeOptions - List of unset keys from content
|
||||
* @param bool $isReturn - Is result to be returned or stored
|
||||
*
|
||||
* @return bool
|
||||
* @return bool | array
|
||||
*/
|
||||
public function mergeContents($path, $content, $isJSON = false, $mergeOptions = null)
|
||||
public function mergeContents($path, $content, $isJSON = false, $mergeOptions = null, $removeOptions = null, $isReturn = false)
|
||||
{
|
||||
$fileContent = $this->getContents($path);
|
||||
|
||||
$savedDataArray = Utils\Json::getArrayData($fileContent);
|
||||
$newDataArray = Utils\Json::getArrayData($content);
|
||||
|
||||
if (isset($removeOptions)) {
|
||||
$savedDataArray = Utils\Util::unsetInArray($savedDataArray, $removeOptions);
|
||||
$newDataArray = Utils\Util::unsetInArray($newDataArray, $removeOptions);
|
||||
}
|
||||
|
||||
$data = Utils\Util::merge($savedDataArray, $newDataArray, $mergeOptions);
|
||||
if ($isJSON) {
|
||||
$data = Utils\Json::encode($data, JSON_PRETTY_PRINT);
|
||||
}
|
||||
|
||||
if ($isReturn) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
return $this->putContents($path, $data);
|
||||
}
|
||||
|
||||
@@ -248,26 +259,14 @@ class Manager
|
||||
* Merge PHP content and save it to a file
|
||||
*
|
||||
* @param string | array $path
|
||||
* @param string $content
|
||||
* @param bool $onlyFirstLevel - Merge only first level. Ex. current: array('test'=>array('item1', 'item2')). $content= array('test'=>array('item1'),). Result will be array('test'=>array('item1')).
|
||||
*
|
||||
* @param string $content JSON string
|
||||
* @param string | array $mergeOptions
|
||||
* @param string | array $removeOptions - List of unset keys from content
|
||||
* @return bool
|
||||
*/
|
||||
public function mergeContentsPHP($path, $content, $onlyFirstLevel = false, $mergeOptions = null)
|
||||
public function mergeContentsPHP($path, $content, $mergeOptions = null, $removeOptions = null)
|
||||
{
|
||||
$fileContent = $this->getContents($path);
|
||||
|
||||
$savedDataArray = Utils\Json::getArrayData($fileContent);
|
||||
$newDataArray = Utils\Json::getArrayData($content);
|
||||
|
||||
if ($onlyFirstLevel) {
|
||||
foreach($newDataArray as $key => $val) {
|
||||
$setVal = is_array($val) ? array() : '';
|
||||
$savedDataArray[$key] = $setVal;
|
||||
}
|
||||
}
|
||||
|
||||
$data = Utils\Util::merge($savedDataArray, $newDataArray, $mergeOptions);
|
||||
$data = $this->mergeContents($path, $content, false, $mergeOptions, $removeOptions, true);
|
||||
|
||||
return $this->putContentsPHP($path, $data);
|
||||
}
|
||||
|
||||
@@ -480,11 +480,12 @@ class Permission
|
||||
if (file_exists($item)) {
|
||||
|
||||
try {
|
||||
$res = $this->chmod($item, $permission, true);
|
||||
$this->chmod($item, $permission, true);
|
||||
} catch (\Exception $e) {
|
||||
$res = false;
|
||||
}
|
||||
|
||||
$res = is_readable($item);
|
||||
|
||||
/** check is wtitable */
|
||||
if ($type == 'writable') {
|
||||
|
||||
|
||||
@@ -154,10 +154,10 @@ class Language
|
||||
|
||||
return $translated;
|
||||
}
|
||||
|
||||
|
||||
public function translateOption($value, $field, $scope)
|
||||
{
|
||||
$options = $this->get($scope. '.options.' . $field);
|
||||
$options = $this->get($scope. '.options.' . $field);
|
||||
if (array_key_exists($value, $options)) {
|
||||
return $options[$value];
|
||||
}
|
||||
@@ -241,7 +241,7 @@ class Language
|
||||
$i18nCacheFile = str_replace('{*}', $i18nName, $this->cacheFile);
|
||||
|
||||
if ($i18nName != $this->defaultLanguage) {
|
||||
$i18nData = Util::merge($this->fullData[$this->defaultLanguage], $i18nData);
|
||||
$i18nData = Util::merge($this->fullData[$this->defaultLanguage], $i18nData, null, null, true);
|
||||
}
|
||||
$result &= $this->getFileManager()->putContentsPHP($i18nCacheFile, $i18nData);
|
||||
}
|
||||
|
||||
@@ -125,10 +125,13 @@ class Util
|
||||
* ),
|
||||
* )
|
||||
* @param $rewriteKeyName string - Rewrite key name. It is ignored if $rewriteLevel is NULL.
|
||||
* @param $rewriteArrays bool - Rewrite single arrays. Examples:
|
||||
* TRUE: array is [0, 1, 2], main array is [3, 4, 5], Result is [3, 4, 5].
|
||||
* FALSE: array is [0, 1, 2], main array is [3, 4, 5], Result is [0, 1, 2, 3, 4, 5].
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function merge($array, $mainArray, $rewriteLevel = null, $rewriteKeyName = null)
|
||||
public static function merge($array, $mainArray, $rewriteLevel = null, $rewriteKeyName = null, $rewriteArrays = false)
|
||||
{
|
||||
if (is_array($array) && !is_array($mainArray)) {
|
||||
return $array;
|
||||
@@ -169,7 +172,7 @@ class Util
|
||||
} /** END: check the $rewriteKeyName */
|
||||
|
||||
if (!isset($rowRewriteLevel) || $rowRewriteLevel != 1) {
|
||||
$array[$mainKey] = static::merge((array) $value, (array) $mainValue, --$rowRewriteLevel, $rewriteKeyName);
|
||||
$array[$mainKey] = static::merge((array) $value, (array) $mainValue, --$rowRewriteLevel, $rewriteKeyName, $rewriteArrays);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -185,7 +188,11 @@ class Util
|
||||
$array[$mainKey] = $mainValue;
|
||||
}
|
||||
elseif (!in_array($mainValue, $array)) {
|
||||
$array[] = $mainValue;
|
||||
if ($rewriteArrays) {
|
||||
$array[$mainKey] = $mainValue;
|
||||
} else {
|
||||
$array[] = $mainValue;
|
||||
}
|
||||
} /** END: merge logic */
|
||||
|
||||
break;
|
||||
@@ -359,11 +366,17 @@ class Util
|
||||
if (!empty($unsetSett)){
|
||||
$keyItems = explode('.', $unsetSett);
|
||||
$currVal = isset($content[$rootKey]) ? "\$content['{$rootKey}']" : "\$content";
|
||||
|
||||
$lastKey = array_pop($keyItems);
|
||||
foreach($keyItems as $keyItem){
|
||||
$currVal .= "['{$keyItem}']";
|
||||
}
|
||||
|
||||
$currVal = "if (isset({$currVal})) unset({$currVal});";
|
||||
$unsetElem = $currVal . "['{$lastKey}']";
|
||||
$currVal = "
|
||||
if (isset({$unsetElem}) || array_key_exists({$lastKey}, {$currVal})) {
|
||||
unset({$unsetElem});
|
||||
} ";
|
||||
eval($currVal);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,11 +46,8 @@ return array (
|
||||
array (
|
||||
),
|
||||
'defaultCurrency' => 'USD',
|
||||
'currency' =>
|
||||
array(
|
||||
'base' => 'USD',
|
||||
'rate' => array(
|
||||
),
|
||||
'baseCurrency' => 'USD',
|
||||
'currencyRates' => array(
|
||||
),
|
||||
'outboundEmailIsShared' => true,
|
||||
'outboundEmailFromName' => 'EspoCRM',
|
||||
@@ -62,13 +59,15 @@ return array (
|
||||
'smtpUsername' => '',
|
||||
'smtpPassword' => '',
|
||||
'languageList' => array(
|
||||
'en_US',
|
||||
'en_US',
|
||||
'de_DE',
|
||||
'es_ES',
|
||||
'fr_FR',
|
||||
'nl_NL',
|
||||
'tr_TR',
|
||||
'ro_RO',
|
||||
'pt_BR'
|
||||
'pt_BR',
|
||||
'vi_VN'
|
||||
),
|
||||
'language' => 'en_US',
|
||||
'logger' =>
|
||||
@@ -89,6 +88,9 @@ return array (
|
||||
"tabList" => array("Account", "Contact", "Lead", "Opportunity", "Calendar", "Meeting", "Call", "Task", "Case", "Email"),
|
||||
"quickCreateList" => array("Account", "Contact", "Lead", "Opportunity", "Meeting", "Call", "Task", "Case"),
|
||||
'calendarDefaultEntity' => 'Meeting',
|
||||
'disableExport' => false,
|
||||
'assignmentEmailNotifications' => false,
|
||||
'assignmentEmailNotificationsEntityList' => array('Lead', 'Opportunity', 'Task', 'Case'),
|
||||
'isInstalled' => false,
|
||||
);
|
||||
|
||||
|
||||
@@ -30,6 +30,10 @@ class Download extends \Espo\Core\EntryPoints\Base
|
||||
{
|
||||
public static $authRequired = true;
|
||||
|
||||
protected $fileTypesToShowInline = array(
|
||||
'application/pdf',
|
||||
);
|
||||
|
||||
public function run()
|
||||
{
|
||||
$id = $_GET['id'];
|
||||
@@ -54,13 +58,21 @@ class Download extends \Espo\Core\EntryPoints\Base
|
||||
|
||||
if (!file_exists($fileName)) {
|
||||
throw new NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
$type = $attachment->get('type');
|
||||
|
||||
$disposition = 'attachment';
|
||||
if (in_array($type, $this->fileTypesToShowInline)) {
|
||||
$disposition = 'inline';
|
||||
}
|
||||
|
||||
|
||||
header('Content-Description: File Transfer');
|
||||
if ($attachment->get('type')) {
|
||||
header('Content-Type: ' . $attachment->get('type'));
|
||||
if ($type) {
|
||||
header('Content-Type: ' . $type);
|
||||
}
|
||||
header('Content-Disposition: attachment; filename=' . $attachment->get('name'));
|
||||
header('Content-Disposition: ' . $disposition . '; filename=' . $attachment->get('name'));
|
||||
header('Expires: 0');
|
||||
header('Cache-Control: must-revalidate');
|
||||
header('Pragma: public');
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014 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/.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Hooks\Common;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class AssignmentEmailNotification extends \Espo\Core\Hooks\Base
|
||||
{
|
||||
|
||||
public function afterSave(Entity $entity)
|
||||
{
|
||||
if (
|
||||
$this->getConfig()->get('assignmentEmailNotifications')
|
||||
&&
|
||||
in_array($entity->getEntityName(), $this->getConfig()->get('assignmentEmailNotificationsEntityList', array()))
|
||||
) {
|
||||
|
||||
$userId = $entity->get('assignedUserId');
|
||||
if (!empty($userId) && $userId != $this->getUser()->id && $entity->isFieldChanged('assignedUserId')) {
|
||||
$job = $this->getEntityManager()->getEntity('Job');
|
||||
$job->set(array(
|
||||
'serviceName' => 'EmailNotification',
|
||||
'method' => 'notifyAboutAssignmentJob',
|
||||
'data' => json_encode(array(
|
||||
'userId' => $userId,
|
||||
'assignerUserId' => $this->getUser()->id,
|
||||
'entityId' => $entity->id,
|
||||
'entityType' => $entity->getEntityName()
|
||||
)),
|
||||
'executeTime' => date('Y-m-d H:i:s'),
|
||||
));
|
||||
$this->getEntityManager()->saveEntity($job);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -53,11 +53,25 @@ class Notifications extends \Espo\Core\Hooks\Base
|
||||
WHERE entity_id = " . $pdo->quote($parentId) . " AND entity_type = " . $pdo->quote($parentType);
|
||||
$sth = $pdo->prepare($sql);
|
||||
$sth->execute();
|
||||
$userIdList = array();
|
||||
while ($row = $sth->fetch(\PDO::FETCH_ASSOC)) {
|
||||
if ($this->getUser()->id != $row['userId']) {
|
||||
$this->getNotificationService()->notifyAboutNote($row['userId'], $entity->id);
|
||||
$userIdList[] = $row['userId'];
|
||||
}
|
||||
}
|
||||
if (!empty($userIdList)) {
|
||||
$job = $this->getEntityManager()->getEntity('Job');
|
||||
$job->set(array(
|
||||
'serviceName' => 'Notification',
|
||||
'method' => 'notifyAboutNoteFromJob',
|
||||
'data' => json_encode(array(
|
||||
'userIdList' => $userIdList,
|
||||
'noteId' => $entity->id
|
||||
)),
|
||||
'executeTime' => date('Y-m-d H:i:s'),
|
||||
));
|
||||
$this->getEntityManager()->saveEntity($job);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ class Opportunity extends \Espo\Core\Controllers\Record
|
||||
opportunity.close_date < ".$pdo->quote($dateTo)." AND
|
||||
opportunity.stage <> 'Closed Lost' AND
|
||||
opportunity.lead_source <> ''
|
||||
GROUP BY opportunity.lead_source
|
||||
GROUP BY opportunity.lead_source
|
||||
";
|
||||
|
||||
$sth = $pdo->prepare($sql);
|
||||
@@ -72,8 +72,8 @@ class Opportunity extends \Espo\Core\Controllers\Record
|
||||
opportunity.close_date >= ".$pdo->quote($dateFrom)." AND
|
||||
opportunity.close_date < ".$pdo->quote($dateTo)." AND
|
||||
opportunity.stage <> 'Closed Lost'
|
||||
GROUP BY opportunity.lead_source
|
||||
ORDER BY `amount` DESC
|
||||
GROUP BY opportunity.stage
|
||||
ORDER BY FIELD(opportunity.stage, 'Prospecting', 'Qualification', 'Needs Analysis', 'Value Proposition', 'Id. Decision Makers', 'Perception Analysis', 'Proposal/Price Quote', 'Negotiation/Review', 'Closed Won')
|
||||
";
|
||||
|
||||
$sth = $pdo->prepare($sql);
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014 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/.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Modules\Crm\Repositories;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class Lead extends \Espo\Core\ORM\Repositories\RDB
|
||||
{
|
||||
public function handleSelectParams(&$params)
|
||||
{
|
||||
parent::handleSelectParams($params);
|
||||
|
||||
if (empty($params['customJoin'])) {
|
||||
$params['customJoin'] = '';
|
||||
}
|
||||
|
||||
$params['customJoin'] .= "
|
||||
LEFT JOIN currency ON currency.id = lead.opportunity_amount_currency
|
||||
";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014 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/.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Modules\Crm\Repositories;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class Opportunity extends \Espo\Core\ORM\Repositories\RDB
|
||||
{
|
||||
public function handleSelectParams(&$params)
|
||||
{
|
||||
parent::handleSelectParams($params);
|
||||
|
||||
if (empty($params['customJoin'])) {
|
||||
$params['customJoin'] = '';
|
||||
}
|
||||
|
||||
$params['customJoin'] .= "
|
||||
LEFT JOIN currency ON currency.id = opportunity.amount_currency
|
||||
";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -30,5 +30,10 @@
|
||||
"Set Held": "Set Held",
|
||||
"Set Not Held": "Set Not Held",
|
||||
"Send Invitations": "Send Invitations"
|
||||
},
|
||||
"presetFilters": {
|
||||
"planned": "Planned",
|
||||
"held": "Held",
|
||||
"todays": "Today's"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,5 +34,9 @@
|
||||
},
|
||||
"labels": {
|
||||
"Create Case": "Create Case"
|
||||
},
|
||||
"presetFilters": {
|
||||
"open": "Open",
|
||||
"closed": "Closed"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
"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",
|
||||
|
||||
@@ -16,8 +16,17 @@
|
||||
"caseDistribution": "Case Distribution",
|
||||
"replyEmailTemplate": "Reply Email Template",
|
||||
"replyFromAddress": "Reply From Address",
|
||||
"replyToAddress": "Reply To Address",
|
||||
"replyFromName": "Reply From Name"
|
||||
},
|
||||
"tooltips": {
|
||||
"reply": "Notify email senders that their emails has been received.",
|
||||
"createCase": "Automatically create case from incoming emails.",
|
||||
"replyToAddress": "Specify email address of this mailbox to make response come here.",
|
||||
"caseDistribution": "How cases will be assigned to. Assigned directly to the user or among the team.",
|
||||
"assignToUser": "User emails/cases will be assigned to.",
|
||||
"team": "Team emails/cases will be related to."
|
||||
},
|
||||
"links": {
|
||||
},
|
||||
"options": {
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
"status": "Status",
|
||||
"source": "Source",
|
||||
"opportunityAmount": "Opportunity Amount",
|
||||
"opportunityAmountConverted": "Opportunity Amount (converted)",
|
||||
"description": "Description",
|
||||
"createdAccount": "Account",
|
||||
"createdContact": "Contact",
|
||||
@@ -42,5 +43,8 @@
|
||||
"Campaign": "Campaign",
|
||||
"Other": "Other"
|
||||
}
|
||||
},
|
||||
"presetFilters": {
|
||||
"active": "Active"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,13 @@
|
||||
"Create Meeting": "Create Meeting",
|
||||
"Set Held": "Set Held",
|
||||
"Set Not Held": "Set Not Held",
|
||||
"Send Invitations": "Send Invitations"
|
||||
"Send Invitations": "Send Invitations",
|
||||
"Saved as Held": "Saved as Held",
|
||||
"Saved as Not Held": "Saved as Not Held"
|
||||
},
|
||||
"presetFilters": {
|
||||
"planned": "Planned",
|
||||
"held": "Held",
|
||||
"todays": "Today's"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
"doNotCall": "Do Not Call",
|
||||
"closeDate": "Close Date",
|
||||
"contacts": "Contacts",
|
||||
"description": "Description"
|
||||
"description": "Description",
|
||||
"amountConverted": "Amount (converted)"
|
||||
},
|
||||
"links": {
|
||||
"contacts": "Contacts"
|
||||
@@ -30,5 +31,9 @@
|
||||
},
|
||||
"labels": {
|
||||
"Create Opportunity": "Create Opportunity"
|
||||
},
|
||||
"presetFilters": {
|
||||
"open": "Open",
|
||||
"won": "Won"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,5 +27,11 @@
|
||||
},
|
||||
"labels": {
|
||||
"Create Task": "Create Task"
|
||||
},
|
||||
"presetFilters": {
|
||||
"active": "Active",
|
||||
"completed": "Completed",
|
||||
"todays": "Today's",
|
||||
"overdue": "Overdue"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Record Naam",
|
||||
"emailAddress": "Email",
|
||||
"website": "Website",
|
||||
"phoneNumber": "Telefoon",
|
||||
"billingAddress": "Factuur Adres",
|
||||
"shippingAddress": "Bezoek adres",
|
||||
"description": "Beschrijving",
|
||||
"sicCode": "Sic Code",
|
||||
"industry": "Industrie",
|
||||
"type": "Type",
|
||||
"contactRole": "Voorwaarde"
|
||||
},
|
||||
"links": {
|
||||
"contacts": "Contactpersoon",
|
||||
"opportunities": "Kansen",
|
||||
"cases": "Cases"
|
||||
},
|
||||
"options": {
|
||||
"type": {
|
||||
"Customer": "Klant",
|
||||
"Investor": "Investeerder",
|
||||
"Partner": "Partner",
|
||||
"Reseller": "Reseller"
|
||||
},
|
||||
"industry": {
|
||||
"Apparel": "Apparel",
|
||||
"Banking": "Banking",
|
||||
"Computer Software": "Computer Software",
|
||||
"Education": "Educatie",
|
||||
"Electronics": "Electronica",
|
||||
"Finance": "Finance",
|
||||
"Insurance": "Verzekeringen"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
"Create Account": "Maak Relatie"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"modes": {
|
||||
"month": "Maand",
|
||||
"week": "Week",
|
||||
"day": "Dag",
|
||||
"agendaWeek": "Week",
|
||||
"agendaDay": "Dag"
|
||||
},
|
||||
"labels": {
|
||||
"Today": "Vandaag",
|
||||
"Create": "Maak"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Record Naam",
|
||||
"parent": "Bovenliggende item",
|
||||
"status": "Status",
|
||||
"dateStart": "Start Datum",
|
||||
"dateEnd": "Eind Datum",
|
||||
"direction": "Richting",
|
||||
"duration": "Gedurende",
|
||||
"description": "Beschrijving",
|
||||
"users": "Gebruikers",
|
||||
"contacts": "Contactpersoon",
|
||||
"leads": "Leads"
|
||||
},
|
||||
"links": {
|
||||
},
|
||||
"options": {
|
||||
"status": {
|
||||
"Planned": "Plannen",
|
||||
"Held": "Volgen",
|
||||
"Not Held": "Niet volgen"
|
||||
},
|
||||
"direction": {
|
||||
"Outbound": "Uitgaande",
|
||||
"Inbound": "Binnenkomende"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
"Create Call": "Maak Call",
|
||||
"Set Held": "Vasthouden",
|
||||
"Set Not Held": "Niet Vasthouden",
|
||||
"Send Invitations": "Uitnodiging versturen"
|
||||
},
|
||||
"presetFilters": {
|
||||
"planned": "Plannen",
|
||||
"held": "Volgen",
|
||||
"todays": "Vandaag"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Record Naam",
|
||||
"number": "Nummer",
|
||||
"status": "Status",
|
||||
"account": "Relatie",
|
||||
"contact": "Contact",
|
||||
"priority": "Prioriteit",
|
||||
"type": "Type",
|
||||
"description": "Beschrijving"
|
||||
},
|
||||
"links": {
|
||||
},
|
||||
"options": {
|
||||
"status": {
|
||||
"New": "Nieuw",
|
||||
"Assigned": "Toegewezen",
|
||||
"Pending": "Pending",
|
||||
"Closed": "Gesloten",
|
||||
"Rejected": "Geweigerd",
|
||||
"Duplicate": "Dupliceer"
|
||||
},
|
||||
"priority" : {
|
||||
"Low": "Laag",
|
||||
"Normal": "Normaal",
|
||||
"High": "Hoog",
|
||||
"Urgent": "Urgent"
|
||||
},
|
||||
"type": {
|
||||
"Question": "Vraag",
|
||||
"Incident": "Incident",
|
||||
"Problem": "Probleem"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
"Create Case": "Maak Case"
|
||||
},
|
||||
"presetFilters": {
|
||||
"open": "Open",
|
||||
"closed": "Gesloten"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Record Naam",
|
||||
"emailAddress": "Email",
|
||||
"title": "Titel",
|
||||
"account": "Relatie",
|
||||
"accounts": "Relaties",
|
||||
"phoneNumber": "Telefoon",
|
||||
"accountType": "Relatie Type",
|
||||
"doNotCall": "Niet Bellen",
|
||||
"address": "Adres",
|
||||
"opportunityRole": "Opportunity Role",
|
||||
"accountRole": "Voorwaarde",
|
||||
"description": "Beschrijving"
|
||||
},
|
||||
"links": {
|
||||
"opportunities": "Kansen",
|
||||
"cases": "Cases"
|
||||
},
|
||||
"labels": {
|
||||
"Create Contact": "Maak Contact"
|
||||
},
|
||||
"options": {
|
||||
"opportunityRole": {
|
||||
"": "--Geen--",
|
||||
"Decision Maker": "Beslisser",
|
||||
"Evaluator": "Evaluator",
|
||||
"Influencer": "Beinvloeder"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
{
|
||||
"scopeNames": {
|
||||
"Account": "Relatie",
|
||||
"Contact": "Contact",
|
||||
"Lead": "Lead",
|
||||
"Target": "Doel",
|
||||
"Opportunity": "Kans",
|
||||
"Meeting": "Vergadering",
|
||||
"Calendar": "Kalender",
|
||||
"Call": "Oproep",
|
||||
"Task": "Taak",
|
||||
"Case": "Zaak",
|
||||
"InboundEmail": "Binnenkomende Email"
|
||||
},
|
||||
"scopeNamesPlural": {
|
||||
"Account": "Relaties",
|
||||
"Contact": "Contactpersoon",
|
||||
"Lead": "Leads",
|
||||
"Target": "Doel",
|
||||
"Opportunity": "Kansen",
|
||||
"Meeting": "Afspraken",
|
||||
"Calendar": "Kalender",
|
||||
"Call": "Tel.gesprekken",
|
||||
"Task": "Taken",
|
||||
"Case": "Cases",
|
||||
"InboundEmail": "Inkomende Emails"
|
||||
},
|
||||
"dashlets": {
|
||||
"Leads": "Mijn Leads",
|
||||
"Opportunities": "Mijn Kansen",
|
||||
"Tasks": "Mijn Taken",
|
||||
"Cases": "Mijn Zaken",
|
||||
"Calendar": "Kalender",
|
||||
"Calls": "Mijn Tel.gesprekken",
|
||||
"Meetings": "Mijn Afspraken",
|
||||
"OpportunitiesByStage": "Status van Kansen",
|
||||
"OpportunitiesByLeadSource": "Kans van Lead bron",
|
||||
"SalesByMonth": "Verkopen per maand",
|
||||
"SalesPipeline": "Verkoop mogelijkheden"
|
||||
},
|
||||
"labels": {
|
||||
"Create InboundEmail": "Instellen Email Gebruiker",
|
||||
"Activities": "Activiteiten",
|
||||
"History": "Historie",
|
||||
"Attendees": "Genodigden",
|
||||
"Schedule Meeting": "Plan Afspraak",
|
||||
"Schedule Call": "Geplande Oproep",
|
||||
"Compose Email": "Maak een Email",
|
||||
"Log Meeting": "Leg afspraak vast",
|
||||
"Log Call": "Leg tel.afspraak vast",
|
||||
"Archive Email": "Archiveer Email",
|
||||
"Create Task": "Maak een Taak",
|
||||
"Tasks": "Taken"
|
||||
},
|
||||
"fields": {
|
||||
"billingAddressCity": "Plaats",
|
||||
"billingAddressCountry": "Land",
|
||||
"billingAddressPostalCode": "Postcode",
|
||||
"billingAddressState": "Deelstaat",
|
||||
"billingAddressStreet": "Straat",
|
||||
"addressCity": "Plaats",
|
||||
"addressStreet": "Straat",
|
||||
"addressCountry": "Land",
|
||||
"addressState": "Deelstaat",
|
||||
"addressPostalCode": "Postcode",
|
||||
"shippingAddressCity": "City (Shipping)",
|
||||
"shippingAddressStreet": "Street (Shipping)",
|
||||
"shippingAddressCountry": "Country (Shipping)",
|
||||
"shippingAddressState": "State (Shipping)",
|
||||
"shippingAddressPostalCode": "Postal Code (Shipping)"
|
||||
},
|
||||
"links": {
|
||||
"contacts": "Contactpersoon",
|
||||
"opportunities": "Kansen",
|
||||
"leads": "Leads",
|
||||
"meetings": "Afspraken",
|
||||
"calls": "Tel.gesprekken",
|
||||
"tasks": "Taken",
|
||||
"emails": "Emails"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Record Naam",
|
||||
"team": "Team",
|
||||
"status": "Status",
|
||||
"assignToUser": "Toegewezen aan gebruiker",
|
||||
"host": "Host",
|
||||
"username": "Gebruikersnaam",
|
||||
"password": "Wachtwoord",
|
||||
"port": "Poort",
|
||||
"monitoredFolders": "Gecontroleerde Folders",
|
||||
"trashFolder": "Prullenbak Folder",
|
||||
"ssl": "SSL",
|
||||
"createCase": "Maak Case",
|
||||
"reply": "Antw.",
|
||||
"caseDistribution": "Zaak Verdelen",
|
||||
"replyEmailTemplate": "Antw. Email Template",
|
||||
"replyFromAddress": "Antw. van Adres",
|
||||
"replyToAddress": "Reply To Address",
|
||||
"replyFromName": "Antw. van Naam"
|
||||
},
|
||||
"links": {
|
||||
},
|
||||
"options": {
|
||||
"status": {
|
||||
"Active": "Active",
|
||||
"Inactive": "Inactive"
|
||||
},
|
||||
"caseDistribution": {
|
||||
"Direct-Assignment": "Directe-Toewijzing",
|
||||
"Round-Robin": "Round-Robin",
|
||||
"Least-Busy": "Minst-Bezet"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
"Create InboundEmail": "Instellen Email Gebruiker",
|
||||
"IMAP": "IMAP",
|
||||
"Actions": "Acties",
|
||||
"Main": "Hoofd"
|
||||
},
|
||||
"messages": {
|
||||
"couldNotConnectToImap": "Kan geen verbinding maken met IMAP server"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"labels": {
|
||||
"Converted To": "Vertaald naar",
|
||||
"Create Lead": "Grote Lead",
|
||||
"Convert": "Vertaald"
|
||||
},
|
||||
"fields": {
|
||||
"name": "Record Naam",
|
||||
"emailAddress": "Email",
|
||||
"title": "Titel",
|
||||
"website": "Website",
|
||||
"phoneNumber": "Telefoon",
|
||||
"accountName": "Relatie Naam",
|
||||
"doNotCall": "Niet Bellen",
|
||||
"address": "Adres",
|
||||
"status": "Status",
|
||||
"source": "Bron",
|
||||
"opportunityAmount": "Aantal uitdagingen",
|
||||
"opportunityAmountConverted": "Opportunity Amount (converted)",
|
||||
"description": "Beschrijving",
|
||||
"createdAccount": "Relatie",
|
||||
"createdContact": "Contact",
|
||||
"createdOpportunity": "Kans"
|
||||
},
|
||||
"links": {
|
||||
},
|
||||
"options": {
|
||||
"status": {
|
||||
"New": "Nieuw",
|
||||
"Assigned": "Toegewezen",
|
||||
"In Process": "In Behandeling",
|
||||
"Converted": "Vertaald",
|
||||
"Recycled": "Opnieuw verwerkt",
|
||||
"Dead": "Dood"
|
||||
},
|
||||
"source": {
|
||||
"Call": "Oproep",
|
||||
"Email": "Email",
|
||||
"Existing Customer": "Bestaande Klant",
|
||||
"Partner": "Partner",
|
||||
"Public Relations": "Public Relations",
|
||||
"Web Site": "Web Pagina",
|
||||
"Campaign": "Campagne",
|
||||
"Other": "Ander"
|
||||
}
|
||||
},
|
||||
"presetFilters": {
|
||||
"active": "Active"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Record Naam",
|
||||
"parent": "Bovenliggende item",
|
||||
"status": "Status",
|
||||
"dateStart": "Start Datum",
|
||||
"dateEnd": "Eind Datum",
|
||||
"duration": "Gedurende",
|
||||
"description": "Beschrijving",
|
||||
"users": "Gebruikers",
|
||||
"contacts": "Contactpersoon",
|
||||
"leads": "Leads"
|
||||
},
|
||||
"links": {
|
||||
},
|
||||
"options": {
|
||||
"status": {
|
||||
"Planned": "Plannen",
|
||||
"Held": "Volgen",
|
||||
"Not Held": "Niet volgen"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
"Create Meeting": "Plan Vergadering",
|
||||
"Set Held": "Vasthouden",
|
||||
"Set Not Held": "Niet Vasthouden",
|
||||
"Send Invitations": "Uitnodiging versturen",
|
||||
"Saved as Held": "Opslaan Bewaren",
|
||||
"Saved as Not Held": "Opslaan niet Bewaren"
|
||||
},
|
||||
"presetFilters": {
|
||||
"planned": "Plannen",
|
||||
"held": "Volgen",
|
||||
"todays": "Vandaag"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Record Naam",
|
||||
"account": "Relatie",
|
||||
"stage": "Status",
|
||||
"amount": "Aantal",
|
||||
"probability": "Naar waarschijnlijkheid, %",
|
||||
"leadSource": "Lead Bron",
|
||||
"doNotCall": "Niet Bellen",
|
||||
"closeDate": "Datum gesloten",
|
||||
"contacts": "Contactpersoon",
|
||||
"description": "Beschrijving",
|
||||
"amountConverted": "Amount (converted)"
|
||||
},
|
||||
"links": {
|
||||
"contacts": "Contactpersoon"
|
||||
},
|
||||
"options": {
|
||||
"stage": {
|
||||
"Prospecting": "Prospecting",
|
||||
"Qualification": "Kwalificeren",
|
||||
"Needs Analysis": "Benodigde Analyse",
|
||||
"Value Proposition": "Waarde Schatting",
|
||||
"Id. Decision Makers": "Id. Beslissiers",
|
||||
"Perception Analysis": "Perceptie Analyse",
|
||||
"Proposal/Price Quote": "Prijs/Voorstel",
|
||||
"Negotiation/Review": "Onderhandeling/Herziening",
|
||||
"Closed Won": "Gesloten Gewonnen",
|
||||
"Closed Lost": "Gesloten Verloren"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
"Create Opportunity": "Grote Uitdaging"
|
||||
},
|
||||
"presetFilters": {
|
||||
"open": "Open",
|
||||
"won": "Gewonnen"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Record Naam",
|
||||
"emailAddress": "Email",
|
||||
"title": "Titel",
|
||||
"website": "Website",
|
||||
"accountName": "Relatie Naam",
|
||||
"phoneNumber": "Telefoon",
|
||||
"doNotCall": "Niet Bellen",
|
||||
"address": "Adres",
|
||||
"description": "Beschrijving"
|
||||
},
|
||||
"links": {
|
||||
},
|
||||
"labels": {
|
||||
"Create Target": "Create Target",
|
||||
"Convert to Lead": "Omgezet naar Lead"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Record Naam",
|
||||
"parent": "Bovenliggende item",
|
||||
"status": "Status",
|
||||
"dateStart": "Start Datum",
|
||||
"dateEnd": "Vervaldatum",
|
||||
"priority": "Prioriteit",
|
||||
"description": "Beschrijving",
|
||||
"isOverdue": "Te Laat"
|
||||
},
|
||||
"links": {
|
||||
},
|
||||
"options": {
|
||||
"status": {
|
||||
"Not Started": "Niet Gestart",
|
||||
"Started": "Gestart",
|
||||
"Completed": "Beeindigd",
|
||||
"Canceled": "Geannuleerd"
|
||||
},
|
||||
"priority" : {
|
||||
"Low": "Laag",
|
||||
"Normal": "Normaal",
|
||||
"High": "Hoog",
|
||||
"Urgent": "Urgent"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
"Create Task": "Maak een Taak"
|
||||
},
|
||||
"presetFilters": {
|
||||
"active": "Active",
|
||||
"completed": "Beeindigd",
|
||||
"todays": "Vandaag",
|
||||
"overdue": "Laat"
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
},
|
||||
"links": {
|
||||
"contacts": "Contacte",
|
||||
"opportunities": "Opportunitati",
|
||||
"opportunities": "Oportunitati",
|
||||
"cases": "Cazuri"
|
||||
},
|
||||
"options": {
|
||||
|
||||
@@ -30,5 +30,10 @@
|
||||
"Set Held": "Setare detinere",
|
||||
"Set Not Held": "Setare nedetinere",
|
||||
"Send Invitations": "Trimite invitatii"
|
||||
},
|
||||
"presetFilters": {
|
||||
"planned": "Planificat",
|
||||
"held": "Detinut",
|
||||
"todays": "Today's"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,5 +34,9 @@
|
||||
},
|
||||
"labels": {
|
||||
"Create Case": "Creare Caz"
|
||||
},
|
||||
"presetFilters": {
|
||||
"open": "Deschide",
|
||||
"closed": "Inchis"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
"description": "Descriere"
|
||||
},
|
||||
"links": {
|
||||
"opportunities": "Opportunitati",
|
||||
"opportunities": "Oportunitati",
|
||||
"cases": "Cazuri"
|
||||
},
|
||||
"labels": {
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
"Contact": "Contacte",
|
||||
"Lead": "Lead-uri",
|
||||
"Target": "Tinte",
|
||||
"Opportunity": "Opportunitati",
|
||||
"Opportunity": "Oportunitati",
|
||||
"Meeting": "Intalniri",
|
||||
"Calendar": "Calendar",
|
||||
"Call": "Apeluri",
|
||||
@@ -69,7 +69,7 @@
|
||||
},
|
||||
"links": {
|
||||
"contacts": "Contacte",
|
||||
"opportunities": "Opportunitati",
|
||||
"opportunities": "Oportunitati",
|
||||
"leads": "Lead-uri",
|
||||
"meetings": "Intalniri",
|
||||
"calls": "Apeluri",
|
||||
|
||||
@@ -42,5 +42,8 @@
|
||||
"Campaign": "Campanie",
|
||||
"Other": "Altele"
|
||||
}
|
||||
},
|
||||
"presetFilters": {
|
||||
"active": "Activ"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,13 @@
|
||||
"Create Meeting": "Creare Intalnire",
|
||||
"Set Held": "Setare detinere",
|
||||
"Set Not Held": "Setare nedetinere",
|
||||
"Send Invitations": "Trimite invitatii"
|
||||
"Send Invitations": "Trimite invitatii",
|
||||
"Saved as Held": "Saved as Held",
|
||||
"Saved as Not Held": "Saved as Not Held"
|
||||
},
|
||||
"presetFilters": {
|
||||
"planned": "Planificat",
|
||||
"held": "Detinut",
|
||||
"todays": "Today's"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,5 +30,9 @@
|
||||
},
|
||||
"labels": {
|
||||
"Create Opportunity": "Creare Oportunitate"
|
||||
},
|
||||
"presetFilters": {
|
||||
"open": "Deschide",
|
||||
"won": "Won"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,5 +27,11 @@
|
||||
},
|
||||
"labels": {
|
||||
"Create Task": "Creaza Activitate"
|
||||
},
|
||||
"presetFilters": {
|
||||
"active": "Activ",
|
||||
"completed": "Completat",
|
||||
"todays": "Today's",
|
||||
"overdue": "Overdue"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Tên",
|
||||
"emailAddress": "Email",
|
||||
"website": "Website",
|
||||
"phoneNumber": "Điện thoại",
|
||||
"billingAddress": "Địa chủ thanh toán",
|
||||
"shippingAddress": "Địa chỉ vận chuyển",
|
||||
"description": "Mô tả",
|
||||
"sicCode": "Mã Sic",
|
||||
"industry": "Industry",
|
||||
"type": "Loại",
|
||||
"contactRole": "Vai trò"
|
||||
},
|
||||
"links": {
|
||||
"contacts": "Sổ liên lạc",
|
||||
"opportunities": "Cơ hội",
|
||||
"cases": "Trường hợp"
|
||||
},
|
||||
"options": {
|
||||
"type": {
|
||||
"Customer": "Khách hàng",
|
||||
"Investor": "Nhà đầu tư",
|
||||
"Partner": "Đối tác",
|
||||
"Reseller": "Đại lý"
|
||||
},
|
||||
"industry": {
|
||||
"Apparel": "May mặc",
|
||||
"Banking": "Ngân hàng",
|
||||
"Computer Software": "Phần mềm",
|
||||
"Education": "Giáo dục",
|
||||
"Electronics": "Điện máy",
|
||||
"Finance": "Tín dụng",
|
||||
"Insurance": "Bảo hiểm"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
"Create Account": "Tạo tài khoản"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"modes": {
|
||||
"month": "Tháng",
|
||||
"week": "Tuần",
|
||||
"day": "Ngày",
|
||||
"agendaWeek": "Tuần",
|
||||
"agendaDay": "Ngày"
|
||||
},
|
||||
"labels": {
|
||||
"Today": "Today",
|
||||
"Create": "Tạo"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Tên",
|
||||
"parent": "Chủ",
|
||||
"status": "Trạng thái",
|
||||
"dateStart": "Ngày bắt đầu",
|
||||
"dateEnd": "Ngày kết thúc",
|
||||
"direction": "Hướng",
|
||||
"duration": "Thời gian",
|
||||
"description": "Mô tả",
|
||||
"users": "Người dùng",
|
||||
"contacts": "Sổ liên lạc",
|
||||
"leads": "Trưởng nhóm"
|
||||
},
|
||||
"links": {
|
||||
},
|
||||
"options": {
|
||||
"status": {
|
||||
"Planned": "Đã lên kế hoạch",
|
||||
"Held": "Đã được tổ chức",
|
||||
"Not Held": "Chưa được tổ chức"
|
||||
},
|
||||
"direction": {
|
||||
"Outbound": "Ra ngoài",
|
||||
"Inbound": "Vào trong"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
"Create Call": "Tạo cuộc gọi",
|
||||
"Set Held": "Tổ chức",
|
||||
"Set Not Held": "Không tổ chức",
|
||||
"Send Invitations": "Gửi giấy mời"
|
||||
},
|
||||
"presetFilters": {
|
||||
"planned": "Đã lên kế hoạch",
|
||||
"held": "Đã được tổ chức",
|
||||
"todays": "Hôm nay"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Tên",
|
||||
"number": "Số",
|
||||
"status": "Trạng thái",
|
||||
"account": "Tài khoản",
|
||||
"contact": "Liên hệ",
|
||||
"priority": "Ưu tiên",
|
||||
"type": "Loại",
|
||||
"description": "Mô tả"
|
||||
},
|
||||
"links": {
|
||||
},
|
||||
"options": {
|
||||
"status": {
|
||||
"New": "Mới",
|
||||
"Assigned": "Chỉ định",
|
||||
"Pending": "Đang chờ",
|
||||
"Closed": "Đã đóng",
|
||||
"Rejected": "Đã từ chối",
|
||||
"Duplicate": "Trùng"
|
||||
},
|
||||
"priority" : {
|
||||
"Low": "Thấp",
|
||||
"Normal": "Bình thường",
|
||||
"High": "Cao",
|
||||
"Urgent": "Gấp"
|
||||
},
|
||||
"type": {
|
||||
"Question": "Câu hỏi",
|
||||
"Incident": "Sự cố",
|
||||
"Problem": "Có vấn đề"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
"Create Case": "Tạo trường hợp"
|
||||
},
|
||||
"presetFilters": {
|
||||
"open": "Mở",
|
||||
"closed": "Đã đóng"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Tên",
|
||||
"emailAddress": "Email",
|
||||
"title": "Tiêu đề",
|
||||
"account": "Tài khoản",
|
||||
"accounts": "Tài khoản",
|
||||
"phoneNumber": "Điện thoại",
|
||||
"accountType": "Loại tài khoản",
|
||||
"doNotCall": "Không gọi",
|
||||
"address": "Địa chỉ",
|
||||
"opportunityRole": "Vai trò cơ hội",
|
||||
"accountRole": "Vai trò",
|
||||
"description": "Mô tả"
|
||||
},
|
||||
"links": {
|
||||
"opportunities": "Cơ hội",
|
||||
"cases": "Trường hợp"
|
||||
},
|
||||
"labels": {
|
||||
"Create Contact": "Tạo liên hệ"
|
||||
},
|
||||
"options": {
|
||||
"opportunityRole": {
|
||||
"": "--Trống--",
|
||||
"Decision Maker": "Tạo quyết định",
|
||||
"Evaluator": "Đánh giá",
|
||||
"Influencer": "Phụ thuộc"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
{
|
||||
"scopeNames": {
|
||||
"Account": "Tài khoản",
|
||||
"Contact": "Liên hệ",
|
||||
"Lead": "Chỉ dẫn",
|
||||
"Target": "Mục tiêu",
|
||||
"Opportunity": "Cơ hội",
|
||||
"Meeting": "Buổi gặp",
|
||||
"Calendar": "Lịch",
|
||||
"Call": "Gọi",
|
||||
"Task": "Nhiệm vụ",
|
||||
"Case": "Trường hợp",
|
||||
"InboundEmail": "Email tới"
|
||||
},
|
||||
"scopeNamesPlural": {
|
||||
"Account": "Tài khoản",
|
||||
"Contact": "Sổ liên lạc",
|
||||
"Lead": "Trưởng nhóm",
|
||||
"Target": "Mục tiêu",
|
||||
"Opportunity": "Cơ hội",
|
||||
"Meeting": "Hẹn gặp",
|
||||
"Calendar": "Lịch",
|
||||
"Call": "Cuộc gọi",
|
||||
"Task": "Nhiệm vụ",
|
||||
"Case": "Trường hợp",
|
||||
"InboundEmail": "Email đã nhận"
|
||||
},
|
||||
"dashlets": {
|
||||
"Leads": "Chỉ dẫn của tôi",
|
||||
"Opportunities": "Cơ hội của tôi",
|
||||
"Tasks": "Nhiệm vụ của tôi",
|
||||
"Cases": "Công việc của tôi",
|
||||
"Calendar": "Lịch",
|
||||
"OpportunitiesByStage": "Chia mức cơ hội",
|
||||
"OpportunitiesByLeadSource": "Phân chia cơ hội theo người chỉ dẫn",
|
||||
"SalesByMonth": "Doanh thu hàng tháng",
|
||||
"SalesPipeline": "Doanh thu đường ống"
|
||||
},
|
||||
"labels": {
|
||||
"Create InboundEmail": "Tạo email đến",
|
||||
"Activities": "Hành động",
|
||||
"History": "Lịch sử",
|
||||
"Attendees": "Người dự",
|
||||
"Schedule Meeting": "Lên lịch hẹn",
|
||||
"Schedule Call": "Lên lịch gọi",
|
||||
"Compose Email": "Tạo email",
|
||||
"Log Meeting": "Log cuộc hẹn",
|
||||
"Log Call": "Log cuộc gọi",
|
||||
"Archive Email": "Email lưu trữ",
|
||||
"Create Task": "Tạo nhiệm vụ",
|
||||
"Tasks": "Nhiệm vụ"
|
||||
},
|
||||
"fields": {
|
||||
"billingAddressCity": "Quận - huyện",
|
||||
"billingAddressCountry": "Quốc gia",
|
||||
"billingAddressPostalCode": "Mã bưu điện",
|
||||
"billingAddressState": "Thành phố",
|
||||
"billingAddressStreet": "Đường",
|
||||
"addressCity": "Quận - huyện",
|
||||
"addressStreet": "Đường",
|
||||
"addressCountry": "Quốc gia",
|
||||
"addressState": "Thành phố",
|
||||
"addressPostalCode": "Mã bưu điện",
|
||||
"shippingAddressCity": "City (Shipping)",
|
||||
"shippingAddressStreet": "Street (Shipping)",
|
||||
"shippingAddressCountry": "Country (Shipping)",
|
||||
"shippingAddressState": "State (Shipping)",
|
||||
"shippingAddressPostalCode": "Postal Code (Shipping)"
|
||||
},
|
||||
"links": {
|
||||
"contacts": "Sổ liên lạc",
|
||||
"opportunities": "Cơ hội",
|
||||
"leads": "Trưởng nhóm",
|
||||
"meetings": "Hẹn gặp",
|
||||
"calls": "Cuộc gọi",
|
||||
"tasks": "Nhiệm vụ",
|
||||
"emails": "Địa chỉ email"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Tên",
|
||||
"team": "Nhóm",
|
||||
"status": "Trạng thái",
|
||||
"assignToUser": "Chỉ định",
|
||||
"host": "Máy chủ",
|
||||
"username": "Tên đăng nhập",
|
||||
"password": "Mật khẩu",
|
||||
"port": "Cổng",
|
||||
"monitoredFolders": "Thư mục được theo dõi",
|
||||
"trashFolder": "Thùng rác",
|
||||
"ssl": "SSL",
|
||||
"createCase": "Tạo trường hợp",
|
||||
"reply": "Trả lời",
|
||||
"caseDistribution": "Trường hợp phân phối",
|
||||
"replyEmailTemplate": "Mẫu email trả lời",
|
||||
"replyFromAddress": "Địa chỉ email trả lời",
|
||||
"replyFromName": "Tên người gửi"
|
||||
},
|
||||
"links": {
|
||||
},
|
||||
"options": {
|
||||
"status": {
|
||||
"Active": "Đang hoạt động",
|
||||
"Inactive": "Chưa hoạt động"
|
||||
},
|
||||
"caseDistribution": {
|
||||
"Direct-Assignment": "Direct-Assignment",
|
||||
"Round-Robin": "Round-Robin",
|
||||
"Least-Busy": "Least-Busy"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
"Create InboundEmail": "Tạo email đến",
|
||||
"IMAP": "IMAP",
|
||||
"Actions": "Hoạt động",
|
||||
"Main": "Chính"
|
||||
},
|
||||
"messages": {
|
||||
"couldNotConnectToImap": "Không thể kết nối với máy chủ IMAP"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"labels": {
|
||||
"Converted To": "Đã chuyển đổi sang",
|
||||
"Create Lead": "Tạo chỉ dẫn",
|
||||
"Convert": "Chuyển đổi"
|
||||
},
|
||||
"fields": {
|
||||
"name": "Tên",
|
||||
"emailAddress": "Email",
|
||||
"title": "Tiêu đề",
|
||||
"website": "Website",
|
||||
"phoneNumber": "Điện thoại",
|
||||
"accountName": "Tên tài khoản",
|
||||
"doNotCall": "Không gọi",
|
||||
"address": "Địa chỉ",
|
||||
"status": "Trạng thái",
|
||||
"source": "Nguồn",
|
||||
"opportunityAmount": "Trị giá",
|
||||
"description": "Mô tả",
|
||||
"createdAccount": "Tài khoản",
|
||||
"createdContact": "Liên hệ",
|
||||
"createdOpportunity": "Cơ hội"
|
||||
},
|
||||
"links": {
|
||||
},
|
||||
"options": {
|
||||
"status": {
|
||||
"New": "Mới",
|
||||
"Assigned": "Chỉ định",
|
||||
"In Process": "Đang tiến hành",
|
||||
"Converted": "Đã chuyển đổi",
|
||||
"Recycled": "Thùng rác",
|
||||
"Dead": "Chết"
|
||||
},
|
||||
"source": {
|
||||
"Call": "Gọi",
|
||||
"Email": "Email",
|
||||
"Existing Customer": "Khách hàng hiện có",
|
||||
"Partner": "Đối tác",
|
||||
"Public Relations": "Khách hàng công khai",
|
||||
"Web Site": "Web Site",
|
||||
"Campaign": "Chiến dịch",
|
||||
"Other": "Khác"
|
||||
}
|
||||
},
|
||||
"presetFilters": {
|
||||
"active": "Đang hoạt động"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Tên",
|
||||
"parent": "Chủ",
|
||||
"status": "Trạng thái",
|
||||
"dateStart": "Ngày bắt đầu",
|
||||
"dateEnd": "Ngày kết thúc",
|
||||
"duration": "Thời gian",
|
||||
"description": "Mô tả",
|
||||
"users": "Người dùng",
|
||||
"contacts": "Sổ liên lạc",
|
||||
"leads": "Trưởng nhóm"
|
||||
},
|
||||
"links": {
|
||||
},
|
||||
"options": {
|
||||
"status": {
|
||||
"Planned": "Đã lên kế hoạch",
|
||||
"Held": "Đã được tổ chức",
|
||||
"Not Held": "Chưa được tổ chức"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
"Create Meeting": "Tạo buổi hẹn",
|
||||
"Set Held": "Tổ chức",
|
||||
"Set Not Held": "Không tổ chức",
|
||||
"Send Invitations": "Gửi giấy mời",
|
||||
"Saved as Held": "Lưu là đã tổ chức",
|
||||
"Saved as Not Held": "Lưu là chưa tổ chức"
|
||||
},
|
||||
"presetFilters": {
|
||||
"planned": "Đã lên kế hoạch",
|
||||
"held": "Đã được tổ chức",
|
||||
"todays": "Hôm nay"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Tên",
|
||||
"account": "Tài khoản",
|
||||
"stage": "Mức",
|
||||
"amount": "Tổng",
|
||||
"probability": "Xác suất, %",
|
||||
"leadSource": "Nguồn dẫn",
|
||||
"doNotCall": "Không gọi",
|
||||
"closeDate": "Ngày kết thúc",
|
||||
"contacts": "Sổ liên lạc",
|
||||
"description": "Mô tả"
|
||||
},
|
||||
"links": {
|
||||
"contacts": "Sổ liên lạc"
|
||||
},
|
||||
"options": {
|
||||
"stage": {
|
||||
"Prospecting": "Khảo sát",
|
||||
"Qualification": "Trình độ chuyên môn",
|
||||
"Needs Analysis": "Phân tích nhu cầu",
|
||||
"Value Proposition": "Đề xuất giá trị",
|
||||
"Id. Decision Makers": "Id. Người tạo quyết định",
|
||||
"Perception Analysis": "Phân tích khả năng",
|
||||
"Proposal/Price Quote": "Giá đặt ra",
|
||||
"Negotiation/Review": "Đàm phán / đánh giá",
|
||||
"Closed Won": "Thắng thầu",
|
||||
"Closed Lost": "Thua thầu"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
"Create Opportunity": "Tạo cơ hội"
|
||||
},
|
||||
"presetFilters": {
|
||||
"open": "Mở",
|
||||
"won": "Thắng"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Tên",
|
||||
"emailAddress": "Email",
|
||||
"title": "Tiêu đề",
|
||||
"website": "Website",
|
||||
"accountName": "Tên tài khoản",
|
||||
"phoneNumber": "Điện thoại",
|
||||
"doNotCall": "Không gọi",
|
||||
"address": "Địa chỉ",
|
||||
"description": "Mô tả"
|
||||
},
|
||||
"links": {
|
||||
},
|
||||
"labels": {
|
||||
"Create Target": "Tạo mục tiêu",
|
||||
"Convert to Lead": "Chuyển đổi thành chỉ dẫn"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Tên",
|
||||
"parent": "Chủ",
|
||||
"status": "Trạng thái",
|
||||
"dateStart": "Ngày bắt đầu",
|
||||
"dateEnd": "Hạn",
|
||||
"priority": "Ưu tiên",
|
||||
"description": "Mô tả",
|
||||
"isOverdue": "Đã quá hạn"
|
||||
},
|
||||
"links": {
|
||||
},
|
||||
"options": {
|
||||
"status": {
|
||||
"Not Started": "Chưa bắt đầu",
|
||||
"Started": "Đã bắt đầu",
|
||||
"Completed": "Hoàn thành",
|
||||
"Canceled": "Hủy"
|
||||
},
|
||||
"priority" : {
|
||||
"Low": "Thấp",
|
||||
"Normal": "Bình thường",
|
||||
"High": "Cao",
|
||||
"Urgent": "Gấp"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
"Create Task": "Tạo nhiệm vụ"
|
||||
},
|
||||
"presetFilters": {
|
||||
"active": "Đang hoạt động",
|
||||
"completed": "Hoàn thành",
|
||||
"todays": "Hôm nay",
|
||||
"overdue": "Quá hạn"
|
||||
}
|
||||
}
|
||||
@@ -42,6 +42,10 @@
|
||||
{"name":"caseDistribution"},
|
||||
{"name":"replyEmailTemplate"}
|
||||
],
|
||||
[
|
||||
false,
|
||||
{"name":"replyToAddress"}
|
||||
],
|
||||
[
|
||||
false,
|
||||
{"name":"replyFromAddress"}
|
||||
|
||||
@@ -1 +1,7 @@
|
||||
["status","source","opportunityAmount","teams","address"]
|
||||
[
|
||||
"status",
|
||||
"source",
|
||||
"opportunityAmountConverted",
|
||||
"teams",
|
||||
"address"
|
||||
]
|
||||
|
||||
@@ -1 +1,10 @@
|
||||
["teams","assignedUser","stage","probability","account","amount","closeDate","leadSource"]
|
||||
[
|
||||
"teams",
|
||||
"assignedUser",
|
||||
"stage",
|
||||
"probability",
|
||||
"account",
|
||||
"amountConverted",
|
||||
"closeDate",
|
||||
"leadSource"
|
||||
]
|
||||
|
||||
@@ -1 +1 @@
|
||||
["status","priority","dateStart","dateEnd"]
|
||||
["status","priority","dateStart","dateEnd"]
|
||||
|
||||
@@ -29,5 +29,6 @@
|
||||
],
|
||||
"layout":"listForAccount"
|
||||
}
|
||||
}
|
||||
},
|
||||
"boolFilters": ["onlyMy"]
|
||||
}
|
||||
|
||||
@@ -1,38 +1,81 @@
|
||||
{
|
||||
"controller": "Controllers.Record",
|
||||
"views":{
|
||||
"detail":"Crm:Call.Detail"
|
||||
},
|
||||
"sidePanels":{
|
||||
"detail":[
|
||||
{
|
||||
"name":"attendees",
|
||||
"label":"Attendees",
|
||||
"view":"Record.Panels.Side",
|
||||
"options":{
|
||||
"fields":[
|
||||
"users",
|
||||
"contacts",
|
||||
"leads"
|
||||
],
|
||||
"mode":"detail"
|
||||
}
|
||||
}
|
||||
],
|
||||
"edit":[
|
||||
{
|
||||
"name":"attendees",
|
||||
"label":"Attendees",
|
||||
"view":"Record.Panels.Side",
|
||||
"options":{
|
||||
"fields":[
|
||||
"users",
|
||||
"contacts",
|
||||
"leads"
|
||||
],
|
||||
"mode":"edit"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
"controller": "Controllers.Record",
|
||||
"views":{
|
||||
"detail":"Crm:Call.Detail"
|
||||
},
|
||||
"menu": {
|
||||
"detail": {
|
||||
"dropdown": [
|
||||
{
|
||||
"label": "Duplicate",
|
||||
"action": "duplicate",
|
||||
"acl": "edit"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"sidePanels":{
|
||||
"detail":[
|
||||
{
|
||||
"name":"attendees",
|
||||
"label":"Attendees",
|
||||
"view":"Record.Panels.Side",
|
||||
"options":{
|
||||
"fields":[
|
||||
"users",
|
||||
"contacts",
|
||||
"leads"
|
||||
],
|
||||
"mode":"detail"
|
||||
}
|
||||
}
|
||||
],
|
||||
"edit":[
|
||||
{
|
||||
"name":"attendees",
|
||||
"label":"Attendees",
|
||||
"view":"Record.Panels.Side",
|
||||
"options":{
|
||||
"fields":[
|
||||
"users",
|
||||
"contacts",
|
||||
"leads"
|
||||
],
|
||||
"mode":"edit"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"presetFilters": [
|
||||
{
|
||||
"name":"planned",
|
||||
"style": "primary",
|
||||
"data": {
|
||||
"status": {
|
||||
"type": "in",
|
||||
"value": ["Planned"]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name":"held",
|
||||
"style": "success",
|
||||
"data": {
|
||||
"status": {
|
||||
"type": "in",
|
||||
"value": ["Held"]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name":"todays",
|
||||
"data": {
|
||||
"dateStart": {
|
||||
"type": "today",
|
||||
"dateTime": true
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"boolFilters": ["onlyMy"]
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
{
|
||||
"name":"activities",
|
||||
"label":"Activities",
|
||||
"view":"Crm:Record.Panels.Activities"
|
||||
"view":"Crm:Case.Record.Panels.Activities"
|
||||
},
|
||||
{
|
||||
"name":"history",
|
||||
@@ -22,5 +22,28 @@
|
||||
"view":"Crm:Record.Panels.Tasks"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"presetFilters": [
|
||||
{
|
||||
"name":"open",
|
||||
"style": "primary",
|
||||
"data": {
|
||||
"status": {
|
||||
"type": "in",
|
||||
"value": ["New", "Assigned", "Pending"]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name":"closed",
|
||||
"style": "success",
|
||||
"data": {
|
||||
"status": {
|
||||
"type": "in",
|
||||
"value": ["Closed"]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"boolFilters": ["onlyMy"]
|
||||
}
|
||||
|
||||
@@ -21,5 +21,6 @@
|
||||
"view":"Crm:Record.Panels.Tasks"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"boolFilters": ["onlyMy"]
|
||||
}
|
||||
|
||||
@@ -1,6 +1,46 @@
|
||||
{
|
||||
"recordViews":{
|
||||
"detail":"Crm:InboundEmail.Record.Detail",
|
||||
"edit":"Crm:InboundEmail.Record.Edit"
|
||||
}
|
||||
"recordViews":{
|
||||
"detail":"Crm:InboundEmail.Record.Detail",
|
||||
"edit":"Crm:InboundEmail.Record.Edit"
|
||||
},
|
||||
"formDependency": {
|
||||
"createCase": {
|
||||
"map": {
|
||||
"true" : [
|
||||
{
|
||||
"action": "show",
|
||||
"fields": ["caseDistribution"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"default": [
|
||||
{
|
||||
"action": "hide",
|
||||
"fields": ["caseDistribution"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"reply": {
|
||||
"map": {
|
||||
"true" : [
|
||||
{
|
||||
"action": "show",
|
||||
"fields": ["replyEmailTemplate", "replyFromAddress", "replyFromName", "replyToAddress"]
|
||||
}, {
|
||||
"action": "setRequired",
|
||||
"fields": ["replyEmailTemplate"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"default": [
|
||||
{
|
||||
"action": "hide",
|
||||
"fields": ["replyEmailTemplate", "replyFromAddress", "replyFromName", "replyToAddress"]
|
||||
}, {
|
||||
"action": "setNotRequired",
|
||||
"fields": ["replyEmailTemplate"]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,5 +24,18 @@
|
||||
"view":"Crm:Record.Panels.Tasks"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"presetFilters": [
|
||||
{
|
||||
"name":"active",
|
||||
"style": "primary",
|
||||
"data": {
|
||||
"status": {
|
||||
"type": "in",
|
||||
"value": ["New", "Assigned", "In Process"]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"boolFilters": ["onlyMy"]
|
||||
}
|
||||
|
||||
@@ -1,38 +1,81 @@
|
||||
{
|
||||
"controller": "Controllers.Record",
|
||||
"views":{
|
||||
"detail":"Crm:Meeting.Detail"
|
||||
},
|
||||
"sidePanels":{
|
||||
"detail":[
|
||||
{
|
||||
"name":"attendees",
|
||||
"label":"Attendees",
|
||||
"view":"Record.Panels.Side",
|
||||
"options":{
|
||||
"fields":[
|
||||
"users",
|
||||
"contacts",
|
||||
"leads"
|
||||
],
|
||||
"mode":"detail"
|
||||
}
|
||||
}
|
||||
],
|
||||
"edit":[
|
||||
{
|
||||
"name":"attendees",
|
||||
"label":"Attendees",
|
||||
"view":"Record.Panels.Side",
|
||||
"options":{
|
||||
"fields":[
|
||||
"users",
|
||||
"contacts",
|
||||
"leads"
|
||||
],
|
||||
"mode":"edit"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
"controller": "Controllers.Record",
|
||||
"views":{
|
||||
"detail":"Crm:Meeting.Detail"
|
||||
},
|
||||
"menu": {
|
||||
"detail": {
|
||||
"dropdown": [
|
||||
{
|
||||
"label": "Duplicate",
|
||||
"action": "duplicate",
|
||||
"acl": "edit"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"sidePanels":{
|
||||
"detail":[
|
||||
{
|
||||
"name":"attendees",
|
||||
"label":"Attendees",
|
||||
"view":"Record.Panels.Side",
|
||||
"options":{
|
||||
"fields":[
|
||||
"users",
|
||||
"contacts",
|
||||
"leads"
|
||||
],
|
||||
"mode":"detail"
|
||||
}
|
||||
}
|
||||
],
|
||||
"edit":[
|
||||
{
|
||||
"name":"attendees",
|
||||
"label":"Attendees",
|
||||
"view":"Record.Panels.Side",
|
||||
"options":{
|
||||
"fields":[
|
||||
"users",
|
||||
"contacts",
|
||||
"leads"
|
||||
],
|
||||
"mode":"edit"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"presetFilters": [
|
||||
{
|
||||
"name":"planned",
|
||||
"style": "primary",
|
||||
"data": {
|
||||
"status": {
|
||||
"type": "in",
|
||||
"value": ["Planned"]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name":"held",
|
||||
"style": "success",
|
||||
"data": {
|
||||
"status": {
|
||||
"type": "in",
|
||||
"value": ["Held"]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name":"todays",
|
||||
"data": {
|
||||
"dateStart": {
|
||||
"type": "today",
|
||||
"dateTime": true
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"boolFilters": ["onlyMy"]
|
||||
}
|
||||
|
||||
@@ -21,5 +21,28 @@
|
||||
"view":"Crm:Record.Panels.Tasks"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"presetFilters": [
|
||||
{
|
||||
"name":"open",
|
||||
"style": "primary",
|
||||
"data": {
|
||||
"stage": {
|
||||
"type": "in",
|
||||
"value": ["Prospecting", "Qualification", "Needs Analysis", "Value Proposition", "Id. Decision Makers", "Perception Analysis","Proposal/Price Quote","Negotiation/Review"]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name":"won",
|
||||
"style": "success",
|
||||
"data": {
|
||||
"stage": {
|
||||
"type": "in",
|
||||
"value": ["Closed Won"]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"boolFilters": ["onlyMy"]
|
||||
}
|
||||
|
||||
@@ -13,5 +13,6 @@
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"boolFilters": ["onlyMy"]
|
||||
}
|
||||
|
||||
@@ -1,3 +1,49 @@
|
||||
{
|
||||
"controller": "Controllers.Record"
|
||||
"controller": "Controllers.Record",
|
||||
"presetFilters": [
|
||||
{
|
||||
"name":"active",
|
||||
"style": "primary",
|
||||
"data": {
|
||||
"status": {
|
||||
"type": "in",
|
||||
"value": ["Not Started", "Started"]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name":"completed",
|
||||
"style": "success",
|
||||
"data": {
|
||||
"status": {
|
||||
"type": "in",
|
||||
"value": ["Completed"]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name":"todays",
|
||||
"data": {
|
||||
"dateEnd": {
|
||||
"type": "today",
|
||||
"dateTime": true
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name":"overdue",
|
||||
"style": "danger",
|
||||
"data": {
|
||||
"dateEnd": {
|
||||
"type": "past",
|
||||
"dateTime": true
|
||||
},
|
||||
"status": {
|
||||
"type": "in",
|
||||
"value": ["Not Started", "Started"]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"boolFilters": ["onlyMy"]
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"module":"Crm"}
|
||||
{"view":"Crm:Dashlets.Calendar"}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
{"view":"Crm:Dashlets.Calls"}
|
||||
@@ -1 +1 @@
|
||||
{"module":"Crm"}
|
||||
{"view":"Crm:Dashlets.Cases"}
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"module":"Crm"}
|
||||
{"view":"Crm:Dashlets.Leads"}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
{"view":"Crm:Dashlets.Meetings"}
|
||||
@@ -1 +1 @@
|
||||
{"module":"Crm"}
|
||||
{"view":"Crm:Dashlets.Opportunities"}
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
{"module":"Crm"}
|
||||
{"view":"Crm:Dashlets.OpportunitiesByLeadSource"}
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"module":"Crm"}
|
||||
{"view":"Crm:Dashlets.OpportunitiesByStage"}
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"module":"Crm"}
|
||||
{"view":"Crm:Dashlets.SalesByMonth"}
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"module":"Crm"}
|
||||
{"view":"Crm:Dashlets.SalesPipeline"}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user