mirror of
https://github.com/espocrm/espocrm.git
synced 2026-03-05 12:47:01 +00:00
Compare commits
105 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0a2c79ba81 | ||
|
|
5360ba0147 | ||
|
|
6620254d00 | ||
|
|
f6eb0bcce8 | ||
|
|
c1116ff5dc | ||
|
|
7dcdfcd231 | ||
|
|
0eadb9af69 | ||
|
|
3c3518b857 | ||
|
|
f3ab0a734c | ||
|
|
33adc67dee | ||
|
|
18e475e1b6 | ||
|
|
438c0f7edd | ||
|
|
3159c9d288 | ||
|
|
fe0f93784b | ||
|
|
2d237eae29 | ||
|
|
747aa2d882 | ||
|
|
46a7119ce1 | ||
|
|
c18342694f | ||
|
|
bb47b70f31 | ||
|
|
07767b2dae | ||
|
|
88037c8291 | ||
|
|
ee03c686ca | ||
|
|
78140f7d5e | ||
|
|
549acfd032 | ||
|
|
e4dab33792 | ||
|
|
287f95a8ac | ||
|
|
4951f8464e | ||
|
|
8ed9b9ebd2 | ||
|
|
96ed9612d4 | ||
|
|
1fd77a4c13 | ||
|
|
2390ac10a8 | ||
|
|
03572ecaad | ||
|
|
c1ac692304 | ||
|
|
f371090bde | ||
|
|
e28341f154 | ||
|
|
870f871ceb | ||
|
|
c18d892a4e | ||
|
|
c8bfd1c6dd | ||
|
|
c582860d5c | ||
|
|
1796db30fa | ||
|
|
25aa0ec564 | ||
|
|
f3dc904c65 | ||
|
|
343d33e741 | ||
|
|
276480dcfa | ||
|
|
b00b725af5 | ||
|
|
ab71ced531 | ||
|
|
ba7988a842 | ||
|
|
e1355acda1 | ||
|
|
1853f4f113 | ||
|
|
da677cfae8 | ||
|
|
272bccc2fd | ||
|
|
5372155773 | ||
|
|
e1579295da | ||
|
|
cc708e03d1 | ||
|
|
34e91958d6 | ||
|
|
928e4c2fb5 | ||
|
|
cf86fcda85 | ||
|
|
db3b36a639 | ||
|
|
a4a731437e | ||
|
|
51f4c7fa09 | ||
|
|
cbce4fc327 | ||
|
|
4e953f6fa8 | ||
|
|
0ed0420a4b | ||
|
|
16961795af | ||
|
|
c52c7fed59 | ||
|
|
95c00fc49d | ||
|
|
9f8606dd06 | ||
|
|
b33dc9baae | ||
|
|
8cb95f1b0e | ||
|
|
86cd1ab864 | ||
|
|
df842f3e3e | ||
|
|
572455ecf6 | ||
|
|
7692f9e3ad | ||
|
|
be0c1d8ab1 | ||
|
|
4a6c3d9e18 | ||
|
|
e0fdbd90fd | ||
|
|
18a3f2658a | ||
|
|
80ee06ec1d | ||
|
|
f16adeed99 | ||
|
|
9ca39f3559 | ||
|
|
19285372d6 | ||
|
|
61df6bec45 | ||
|
|
8904d4ddaf | ||
|
|
ca5fba97df | ||
|
|
fa755efefb | ||
|
|
d6085f4985 | ||
|
|
4c01e9329d | ||
|
|
9813eeb5bc | ||
|
|
09d571a639 | ||
|
|
fffd44316e | ||
|
|
a704830b86 | ||
|
|
7910f71428 | ||
|
|
52dcc51f4f | ||
|
|
f870ded9e0 | ||
|
|
224c72c875 | ||
|
|
ed50802073 | ||
|
|
1f5036eb5f | ||
|
|
701a60a07f | ||
|
|
c760f7364c | ||
|
|
4c28409a36 | ||
|
|
e932681166 | ||
|
|
a8209488ee | ||
|
|
d48642ca81 | ||
|
|
6561c4b6c2 | ||
|
|
4f5f84c8f7 |
@@ -1,3 +1,7 @@
|
||||
<ifModule mod_headers.c>
|
||||
Header always set Access-Control-Allow-Methods "POST, GET, PUT, PATCH, DELETE"
|
||||
</ifModule>
|
||||
|
||||
DirectoryIndex index.php index.html
|
||||
|
||||
# PROTECTED DIRECTORIES
|
||||
|
||||
@@ -24,5 +24,11 @@ namespace Espo\Controllers;
|
||||
|
||||
class Email extends \Espo\Core\Controllers\Record
|
||||
{
|
||||
|
||||
public function actionGetCopiedAttachments($params, $data, $request)
|
||||
{
|
||||
$id = $request->get('id');
|
||||
|
||||
return $this->getRecordService()->getCopiedAttachments($id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
40
application/Espo/Controllers/EmailAccount.php
Normal file
40
application/Espo/Controllers/EmailAccount.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?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\Controllers;
|
||||
|
||||
class EmailAccount extends \Espo\Core\Controllers\Record
|
||||
{
|
||||
public function actionGetFolders($params, $data, $request)
|
||||
{
|
||||
return $this->getRecordService()->getFolders(array(
|
||||
'host' => $request->get('host'),
|
||||
'port' => $request->get('port'),
|
||||
'ssl' => $request->get('ssl'),
|
||||
'username' => $request->get('username'),
|
||||
'password' => $request->get('password'),
|
||||
'id' => $request->get('id')
|
||||
));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,5 +24,14 @@ namespace Espo\Controllers;
|
||||
|
||||
class EmailAddress extends \Espo\Core\Controllers\Record
|
||||
{
|
||||
|
||||
public function actionSearchInAddressBook($params, $data, $request)
|
||||
{
|
||||
$q = $request->get('q');
|
||||
$limit = intval($request->get('limit'));
|
||||
if (empty($limit) || $limit > 30) {
|
||||
$limit = 5;
|
||||
}
|
||||
return $this->getRecordService()->searchInAddressBook($q, $limit);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
104
application/Espo/Controllers/ExternalAccount.php
Normal file
104
application/Espo/Controllers/ExternalAccount.php
Normal file
@@ -0,0 +1,104 @@
|
||||
<?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\Controllers;
|
||||
|
||||
use \Espo\Core\Exceptions\Error;
|
||||
use \Espo\Core\Exceptions\Forbidden;
|
||||
|
||||
class ExternalAccount extends \Espo\Core\Controllers\Record
|
||||
{
|
||||
public static $defaultAction = 'list';
|
||||
|
||||
public function actionList($params, $data, $request)
|
||||
{
|
||||
$integrations = $this->getEntityManager()->getRepository('Integration')->find();
|
||||
$arr = array();
|
||||
foreach ($integrations as $entity) {
|
||||
if ($entity->get('enabled') && $this->getMetadata()->get('integrations.' . $entity->id .'.allowUserAccounts')) {
|
||||
$arr[] = array(
|
||||
'id' => $entity->id
|
||||
);
|
||||
}
|
||||
}
|
||||
return array(
|
||||
'list' => $arr
|
||||
);
|
||||
}
|
||||
|
||||
public function actionGetOAuthCredentials($params, $data, $request)
|
||||
{
|
||||
$id = $request->get('id');
|
||||
list($integration, $userId) = explode('__', $id);
|
||||
|
||||
if (!$this->getUser()->isAdmin()) {
|
||||
if ($this->getUser()->id != $userId) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
}
|
||||
|
||||
$entity = $this->getEntityManager()->getEntity('Integration', $integration);
|
||||
if ($entity) {
|
||||
return array(
|
||||
'clientId' => $entity->get('clientId'),
|
||||
'redirectUri' => $this->getConfig()->get('siteUrl') . '/oauthcallback'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function actionRead($params, $data, $request)
|
||||
{
|
||||
list($integration, $userId) = explode('__', $params['id']);
|
||||
|
||||
if (!$this->getUser()->isAdmin()) {
|
||||
if ($this->getUser()->id != $userId) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
}
|
||||
|
||||
$entity = $this->getEntityManager()->getEntity('ExternalAccount', $params['id']);
|
||||
return $entity->toArray();
|
||||
}
|
||||
|
||||
public function actionUpdate($params, $data)
|
||||
{
|
||||
return $this->actionPatch($params, $data);
|
||||
}
|
||||
|
||||
public function actionPatch($params, $data)
|
||||
{
|
||||
list($integration, $userId) = explode('__', $params['id']);
|
||||
|
||||
if (!$this->getUser()->isAdmin()) {
|
||||
if ($this->getUser()->id != $userId) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
}
|
||||
|
||||
$entity = $this->getEntityManager()->getEntity('ExternalAccount', $params['id']);
|
||||
$entity->set($data);
|
||||
$this->getEntityManager()->saveEntity($entity);
|
||||
|
||||
return $entity->toArray();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ class GlobalSearch extends \Espo\Core\Controllers\Base
|
||||
$offset = $request->get('offset');
|
||||
$maxSize = $request->get('maxSize');
|
||||
|
||||
return $this->getService('GlobalSearch')->find($query, $offset);
|
||||
return $this->getService('GlobalSearch')->find($query, $offset, $maxSize);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +44,8 @@ class Import extends \Espo\Core\Controllers\Base
|
||||
$contents = $data;
|
||||
|
||||
$attachment = $this->getEntityManager()->getEntity('Attachment');
|
||||
$attachment->set('type', 'text/csv');
|
||||
$attachment->set('type', 'text/csv');
|
||||
$attachment->set('role', 'Import File');
|
||||
$this->getEntityManager()->saveEntity($attachment);
|
||||
|
||||
$this->getFileManager()->putContents('data/upload/' . $attachment->id, $contents);
|
||||
|
||||
61
application/Espo/Controllers/Integration.php
Normal file
61
application/Espo/Controllers/Integration.php
Normal file
@@ -0,0 +1,61 @@
|
||||
<?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\Controllers;
|
||||
|
||||
use \Espo\Core\Exceptions\Error;
|
||||
|
||||
class Integration extends \Espo\Core\Controllers\Record
|
||||
{
|
||||
protected function checkControllerAccess()
|
||||
{
|
||||
if (!$this->getUser()->isAdmin()) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
}
|
||||
|
||||
public function actionIndex($params, $data, $request)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function actionRead($params, $data, $request)
|
||||
{
|
||||
$entity = $this->getEntityManager()->getEntity('Integration', $params['id']);
|
||||
return $entity->toArray();
|
||||
}
|
||||
|
||||
public function actionUpdate($params, $data)
|
||||
{
|
||||
return $this->actionPatch($params, $data);
|
||||
}
|
||||
|
||||
public function actionPatch($params, $data)
|
||||
{
|
||||
$entity = $this->getEntityManager()->getEntity('Integration', $params['id']);
|
||||
$entity->set($data);
|
||||
$this->getEntityManager()->saveEntity($entity);
|
||||
|
||||
return $entity->toArray();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +68,8 @@ class Preferences extends \Espo\Core\Controllers\Base
|
||||
$entity->set('smtpEmailAddress', $user->get('emailAddress'));
|
||||
$entity->set('name', $user->get('name'));
|
||||
|
||||
$entity->clear('smtpPassword');
|
||||
|
||||
return $entity->toArray();
|
||||
}
|
||||
throw new Error();
|
||||
@@ -83,6 +85,9 @@ class Preferences extends \Espo\Core\Controllers\Base
|
||||
|
||||
$entity->set('smtpEmailAddress', $user->get('emailAddress'));
|
||||
$entity->set('name', $user->get('name'));
|
||||
|
||||
$entity->clear('smtpPassword');
|
||||
|
||||
if ($entity) {
|
||||
return $entity->toArray();
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ class User extends \Espo\Core\Controllers\Record
|
||||
throw new NotFound();
|
||||
}
|
||||
|
||||
$acl = new \Espo\Core\Acl($user);
|
||||
$acl = new \Espo\Core\Acl($user, $this->getConfig(), $this->getContainer()->get('fileManager'), $this->getMetadata());
|
||||
|
||||
return $acl->toArray();
|
||||
}
|
||||
|
||||
@@ -34,11 +34,15 @@ class Acl
|
||||
|
||||
private $levelList = array('all', 'team', 'own', 'no');
|
||||
|
||||
private $fileManager;
|
||||
protected $fileManager;
|
||||
|
||||
protected $metadata;
|
||||
|
||||
public function __construct(\Espo\Entities\User $user, $config = null, $fileManager = null)
|
||||
public function __construct(\Espo\Entities\User $user, $config = null, $fileManager = null, $metadata = null)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->user = $user;
|
||||
|
||||
$this->metadata = $metadata;
|
||||
|
||||
if (!$this->user->isFetched()) {
|
||||
throw new Error();
|
||||
@@ -197,32 +201,11 @@ class Acl
|
||||
|
||||
private function initSolid()
|
||||
{
|
||||
$this->data['User'] = array(
|
||||
'read' => 'all',
|
||||
'edit' => 'no',
|
||||
'delete' => 'no',
|
||||
);
|
||||
$this->data['Team'] = array(
|
||||
'read' => 'all',
|
||||
'edit' => 'no',
|
||||
'delete' => 'no',
|
||||
);
|
||||
$this->data['Role'] = false;
|
||||
$this->data['Note'] = array(
|
||||
'read' => 'own',
|
||||
'edit' => 'own',
|
||||
'delete' => 'own',
|
||||
);
|
||||
$this->data['EmailAddress'] = array(
|
||||
'read' => 'no',
|
||||
'edit' => 'no',
|
||||
'delete' => 'no',
|
||||
);
|
||||
$this->data['Note'] = array(
|
||||
'read' => 'all',
|
||||
'edit' => 'own',
|
||||
'delete' => 'own',
|
||||
);
|
||||
$data = $this->metadata->get('app.acl.solid', array());
|
||||
|
||||
foreach ($data as $entityName => $item) {
|
||||
$this->data[$entityName] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
private function merge($tables)
|
||||
|
||||
@@ -51,7 +51,6 @@ class Container
|
||||
$obj = $this->$loadMethod();
|
||||
$this->data[$name] = $obj;
|
||||
} else {
|
||||
//external loader class \Espo\Core\Loaders\<className> or \Espo\Custom\Core\Loaders\<className> with load() method
|
||||
$className = '\Espo\Custom\Core\Loaders\\'.ucfirst($name);
|
||||
if (!class_exists($className)) {
|
||||
$className = '\Espo\Core\Loaders\\'.ucfirst($name);
|
||||
@@ -63,13 +62,18 @@ class Container
|
||||
}
|
||||
}
|
||||
|
||||
// TODO throw an exception
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function getServiceClassName($name, $default)
|
||||
{
|
||||
$metadata = $this->get('metadata');
|
||||
$className = $metadata->get('app.serviceContainer.classNames.' . $name, $default);
|
||||
return $className;
|
||||
}
|
||||
|
||||
private function loadSlim()
|
||||
{
|
||||
//return new \Slim\Slim();
|
||||
return new \Espo\Core\Utils\Api\Slim();
|
||||
}
|
||||
|
||||
@@ -108,7 +112,8 @@ class Container
|
||||
|
||||
private function loadMailSender()
|
||||
{
|
||||
return new \Espo\Core\Mail\Sender(
|
||||
$className = $this->getServiceClassName('mailSernder', '\\Espo\\Core\\Mail\\Sender');
|
||||
return new $className(
|
||||
$this->get('config')
|
||||
);
|
||||
}
|
||||
@@ -157,10 +162,12 @@ class Container
|
||||
|
||||
private function loadAcl()
|
||||
{
|
||||
return new \Espo\Core\Acl(
|
||||
$className = $this->getServiceClassName('acl', '\\Espo\\Core\\Acl');
|
||||
return new $className(
|
||||
$this->get('user'),
|
||||
$this->get('config'),
|
||||
$this->get('fileManager')
|
||||
$this->get('fileManager'),
|
||||
$this->get('metadata')
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -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\Cron;
|
||||
|
||||
@@ -46,22 +46,22 @@ class Service
|
||||
$serviceName = $job['service_name'];
|
||||
|
||||
if (!$this->getServiceFactory()->checkExists($serviceName)) {
|
||||
throw new NotFound();
|
||||
throw new NotFound();
|
||||
}
|
||||
|
||||
$service = $this->getServiceFactory()->create($serviceName);
|
||||
$serviceMethod = $job['method'];
|
||||
$service = $this->getServiceFactory()->create($serviceName);
|
||||
$serviceMethod = $job['method'];
|
||||
|
||||
if (!method_exists($service, $serviceMethod)) {
|
||||
throw new NotFound();
|
||||
}
|
||||
throw new NotFound();
|
||||
}
|
||||
|
||||
$data = $job['data'];
|
||||
if (Json::isJSON($data)) {
|
||||
$data = Json::decode($data, true);
|
||||
}
|
||||
|
||||
$service->$serviceMethod($data);
|
||||
$service->$serviceMethod($data);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -34,6 +34,11 @@ class CronManager
|
||||
private $jobService;
|
||||
private $scheduledJobService;
|
||||
|
||||
const PENDING = 'Pending';
|
||||
const RUNNING = 'Running';
|
||||
const SUCCESS = 'Success';
|
||||
const FAILED = 'Failed';
|
||||
|
||||
protected $lastRunTime = 'data/cache/application/cronLastRunTime.php';
|
||||
|
||||
|
||||
@@ -128,13 +133,12 @@ class CronManager
|
||||
//Check scheduled jobs and create related jobs
|
||||
$this->createJobsFromScheduledJobs();
|
||||
|
||||
|
||||
$pendingJobs = $this->getJobService()->getPendingJobs();
|
||||
|
||||
foreach ($pendingJobs as $job) {
|
||||
|
||||
$this->getJobService()->updateEntity($job['id'], array(
|
||||
'status' => 'Running',
|
||||
'status' => self::RUNNING,
|
||||
));
|
||||
|
||||
$isSuccess = true;
|
||||
@@ -150,7 +154,7 @@ class CronManager
|
||||
$GLOBALS['log']->error('Failed job running, job ['.$job['id'].']. Error Details: '.$e->getMessage());
|
||||
}
|
||||
|
||||
$status = $isSuccess ? 'Success' : 'Failed';
|
||||
$status = $isSuccess ? self::SUCCESS : self::FAILED;
|
||||
|
||||
$this->getJobService()->updateEntity($job['id'], array(
|
||||
'status' => $status,
|
||||
@@ -180,7 +184,6 @@ class CronManager
|
||||
$cronExpression = \Cron\CronExpression::factory($scheduling);
|
||||
|
||||
try {
|
||||
//$nextDate = $cronExpression->getNextRunDate()->format('Y-m-d H:i:s');
|
||||
$prevDate = $cronExpression->getPreviousRunDate()->format('Y-m-d H:i:s');
|
||||
} catch (\Exception $e) {
|
||||
$GLOBALS['log']->error('ScheduledJob ['.$scheduledJob['id'].']: CronExpression - Impossible CRON expression ['.$scheduling.']');
|
||||
@@ -197,7 +200,7 @@ class CronManager
|
||||
//create a job
|
||||
$data = array(
|
||||
'name' => $scheduledJob['name'],
|
||||
'status' => 'Pending',
|
||||
'status' => self::PENDING,
|
||||
'scheduledJobId' => $scheduledJob['id'],
|
||||
'executeTime' => $prevDate,
|
||||
'method' => $scheduledJob['job'],
|
||||
|
||||
@@ -121,8 +121,9 @@ class DataManager
|
||||
*/
|
||||
public function updateCacheTimestamp()
|
||||
{
|
||||
return $this->getContainer()->get('config')->updateCacheTimestamp();
|
||||
$this->getContainer()->get('config')->updateCacheTimestamp();
|
||||
$this->getContainer()->get('config')->save();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -25,7 +25,7 @@ namespace Espo\Core\Loaders;
|
||||
use Doctrine\ORM\Tools\Setup,
|
||||
Espo\Core\Doctrine\ORM\Mapping\Driver\EspoPHPDriver;
|
||||
|
||||
class EntityManager
|
||||
class EntityManager implements Loader
|
||||
{
|
||||
private $container;
|
||||
|
||||
|
||||
31
application/Espo/Core/Loaders/Loader.php
Normal file
31
application/Espo/Core/Loaders/Loader.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?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\Core\Loaders;
|
||||
|
||||
|
||||
interface Loader
|
||||
{
|
||||
public function load();
|
||||
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace Espo\Core\Loaders;
|
||||
use Espo\Core\Utils,
|
||||
Espo\Core\Utils\Log\Monolog\Handler;
|
||||
|
||||
class Log
|
||||
class Log implements Loader
|
||||
{
|
||||
private $container;
|
||||
|
||||
|
||||
244
application/Espo/Core/Mail/Importer.php
Normal file
244
application/Espo/Core/Mail/Importer.php
Normal file
@@ -0,0 +1,244 @@
|
||||
<?php
|
||||
|
||||
namespace Espo\Core\Mail;
|
||||
|
||||
use \Zend\Mime\Mime as Mime;
|
||||
|
||||
class Importer
|
||||
{
|
||||
private $entityManager;
|
||||
|
||||
private $fileManager;
|
||||
|
||||
public function __construct($entityManager, $fileManager)
|
||||
{
|
||||
$this->entityManager = $entityManager;
|
||||
$this->fileManager = $fileManager;
|
||||
}
|
||||
|
||||
protected function getEntityManager()
|
||||
{
|
||||
return $this->entityManager;
|
||||
}
|
||||
|
||||
protected function getFileManager()
|
||||
{
|
||||
return $this->fileManager;
|
||||
}
|
||||
|
||||
public function importMessage($message, $userId, $teamsIds = array())
|
||||
{
|
||||
try {
|
||||
$email = $this->getEntityManager()->getEntity('Email');
|
||||
|
||||
$email->set('isHtml', false);
|
||||
$email->set('name', $message->subject);
|
||||
$email->set('status', 'Archived');
|
||||
$email->set('attachmentsIds', array());
|
||||
$email->set('assignedUserId', $userId);
|
||||
$email->set('teamsIds', $teamsIds);
|
||||
|
||||
$fromArr = $this->getAddressListFromMessage($message, 'from');
|
||||
if (isset($message->from)) {
|
||||
$email->set('fromName', $message->from);
|
||||
}
|
||||
$email->set('from', $fromArr[0]);
|
||||
$email->set('to', implode(';', $this->getAddressListFromMessage($message, 'to')));
|
||||
$email->set('cc', implode(';', $this->getAddressListFromMessage($message, 'cc')));
|
||||
|
||||
if (isset($message->messageId) && !empty($message->messageId)) {
|
||||
$email->set('messageId', $message->messageId);
|
||||
if (isset($message->deliveredTo)) {
|
||||
$email->set('messageIdInternal', $message->messageId . '-' . $message->deliveredTo);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->checkIsDuplicate($email)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($message->date)) {
|
||||
$dt = new \DateTime($message->date);
|
||||
if ($dt) {
|
||||
$dateSent = $dt->setTimezone(new \DateTimeZone('UTC'))->format('Y-m-d H:i:s');
|
||||
$email->set('dateSent', $dateSent);
|
||||
}
|
||||
}
|
||||
if (isset($message->deliveryDate)) {
|
||||
$dt = new \DateTime($message->deliveryDate);
|
||||
if ($dt) {
|
||||
$deliveryDate = $dt->setTimezone(new \DateTimeZone('UTC'))->format('Y-m-d H:i:s');
|
||||
$email->set('deliveryDate', $deliveryDate);
|
||||
}
|
||||
}
|
||||
|
||||
$inlineIds = array();
|
||||
|
||||
if ($message->isMultipart()) {
|
||||
foreach (new \RecursiveIteratorIterator($message) as $part) {
|
||||
$this->importPartDataToEmail($email, $part, $inlineIds);
|
||||
}
|
||||
} else {
|
||||
$this->importPartDataToEmail($email, $message, $inlineIds);
|
||||
}
|
||||
|
||||
$body = $email->get('body');
|
||||
if (!empty($body)) {
|
||||
foreach ($inlineIds as $cid => $attachmentId) {
|
||||
$body = str_replace('cid:' . $cid, '?entryPoint=attachment&id=' . $attachmentId, $body);
|
||||
}
|
||||
$email->set('body', $body);
|
||||
}
|
||||
|
||||
$this->getEntityManager()->saveEntity($email);
|
||||
|
||||
return $email;
|
||||
|
||||
} catch (\Exception $e) {}
|
||||
}
|
||||
|
||||
protected function checkIsDuplicate($email)
|
||||
{
|
||||
if ($email->get('messageIdInternal')) {
|
||||
$duplicate = $this->getEntityManager()->getRepository('Email')->where(array(
|
||||
'messageIdInternal' => $email->get('messageIdInternal')
|
||||
))->findOne();
|
||||
if ($duplicate) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function getAddressListFromMessage($message, $type)
|
||||
{
|
||||
$addressList = array();
|
||||
if (isset($message->$type)) {
|
||||
|
||||
$list = $message->getHeader($type)->getAddressList();
|
||||
foreach ($list as $address) {
|
||||
$addressList[] = $address->getEmail();
|
||||
}
|
||||
}
|
||||
return $addressList;
|
||||
}
|
||||
|
||||
protected function importPartDataToEmail(\Espo\Entities\Email $email, $part, &$inlineIds = array())
|
||||
{
|
||||
try {
|
||||
$type = strtok($part->contentType, ';');
|
||||
$encoding = null;
|
||||
|
||||
switch ($type) {
|
||||
case 'text/plain':
|
||||
$content = $this->getContentFromPart($part);
|
||||
if (!$email->get('body')) {
|
||||
$email->set('body', $content);
|
||||
}
|
||||
$email->set('bodyPlain', $content);
|
||||
break;
|
||||
case 'text/html':
|
||||
$content = $this->getContentFromPart($part);
|
||||
$email->set('body', $content);
|
||||
$email->set('isHtml', true);
|
||||
break;
|
||||
default:
|
||||
$content = $part->getContent();
|
||||
$disposition = null;
|
||||
|
||||
$fileName = null;
|
||||
$contentId = null;
|
||||
|
||||
if (isset($part->ContentDisposition)) {
|
||||
if (strpos($part->ContentDisposition, 'attachment') === 0) {
|
||||
if (preg_match('/filename="?([^"]+)"?/i', $part->ContentDisposition, $m)) {
|
||||
$fileName = $m[1];
|
||||
$disposition = 'attachment';
|
||||
}
|
||||
} else if (strpos($part->ContentDisposition, 'inline') === 0) {
|
||||
$contentId = trim($part->contentID, '<>');
|
||||
$fileName = $contentId;
|
||||
$disposition = 'inline';
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($part->contentTransferEncoding)) {
|
||||
$encoding = strtolower($part->getHeader('Content-Transfer-Encoding')->getTransferEncoding());
|
||||
}
|
||||
|
||||
$attachment = $this->getEntityManager()->getEntity('Attachment');
|
||||
$attachment->set('name', $fileName);
|
||||
$attachment->set('type', $type);
|
||||
|
||||
if ($disposition == 'inline') {
|
||||
$attachment->set('role', 'Inline Attachment');
|
||||
} else {
|
||||
$attachment->set('role', 'Attachment');
|
||||
}
|
||||
|
||||
if ($encoding == 'base64') {
|
||||
$content = base64_decode($content);
|
||||
}
|
||||
|
||||
$attachment->set('size', strlen($content));
|
||||
|
||||
$this->getEntityManager()->saveEntity($attachment);
|
||||
|
||||
$path = 'data/upload/' . $attachment->id;
|
||||
$this->getFileManager()->putContents($path, $content);
|
||||
|
||||
if ($disposition == 'attachment') {
|
||||
$attachmentsIds = $email->get('attachmentsIds');
|
||||
$attachmentsIds[] = $attachment->id;
|
||||
$email->set('attachmentsIds', $attachmentsIds);
|
||||
} else if ($disposition == 'inline') {
|
||||
$inlineIds[$contentId] = $attachment->id;
|
||||
}
|
||||
}
|
||||
} catch (\Exception $e) {}
|
||||
}
|
||||
|
||||
protected function getContentFromPart($part)
|
||||
{
|
||||
if ($part instanceof \Zend\Mime\Part) {
|
||||
$content = $part->getRawContent();
|
||||
if (strtolower($part->charset) != 'utf-8') {
|
||||
$content = mb_convert_encoding($content, 'UTF-8', $part->charset);
|
||||
}
|
||||
} else {
|
||||
$content = $part->getContent();
|
||||
|
||||
$encoding = null;
|
||||
|
||||
if (isset($part->contentTransferEncoding)) {
|
||||
$cteHeader = $part->getHeader('Content-Transfer-Encoding');
|
||||
$encoding = strtolower($cteHeader->getTransferEncoding());
|
||||
}
|
||||
|
||||
if ($encoding == 'base64') {
|
||||
$content = base64_decode($content);
|
||||
}
|
||||
|
||||
$charset = 'UTF-8';
|
||||
|
||||
if (isset($part->contentType)) {
|
||||
$ctHeader = $part->getHeader('Content-Type');
|
||||
$charsetParamValue = $ctHeader->getParameter('charset');
|
||||
if (!empty($charsetParamValue)) {
|
||||
$charset = strtoupper($charsetParamValue);
|
||||
}
|
||||
}
|
||||
|
||||
if ($charset !== 'UTF-8') {
|
||||
$content = mb_convert_encoding($content, 'UTF-8', $charset);
|
||||
}
|
||||
|
||||
if (isset($part->contentTransferEncoding)) {
|
||||
$cteHeader = $part->getHeader('Content-Transfer-Encoding');
|
||||
if ($cteHeader->getTransferEncoding() == 'quoted-printable') {
|
||||
$content = quoted_printable_decode($content);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $content;
|
||||
}
|
||||
}
|
||||
@@ -201,23 +201,21 @@ class Sender
|
||||
|
||||
$body = new MimeMessage;
|
||||
$parts = array();
|
||||
|
||||
|
||||
|
||||
$bodyPart = new MimePart($email->getBodyPlainForSending());
|
||||
$bodyPart->type = 'text/plain';
|
||||
$bodyPart->charset = 'utf-8';
|
||||
$parts[] = $bodyPart;
|
||||
|
||||
|
||||
if ($email->get('isHtml')) {
|
||||
$bodyPart = new MimePart($email->getBodyForSending());
|
||||
$bodyPart->type = 'text/html';
|
||||
$bodyPart->charset = 'utf-8';
|
||||
} else {
|
||||
if ($email->get('bodyPlain')) {
|
||||
$bodyPart = new MimePart($email->get('bodyPlain'));
|
||||
} else {
|
||||
$bodyPart = new MimePart($email->get('body'));
|
||||
}
|
||||
$bodyPart->type = 'text/plain';
|
||||
$bodyPart->charset = 'utf-8';
|
||||
$parts[] = $bodyPart;
|
||||
}
|
||||
|
||||
$parts[] = $bodyPart;
|
||||
|
||||
|
||||
$aCollection = $email->get('attachments');
|
||||
if (!empty($aCollection)) {
|
||||
@@ -251,9 +249,19 @@ class Sender
|
||||
|
||||
$body->setParts($parts);
|
||||
$message->setBody($body);
|
||||
|
||||
if ($email->get('isHtml')) {
|
||||
$message->getHeaders()->get('content-type')->setType('multipart/alternative');
|
||||
}
|
||||
|
||||
try {
|
||||
$this->transport->send($message);
|
||||
|
||||
$headers = $message->getHeaders();
|
||||
if ($headers->has('messageId')) {
|
||||
$email->set('messageId', $headers->get('messageId')->getId());
|
||||
}
|
||||
|
||||
$email->set('status', 'Sent');
|
||||
$email->set('dateSent', date("Y-m-d H:i:s"));
|
||||
} catch (\Exception $e) {
|
||||
|
||||
19
application/Espo/Core/Mail/Storage/Imap.php
Normal file
19
application/Espo/Core/Mail/Storage/Imap.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace Espo\Core\Mail\Storage;
|
||||
|
||||
class Imap extends \Zend\Mail\Storage\Imap
|
||||
{
|
||||
public function getIdsFromUID($uid)
|
||||
{
|
||||
$uid = intval($uid) + 1;
|
||||
return $this->protocol->search(array('UID ' . $uid . ':*'));
|
||||
}
|
||||
|
||||
public function getIdsFromDate($date)
|
||||
{
|
||||
return $this->protocol->search(array('SINCE "' . $date . '"'));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -39,6 +39,8 @@ class Base
|
||||
protected $entityName;
|
||||
|
||||
protected $metadata;
|
||||
|
||||
const MIN_LENGTH_FOR_CONTENT_SEARCH = 4;
|
||||
|
||||
public function __construct($entityManager, \Espo\Entities\User $user, Acl $acl, $metadata)
|
||||
{
|
||||
@@ -106,10 +108,19 @@ class Base
|
||||
if (empty($result['whereClause'])) {
|
||||
$result['whereClause'] = array();
|
||||
}
|
||||
$fieldDefs = $this->entityManager->getEntity($this->entityName)->getFields();
|
||||
$fieldList = $this->getTextFilterFields();
|
||||
$d = array();
|
||||
foreach ($fieldList as $field) {
|
||||
$d[$field . '*'] = $item['value'] . '%';
|
||||
foreach ($fieldList as $field) {
|
||||
if (
|
||||
strlen($item['value']) >= self::MIN_LENGTH_FOR_CONTENT_SEARCH
|
||||
&&
|
||||
!empty($fieldDefs[$field]['type']) && $fieldDefs[$field]['type'] == 'text'
|
||||
) {
|
||||
$d[$field . '*'] = '%' . $item['value'] . '%';
|
||||
} else {
|
||||
$d[$field . '*'] = $item['value'] . '%';
|
||||
}
|
||||
}
|
||||
$where['OR'] = $d;
|
||||
}
|
||||
|
||||
@@ -319,7 +319,7 @@ abstract class Base
|
||||
|
||||
$manifestPath = Util::concatPath($upgradePath, $this->manifestName);
|
||||
if (!file_exists($manifestPath)) {
|
||||
throw new Error('It\'s not an uprgade package.');
|
||||
throw new Error('It\'s not an upgrade package.');
|
||||
}
|
||||
|
||||
$manifestJson = $this->getFileManager()->getContents($manifestPath);
|
||||
@@ -390,4 +390,4 @@ abstract class Base
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,15 +18,13 @@
|
||||
*
|
||||
* 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\DBAL\FieldTypes;
|
||||
|
||||
use Doctrine\DBAL\Types\Type;
|
||||
use Doctrine\DBAL\Platforms\AbstractPlatform;
|
||||
use Doctrine\DBAL\Types\BooleanType;
|
||||
|
||||
|
||||
class Bool extends Type
|
||||
class Bool extends BooleanType
|
||||
{
|
||||
const BOOL = 'bool';
|
||||
|
||||
@@ -39,27 +37,4 @@ class Bool extends Type
|
||||
{
|
||||
return 'TINYINT';
|
||||
}
|
||||
|
||||
|
||||
public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
|
||||
{
|
||||
return $platform->getBooleanTypeDeclarationSQL($fieldDeclaration);
|
||||
}
|
||||
|
||||
|
||||
public function convertToDatabaseValue($value, AbstractPlatform $platform)
|
||||
{
|
||||
return $platform->convertBooleans($value);
|
||||
}
|
||||
|
||||
|
||||
public function convertToPHPValue($value, AbstractPlatform $platform)
|
||||
{
|
||||
return (null === $value) ? null : (bool) $value;
|
||||
}
|
||||
|
||||
public function getBindingType()
|
||||
{
|
||||
return \PDO::PARAM_BOOL;
|
||||
}
|
||||
}
|
||||
@@ -18,38 +18,18 @@
|
||||
*
|
||||
* 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\DBAL\FieldTypes;
|
||||
|
||||
use Doctrine\DBAL\Types\Type;
|
||||
use Doctrine\DBAL\Platforms\AbstractPlatform;
|
||||
use Doctrine\DBAL\Types\IntegerType;
|
||||
|
||||
|
||||
class Int extends Type
|
||||
class Int extends IntegerType
|
||||
{
|
||||
const INTtype = 'int';
|
||||
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return self::INTtype;
|
||||
}
|
||||
|
||||
public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
|
||||
{
|
||||
return $platform->getIntegerTypeDeclarationSQL($fieldDeclaration);
|
||||
}
|
||||
|
||||
|
||||
public function convertToPHPValue($value, AbstractPlatform $platform)
|
||||
{
|
||||
return (null === $value) ? null : (int) $value;
|
||||
}
|
||||
|
||||
|
||||
public function getBindingType()
|
||||
{
|
||||
return \PDO::PARAM_INT;
|
||||
}
|
||||
}
|
||||
@@ -18,14 +18,13 @@
|
||||
*
|
||||
* 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\DBAL\FieldTypes;
|
||||
|
||||
use Doctrine\DBAL\Types\Type;
|
||||
use Doctrine\DBAL\Platforms\AbstractPlatform;
|
||||
use Doctrine\DBAL\Types\StringType;
|
||||
|
||||
class Password extends Type
|
||||
class Password extends StringType
|
||||
{
|
||||
const PASSWORD = 'password';
|
||||
|
||||
@@ -38,23 +37,5 @@ class Password extends Type
|
||||
{
|
||||
return 'VARCHAR';
|
||||
}
|
||||
|
||||
public function getSqlDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
|
||||
{
|
||||
return $platform->getVarcharTypeDeclarationSQL($fieldDeclaration);
|
||||
//return "MD5";
|
||||
}
|
||||
|
||||
/*public function convertToPHPValue($value, AbstractPlatform $platform)
|
||||
{
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function convertToDatabaseValue($value, AbstractPlatform $platform)
|
||||
{
|
||||
return $value;
|
||||
} */
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -18,15 +18,13 @@
|
||||
*
|
||||
* 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\DBAL\FieldTypes;
|
||||
|
||||
use Doctrine\DBAL\Types\Type;
|
||||
use Doctrine\DBAL\Platforms\AbstractPlatform;
|
||||
use Doctrine\DBAL\Types\StringType;
|
||||
|
||||
|
||||
class Varchar extends Type
|
||||
class Varchar extends StringType
|
||||
{
|
||||
const VARCHAR = 'varchar';
|
||||
|
||||
@@ -34,16 +32,4 @@ class Varchar extends Type
|
||||
{
|
||||
return self::VARCHAR;
|
||||
}
|
||||
|
||||
public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
|
||||
{
|
||||
return $platform->getVarcharTypeDeclarationSQL($fieldDeclaration);
|
||||
//return 'varchar';
|
||||
}
|
||||
|
||||
|
||||
public function getDefaultLength(AbstractPlatform $platform)
|
||||
{
|
||||
return $platform->getVarcharDefaultLength();
|
||||
}
|
||||
}
|
||||
@@ -244,17 +244,8 @@ class Base
|
||||
$foreignField = $this->getMetadata()->get('entityDefs.'.$entityName.'.fields.'.$name);
|
||||
|
||||
if ($foreignField['type'] != 'varchar') {
|
||||
$fieldDefs = $this->getMetadata()->get('fields.'.$foreignField['type']);
|
||||
$naming = isset($fieldDefs['naming']) ? $fieldDefs['naming'] : 'postfix';
|
||||
|
||||
if (isset($fieldDefs['actualFields']) && is_array($fieldDefs['actualFields'])) {
|
||||
$foreignFieldArray = array();
|
||||
foreach($fieldDefs['actualFields'] as $fieldName) {
|
||||
if ($fieldName != 'salutation') {
|
||||
$foreignFieldArray[] = Util::getNaming($name, $fieldName, $naming);
|
||||
}
|
||||
}
|
||||
return explode('|', implode('| |', $foreignFieldArray)); //add an empty string between items
|
||||
if ($foreignField['type'] == 'personName') {
|
||||
return array('first' . ucfirst($name), ' ', 'last' . ucfirst($name));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -57,6 +57,7 @@ class Converter
|
||||
'len' => 'len',
|
||||
'notNull' => 'notNull',
|
||||
'autoincrement' => 'autoincrement',
|
||||
'entity' => 'entity',
|
||||
'notStorable' => 'notStorable',
|
||||
'link' => 'relation',
|
||||
'field' => 'foreign', //todo change "foreign" to "field"
|
||||
|
||||
@@ -48,6 +48,14 @@ class Email extends \Espo\Core\Utils\Database\Orm\Base
|
||||
WHERE
|
||||
entity_email_address.deleted = 0 AND entity_email_address.entity_type = '{$entityName}' AND
|
||||
email_address.deleted = 0 AND email_address.name = {value}
|
||||
)",
|
||||
'<>' => \Espo\Core\Utils\Util::toUnderScore($entityName) . ".id IN (
|
||||
SELECT entity_id
|
||||
FROM entity_email_address
|
||||
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 <> {value}
|
||||
)"
|
||||
),
|
||||
'orderBy' => 'email_address.name {direction}',
|
||||
|
||||
@@ -28,7 +28,8 @@ class PersonName extends \Espo\Core\Utils\Database\Orm\Base
|
||||
{
|
||||
protected function load($fieldName, $entityName)
|
||||
{
|
||||
$foreignField = $this->getForeignField($fieldName, $entityName);
|
||||
$foreignField = array('first' . ucfirst($fieldName), ' ', 'last' . ucfirst($fieldName));
|
||||
|
||||
$tableName = Util::toUnderScore($entityName);
|
||||
|
||||
$fullList = array(); //contains empty string (" ") like delimiter
|
||||
|
||||
@@ -48,6 +48,14 @@ class Phone extends \Espo\Core\Utils\Database\Orm\Base
|
||||
WHERE
|
||||
entity_phone_number.deleted = 0 AND entity_phone_number.entity_type = '{$entityName}' AND
|
||||
phone_number.deleted = 0 AND phone_number.name = {value}
|
||||
)",
|
||||
'<>' => \Espo\Core\Utils\Util::toUnderScore($entityName) . ".id IN (
|
||||
SELECT entity_id
|
||||
FROM entity_phone_number
|
||||
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 <> {value}
|
||||
)"
|
||||
),
|
||||
'orderBy' => 'phone_number.name {direction}',
|
||||
|
||||
@@ -31,7 +31,12 @@ class Base extends \Espo\Core\Utils\Database\Orm\Base
|
||||
protected $foreignLinkName = null;
|
||||
protected $foreignEntityName = null;
|
||||
|
||||
protected $allowParams = array();
|
||||
protected $allowedParams = array(
|
||||
'relationName',
|
||||
'conditions',
|
||||
'additionalColumns',
|
||||
'midKeys',
|
||||
);
|
||||
|
||||
protected function getParams()
|
||||
{
|
||||
@@ -106,10 +111,10 @@ class Base extends \Espo\Core\Utils\Database\Orm\Base
|
||||
$linkName = $this->getLinkName();
|
||||
$entityName = $this->getEntityName();
|
||||
|
||||
if (!empty($this->allowParams)) {
|
||||
if (!empty($this->allowedParams)) {
|
||||
$linkParams = &$loads[$entityName]['relations'][$linkName];
|
||||
|
||||
foreach ($this->allowParams as $name) {
|
||||
foreach ($this->allowedParams as $name) {
|
||||
|
||||
$additionalParrams = $this->getAllowedAdditionalParams($name);
|
||||
|
||||
|
||||
@@ -24,12 +24,6 @@ namespace Espo\Core\Utils\Database\Orm\Relations;
|
||||
|
||||
class HasMany extends Base
|
||||
{
|
||||
protected $allowParams = array(
|
||||
'relationName',
|
||||
'conditions',
|
||||
'additionalColumns',
|
||||
);
|
||||
|
||||
protected function load($linkName, $entityName)
|
||||
{
|
||||
$linkParams = $this->getLinkParams();
|
||||
|
||||
@@ -26,12 +26,6 @@ use Espo\Core\Utils\Util;
|
||||
|
||||
class ManyMany extends Base
|
||||
{
|
||||
protected $allowParams = array(
|
||||
'relationName',
|
||||
'conditions',
|
||||
'additionalColumns',
|
||||
);
|
||||
|
||||
protected function load($linkName, $entityName)
|
||||
{
|
||||
$foreignEntityName = $this->getForeignEntityName();
|
||||
|
||||
@@ -101,8 +101,8 @@ class Unifier
|
||||
$dirName = $this->getFileManager()->getDirName($dirPath, false);
|
||||
$defaultValues = $this->loadDefaultValues($dirName, $type);
|
||||
|
||||
$content= array();
|
||||
$unsets= array();
|
||||
$content = array();
|
||||
$unsets = array();
|
||||
foreach($fileList as $dirName => $fileName) {
|
||||
|
||||
if (is_array($fileName)) { /*get content from files in a sub directory*/
|
||||
@@ -125,7 +125,7 @@ class Unifier
|
||||
}
|
||||
|
||||
//unset content
|
||||
$content= Utils\Util::unsetInArray($content, $unsets);
|
||||
$content = Utils\Util::unsetInArray($content, $unsets);
|
||||
//END: unset content
|
||||
|
||||
return $content;
|
||||
@@ -141,27 +141,16 @@ class Unifier
|
||||
*/
|
||||
protected function unifyGetContents($paths, $defaults)
|
||||
{
|
||||
$fileContent= $this->getFileManager()->getContents($paths);
|
||||
$decoded= Utils\Json::getArrayData($fileContent);
|
||||
$fileContent = $this->getFileManager()->getContents($paths);
|
||||
|
||||
if (empty($decoded) && !is_array($decoded)) {
|
||||
$GLOBALS['log']->emergency('Syntax error or empty file - '.Utils\Util::concatPath($folderPath, $fileName));
|
||||
} else {
|
||||
//Default values
|
||||
if (is_string($defaults) && !empty($defaults)) {
|
||||
$defType= $defaults;
|
||||
unset($defaults);
|
||||
$name= $this->getFileManager()->getFileName($fileName, '.json');
|
||||
$decoded = Utils\Json::getArrayData($fileContent, null);
|
||||
|
||||
$defaults= $this->loadDefaultValues($name, $defType);
|
||||
}
|
||||
$mergedValues= Utils\Util::merge($defaults, $decoded);
|
||||
//END: Default values
|
||||
|
||||
return $mergedValues;
|
||||
if (!isset($decoded)) {
|
||||
$GLOBALS['log']->emergency('Syntax error in '.Utils\Util::concatPath($paths));
|
||||
return array();
|
||||
}
|
||||
|
||||
return array();
|
||||
return $decoded;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -174,10 +163,10 @@ class Unifier
|
||||
*/
|
||||
protected function loadDefaultValues($name, $type='metadata')
|
||||
{
|
||||
$defaultPath= $this->params['defaultsPath'];
|
||||
$defaultPath = $this->params['defaultsPath'];
|
||||
|
||||
$defaultValue= $this->getFileManager()->getContents( array($defaultPath, $type, $name.'.json') );
|
||||
if ($defaultValue!==false) {
|
||||
$defaultValue = $this->getFileManager()->getContents( array($defaultPath, $type, $name.'.json') );
|
||||
if ($defaultValue !== false) {
|
||||
//return default array
|
||||
return Utils\Json::decode($defaultValue, true);
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ class Json
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getArrayData($data)
|
||||
public static function getArrayData($data, $returns = array())
|
||||
{
|
||||
if (is_array($data)) {
|
||||
return $data;
|
||||
@@ -127,7 +127,7 @@ class Json
|
||||
return static::decode($data, true);
|
||||
}
|
||||
|
||||
return array();
|
||||
return $returns;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -142,13 +142,13 @@ class Metadata
|
||||
* Get Metadata
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $return
|
||||
* @param mixed $default
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get($key = null, $returns = null)
|
||||
public function get($key = null, $default = null)
|
||||
{
|
||||
return Util::getValueByKey($this->getData(), $key, $returns);
|
||||
return Util::getValueByKey($this->getData(), $key, $default);
|
||||
}
|
||||
|
||||
|
||||
@@ -430,4 +430,4 @@ class Metadata
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -408,10 +408,10 @@ class Util
|
||||
*
|
||||
* @param array $array
|
||||
* @param string $key Ex. of key is "entityDefs", "entityDefs.User"
|
||||
* @param mixed $returns
|
||||
* @param mixed $default
|
||||
* @return mixed
|
||||
*/
|
||||
public static function getValueByKey(array $array, $key = null, $returns = null)
|
||||
public static function getValueByKey(array $array, $key = null, $default = null)
|
||||
{
|
||||
if (!isset($key) || empty($key)) {
|
||||
return $array;
|
||||
@@ -424,7 +424,7 @@ class Util
|
||||
if (isset($lastItem[$keyName]) && is_array($lastItem)) {
|
||||
$lastItem = $lastItem[$keyName];
|
||||
} else {
|
||||
return $returns;
|
||||
return $default;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -66,6 +66,7 @@ return array (
|
||||
'nl_NL',
|
||||
'tr_TR',
|
||||
'ro_RO',
|
||||
'pl_PL',
|
||||
'pt_BR',
|
||||
'vi_VN'
|
||||
),
|
||||
@@ -91,6 +92,7 @@ return array (
|
||||
'disableExport' => false,
|
||||
'assignmentEmailNotifications' => false,
|
||||
'assignmentEmailNotificationsEntityList' => array('Lead', 'Opportunity', 'Task', 'Case'),
|
||||
'emailMessageMaxSize' => 10,
|
||||
'isInstalled' => false,
|
||||
);
|
||||
|
||||
|
||||
@@ -46,6 +46,21 @@ class Email extends \Espo\Core\ORM\Entity
|
||||
}
|
||||
}
|
||||
|
||||
public function getBodyPlainForSending()
|
||||
{
|
||||
$bodyPlain = $this->get('bodyPlain');
|
||||
if (!empty($bodyPlain)) {
|
||||
return $bodyPlain;
|
||||
}
|
||||
|
||||
$body = $this->get('body');
|
||||
|
||||
$breaks = array("<br />","<br>","<br/>","<br />","<br />","<br/>","<br>");
|
||||
$body = str_ireplace($breaks, "\r\n", $body);
|
||||
$body = strip_tags($body);
|
||||
return $body;
|
||||
}
|
||||
|
||||
public function getBodyForSending()
|
||||
{
|
||||
$body = $this->get('body');
|
||||
@@ -55,6 +70,7 @@ class Email extends \Espo\Core\ORM\Entity
|
||||
$body = str_replace("?entryPoint=attachment&id={$attachment->id}", "cid:{$attachment->id}", $body);
|
||||
}
|
||||
}
|
||||
|
||||
$body = str_replace("<table class=\"table table-bordered\">", "<table class=\"table table-bordered\" width=\"100%\">", $body);
|
||||
|
||||
return $body;
|
||||
|
||||
30
application/Espo/Entities/EmailAccount.php
Normal file
30
application/Espo/Entities/EmailAccount.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?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\Entities;
|
||||
|
||||
class EmailAccount extends \Espo\Core\ORM\Entity
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
28
application/Espo/Entities/ExternalAccount.php
Normal file
28
application/Espo/Entities/ExternalAccount.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?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\Entities;
|
||||
|
||||
class ExternalAccount extends Integration
|
||||
{
|
||||
}
|
||||
|
||||
152
application/Espo/Entities/Integration.php
Normal file
152
application/Espo/Entities/Integration.php
Normal file
@@ -0,0 +1,152 @@
|
||||
<?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\Entities;
|
||||
|
||||
class Integration extends \Espo\Core\ORM\Entity
|
||||
{
|
||||
public function get($name)
|
||||
{
|
||||
if ($name == 'id') {
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
if ($this->hasField($name)) {
|
||||
if (array_key_exists($name, $this->valuesContainer)) {
|
||||
return $this->valuesContainer[$name];
|
||||
}
|
||||
} else {
|
||||
if ($this->get('data')) {
|
||||
$data = json_decode($this->get('data'), true);
|
||||
} else {
|
||||
$data = array();
|
||||
}
|
||||
if (isset($data[$name])) {
|
||||
return $data[$name];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function set($p1, $p2)
|
||||
{
|
||||
if (is_array($p1)) {
|
||||
if ($p2 === null) {
|
||||
$p2 = false;
|
||||
}
|
||||
$this->populateFromArray($p1, $p2);
|
||||
return;
|
||||
}
|
||||
|
||||
$name = $p1;
|
||||
$value = $p2;
|
||||
|
||||
if ($name == 'id') {
|
||||
$this->id = $value;
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->hasField($name)) {
|
||||
$this->valuesContainer[$name] = $value;
|
||||
} else {
|
||||
$data = json_decode($this->get('data'), true);
|
||||
if (empty($data)) {
|
||||
$data = array();
|
||||
}
|
||||
$data[$name] = $value;
|
||||
$this->set('data', json_encode($data));
|
||||
}
|
||||
}
|
||||
|
||||
public function populateFromArray(array $arr, $onlyAccessible = true, $reset = false)
|
||||
{
|
||||
if ($reset) {
|
||||
$this->reset();
|
||||
}
|
||||
|
||||
foreach ($arr as $field => $value) {
|
||||
if (is_string($field)) {
|
||||
if (is_array($value)) {
|
||||
$value = json_encode($value);
|
||||
}
|
||||
|
||||
if ($this->hasField($field)) {
|
||||
$fields = $this->getFields();
|
||||
$fieldDefs = $fields[$field];
|
||||
|
||||
if (!is_null($value)) {
|
||||
switch ($fieldDefs['type']) {
|
||||
case self::VARCHAR:
|
||||
break;
|
||||
case self::BOOL:
|
||||
$value = ($value === 'true' || $value === '1' || $value === true);
|
||||
break;
|
||||
case self::INT:
|
||||
$value = intval($value);
|
||||
break;
|
||||
case self::FLOAT:
|
||||
$value = floatval($value);
|
||||
break;
|
||||
case self::JSON_ARRAY:
|
||||
$value = is_string($value) ? json_decode($value) : $value;
|
||||
if (!is_array($value)) {
|
||||
$value = null;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$this->set($field, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function toArray()
|
||||
{
|
||||
$arr = array();
|
||||
if (isset($this->id)) {
|
||||
$arr['id'] = $this->id;
|
||||
}
|
||||
foreach ($this->fields as $field => $defs) {
|
||||
if ($field == 'id') {
|
||||
continue;
|
||||
}
|
||||
if ($this->has($field)) {
|
||||
$arr[$field] = $this->get($field);
|
||||
}
|
||||
}
|
||||
|
||||
$data = json_decode($this->get('data'), true);
|
||||
if (empty($data)) {
|
||||
$data = array();
|
||||
}
|
||||
|
||||
$arr = array_merge($arr, $data);
|
||||
return $arr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -69,26 +69,29 @@ class Stream extends \Espo\Core\Hooks\Base
|
||||
{
|
||||
$linkDefs = $this->getMetadata()->get("entityDefs." . $entity->getEntityName() . ".links", array());
|
||||
|
||||
$scopeNotifiedList = array();
|
||||
foreach ($linkDefs as $link => $defs) {
|
||||
if ($defs['type'] == 'belongsTo') {
|
||||
$foreign = $defs['foreign'];
|
||||
$scope = $defs['entity'];
|
||||
$entityId = $entity->get($link . 'Id');
|
||||
if (!empty($scope) && !empty($entityId)) {
|
||||
if (!$this->isLinkObservableInStream($scope, $foreign)) {
|
||||
if (in_array($scope, $scopeNotifiedList) || !$this->isLinkObservableInStream($scope, $foreign)) {
|
||||
continue;
|
||||
}
|
||||
$this->getStreamService()->noteCreateRelated($entity, $scope, $entityId);
|
||||
$scopeNotifiedList[] = $scope;
|
||||
}
|
||||
} else if ($defs['type'] == 'belongsToParent') {
|
||||
$foreign = $defs['foreign'];
|
||||
$scope = $entity->get($link . 'Type');
|
||||
$entityId = $entity->get($link . 'Id');
|
||||
if (!empty($scope) && !empty($entityId)) {
|
||||
if (!$this->isLinkObservableInStream($scope, $foreign)) {
|
||||
if (in_array($scope, $scopeNotifiedList) || !$this->isLinkObservableInStream($scope, $foreign)) {
|
||||
continue;
|
||||
}
|
||||
$this->getStreamService()->noteCreateRelated($entity, $scope, $entityId);
|
||||
$scopeNotifiedList[] = $scope;
|
||||
|
||||
}
|
||||
} else if ($defs['type'] == 'hasMany') {
|
||||
@@ -96,11 +99,12 @@ class Stream extends \Espo\Core\Hooks\Base
|
||||
$scope = $defs['entity'];
|
||||
$entityIds = $entity->get($link . 'Ids');
|
||||
if (!empty($scope) && is_array($entityIds) && !empty($entityIds)) {
|
||||
if (!$this->isLinkObservableInStream($scope, $foreign)) {
|
||||
if (in_array($scope, $scopeNotifiedList) || !$this->isLinkObservableInStream($scope, $foreign)) {
|
||||
continue;
|
||||
}
|
||||
$entityId = $entityIds[0];
|
||||
$this->getStreamService()->noteCreateRelated($entity, $scope, $entityId);
|
||||
$this->getStreamService()->noteCreateRelated($entity, $scope, $entityId);
|
||||
$scopeNotifiedList[] = $scope;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,32 +28,8 @@ class Opportunity extends \Espo\Core\Controllers\Record
|
||||
{
|
||||
$dateFrom = $request->get('dateFrom');
|
||||
$dateTo = $request->get('dateTo');
|
||||
|
||||
$pdo = $this->getEntityManager()->getPDO();
|
||||
|
||||
$sql = "
|
||||
SELECT opportunity.lead_source AS `leadSource`, SUM(opportunity.amount * currency.rate * opportunity.probability / 100) as `amount`
|
||||
FROM opportunity
|
||||
JOIN currency ON currency.id = opportunity.amount_currency
|
||||
WHERE
|
||||
opportunity.deleted = 0 AND
|
||||
opportunity.close_date >= ".$pdo->quote($dateFrom)." AND
|
||||
opportunity.close_date < ".$pdo->quote($dateTo)." AND
|
||||
opportunity.stage <> 'Closed Lost' AND
|
||||
opportunity.lead_source <> ''
|
||||
GROUP BY opportunity.lead_source
|
||||
";
|
||||
|
||||
$sth = $pdo->prepare($sql);
|
||||
$sth->execute();
|
||||
|
||||
$rows = $sth->fetchAll(\PDO::FETCH_ASSOC);
|
||||
|
||||
$result = array();
|
||||
foreach ($rows as $row) {
|
||||
$result[$row['leadSource']] = floatval($row['amount']);
|
||||
}
|
||||
return $result;
|
||||
|
||||
return $this->getService('Opportunity')->reportByLeadSource($dateFrom, $dateTo);
|
||||
}
|
||||
|
||||
public function actionReportByStage($params, $data, $request)
|
||||
@@ -61,32 +37,7 @@ class Opportunity extends \Espo\Core\Controllers\Record
|
||||
$dateFrom = $request->get('dateFrom');
|
||||
$dateTo = $request->get('dateTo');
|
||||
|
||||
$pdo = $this->getEntityManager()->getPDO();
|
||||
|
||||
$sql = "
|
||||
SELECT opportunity.stage AS `stage`, SUM(opportunity.amount * currency.rate) as `amount`
|
||||
FROM opportunity
|
||||
JOIN currency ON currency.id = opportunity.amount_currency
|
||||
WHERE
|
||||
opportunity.deleted = 0 AND
|
||||
opportunity.close_date >= ".$pdo->quote($dateFrom)." AND
|
||||
opportunity.close_date < ".$pdo->quote($dateTo)." AND
|
||||
opportunity.stage <> 'Closed Lost'
|
||||
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);
|
||||
$sth->execute();
|
||||
|
||||
$rows = $sth->fetchAll(\PDO::FETCH_ASSOC);
|
||||
|
||||
$result = array();
|
||||
foreach ($rows as $row) {
|
||||
$result[$row['stage']] = floatval($row['amount']);
|
||||
}
|
||||
|
||||
return $result;
|
||||
return $this->getService('Opportunity')->reportByStage($dateFrom, $dateTo);
|
||||
}
|
||||
|
||||
public function actionReportSalesByMonth($params, $data, $request)
|
||||
@@ -94,34 +45,7 @@ class Opportunity extends \Espo\Core\Controllers\Record
|
||||
$dateFrom = $request->get('dateFrom');
|
||||
$dateTo = $request->get('dateTo');
|
||||
|
||||
$pdo = $this->getEntityManager()->getPDO();
|
||||
|
||||
$sql = "
|
||||
SELECT DATE_FORMAT(opportunity.close_date, '%Y-%m') AS `month`, SUM(opportunity.amount * currency.rate) as `amount`
|
||||
FROM opportunity
|
||||
JOIN currency ON currency.id = opportunity.amount_currency
|
||||
WHERE
|
||||
opportunity.deleted = 0 AND
|
||||
opportunity.close_date >= ".$pdo->quote($dateFrom)." AND
|
||||
opportunity.close_date < ".$pdo->quote($dateTo)." AND
|
||||
opportunity.stage = 'Closed Won'
|
||||
|
||||
GROUP BY DATE_FORMAT(opportunity.close_date, '%Y-%m')
|
||||
ORDER BY opportunity.close_date
|
||||
";
|
||||
|
||||
$sth = $pdo->prepare($sql);
|
||||
$sth->execute();
|
||||
|
||||
$rows = $sth->fetchAll(\PDO::FETCH_ASSOC);
|
||||
|
||||
$result = array();
|
||||
foreach ($rows as $row) {
|
||||
$result[$row['month']] = floatval($row['amount']);
|
||||
}
|
||||
|
||||
return $result;
|
||||
|
||||
return $this->getService('Opportunity')->reportSalesByMonth($dateFrom, $dateTo);
|
||||
}
|
||||
|
||||
public function actionReportSalesPipeline($params, $data, $request)
|
||||
|
||||
@@ -28,12 +28,23 @@ class CheckInboundEmails extends \Espo\Core\Jobs\Base
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$service = $this->getServiceFactory()->create('InboundEmail');
|
||||
|
||||
$collection = $this->getEntityManager()->getRepository('InboundEmail')->find();
|
||||
$service = $this->getServiceFactory()->create('InboundEmail');
|
||||
$collection = $this->getEntityManager()->getRepository('InboundEmail')->where(array('status' => 'Active'))->find();
|
||||
foreach ($collection as $entity) {
|
||||
$service->fetchFromMailServer($entity->id);
|
||||
try {
|
||||
$service->fetchFromMailServer($entity);
|
||||
} catch (\Exception $e) {}
|
||||
}
|
||||
|
||||
$service = $this->getServiceFactory()->create('EmailAccount');
|
||||
$collection = $this->getEntityManager()->getRepository('EmailAccount')->where(array('status' => 'Active'))->find();
|
||||
foreach ($collection as $entity) {
|
||||
try {
|
||||
$service->fetchFromMailServer($entity);
|
||||
} catch (\Exception $e) {}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,5 +30,10 @@
|
||||
"Set Held": "Auf Gehalten setzen",
|
||||
"Set Not Held": "Auf nicht gehalten setzen",
|
||||
"Send Invitations": "Einladungen versenden"
|
||||
},
|
||||
"presetFilters": {
|
||||
"planned": "Geplant",
|
||||
"held": "Durchgeführt",
|
||||
"todays": "Heutige"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,5 +34,9 @@
|
||||
},
|
||||
"labels": {
|
||||
"Create Case": "Neuer Fall"
|
||||
},
|
||||
"presetFilters": {
|
||||
"open": "Offen",
|
||||
"closed": "Abgeschlossen"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"accountType": "Firmentyp",
|
||||
"doNotCall": "Nicht anrufen",
|
||||
"address": "Adresse",
|
||||
"opportunityRole": "Opportunity Role",
|
||||
"opportunityRole": "Verkaufschance Rolle",
|
||||
"accountRole": "Rolle",
|
||||
"description": "Beschreibung"
|
||||
},
|
||||
@@ -22,10 +22,10 @@
|
||||
},
|
||||
"options": {
|
||||
"opportunityRole": {
|
||||
"": "--None--",
|
||||
"Decision Maker": "Decision Maker",
|
||||
"Evaluator": "Evaluator",
|
||||
"Influencer": "Influencer"
|
||||
"": "--Kein(e)--",
|
||||
"Decision Maker": "Entscheider",
|
||||
"Evaluator": "Vorentscheider",
|
||||
"Influencer": "Einflussreiche Person"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
"Account": "Firmen",
|
||||
"Contact": "Kontakte",
|
||||
"Lead": "Interessenten",
|
||||
"Target": "Targets",
|
||||
"Target": "Zielkontakte",
|
||||
"Opportunity": "Verkaufschancen",
|
||||
"Meeting": "Meetings",
|
||||
"Calendar": "Kalender",
|
||||
@@ -31,6 +31,8 @@
|
||||
"Tasks": "Meine Aufgaben",
|
||||
"Cases": "Meine Fälle",
|
||||
"Calendar": "Kalender",
|
||||
"Calls": "Meine Anrufe",
|
||||
"Meetings": "Meine Meetings",
|
||||
"OpportunitiesByStage": "Verkaufschancen nach Verkaufsphase",
|
||||
"OpportunitiesByLeadSource": "Verkaufschancen nach Quelle",
|
||||
"SalesByMonth": "Umsätze nach Monat",
|
||||
@@ -61,11 +63,11 @@
|
||||
"addressCountry": "Land",
|
||||
"addressState": "Bundesland",
|
||||
"addressPostalCode": "PLZ",
|
||||
"shippingAddressCity": "City (Shipping)",
|
||||
"shippingAddressStreet": "Street (Shipping)",
|
||||
"shippingAddressCountry": "Country (Shipping)",
|
||||
"shippingAddressState": "State (Shipping)",
|
||||
"shippingAddressPostalCode": "Postal Code (Shipping)"
|
||||
"shippingAddressCity": "Ort (Lieferadresse)",
|
||||
"shippingAddressStreet": "Straße (Lieferadresse)",
|
||||
"shippingAddressCountry": "Land (Lieferadresse)",
|
||||
"shippingAddressState": "Bundesland\/Kanton (Lieferadresse)",
|
||||
"shippingAddressPostalCode": "PLZ (Lieferadresse)"
|
||||
},
|
||||
"links": {
|
||||
"contacts": "Kontakte",
|
||||
|
||||
@@ -16,8 +16,17 @@
|
||||
"caseDistribution": "Fall Verteilung",
|
||||
"replyEmailTemplate": "Vorlage E-Mail Antwort",
|
||||
"replyFromAddress": "Von Adresse antworten",
|
||||
"replyToAddress": "Antwort an Adresse",
|
||||
"replyFromName": "Von Name antworten"
|
||||
},
|
||||
"tooltips": {
|
||||
"reply": "Absender informieren dass die E-Mail empfangen wurde.",
|
||||
"createCase": "Fall aus eingehender E-Mail automatisch erstellen.",
|
||||
"replyToAddress": "Geben Sie die E-Mail Adresse dieser Mailbox an, um Antworten hier zu empfangen.",
|
||||
"caseDistribution": "Wie Fälle zugewiesen werden. Entweder direkt dem Benutzer oder im Team.",
|
||||
"assignToUser": "Benutzer E-Mails\/Fälle werden zugewiesen an",
|
||||
"team": "Team E-Mails\/Fälle werden verknüpft mit"
|
||||
},
|
||||
"links": {
|
||||
},
|
||||
"options": {
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
"status": "Status",
|
||||
"source": "Quelle",
|
||||
"opportunityAmount": "Verkaufschance Betrag",
|
||||
"opportunityAmountConverted": "Verkaufschance Betrag (konvertiert)",
|
||||
"description": "Beschreibung",
|
||||
"createdAccount": "Firma",
|
||||
"createdContact": "Kontakt",
|
||||
@@ -42,5 +43,8 @@
|
||||
"Campaign": "Kampagne",
|
||||
"Other": "Andere"
|
||||
}
|
||||
},
|
||||
"presetFilters": {
|
||||
"active": "Aktiv"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,13 @@
|
||||
"Create Meeting": "Neues Meeting",
|
||||
"Set Held": "Auf Gehalten setzen",
|
||||
"Set Not Held": "Auf nicht gehalten setzen",
|
||||
"Send Invitations": "Einladungen versenden"
|
||||
"Send Invitations": "Einladungen versenden",
|
||||
"Saved as Held": "Gespeichert als durchgeführt",
|
||||
"Saved as Not Held": "Gespeichert als nicht durchgeführt"
|
||||
},
|
||||
"presetFilters": {
|
||||
"planned": "Geplant",
|
||||
"held": "Durchgeführt",
|
||||
"todays": "Heutige"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
"doNotCall": "Nicht anrufen",
|
||||
"closeDate": "Abschlussdatum",
|
||||
"contacts": "Kontakte",
|
||||
"description": "Beschreibung"
|
||||
"description": "Beschreibung",
|
||||
"amountConverted": "Betrag (konvertiert)"
|
||||
},
|
||||
"links": {
|
||||
"contacts": "Kontakte"
|
||||
@@ -23,12 +24,16 @@
|
||||
"Id. Decision Makers": "Entscheider ident.",
|
||||
"Perception Analysis": "Analyse Sichtweise",
|
||||
"Proposal/Price Quote": "Preisangebot",
|
||||
"Negotiation/Review": "Verhandlung/Überarbeitung",
|
||||
"Negotiation/Review": "Verhandlung\/Überarbeitung",
|
||||
"Closed Won": "Gewonnen",
|
||||
"Closed Lost": "Verloren"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
"Create Opportunity": "Neue Verkaufschance"
|
||||
},
|
||||
"presetFilters": {
|
||||
"open": "Offen",
|
||||
"won": "Gewonnen"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
"links": {
|
||||
},
|
||||
"labels": {
|
||||
"Create Target": "Create Target",
|
||||
"Create Target": "Neuer Zielkontakt",
|
||||
"Convert to Lead": "Zu Interessent umwandeln"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,5 +27,11 @@
|
||||
},
|
||||
"labels": {
|
||||
"Create Task": "Neue Aufgabe"
|
||||
},
|
||||
"presetFilters": {
|
||||
"active": "Aktiv",
|
||||
"completed": "Abgeschlossen",
|
||||
"todays": "Heutige",
|
||||
"overdue": "Überfällig"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
"Create Account": "Create Account"
|
||||
"Create Account": "Create Account",
|
||||
"Copy Billing": "Copy Billing"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,11 @@
|
||||
"direction": {
|
||||
"Outbound": "Outbound",
|
||||
"Inbound": "Inbound"
|
||||
},
|
||||
"acceptanceStatus": {
|
||||
"None": "None",
|
||||
"Accepted": "Accepted",
|
||||
"Declined": "Declined"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
|
||||
@@ -18,6 +18,11 @@
|
||||
"Planned": "Planned",
|
||||
"Held": "Held",
|
||||
"Not Held": "Not Held"
|
||||
},
|
||||
"acceptanceStatus": {
|
||||
"None": "None",
|
||||
"Accepted": "Accepted",
|
||||
"Declined": "Declined"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
"links": {
|
||||
"contacts": "Contactpersoon",
|
||||
"opportunities": "Kansen",
|
||||
"cases": "Cases"
|
||||
"cases": "Zaken"
|
||||
},
|
||||
"options": {
|
||||
"type": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Record Naam",
|
||||
"parent": "Bovenliggende item",
|
||||
"parent": "Behorende bij",
|
||||
"status": "Status",
|
||||
"dateStart": "Start Datum",
|
||||
"dateEnd": "Eind Datum",
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
},
|
||||
"links": {
|
||||
"opportunities": "Kansen",
|
||||
"cases": "Cases"
|
||||
"cases": "Zaken"
|
||||
},
|
||||
"labels": {
|
||||
"Create Contact": "Maak Contact"
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
"Calendar": "Kalender",
|
||||
"Call": "Tel.gesprekken",
|
||||
"Task": "Taken",
|
||||
"Case": "Cases",
|
||||
"Case": "Zaken",
|
||||
"InboundEmail": "Inkomende Emails"
|
||||
},
|
||||
"dashlets": {
|
||||
|
||||
@@ -19,6 +19,14 @@
|
||||
"replyToAddress": "Reply To Address",
|
||||
"replyFromName": "Antw. van Naam"
|
||||
},
|
||||
"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": {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"labels": {
|
||||
"Converted To": "Vertaald naar",
|
||||
"Create Lead": "Grote Lead",
|
||||
"Convert": "Vertaald"
|
||||
"Convert": "Converteer"
|
||||
},
|
||||
"fields": {
|
||||
"name": "Record Naam",
|
||||
@@ -29,7 +29,7 @@
|
||||
"New": "Nieuw",
|
||||
"Assigned": "Toegewezen",
|
||||
"In Process": "In Behandeling",
|
||||
"Converted": "Vertaald",
|
||||
"Converted": "Converteren",
|
||||
"Recycled": "Opnieuw verwerkt",
|
||||
"Dead": "Dood"
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Record Naam",
|
||||
"parent": "Bovenliggende item",
|
||||
"parent": "Behorende bij",
|
||||
"status": "Status",
|
||||
"dateStart": "Start Datum",
|
||||
"dateEnd": "Eind Datum",
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
"links": {
|
||||
},
|
||||
"labels": {
|
||||
"Create Target": "Create Target",
|
||||
"Convert to Lead": "Omgezet naar Lead"
|
||||
"Create Target": "Maak een doel",
|
||||
"Convert to Lead": "Naar Lead omzetten"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Record Naam",
|
||||
"parent": "Bovenliggende item",
|
||||
"parent": "Behorende bij",
|
||||
"status": "Status",
|
||||
"dateStart": "Start Datum",
|
||||
"dateEnd": "Vervaldatum",
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Imię",
|
||||
"emailAddress": "E-mail",
|
||||
"website": "Strona Internetowa",
|
||||
"phoneNumber": "Telefon",
|
||||
"billingAddress": "Adres Firmy",
|
||||
"shippingAddress": "Adres Dostawy",
|
||||
"description": "Opis ",
|
||||
"sicCode": "PKD",
|
||||
"industry": "Branża",
|
||||
"type": "Rodzaj",
|
||||
"contactRole": "Rola"
|
||||
},
|
||||
"links": {
|
||||
"contacts": "Kontakty",
|
||||
"opportunities": "Szanse Sprzedaży",
|
||||
"cases": "Zlecenia"
|
||||
},
|
||||
"options": {
|
||||
"type": {
|
||||
"Customer": "Klient",
|
||||
"Investor": "Inwestor",
|
||||
"Partner": "Partner",
|
||||
"Reseller": "Sprzedawca"
|
||||
},
|
||||
"industry": {
|
||||
"Apparel": "Odzież",
|
||||
"Banking": "Bankowość",
|
||||
"Computer Software": "Oprogramowanie Komputerowe",
|
||||
"Education": "Edukacja",
|
||||
"Electronics": "Elektronika",
|
||||
"Finance": "Finanse",
|
||||
"Insurance": "Ubezpieczenia"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
"Create Account": "Utwórz Konto"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"modes": {
|
||||
"month": "Miesiąc",
|
||||
"week": "Tydzień",
|
||||
"day": "Dzień",
|
||||
"agendaWeek": "Tydzień",
|
||||
"agendaDay": "Dzień"
|
||||
},
|
||||
"labels": {
|
||||
"Today": "Dziś",
|
||||
"Create": "Utwórz"
|
||||
}
|
||||
}
|
||||
39
application/Espo/Modules/Crm/Resources/i18n/pl_PL/Call.json
Normal file
39
application/Espo/Modules/Crm/Resources/i18n/pl_PL/Call.json
Normal file
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Imię",
|
||||
"parent": "Konto",
|
||||
"status": "Status",
|
||||
"dateStart": "Data Startu",
|
||||
"dateEnd": "Data Zakończenia",
|
||||
"direction": "Kierunek",
|
||||
"duration": "Czas",
|
||||
"description": "Opis ",
|
||||
"users": "Użytkownik",
|
||||
"contacts": "Kontakty",
|
||||
"leads": "Potencjalne Kontakty"
|
||||
},
|
||||
"links": {
|
||||
},
|
||||
"options": {
|
||||
"status": {
|
||||
"Planned": "Planowane",
|
||||
"Held": "Zatrzymany",
|
||||
"Not Held": "Nie zatrzymany"
|
||||
},
|
||||
"direction": {
|
||||
"Outbound": "Wychodzący",
|
||||
"Inbound": "Przychodzący"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
"Create Call": "Utwórz Telefon",
|
||||
"Set Held": "Ustaw Zatrzymanie",
|
||||
"Set Not Held": "Ustaw nie Zatrzymany",
|
||||
"Send Invitations": "Wyślij Powiadomienie"
|
||||
},
|
||||
"presetFilters": {
|
||||
"planned": "Planowane",
|
||||
"held": "Zatrzymany",
|
||||
"todays": "Dzisiaj"
|
||||
}
|
||||
}
|
||||
42
application/Espo/Modules/Crm/Resources/i18n/pl_PL/Case.json
Normal file
42
application/Espo/Modules/Crm/Resources/i18n/pl_PL/Case.json
Normal file
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Imię",
|
||||
"number": "Numer",
|
||||
"status": "Status",
|
||||
"account": "Konto",
|
||||
"contact": "Kontakty",
|
||||
"priority": "Pryjorytet",
|
||||
"type": "Rodzaj",
|
||||
"description": "Opis "
|
||||
},
|
||||
"links": {
|
||||
},
|
||||
"options": {
|
||||
"status": {
|
||||
"New": "Nowy",
|
||||
"Assigned": "Przypisany",
|
||||
"Pending": "Oczekuje",
|
||||
"Closed": "Zamknięty",
|
||||
"Rejected": "Odrzucony",
|
||||
"Duplicate": "Powielony"
|
||||
},
|
||||
"priority" : {
|
||||
"Low": "Niski",
|
||||
"Normal": "Normalny",
|
||||
"High": "Wysoki",
|
||||
"Urgent": "Pilne"
|
||||
},
|
||||
"type": {
|
||||
"Question": "Pytanie",
|
||||
"Incident": "Zdarzenie",
|
||||
"Problem": "Problem"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
"Create Case": "Utwórz Sprawę"
|
||||
},
|
||||
"presetFilters": {
|
||||
"open": "Otwórz",
|
||||
"closed": "Zamknięty"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Imię",
|
||||
"emailAddress": "E-mail",
|
||||
"title": "Tytuł",
|
||||
"account": "Konto",
|
||||
"accounts": "Klienci",
|
||||
"phoneNumber": "Telefon",
|
||||
"accountType": "Typ Klienta",
|
||||
"doNotCall": "Nie Dzwoń",
|
||||
"address": "Adres",
|
||||
"opportunityRole": "Rola Szansy Sprzedaży",
|
||||
"accountRole": "Rola",
|
||||
"description": "Opis "
|
||||
},
|
||||
"links": {
|
||||
"opportunities": "Szanse Sprzedaży",
|
||||
"cases": "Zlecenia"
|
||||
},
|
||||
"labels": {
|
||||
"Create Contact": "Utwórz Kontakt"
|
||||
},
|
||||
"options": {
|
||||
"opportunityRole": {
|
||||
"": "--NIC--",
|
||||
"Decision Maker": "Osoba Decyzyjna",
|
||||
"Evaluator": "Oceniający",
|
||||
"Influencer": "Wpływający"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
{
|
||||
"scopeNames": {
|
||||
"Account": "Konto",
|
||||
"Contact": "Kontakty",
|
||||
"Lead": "Potencjalny Kontakt",
|
||||
"Target": "Cel",
|
||||
"Opportunity": "Szansa Sprzedaży",
|
||||
"Meeting": "Spotkanie",
|
||||
"Calendar": "Kalendarz",
|
||||
"Call": "Telefon",
|
||||
"Task": "Zadanie",
|
||||
"Case": "Sprawa",
|
||||
"InboundEmail": "Poczta Przychodząca"
|
||||
},
|
||||
"scopeNamesPlural": {
|
||||
"Account": "Klienci",
|
||||
"Contact": "Kontakty",
|
||||
"Lead": "Potencjalne Kontakty",
|
||||
"Target": "Cele",
|
||||
"Opportunity": "Szanse Sprzedaży",
|
||||
"Meeting": "Spotkania",
|
||||
"Calendar": "Kalendarz",
|
||||
"Call": "Telefony",
|
||||
"Task": "Zadania",
|
||||
"Case": "Zlecenia",
|
||||
"InboundEmail": "Poczta Przychodząca"
|
||||
},
|
||||
"dashlets": {
|
||||
"Leads": "Moje Potencjalne Kontakty",
|
||||
"Opportunities": "Moje Szanse Sprzedaży",
|
||||
"Tasks": "Moje Zadania",
|
||||
"Cases": "Moje Zlecenia",
|
||||
"Calendar": "Kalendarz",
|
||||
"Calls": "Moje Telefony",
|
||||
"Meetings": "Moje Spotkania",
|
||||
"OpportunitiesByStage": "Szansa Sprzedaży/Etap/",
|
||||
"OpportunitiesByLeadSource": "Szansa Sprzedaży/Potencjalny kontakt/",
|
||||
"SalesByMonth": "Sprzedaż Miesięczna",
|
||||
"SalesPipeline": "Lejek Sprzedaży"
|
||||
},
|
||||
"labels": {
|
||||
"Create InboundEmail": "Utwórz Pocztę Przychodzącą",
|
||||
"Activities": "Aktywności",
|
||||
"History": "Historia",
|
||||
"Attendees": "Uczestnicy",
|
||||
"Schedule Meeting": "Zaplanuj Spotkanie",
|
||||
"Schedule Call": "Zaplanuj Telefon",
|
||||
"Compose Email": "Utwórz Wiadomość",
|
||||
"Log Meeting": "Zarejestruj Spotkanie",
|
||||
"Log Call": "Zarejestruj Telefon",
|
||||
"Archive Email": "Archiwizuj e-mail",
|
||||
"Create Task": "Utwórz Zadanie",
|
||||
"Tasks": "Zadania"
|
||||
},
|
||||
"fields": {
|
||||
"billingAddressCity": "Miasto",
|
||||
"billingAddressCountry": "Kraj",
|
||||
"billingAddressPostalCode": "Kod Pocztowy",
|
||||
"billingAddressState": "Województwo",
|
||||
"billingAddressStreet": "Ulica",
|
||||
"addressCity": "Miasto",
|
||||
"addressStreet": "Ulica",
|
||||
"addressCountry": "Kraj",
|
||||
"addressState": "Województwo",
|
||||
"addressPostalCode": "Kod Pocztowy",
|
||||
"shippingAddressCity": "City (Shipping)",
|
||||
"shippingAddressStreet": "Street (Shipping)",
|
||||
"shippingAddressCountry": "Country (Shipping)",
|
||||
"shippingAddressState": "State (Shipping)",
|
||||
"shippingAddressPostalCode": "Postal Code (Shipping)"
|
||||
},
|
||||
"links": {
|
||||
"contacts": "Kontakty",
|
||||
"opportunities": "Szanse Sprzedaży",
|
||||
"leads": "Potencjalne Kontakty",
|
||||
"meetings": "Spotkania",
|
||||
"calls": "Telefony",
|
||||
"tasks": "Zadania",
|
||||
"emails": "Emails"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Imię",
|
||||
"team": "Zespół",
|
||||
"status": "Status",
|
||||
"assignToUser": "Przypisz do Użytkonika",
|
||||
"host": "Host",
|
||||
"username": "Użytkownik",
|
||||
"password": "Hasło",
|
||||
"port": "Port",
|
||||
"monitoredFolders": "Monitorowane Foldery",
|
||||
"trashFolder": "Elementy Usunięte",
|
||||
"ssl": "SSL",
|
||||
"createCase": "Utwórz Sprawę",
|
||||
"reply": "Odpowiedz",
|
||||
"caseDistribution": "Dystrybucja Spraw",
|
||||
"replyEmailTemplate": "Szablon Odpowiedzi",
|
||||
"replyFromAddress": "Odpowiedz z Adresu",
|
||||
"replyToAddress": "Odpowiedz na Adres",
|
||||
"replyFromName": "Odpowiedz z Nazwy"
|
||||
},
|
||||
"tooltips": {
|
||||
"reply": "Potwierdzenie otrzymania wiadomości.",
|
||||
"createCase": "Automatycznie utwórz sprawę z przychodzącej wiadomości.",
|
||||
"replyToAddress": "Podaj adres e-mail z tej skrzynki pocztowej, aby tu odpowiedź.",
|
||||
"caseDistribution": "Jak zlecenie zostanie przypisane do. Przypisane bezpośrednio do użytkownika lub między zespołem",
|
||||
"assignToUser": "E-mail użytkownika/zlecenia zostanie przypisany do.",
|
||||
"team": "E-mail do zespołu/zlecenia zostaną związane z."
|
||||
},
|
||||
"links": {
|
||||
},
|
||||
"options": {
|
||||
"status": {
|
||||
"Active": "Aktywny",
|
||||
"Inactive": "Nie Aktywny"
|
||||
},
|
||||
"caseDistribution": {
|
||||
"Direct-Assignment": "Przypisanie bezpośrednio",
|
||||
"Round-Robin": "Przypisanie Karuzelowe",
|
||||
"Least-Busy": "Least-Busy"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
"Create InboundEmail": "Utwórz Pocztę Przychodzącą",
|
||||
"IMAP": "IMAP",
|
||||
"Actions": "Akcja",
|
||||
"Main": "Główny"
|
||||
},
|
||||
"messages": {
|
||||
"couldNotConnectToImap": "Nie mogę połączyć się z serwerem IMAP"
|
||||
}
|
||||
}
|
||||
50
application/Espo/Modules/Crm/Resources/i18n/pl_PL/Lead.json
Normal file
50
application/Espo/Modules/Crm/Resources/i18n/pl_PL/Lead.json
Normal file
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"labels": {
|
||||
"Converted To": "Przekształcony w ",
|
||||
"Create Lead": "Utwórz Potencjalny Kontakt",
|
||||
"Convert": "Przekształć"
|
||||
},
|
||||
"fields": {
|
||||
"name": "Imię",
|
||||
"emailAddress": "E-mail",
|
||||
"title": "Tytuł",
|
||||
"website": "Strona Internetowa",
|
||||
"phoneNumber": "Telefon",
|
||||
"accountName": "Nazwa Konta",
|
||||
"doNotCall": "Nie Dzwoń",
|
||||
"address": "Adres",
|
||||
"status": "Status",
|
||||
"source": "Źródło",
|
||||
"opportunityAmount": "Wartość Szansy Sprzewdaży",
|
||||
"opportunityAmountConverted": "Opportunity Amount (converted)",
|
||||
"description": "Opis ",
|
||||
"createdAccount": "Konto",
|
||||
"createdContact": "Kontakty",
|
||||
"createdOpportunity": "Szansa Sprzedaży"
|
||||
},
|
||||
"links": {
|
||||
},
|
||||
"options": {
|
||||
"status": {
|
||||
"New": "Nowy",
|
||||
"Assigned": "Przypisany",
|
||||
"In Process": "W trakcie",
|
||||
"Converted": "Przekształcony",
|
||||
"Recycled": "Usunięty",
|
||||
"Dead": "Martwy"
|
||||
},
|
||||
"source": {
|
||||
"Call": "Telefon",
|
||||
"Email": "E-mail",
|
||||
"Existing Customer": "Istniejący klient",
|
||||
"Partner": "Partner",
|
||||
"Public Relations": "Relacje",
|
||||
"Web Site": "Stwona Internetowa",
|
||||
"Campaign": "Kampania",
|
||||
"Other": "Inny"
|
||||
}
|
||||
},
|
||||
"presetFilters": {
|
||||
"active": "Aktywny"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Imię",
|
||||
"parent": "Konto",
|
||||
"status": "Status",
|
||||
"dateStart": "Data Startu",
|
||||
"dateEnd": "Data Zakończenia",
|
||||
"duration": "Czas",
|
||||
"description": "Opis ",
|
||||
"users": "Użytkownik",
|
||||
"contacts": "Kontakty",
|
||||
"leads": "Potencjalne Kontakty"
|
||||
},
|
||||
"links": {
|
||||
},
|
||||
"options": {
|
||||
"status": {
|
||||
"Planned": "Planowane",
|
||||
"Held": "Zatrzymany",
|
||||
"Not Held": "Nie zatrzymany"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
"Create Meeting": "Utwórz Spotkanie",
|
||||
"Set Held": "Ustaw Zatrzymanie",
|
||||
"Set Not Held": "Ustaw nie Zatrzymany",
|
||||
"Send Invitations": "Wyślij Powiadomienie",
|
||||
"Saved as Held": "Zapisz jako zatrzymany",
|
||||
"Saved as Not Held": "Zapisz jako nie utrzymany"
|
||||
},
|
||||
"presetFilters": {
|
||||
"planned": "Planowane",
|
||||
"held": "Zatrzymany",
|
||||
"todays": "Dzisiaj"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Imię",
|
||||
"account": "Konto",
|
||||
"stage": "Estap",
|
||||
"amount": "Wartość",
|
||||
"probability": "Prawdopodobieństwo, %",
|
||||
"leadSource": "Zródło Potencjalnego Kontaktu",
|
||||
"doNotCall": "Nie Dzwoń",
|
||||
"closeDate": "Data Zamknięcia",
|
||||
"contacts": "Kontakty",
|
||||
"description": "Opis ",
|
||||
"amountConverted": "Amount (converted)"
|
||||
},
|
||||
"links": {
|
||||
"contacts": "Kontakty"
|
||||
},
|
||||
"options": {
|
||||
"stage": {
|
||||
"Prospecting": "I Spotkanie",
|
||||
"Qualification": "Kwalifikacja",
|
||||
"Needs Analysis": "Dodatkowa Analiza",
|
||||
"Value Proposition": "Oferta Produktowa",
|
||||
"Id. Decision Makers": "Oferta przekazna do osoby decyzyjnej",
|
||||
"Perception Analysis": "Perception Analysis",
|
||||
"Proposal/Price Quote": "Oferta Cenowa",
|
||||
"Negotiation/Review": "Negocjacje ",
|
||||
"Closed Won": "Zakończone Wygrane",
|
||||
"Closed Lost": "Zakończone Przegrane"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
"Create Opportunity": "Utwórz Szanse"
|
||||
},
|
||||
"presetFilters": {
|
||||
"open": "Otwórz",
|
||||
"won": "Wygrane"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Imię",
|
||||
"emailAddress": "E-mail",
|
||||
"title": "Tytuł",
|
||||
"website": "Strona Internetowa",
|
||||
"accountName": "Nazwa Konta",
|
||||
"phoneNumber": "Telefon",
|
||||
"doNotCall": "Nie Dzwoń",
|
||||
"address": "Adres",
|
||||
"description": "Opis "
|
||||
},
|
||||
"links": {
|
||||
},
|
||||
"labels": {
|
||||
"Create Target": "Utwórz Cel",
|
||||
"Convert to Lead": "Przekształć w Potencjalny Kontakt"
|
||||
}
|
||||
}
|
||||
37
application/Espo/Modules/Crm/Resources/i18n/pl_PL/Task.json
Normal file
37
application/Espo/Modules/Crm/Resources/i18n/pl_PL/Task.json
Normal file
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Imię",
|
||||
"parent": "Konto",
|
||||
"status": "Status",
|
||||
"dateStart": "Data Startu",
|
||||
"dateEnd": "Data Zwrotu",
|
||||
"priority": "Pryjorytet",
|
||||
"description": "Opis ",
|
||||
"isOverdue": "Przegrzany"
|
||||
},
|
||||
"links": {
|
||||
},
|
||||
"options": {
|
||||
"status": {
|
||||
"Not Started": "Nie Rozpoczęte",
|
||||
"Started": "Rozpoczęte",
|
||||
"Completed": "Ukończone",
|
||||
"Canceled": "Anulowane"
|
||||
},
|
||||
"priority" : {
|
||||
"Low": "Niski",
|
||||
"Normal": "Normalny",
|
||||
"High": "Wysoki",
|
||||
"Urgent": "Pilne"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
"Create Task": "Utwórz Zadanie"
|
||||
},
|
||||
"presetFilters": {
|
||||
"active": "Aktywny",
|
||||
"completed": "Ukończone",
|
||||
"todays": "Dzisiaj",
|
||||
"overdue": "Przegrzane"
|
||||
}
|
||||
}
|
||||
@@ -22,13 +22,10 @@
|
||||
{"name":"host"},{"name":"ssl"}
|
||||
],
|
||||
[
|
||||
{"name":"port"},false
|
||||
{"name":"port"},{"name":"username"}
|
||||
],
|
||||
[
|
||||
{"name":"monitoredFolders"},{"name":"username"}
|
||||
],
|
||||
[
|
||||
{"name":"trashFolder"},{"name":"password"}
|
||||
{"name":"monitoredFolders"},{"name":"password"}
|
||||
]
|
||||
]
|
||||
},
|
||||
|
||||
@@ -1 +1 @@
|
||||
[{"name":"name","width":30,"link":true},{"name":"status"},{"name":"createCase"}]
|
||||
[{"name":"name","width":30,"link":true},{"name":"host"},{"name":"status"},{"name":"createCase"}]
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"FullCalendar": {
|
||||
"path": "client/modules/crm/lib/fullcalendar.min.js",
|
||||
"exportsTo": "$",
|
||||
"exportsAs": "fullCalendar"
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
{
|
||||
"recordViews":{
|
||||
"detail":"Crm:InboundEmail.Record.Detail",
|
||||
"edit":"Crm:InboundEmail.Record.Edit"
|
||||
"edit":"Crm:InboundEmail.Record.Edit",
|
||||
"list":"Crm:InboundEmail.Record.List"
|
||||
},
|
||||
"formDependency": {
|
||||
"createCase": {
|
||||
@@ -42,5 +43,6 @@
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"disableSearchPanel": true
|
||||
}
|
||||
|
||||
@@ -53,7 +53,8 @@
|
||||
"type": "varchar"
|
||||
},
|
||||
"shippingAddress": {
|
||||
"type": "address"
|
||||
"type": "address",
|
||||
"view": "Crm:Account.Fields.ShippingAddress"
|
||||
},
|
||||
"shippingAddressStreet": {
|
||||
"type": "text",
|
||||
|
||||
@@ -46,18 +46,35 @@
|
||||
"type": "link",
|
||||
"disabled": true
|
||||
},
|
||||
"acceptanceStatus": {
|
||||
"type": "enum",
|
||||
"notStorable": true,
|
||||
"disabled": true,
|
||||
"options": ["None", "Accepted", "Declined"]
|
||||
},
|
||||
"users": {
|
||||
"type": "linkMultiple",
|
||||
"disabled": true
|
||||
"disabled": true,
|
||||
"view": "Crm:Meeting.Fields.Attendees",
|
||||
"columns": {
|
||||
"status": "acceptanceStatus"
|
||||
}
|
||||
},
|
||||
"contacts": {
|
||||
"type": "linkMultiple",
|
||||
"disabled": true,
|
||||
"view": "Crm:Meeting.Fields.Contacts"
|
||||
"view": "Crm:Meeting.Fields.Contacts",
|
||||
"columns": {
|
||||
"status": "acceptanceStatus"
|
||||
}
|
||||
},
|
||||
"leads": {
|
||||
"type": "linkMultiple",
|
||||
"disabled": true
|
||||
"disabled": true,
|
||||
"view": "Crm:Meeting.Fields.Attendees",
|
||||
"columns": {
|
||||
"status": "acceptanceStatus"
|
||||
}
|
||||
},
|
||||
"createdAt": {
|
||||
"type": "datetime",
|
||||
|
||||
@@ -94,6 +94,11 @@
|
||||
"disabled": true,
|
||||
"options": ["", "Decision Maker", "Evaluator", "Influencer"]
|
||||
},
|
||||
"acceptanceStatus": {
|
||||
"type": "varchar",
|
||||
"notStorable": true,
|
||||
"disabled": true
|
||||
},
|
||||
"createdAt": {
|
||||
"type": "datetime",
|
||||
"readOnly": true
|
||||
|
||||
@@ -33,10 +33,9 @@
|
||||
"default": "INBOX",
|
||||
"view": "Crm:InboundEmail.Fields.Folders"
|
||||
},
|
||||
"trashFolder": {
|
||||
"type": "varchar",
|
||||
"required": true,
|
||||
"view": "Crm:InboundEmail.Fields.Folder"
|
||||
"fetchData": {
|
||||
"type": "text",
|
||||
"readOnly": true
|
||||
},
|
||||
"assignToUser": {
|
||||
"type": "link",
|
||||
|
||||
@@ -116,6 +116,11 @@
|
||||
"type": "link",
|
||||
"required": true
|
||||
},
|
||||
"acceptanceStatus": {
|
||||
"type": "varchar",
|
||||
"notStorable": true,
|
||||
"disabled": true
|
||||
},
|
||||
"teams": {
|
||||
"type": "linkMultiple"
|
||||
},
|
||||
|
||||
@@ -41,18 +41,35 @@
|
||||
"type": "link",
|
||||
"disabled": true
|
||||
},
|
||||
"acceptanceStatus": {
|
||||
"type": "enum",
|
||||
"notStorable": true,
|
||||
"disabled": true,
|
||||
"options": ["None", "Accepted", "Declined"]
|
||||
},
|
||||
"users": {
|
||||
"type": "linkMultiple",
|
||||
"disabled": true
|
||||
"view": "Crm:Meeting.Fields.Attendees",
|
||||
"disabled": true,
|
||||
"columns": {
|
||||
"status": "acceptanceStatus"
|
||||
}
|
||||
},
|
||||
"contacts": {
|
||||
"type": "linkMultiple",
|
||||
"disabled": true,
|
||||
"view": "Crm:Meeting.Fields.Contacts"
|
||||
"view": "Crm:Meeting.Fields.Contacts",
|
||||
"columns": {
|
||||
"status": "acceptanceStatus"
|
||||
}
|
||||
},
|
||||
"leads": {
|
||||
"type": "linkMultiple",
|
||||
"disabled": true
|
||||
"view": "Crm:Meeting.Fields.Attendees",
|
||||
"disabled": true,
|
||||
"columns": {
|
||||
"status": "acceptanceStatus"
|
||||
}
|
||||
},
|
||||
"createdAt": {
|
||||
"type": "datetime",
|
||||
|
||||
@@ -22,32 +22,32 @@
|
||||
|
||||
namespace Espo\Modules\Crm\Services;
|
||||
|
||||
use \Espo\ORM\Entity;
|
||||
|
||||
use \Espo\Core\Exceptions\Error;
|
||||
use \Espo\Core\Exceptions\Forbidden;
|
||||
|
||||
use \Zend\Mime\Mime as Mime;
|
||||
|
||||
class InboundEmail extends \Espo\Services\Record
|
||||
{
|
||||
{
|
||||
protected $internalFields = array('password');
|
||||
|
||||
const PORTION_LIMIT = 20;
|
||||
|
||||
public function createEntity($data)
|
||||
{
|
||||
$entity = parent::createEntity($data);
|
||||
$entity->clear('password');
|
||||
return $entity;
|
||||
}
|
||||
|
||||
public function getEntity($id = null)
|
||||
{
|
||||
$entity = parent::getEntity($id);
|
||||
$entity->clear('password');
|
||||
return $entity;
|
||||
}
|
||||
|
||||
public function updateEntity($id, $data)
|
||||
{
|
||||
$entity = parent::updateEntity($id, $data);
|
||||
$entity->clear('password');
|
||||
return $entity;
|
||||
}
|
||||
|
||||
@@ -55,13 +55,9 @@ class InboundEmail extends \Espo\Services\Record
|
||||
{
|
||||
$result = parent::findEntities($params);
|
||||
|
||||
foreach ($result['collection'] as $entity) {
|
||||
$entity->clear('password');
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
protected function init()
|
||||
{
|
||||
$this->dependencies[] = 'fileManager';
|
||||
@@ -76,17 +72,7 @@ class InboundEmail extends \Espo\Services\Record
|
||||
protected function getMailSender()
|
||||
{
|
||||
return $this->injections['mailSender'];
|
||||
}
|
||||
|
||||
protected function findFolder($storage, $path)
|
||||
{
|
||||
$arr = explode('/', $path);
|
||||
$pointer = $storage->getFolders();
|
||||
foreach ($arr as $folderName) {
|
||||
$pointer = $pointer->$folderName;
|
||||
}
|
||||
return $pointer;
|
||||
}
|
||||
}
|
||||
|
||||
public function getFolders($params)
|
||||
{
|
||||
@@ -121,14 +107,33 @@ class InboundEmail extends \Espo\Services\Record
|
||||
return $foldersArr;
|
||||
}
|
||||
|
||||
public function fetchFromMailServer($id)
|
||||
{
|
||||
$inboundEmail = $this->getEntityManager()->getEntity('InboundEmail', $id);
|
||||
|
||||
public function fetchFromMailServer(Entity $inboundEmail)
|
||||
{
|
||||
if ($inboundEmail->get('status') != 'Active') {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
$importer = new \Espo\Core\Mail\Importer($this->getEntityManager(), $this->getFileManager());
|
||||
|
||||
$maxSize = $this->getConfig()->get('emailMessageMaxSize');
|
||||
|
||||
$teamId = $inboundEmail->get('teamId');
|
||||
$userId = $this->getUser()->id;
|
||||
if ($inboundEmail->get('assignToUserId')) {
|
||||
$userId = $inboundEmail->get('assignToUserId');
|
||||
}
|
||||
|
||||
$fetchData = json_decode($inboundEmail->get('fetchData'), true);
|
||||
if (empty($fetchData)) {
|
||||
$fetchData = array();
|
||||
}
|
||||
if (!array_key_exists('lastUID', $fetchData)) {
|
||||
$fetchData['lastUID'] = array();
|
||||
}
|
||||
if (!array_key_exists('lastUID', $fetchData)) {
|
||||
$fetchData['lastDate'] = array();
|
||||
}
|
||||
|
||||
$imapParams = array(
|
||||
'host' => $inboundEmail->get('host'),
|
||||
'port' => $inboundEmail->get('port'),
|
||||
@@ -140,18 +145,7 @@ class InboundEmail extends \Espo\Services\Record
|
||||
$imapParams['ssl'] = 'SSL';
|
||||
}
|
||||
|
||||
$storage = new \Zend\Mail\Storage\Imap($imapParams);
|
||||
|
||||
$trash = null;
|
||||
$trashFolder = $inboundEmail->get('trashFolder');
|
||||
if (empty($trashFolder)) {
|
||||
$trashFolder = 'INBOX.Trash';
|
||||
}
|
||||
try {
|
||||
$trash = $this->findFolder($storage, $trashFolder);
|
||||
} catch (\Exception $e) {
|
||||
throw new Error("No trash folder '{$trashFolder}' found for Inbound Email {$id}");
|
||||
}
|
||||
$storage = new \Espo\Core\Mail\Storage\Imap($imapParams);
|
||||
|
||||
$monitoredFolders = $inboundEmail->get('monitoredFolders');
|
||||
if (empty($monitoredFolders)) {
|
||||
@@ -159,135 +153,106 @@ class InboundEmail extends \Espo\Services\Record
|
||||
}
|
||||
|
||||
$monitoredFoldersArr = explode(',', $monitoredFolders);
|
||||
foreach ($monitoredFoldersArr as $path) {
|
||||
$toRemove = array();
|
||||
$path = trim($path);
|
||||
|
||||
$folder = $this->findFolder($storage, $path);
|
||||
foreach ($monitoredFoldersArr as $folder) {
|
||||
$folder = trim($folder);
|
||||
$storage->selectFolder($folder);
|
||||
|
||||
foreach ($storage as $number => $message) {
|
||||
$this->importMessage($inboundEmail, $message);
|
||||
$lastUID = 0;
|
||||
$lastDate = 0;
|
||||
if (!empty($fetchData['lastUID'][$folder])) {
|
||||
$lastUID = $fetchData['lastUID'][$folder];
|
||||
}
|
||||
if (!empty($fetchData['lastDate'][$folder])) {
|
||||
$lastDate = $fetchData['lastDate'][$folder];
|
||||
}
|
||||
|
||||
$ids = $storage->getIdsFromUID($lastUID);
|
||||
|
||||
while ($storage->countMessages()) {
|
||||
if ($trash) {
|
||||
$storage->moveMessage(1, $trash);
|
||||
if ((count($ids) == 1) && !empty($lastUID)) {
|
||||
if ($storage->getUniqueId($ids[0]) == $lastUID) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function getAddressListFromMessage($message, $type)
|
||||
{
|
||||
$addressList = array();
|
||||
if (isset($message->$type)) {
|
||||
|
||||
$list = $message->getHeader($type)->getAddressList();
|
||||
foreach ($list as $address) {
|
||||
$addressList[] = $address->getEmail();
|
||||
}
|
||||
}
|
||||
return $addressList;
|
||||
}
|
||||
|
||||
protected function importMessage($inboundEmail, $message)
|
||||
{
|
||||
$result = false;
|
||||
|
||||
try {
|
||||
$email = $this->getEntityManager()->getEntity('Email');
|
||||
if ($inboundEmail->get('teamId')) {
|
||||
$email->set('teamsIds', array($inboundEmail->get('teamId')));
|
||||
}
|
||||
|
||||
$email->set('isHtml', false);
|
||||
$email->set('name', $message->subject);
|
||||
$email->set('attachmentsIds', array());
|
||||
|
||||
$userId = $this->getUser()->id;
|
||||
if ($inboundEmail->get('assignToUserId')) {
|
||||
$userId = $inboundEmail->get('assignToUserId');
|
||||
}
|
||||
$email->set('assignedUserId', $userId);
|
||||
|
||||
$fromArr = $this->getAddressListFromMessage($message, 'from');
|
||||
|
||||
if (isset($message->from)) {
|
||||
$email->set('fromName', $message->from);
|
||||
}
|
||||
|
||||
$email->set('from', $fromArr[0]);
|
||||
$email->set('to', implode(';', $this->getAddressListFromMessage($message, 'to')));
|
||||
$email->set('cc', implode(';', $this->getAddressListFromMessage($message, 'cc')));
|
||||
$email->set('bcc', implode(';', $this->getAddressListFromMessage($message, 'bcc')));
|
||||
|
||||
$email->set('status', 'Archived');
|
||||
|
||||
$dt = new \DateTime($message->date);
|
||||
if ($dt) {
|
||||
$dateSent = $dt->setTimezone(new \DateTimeZone('UTC'))->format('Y-m-d H:i:s');
|
||||
$email->set('dateSent', $dateSent);
|
||||
}
|
||||
|
||||
$inlineIds = array();
|
||||
|
||||
if ($message->isMultipart()) {
|
||||
foreach (new \RecursiveIteratorIterator($message) as $part) {
|
||||
$this->importPartDataToEmail($email, $part, $inlineIds);
|
||||
}
|
||||
} else {
|
||||
$this->importPartDataToEmail($email, $message, $inlineIds);
|
||||
}
|
||||
|
||||
$body = $email->get('body');
|
||||
if (!empty($body)) {
|
||||
foreach ($inlineIds as $cid => $attachmentId) {
|
||||
$body = str_replace('cid:' . $cid, '?entryPoint=attachment&id=' . $attachmentId, $body);
|
||||
$k = 0;
|
||||
foreach ($ids as $i => $id) {
|
||||
if ($k == count($ids) - 1) {
|
||||
$lastUID = $storage->getUniqueId($id);
|
||||
}
|
||||
$email->set('body', $body);
|
||||
}
|
||||
|
||||
$this->getEntityManager()->saveEntity($email);
|
||||
|
||||
if ($inboundEmail->get('createCase')) {
|
||||
if (preg_match('/\[#([0-9]+)[^0-9]*\]/', $email->get('name'), $m)) {
|
||||
$caseNumber = $m[1];
|
||||
$case = $this->getEntityManager()->getRepository('Case')->where(array(
|
||||
'number' => $caseNumber
|
||||
))->findOne();
|
||||
if ($case) {
|
||||
$email->set('parentType', 'Case');
|
||||
$email->set('parentId', $case->id);
|
||||
$this->getEntityManager()->saveEntity($email);
|
||||
$this->getServiceFactory()->create('Stream')->noteEmailReceived($case, $email);
|
||||
}
|
||||
} else {
|
||||
$params = array(
|
||||
'caseDistribution' => $inboundEmail->get('caseDistribution'),
|
||||
'teamId' => $inboundEmail->get('teamId'),
|
||||
'userId' => $inboundEmail->get('assignToUserId'),
|
||||
);
|
||||
$case = $this->emailToCase($email, $params);
|
||||
$user = $this->getEntityManager()->getEntity('User', $case->get('assignedUserId'));
|
||||
if ($inboundEmail->get('reply')) {
|
||||
$this->autoReply($inboundEmail, $email, $case, $user);
|
||||
|
||||
if ($maxSize) {
|
||||
if ($storage->getSize($id) > $maxSize * 1024 * 1024) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ($inboundEmail->get('reply')) {
|
||||
$user = $this->getEntityManager()->getEntity('User', $userId);
|
||||
$this->autoReply($inboundEmail, $email, $user);
|
||||
|
||||
$message = $storage->getMessage($id);
|
||||
|
||||
$email = $importer->importMessage($message, $userId, array($teamId));
|
||||
|
||||
if ($email) {
|
||||
if ($inboundEmail->get('createCase')) {
|
||||
$this->createCase($inboundEmail, $email);
|
||||
} else {
|
||||
if ($inboundEmail->get('reply')) {
|
||||
$user = $this->getEntityManager()->getEntity('User', $userId);
|
||||
$this->autoReply($inboundEmail, $email, $user);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($k == count($ids) - 1) {
|
||||
if ($message) {
|
||||
$dt = new \DateTime($message->date);
|
||||
if ($dt) {
|
||||
$dateSent = $dt->setTimezone(new \DateTimeZone('UTC'))->format('Y-m-d H:i:s');
|
||||
$lastDate = $dateSent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($k == self::PORTION_LIMIT - 1) {
|
||||
$lastUID = $storage->getUniqueId($id);
|
||||
break;
|
||||
}
|
||||
$k++;
|
||||
}
|
||||
|
||||
$result = true;
|
||||
$fetchData['lastUID'][$folder] = $lastUID;
|
||||
$fetchData['lastDate'][$folder] = $lastDate;
|
||||
|
||||
} catch (\Exception $e){
|
||||
// TODO log
|
||||
$inboundEmail->set('fetchData', json_encode($fetchData));
|
||||
$this->getEntityManager()->saveEntity($inboundEmail);
|
||||
}
|
||||
|
||||
return $result;
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function createCase($inboundEmail, $email)
|
||||
{
|
||||
if (preg_match('/\[#([0-9]+)[^0-9]*\]/', $email->get('name'), $m)) {
|
||||
$caseNumber = $m[1];
|
||||
$case = $this->getEntityManager()->getRepository('Case')->where(array(
|
||||
'number' => $caseNumber
|
||||
))->findOne();
|
||||
if ($case) {
|
||||
$email->set('parentType', 'Case');
|
||||
$email->set('parentId', $case->id);
|
||||
$this->getEntityManager()->saveEntity($email);
|
||||
$this->getServiceFactory()->create('Stream')->noteEmailReceived($case, $email);
|
||||
}
|
||||
} else {
|
||||
$params = array(
|
||||
'caseDistribution' => $inboundEmail->get('caseDistribution'),
|
||||
'teamId' => $inboundEmail->get('teamId'),
|
||||
'userId' => $inboundEmail->get('assignToUserId'),
|
||||
);
|
||||
$case = $this->emailToCase($email, $params);
|
||||
$user = $this->getEntityManager()->getEntity('User', $case->get('assignedUserId'));
|
||||
if ($inboundEmail->get('reply')) {
|
||||
$this->autoReply($inboundEmail, $email, $case, $user);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function assignRoundRobin($case, $team)
|
||||
@@ -373,123 +338,10 @@ class InboundEmail extends \Espo\Services\Record
|
||||
$this->getEntityManager()->saveEntity($email);
|
||||
|
||||
$case = $this->getEntityManager()->getEntity('Case', $case->id);
|
||||
|
||||
return $case;
|
||||
}
|
||||
|
||||
protected function getContentFromPart($part)
|
||||
{
|
||||
if ($part instanceof \Zend\Mime\Part) {
|
||||
$content = $part->getRawContent();
|
||||
if (strtolower($part->charset) != 'utf-8') {
|
||||
$content = mb_convert_encoding($content, 'UTF-8', $part->charset);
|
||||
}
|
||||
} else {
|
||||
$content = $part->getContent();
|
||||
|
||||
$encoding = null;
|
||||
|
||||
if (isset($part->contentTransferEncoding)) {
|
||||
$cteHeader = $part->getHeader('Content-Transfer-Encoding');
|
||||
$encoding = strtolower($cteHeader->getTransferEncoding());
|
||||
}
|
||||
|
||||
if ($encoding == 'base64') {
|
||||
$content = base64_decode($content);
|
||||
}
|
||||
|
||||
$charset = 'UTF-8';
|
||||
|
||||
if (isset($part->contentType)) {
|
||||
$ctHeader = $part->getHeader('Content-Type');
|
||||
$charsetParamValue = $ctHeader->getParameter('charset');
|
||||
if (!empty($charsetParamValue)) {
|
||||
$charset = strtoupper($charsetParamValue);
|
||||
}
|
||||
}
|
||||
|
||||
if ($charset !== 'UTF-8') {
|
||||
$content = mb_convert_encoding($content, 'UTF-8', $charset);
|
||||
}
|
||||
|
||||
if (isset($part->contentTransferEncoding)) {
|
||||
$cteHeader = $part->getHeader('Content-Transfer-Encoding');
|
||||
if ($cteHeader->getTransferEncoding() == 'quoted-printable') {
|
||||
$content = quoted_printable_decode($content);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $content;
|
||||
}
|
||||
|
||||
protected function importPartDataToEmail(\Espo\Entities\Email $email, $part, &$inlineIds = array())
|
||||
{
|
||||
try {
|
||||
$type = strtok($part->contentType, ';');
|
||||
$encoding = null;
|
||||
|
||||
switch ($type) {
|
||||
case 'text/plain':
|
||||
$content = $this->getContentFromPart($part);
|
||||
if (!$email->get('body')) {
|
||||
$email->set('body', $content);
|
||||
}
|
||||
$email->set('bodyPlain', $content);
|
||||
break;
|
||||
case 'text/html':
|
||||
$content = $this->getContentFromPart($part);
|
||||
$email->set('body', $content);
|
||||
$email->set('isHtml', true);
|
||||
break;
|
||||
default:
|
||||
$content = $part->getContent();
|
||||
$disposition = null;
|
||||
|
||||
$fileName = null;
|
||||
$contentId = null;
|
||||
|
||||
if (isset($part->ContentDisposition)) {
|
||||
if (strpos($part->ContentDisposition, 'attachment') === 0) {
|
||||
if (preg_match('/filename="?([^"]+)"?/i', $part->ContentDisposition, $m)) {
|
||||
$fileName = $m[1];
|
||||
$disposition = 'attachment';
|
||||
}
|
||||
} else if (strpos($part->ContentDisposition, 'inline') === 0) {
|
||||
$contentId = trim($part->contentID, '<>');
|
||||
$fileName = $contentId;
|
||||
$disposition = 'inline';
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($part->contentTransferEncoding)) {
|
||||
$encoding = strtolower($part->getHeader('Content-Transfer-Encoding')->getTransferEncoding());
|
||||
}
|
||||
|
||||
$attachment = $this->getEntityManager()->getEntity('Attachment');
|
||||
$attachment->set('name', $fileName);
|
||||
$attachment->set('type', $type);
|
||||
|
||||
$this->getEntityManager()->saveEntity($attachment);
|
||||
|
||||
$path = 'data/upload/' . $attachment->id;
|
||||
|
||||
if ($encoding == 'base64') {
|
||||
$content = base64_decode($content);
|
||||
}
|
||||
$this->getFileManager()->putContents($path, $content);
|
||||
|
||||
if ($disposition == 'attachment') {
|
||||
$attachmentsIds = $email->get('attachmentsIds');
|
||||
$attachmentsIds[] = $attachment->id;
|
||||
$email->set('attachmentsIds', $attachmentsIds);
|
||||
} else if ($disposition == 'inline') {
|
||||
$inlineIds[$contentId] = $attachment->id;
|
||||
}
|
||||
}
|
||||
} catch (\Exception $e){
|
||||
// TODO log
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected function autoReply($inboundEmail, $email, $case = null, $user = null)
|
||||
{
|
||||
try {
|
||||
@@ -551,11 +403,11 @@ class InboundEmail extends \Espo\Services\Record
|
||||
}
|
||||
|
||||
$this->getEntityManager()->removeEntity($reply);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} catch (\Exception $e){
|
||||
// TODO log
|
||||
}
|
||||
} catch (\Exception $e) {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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\Modules\Crm\Services;
|
||||
|
||||
@@ -32,6 +32,70 @@ class Opportunity extends \Espo\Services\Record
|
||||
public function reportSalesPipeline($dateFrom, $dateTo)
|
||||
{
|
||||
$pdo = $this->getEntityManager()->getPDO();
|
||||
|
||||
$options = $this->getMetadata()->get('entityDefs.Opportunity.fields.stage.options');
|
||||
|
||||
$sql = "
|
||||
SELECT opportunity.stage AS `stage`, SUM(opportunity.amount * currency.rate) as `amount`
|
||||
FROM opportunity
|
||||
JOIN currency ON currency.id = opportunity.amount_currency
|
||||
WHERE
|
||||
opportunity.deleted = 0 AND
|
||||
opportunity.close_date >= ".$pdo->quote($dateFrom)." AND
|
||||
opportunity.close_date < ".$pdo->quote($dateTo)." AND
|
||||
opportunity.stage <> 'Closed Lost'
|
||||
GROUP BY opportunity.stage
|
||||
ORDER BY FIELD(opportunity.stage, '".implode("','", $options)."')
|
||||
";
|
||||
|
||||
$sth = $pdo->prepare($sql);
|
||||
$sth->execute();
|
||||
|
||||
$rows = $sth->fetchAll(\PDO::FETCH_ASSOC);
|
||||
|
||||
$result = array();
|
||||
foreach ($rows as $row) {
|
||||
$result[$row['stage']] = floatval($row['amount']);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function reportByLeadSource($dateFrom, $dateTo)
|
||||
{
|
||||
$pdo = $this->getEntityManager()->getPDO();
|
||||
|
||||
$sql = "
|
||||
SELECT opportunity.lead_source AS `leadSource`, SUM(opportunity.amount * currency.rate * opportunity.probability / 100) as `amount`
|
||||
FROM opportunity
|
||||
JOIN currency ON currency.id = opportunity.amount_currency
|
||||
WHERE
|
||||
opportunity.deleted = 0 AND
|
||||
opportunity.close_date >= ".$pdo->quote($dateFrom)." AND
|
||||
opportunity.close_date < ".$pdo->quote($dateTo)." AND
|
||||
opportunity.stage <> 'Closed Lost' AND
|
||||
opportunity.lead_source <> ''
|
||||
GROUP BY opportunity.lead_source
|
||||
";
|
||||
|
||||
$sth = $pdo->prepare($sql);
|
||||
$sth->execute();
|
||||
|
||||
$rows = $sth->fetchAll(\PDO::FETCH_ASSOC);
|
||||
|
||||
$result = array();
|
||||
foreach ($rows as $row) {
|
||||
$result[$row['leadSource']] = floatval($row['amount']);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function reportByStage($dateFrom, $dateTo)
|
||||
{
|
||||
$pdo = $this->getEntityManager()->getPDO();
|
||||
|
||||
$options = $this->getMetadata()->get('entityDefs.Opportunity.fields.stage.options');
|
||||
|
||||
$sql = "
|
||||
SELECT opportunity.stage AS `stage`, SUM(opportunity.amount * currency.rate) as `amount`
|
||||
@@ -43,7 +107,7 @@ class Opportunity extends \Espo\Services\Record
|
||||
opportunity.close_date < ".$pdo->quote($dateTo)." AND
|
||||
opportunity.stage <> 'Closed Lost'
|
||||
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')
|
||||
ORDER BY FIELD(opportunity.stage, '".implode("','", $options)."')
|
||||
";
|
||||
|
||||
$sth = $pdo->prepare($sql);
|
||||
@@ -58,6 +122,37 @@ class Opportunity extends \Espo\Services\Record
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function reportSalesByMonth($dateFrom, $dateTo)
|
||||
{
|
||||
$pdo = $this->getEntityManager()->getPDO();
|
||||
|
||||
$sql = "
|
||||
SELECT DATE_FORMAT(opportunity.close_date, '%Y-%m') AS `month`, SUM(opportunity.amount * currency.rate) as `amount`
|
||||
FROM opportunity
|
||||
JOIN currency ON currency.id = opportunity.amount_currency
|
||||
WHERE
|
||||
opportunity.deleted = 0 AND
|
||||
opportunity.close_date >= ".$pdo->quote($dateFrom)." AND
|
||||
opportunity.close_date < ".$pdo->quote($dateTo)." AND
|
||||
opportunity.stage = 'Closed Won'
|
||||
|
||||
GROUP BY DATE_FORMAT(opportunity.close_date, '%Y-%m')
|
||||
ORDER BY opportunity.close_date
|
||||
";
|
||||
|
||||
$sth = $pdo->prepare($sql);
|
||||
$sth->execute();
|
||||
|
||||
$rows = $sth->fetchAll(\PDO::FETCH_ASSOC);
|
||||
|
||||
$result = array();
|
||||
foreach ($rows as $row) {
|
||||
$result[$row['month']] = floatval($row['amount']);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -95,6 +95,31 @@ class EmailAddress extends \Espo\Core\ORM\Repositories\RDB
|
||||
return $this->where(array('lower' => strtolower($address)))->findOne();
|
||||
}
|
||||
|
||||
public function getEntityByAddress($address)
|
||||
{
|
||||
$pdo = $this->getEntityManager()->getPDO();
|
||||
$sql = "
|
||||
SELECT entity_email_address.entity_type AS 'entityType', entity_email_address.entity_id AS 'entityId'
|
||||
FROM entity_email_address
|
||||
JOIN email_address ON email_address.id = entity_email_address.email_address_id AND email_address.deleted = 0
|
||||
WHERE
|
||||
email_address.lower = ".$pdo->quote(strtolower($address))." AND
|
||||
entity_email_address.deleted = 0
|
||||
ORDER BY entity_email_address.primary DESC, FIELD(entity_email_address.entity_type, 'User', 'Contact', 'Lead', 'Account')
|
||||
";
|
||||
|
||||
$sth = $pdo->prepare($sql);
|
||||
$sth->execute();
|
||||
while ($row = $sth->fetch()) {
|
||||
if (!empty($row['entityType']) && !empty($row['entityId'])) {
|
||||
$entity = $this->getEntityManager()->getEntity($row['entityType'], $row['entityId']);
|
||||
if ($entity) {
|
||||
return $entity;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function storeEntityEmailAddress(Entity $entity)
|
||||
{
|
||||
$email = trim($entity->get('emailAddress'));
|
||||
|
||||
39
application/Espo/Repositories/ExternalAccount.php
Normal file
39
application/Espo/Repositories/ExternalAccount.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?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\Repositories;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class ExternalAccount extends \Espo\Core\ORM\Repositories\RDB
|
||||
{
|
||||
public function get($id = null)
|
||||
{
|
||||
$entity = parent::get($id);
|
||||
if (empty($entity) && !empty($id)) {
|
||||
$entity = $this->get();
|
||||
$entity->id = $id;
|
||||
}
|
||||
return $entity;
|
||||
}
|
||||
}
|
||||
|
||||
39
application/Espo/Repositories/Integration.php
Normal file
39
application/Espo/Repositories/Integration.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?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\Repositories;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class Integration extends \Espo\Core\ORM\Repositories\RDB
|
||||
{
|
||||
public function get($id = null)
|
||||
{
|
||||
$entity = parent::get($id);
|
||||
if (empty($entity) && !empty($id)) {
|
||||
$entity = $this->get();
|
||||
$entity->id = $id;
|
||||
}
|
||||
return $entity;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,13 +29,14 @@
|
||||
"Field Manager": "Felder anpassen",
|
||||
"User Interface": "Benutzeroberfläche",
|
||||
"Auth Tokens": "Auth Tokens",
|
||||
"Authentication": "Authentication"
|
||||
"Authentication": "Authentifizierung:",
|
||||
"Currency": "Währung"
|
||||
},
|
||||
"layouts": {
|
||||
"list": "Liste",
|
||||
"detail": "Detail",
|
||||
"listSmall": "List (Small)",
|
||||
"detailSmall": "Detail (Small)",
|
||||
"listSmall": "Liste (Klein)",
|
||||
"detailSmall": "Detail (Klein)",
|
||||
"filters": "Suchfilter",
|
||||
"massUpdate": "Massenänderung",
|
||||
"relationships": "Beziehungen"
|
||||
@@ -51,7 +52,7 @@
|
||||
"bool": "Bool",
|
||||
"currency": "Währung",
|
||||
"date": "Datum",
|
||||
"datetime": "Datum/Zeit",
|
||||
"datetime": "Datum\/Zeit",
|
||||
"email": "E-Mail",
|
||||
"enum": "Einfachauswahl",
|
||||
"enumInt": "Einfachauswahl Ganzzahlwerte",
|
||||
@@ -76,9 +77,9 @@
|
||||
"required": "Erforderlich",
|
||||
"default": "Standard",
|
||||
"maxLength": "Maximallänge",
|
||||
"options": "Options (raw values, not translated)",
|
||||
"after": "After (field)",
|
||||
"before": "Before (field)",
|
||||
"options": "Optionen (Datenbank Werte, nicht übersetzt)",
|
||||
"after": "Nach (Feld)",
|
||||
"before": "Vor (Feld)",
|
||||
"link": "Link",
|
||||
"field": "Feld",
|
||||
"min": "Min",
|
||||
@@ -87,8 +88,8 @@
|
||||
"previewSize": "Vorschau Größe"
|
||||
},
|
||||
"messages": {
|
||||
"upgradeVersion": "Ihr EspoCRM wird nun auf Version <strong>{version}</strong> aktualisiert. Dies kann eine Weile dauern.",
|
||||
"upgradeDone": "Ihr EspoCRM wurde auf Version <strong>{version}</strong> aktualisiert. Bitte aktualisieren Sie Ihren Browser.",
|
||||
"upgradeVersion": "Ihr EspoCRM wird nun auf Version <strong>{version}<\/strong> aktualisiert. Dies kann eine Weile dauern.",
|
||||
"upgradeDone": "Ihr EspoCRM wurde auf Version <strong>{version}<\/strong> aktualisiert. Bitte aktualisieren Sie Ihren Browser.",
|
||||
"upgradeBackup": "Wir empfehlen, vor der Aktualisierung von EspoCRM Verzeichnis sowie Datenbank zu sichern.",
|
||||
"thousandSeparatorEqualsDecimalMark": "Das Tausendertrennzeichen kann nicht gleich dem Dezimaltrennzeichen sein",
|
||||
"userHasNoEmailAddress": "Der Benutzer hat keine E-Mail-Adresse.",
|
||||
@@ -109,11 +110,12 @@
|
||||
"inboundEmails": "IMAP Gruppen E-Mail Konten. E-Mail Import und E-Mail für Fälle.",
|
||||
"emailTemplates": "Vorlagen für ausgehende E-Mails.",
|
||||
"import": "Datenimport aus CSV Datei.",
|
||||
"layoutManager": "Customize layouts (list, detail, edit, search, mass update).",
|
||||
"layoutManager": "Layouts anpassen (Liste, Detailansicht, Bearbeitungsansicht, Suche, Massenaktualisierung).",
|
||||
"fieldManager": "Neue Felder erstellen oder bestehende anpassen.",
|
||||
"userInterface": "Benutzeroberfläche anpassen.",
|
||||
"authTokens": "Active auth sessions. IP address and last access date.",
|
||||
"authentication": "Authentication setttings."
|
||||
"authTokens": "Aktive Auth Sessions. IP Adresse und letztes Zugriffsdatum",
|
||||
"authentication": "Authentifizierungs Einstellungen.",
|
||||
"currency": "Währungseinstellungen und Kurse"
|
||||
},
|
||||
"options": {
|
||||
"previewSize": {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"fields": {
|
||||
"user": "Benutzer",
|
||||
"ipAddress": "IP Address",
|
||||
"lastAccess": "Last Access Date",
|
||||
"createdAt": "Login Date"
|
||||
"ipAddress": "IP Adresse",
|
||||
"lastAccess": "Letztes Zugriffsdatum",
|
||||
"createdAt": "Login Datum"
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"parent": "Bezieht sich auf",
|
||||
"status": "Status",
|
||||
"dateSent": "Sendedatum",
|
||||
"from": "Von ",
|
||||
"from": "Von",
|
||||
"to": "An",
|
||||
"cc": "CC",
|
||||
"bcc": "BCC",
|
||||
@@ -28,5 +28,9 @@
|
||||
"labels": {
|
||||
"Create Email": "E-Mail archivieren",
|
||||
"Compose": "Erstellen"
|
||||
},
|
||||
"presetFilters": {
|
||||
"sent": "Gesendet",
|
||||
"archived": "Archiviert"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,15 +31,15 @@
|
||||
"Loading...": "Lade...",
|
||||
"Uploading...": "Lade hoch...",
|
||||
"Sending...": "Wird gesendet...",
|
||||
"Removed": "Removed",
|
||||
"Removed": "Entfernt",
|
||||
"Posted": "Geposted",
|
||||
"Linked": "Verlinkt",
|
||||
"Unlinked": "Verknüpfung gelöscht",
|
||||
"Access denied": "Zugriff verweigert",
|
||||
"Access": "Zugang",
|
||||
"Are you sure?": "Are you sure?",
|
||||
"Are you sure?": "Sind Sie sicher?",
|
||||
"Record has been removed": "Datensatz wurde gelöscht",
|
||||
"Wrong username/password": "Falscher Benutzername/Passwort",
|
||||
"Wrong username/password": "Falscher Benutzername\/Passwort",
|
||||
"Post cannot be empty": "Notiz dard nicht leer sein",
|
||||
"Removing...": "Entferne...",
|
||||
"Unlinking...": "Lösche Verknüpfung...",
|
||||
@@ -109,7 +109,14 @@
|
||||
"You": "Sie",
|
||||
"you": "Sie",
|
||||
"change": "ändern",
|
||||
"Primary": "Primär"
|
||||
"Primary": "Primär",
|
||||
"Save Filters": "Filter speichern",
|
||||
"Administration": "Administration",
|
||||
"Run Import": "Import durchführen",
|
||||
"Duplicate": "Duplizieren",
|
||||
"Notifications": "Benachrichtigungen",
|
||||
"Mark all read": "Alle als gelesen markieren",
|
||||
"See more": "Mehr anzeigen"
|
||||
},
|
||||
"messages": {
|
||||
"notModified": "Sie haben den Datensatz nicht geändert",
|
||||
@@ -119,13 +126,19 @@
|
||||
"fieldShouldBeFloat": "{field} muss eine gültige Fließkomma Zahl sein",
|
||||
"fieldShouldBeInt": "{field} muss eine gültige Ganzzahl sein",
|
||||
"fieldShouldBeDate": "{field} muss ein gültiges Datum sein",
|
||||
"fieldShouldBeDatetime": "{field} muss ein gültiges Datum/Zeit Feld sein",
|
||||
"fieldShouldBeDatetime": "{field} muss ein gültiges Datum\/Zeit Feld sein",
|
||||
"fieldShouldAfter": "{field} muss nach {otherField} sein",
|
||||
"fieldShouldBefore": "{field} muss vor {otherField} sein",
|
||||
"fieldShouldBeBetween": "{field} muss zwischen {min} und {max} sein",
|
||||
"fieldShouldBeLess": "{field} muss kleiner als {value} sein",
|
||||
"fieldShouldBeGreater": "{field} muss größer als {value} sein",
|
||||
"fieldBadPasswordConfirm": "{field} falsch bestätigt"
|
||||
"fieldBadPasswordConfirm": "{field} falsch bestätigt",
|
||||
"assignmentEmailNotificationSubject": "EspoCRM {entityType}: {Entity.name}",
|
||||
"assignmentEmailNotificationBody": "{assignerUserName} hat {entityType} '{Entity.name}' an Sie zugewiesen {recordUrl}",
|
||||
"confirmation": "Sind Sie sicher?",
|
||||
"removeRecordConfirmation": "Sind Sie sicher, dass Sie den Eintrag entfernen wollen?",
|
||||
"unlinkRecordConfirmation": "Sind Sie sicher dass Sie diese Beziehung lösen möchten?",
|
||||
"removeSelectedRecordsConfirmation": "Sind Sie sicher dass Sie die ausgewählten Sätze entfernen möchten?"
|
||||
},
|
||||
"boolFilters": {
|
||||
"onlyMy": "Nur Meine",
|
||||
@@ -148,7 +161,7 @@
|
||||
"title": "Funktion",
|
||||
"dateFrom": "Von Datum",
|
||||
"dateTo": "Bis Datum",
|
||||
"autorefreshInterval": "Aktualisierungsintervall ",
|
||||
"autorefreshInterval": "Aktualisierungsintervall",
|
||||
"displayRecords": "Sätze anzeigen"
|
||||
},
|
||||
"links": {
|
||||
@@ -175,16 +188,16 @@
|
||||
"postThis": "{user} hat notiert",
|
||||
"attachThis": "{user} hat hinzugefügt",
|
||||
"statusThis": "{user} hat {field} aktualiisiert",
|
||||
"updateThis": "{user} hat diese(s/n) {entityType} aktualisiert",
|
||||
"updateThis": "{user} hat diese(s\/n) {entityType} aktualisiert",
|
||||
"createRelatedThis": "{user} hat {relatedEntityType} {relatedEntity} verbunden mit diesem (r) {entityType} hinzugefügt",
|
||||
"emailReceivedThis": "{entity} wurde empfangen"
|
||||
},
|
||||
"lists": {
|
||||
"monthNames": ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
|
||||
"monthNamesShort": ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
|
||||
"dayNames": ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
|
||||
"dayNamesShort": ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
|
||||
"dayNamesMin": ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"]
|
||||
"monthNames": ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"],
|
||||
"monthNamesShort": ["Jan", "Feb", "Mär", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"],
|
||||
"dayNames": ["Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"],
|
||||
"dayNamesShort": ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"],
|
||||
"dayNamesMin": ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"]
|
||||
},
|
||||
"options": {
|
||||
"salutationName": {
|
||||
@@ -194,84 +207,87 @@
|
||||
"Drs.": "Drs."
|
||||
},
|
||||
"language": {
|
||||
"af_ZA": "Afrikaans",
|
||||
"az_AZ": "Aserbaidschanisch",
|
||||
"be_BY": "Weissrussisch",
|
||||
"bg_BG": "Bulgarisch",
|
||||
"bn_IN": "Benglaisch",
|
||||
"bs_BA": "Bosnisch",
|
||||
"ca_ES": "Katalanisch",
|
||||
"cs_CZ": "Tschechisch",
|
||||
"cy_GB": "Walisisch",
|
||||
"da_DK": "Dänisch",
|
||||
"de_DE": "Deutsch",
|
||||
"el_GR": "Griechisch",
|
||||
"en_GB":"English (UK)",
|
||||
"en_US":"English (US)",
|
||||
"es_ES":"Spanish (Spain)",
|
||||
"et_EE": "Estnisch",
|
||||
"eu_ES": "Baskisch",
|
||||
"fa_IR": "Persisch",
|
||||
"fi_FI": "Finnisch",
|
||||
"fo_FO": "Färöisch",
|
||||
"fr_CA":"French (Canada)",
|
||||
"fr_FR":"French (France)",
|
||||
"ga_IE": "Irisch",
|
||||
"gl_ES": "Galizisch",
|
||||
"gn_PY": "Guarani",
|
||||
"he_IL": "Hebräisch",
|
||||
"hi_IN": "Hindi",
|
||||
"hr_HR": "Kroatisch",
|
||||
"hu_HU": "Ungarisch",
|
||||
"hy_AM": "Armenisch",
|
||||
"id_ID": "Indonesisch",
|
||||
"is_IS": "Isländisch",
|
||||
"it_IT": "Italienisch",
|
||||
"ja_JP": "Japanisch",
|
||||
"ka_GE": "Georgisch",
|
||||
"km_KH": "Khmer",
|
||||
"ko_KR": "Koreanisch",
|
||||
"ku_TR": "Kurdisch",
|
||||
"lt_LT": "Litauisch",
|
||||
"lv_LV": "Lettisch",
|
||||
"mk_MK": "Mazedonisch",
|
||||
"ml_IN": "Malayalam",
|
||||
"ms_MY": "Malaiisch",
|
||||
"nb_NO": "Norwegisch Bokmál",
|
||||
"nn_NO": "Norwegisch Nynorsk",
|
||||
"ne_NP": "Nepali",
|
||||
"nl_NL": "Niederländisch",
|
||||
"pa_IN": "Punjabi",
|
||||
"pl_PL": "Polnisch",
|
||||
"ps_AF": "Pashto",
|
||||
"pt_BR":"Portuguese (Brazil)",
|
||||
"pt_PT":"Portuguese (Portugal)",
|
||||
"ro_RO": "Rumänisch",
|
||||
"ru_RU": "Russisch",
|
||||
"sk_SK": "Slowakisch",
|
||||
"sl_SI": "Slowenisch",
|
||||
"sq_AL": "Albanisch",
|
||||
"sr_RS": "Serbisch",
|
||||
"sv_SE": "Schwedisch",
|
||||
"sw_KE": "Suaheli",
|
||||
"ta_IN": "Tamil",
|
||||
"te_IN": "Telugu",
|
||||
"th_TH": "Thailändisch",
|
||||
"tl_PH": "Tagalog",
|
||||
"tr_TR": "Tükisch",
|
||||
"uk_UA": "Ukrainisch",
|
||||
"ur_PK": "Urdu",
|
||||
"vi_VN": "Vietnamesisch",
|
||||
"zh_CN":"Simplified Chinese (China)",
|
||||
"zh_HK":"Traditional Chinese (Hong Kong)",
|
||||
"zh_TW":"Traditional Chinese (Taiwan)"
|
||||
"af_ZA":"Afrikaans",
|
||||
"az_AZ":"Aserbaidschanisch",
|
||||
"be_BY":"Weissrussisch",
|
||||
"bg_BG":"Bulgarisch",
|
||||
"bn_IN":"Benglaisch",
|
||||
"bs_BA":"Bosnisch",
|
||||
"ca_ES":"Katalanisch",
|
||||
"cs_CZ":"Tschechisch",
|
||||
"cy_GB":"Walisisch",
|
||||
"da_DK":"Dänisch",
|
||||
"de_DE":"Deutsch",
|
||||
"el_GR":"Griechisch",
|
||||
"en_GB":"Englisch (UK)",
|
||||
"en_US":"Englisch (US)",
|
||||
"es_ES":"Spanisch (ES)",
|
||||
"et_EE":"Estnisch",
|
||||
"eu_ES":"Baskisch",
|
||||
"fa_IR":"Persisch",
|
||||
"fi_FI":"Finnisch",
|
||||
"fo_FO":"Färöisch",
|
||||
"fr_CA":"Französisch (CN)",
|
||||
"fr_FR":"Französisch (FR)",
|
||||
"ga_IE":"Irisch",
|
||||
"gl_ES":"Galizisch",
|
||||
"gn_PY":"Guarani",
|
||||
"he_IL":"Hebräisch",
|
||||
"hi_IN":"Hindi",
|
||||
"hr_HR":"Kroatisch",
|
||||
"hu_HU":"Ungarisch",
|
||||
"hy_AM":"Armenisch",
|
||||
"id_ID":"Indonesisch",
|
||||
"is_IS":"Isländisch",
|
||||
"it_IT":"Italienisch",
|
||||
"ja_JP":"Japanisch",
|
||||
"ka_GE":"Georgisch",
|
||||
"km_KH":"Khmer",
|
||||
"ko_KR":"Koreanisch",
|
||||
"ku_TR":"Kurdisch",
|
||||
"lt_LT":"Litauisch",
|
||||
"lv_LV":"Lettisch",
|
||||
"mk_MK":"Mazedonisch",
|
||||
"ml_IN":"Malayalam",
|
||||
"ms_MY":"Malaiisch",
|
||||
"nb_NO":"Norwegisch Bokmál",
|
||||
"nn_NO":"Norwegisch Nynorsk",
|
||||
"ne_NP":"Nepali",
|
||||
"nl_NL":"Niederländisch",
|
||||
"pa_IN":"Punjabi",
|
||||
"pl_PL":"Polnisch",
|
||||
"ps_AF":"Pashto",
|
||||
"pt_BR":"Portugiesisch (BR)",
|
||||
"pt_PT":"Portugiesisch (PT)",
|
||||
"ro_RO":"Rumänisch",
|
||||
"ru_RU":"Russisch",
|
||||
"sk_SK":"Slowakisch",
|
||||
"sl_SI":"Slowenisch",
|
||||
"sq_AL":"Albanisch",
|
||||
"sr_RS":"Serbisch",
|
||||
"sv_SE":"Schwedisch",
|
||||
"sw_KE":"Suaheli",
|
||||
"ta_IN":"Tamil",
|
||||
"te_IN":"Telugu",
|
||||
"th_TH":"Thailändisch",
|
||||
"tl_PH":"Tagalog",
|
||||
"tr_TR":"Tükisch",
|
||||
"uk_UA":"Ukrainisch",
|
||||
"ur_PK":"Urdu",
|
||||
"vi_VN":"Vietnamesisch",
|
||||
"zh_CN":"Chinesisch vereinfacht (CN)",
|
||||
"zh_HK":"Chinesisch traditionell (HK)",
|
||||
"zh_TW":"Chinesisch traditionell (TW)"
|
||||
},
|
||||
"dateSearchRanges": {
|
||||
"on": "Am",
|
||||
"notOn": "Nicht am",
|
||||
"after": "Nach",
|
||||
"before": "Vor",
|
||||
"between": "Zwischen"
|
||||
"between": "Zwischen",
|
||||
"today": "Heute",
|
||||
"past": "Vergangenheit",
|
||||
"future": "Zukunft"
|
||||
},
|
||||
"intSearchRanges": {
|
||||
"equals": "Gleich",
|
||||
@@ -289,108 +305,115 @@
|
||||
"2": "2 Minuten",
|
||||
"5": "5 Minuten",
|
||||
"10": "10 Minuten"
|
||||
},
|
||||
"phoneNumber": {
|
||||
"Mobile": "Telefon Mobil",
|
||||
"Office": "Büro",
|
||||
"Fax": "Fax",
|
||||
"Home": "Startseite",
|
||||
"Other": "Andere"
|
||||
}
|
||||
},
|
||||
"sets": {
|
||||
"summernote": {
|
||||
"NOTICE": "Sie finden die Übersetzung hier: https://github.com/HackerWins/summernote/tree/master/lang",
|
||||
"NOTICE": "Sie finden die Übersetzung hier: https:\/\/github.com\/HackerWins\/summernote\/tree\/master\/lang",
|
||||
"font":{
|
||||
"bold": "Fett",
|
||||
"italic": "Kursiv",
|
||||
"underline": "Unterstrichen",
|
||||
"strike": "Durchgestrichen",
|
||||
"clear": "Font Stil entfernen",
|
||||
"height": "Zeilenhöhe",
|
||||
"name": "Schriftfamilie",
|
||||
"size": "Schriftgröße"
|
||||
"bold":"Fett",
|
||||
"italic":"Kursiv",
|
||||
"underline":"Unterstrichen",
|
||||
"strike":"Durchgestrichen",
|
||||
"clear":"Font Stil entfernen",
|
||||
"height":"Zeilenhöhe",
|
||||
"name":"Schriftfamilie",
|
||||
"size":"Schriftgröße"
|
||||
},
|
||||
"image":{
|
||||
"image": "Bild",
|
||||
"insert": "Bild einfügen",
|
||||
"resizeFull": "Originalgröße",
|
||||
"resizeHalf": "Größe 1/2",
|
||||
"resizeQuarter": "Größe 1/4",
|
||||
"floatLeft": "Linksbündig",
|
||||
"floatRight": "Rechtsbündig",
|
||||
"floatNone": "Kein Textfluss",
|
||||
"dragImageHere": "Ziehen Sie ein Bild mit der Maus hierher",
|
||||
"selectFromFiles": "Wählen Sie eine Datei aus",
|
||||
"url": "Grafik URL",
|
||||
"remove": "Grafik entfernen"
|
||||
"image":"Bild",
|
||||
"insert":"Bild einfügen",
|
||||
"resizeFull":"Originalgröße",
|
||||
"resizeHalf":"Größe 1\/2",
|
||||
"resizeQuarter":"Größe 1\/4",
|
||||
"floatLeft":"Linksbündig",
|
||||
"floatRight":"Rechtsbündig",
|
||||
"floatNone":"Kein Textfluss",
|
||||
"dragImageHere":"Ziehen Sie ein Bild mit der Maus hierher",
|
||||
"selectFromFiles":"Wählen Sie eine Datei aus",
|
||||
"url":"Grafik URL",
|
||||
"remove":"Grafik entfernen"
|
||||
},
|
||||
"link":{
|
||||
"link": "Link",
|
||||
"insert": "Link einfügen",
|
||||
"unlink": "Link entfernen",
|
||||
"edit": "Bearbeiten",
|
||||
"textToDisplay": "Anzeigetext",
|
||||
"url":"To what URL should this link go?",
|
||||
"openInNewWindow": "In einem neuen Fenster öffnen"
|
||||
"link":"Link",
|
||||
"insert":"Link einfügen",
|
||||
"unlink":"Link entfernen",
|
||||
"edit":"Bearbeiten",
|
||||
"textToDisplay":"Anzeigetext",
|
||||
"url":"Ziel des Links?",
|
||||
"openInNewWindow":"In einem neuen Fenster öffnen"
|
||||
},
|
||||
"video":{
|
||||
"video": "Video",
|
||||
"videoLink": "Video Link",
|
||||
"insert": "Video einfügen",
|
||||
"video":"Video",
|
||||
"videoLink":"Video Link",
|
||||
"insert":"Video einfügen",
|
||||
"url":"Video URL?",
|
||||
"providers":"(YouTube, Vimeo, Vine, Instagram, or DailyMotion)"
|
||||
"providers":"(YouTube, Vimeo, Vine, Instagram oder DailyMotion)"
|
||||
},
|
||||
"table":{
|
||||
"table": "Tabelle"
|
||||
"table":"Tabelle"
|
||||
},
|
||||
"hr":{
|
||||
"insert": "Eine horizontale Linie einfügen"
|
||||
"insert":"Eine horizontale Linie einfügen"
|
||||
},
|
||||
"style":{
|
||||
"style": "Stil",
|
||||
"normal": "Normal",
|
||||
"blockquote": "Zitat",
|
||||
"pre": "Quellcode",
|
||||
"h1": "Überschrift 1",
|
||||
"h2": "Überschrift 2",
|
||||
"h3": "Überschrift 3",
|
||||
"h4": "Überschrift 4",
|
||||
"h5": "Überschrift 5",
|
||||
"h6": "Überschrift 6"
|
||||
"style":"Stil",
|
||||
"normal":"Normal",
|
||||
"blockquote":"Zitat",
|
||||
"pre":"Quellcode",
|
||||
"h1":"Überschrift 1",
|
||||
"h2":"Überschrift 2",
|
||||
"h3":"Überschrift 3",
|
||||
"h4":"Überschrift 4",
|
||||
"h5":"Überschrift 5",
|
||||
"h6":"Überschrift 6"
|
||||
},
|
||||
"lists":{
|
||||
"unordered": "Unsortierte Liste",
|
||||
"ordered": "Nummerierte Liste"
|
||||
"unordered":"Unsortierte Liste",
|
||||
"ordered":"Nummerierte Liste"
|
||||
},
|
||||
"options":{
|
||||
"help": "Hilfe",
|
||||
"fullscreen": "Vollbild",
|
||||
"codeview": "HTML-Code anzeigen"
|
||||
"help":"Hilfe",
|
||||
"fullscreen":"Vollbild",
|
||||
"codeview":"HTML-Code anzeigen"
|
||||
},
|
||||
"paragraph":{
|
||||
"paragraph": "Absatz",
|
||||
"outdent": "Ausrückung",
|
||||
"indent": "Einrückung",
|
||||
"left": "Links ausrichten",
|
||||
"center": "Zentriert ausrichten",
|
||||
"right": "Rechts ausrichten",
|
||||
"justify": "Blocksatz"
|
||||
"paragraph":"Absatz",
|
||||
"outdent":"Ausrückung",
|
||||
"indent":"Einrückung",
|
||||
"left":"Links ausrichten",
|
||||
"center":"Zentriert ausrichten",
|
||||
"right":"Rechts ausrichten",
|
||||
"justify":"Blocksatz"
|
||||
},
|
||||
"color":{
|
||||
"recent": "Letzte Farbe",
|
||||
"more": "Mehr Farben",
|
||||
"background": "Hintergrundfarbe",
|
||||
"foreground": "Schriftfarbe",
|
||||
"transparent": "Transparenz",
|
||||
"setTransparent": "Transparenz setzen",
|
||||
"reset": "Zurücksetzen",
|
||||
"resetToDefault": "Zurücksetzen auf Standard"
|
||||
"recent":"Letzte Farbe",
|
||||
"more":"Mehr Farben",
|
||||
"background":"Hintergrundfarbe",
|
||||
"foreground":"Schriftfarbe",
|
||||
"transparent":"Transparenz",
|
||||
"setTransparent":"Transparenz setzen",
|
||||
"reset":"Zurücksetzen",
|
||||
"resetToDefault":"Zurücksetzen auf Standard"
|
||||
},
|
||||
"shortcut":{
|
||||
"shortcuts": "Tastaturkürzel",
|
||||
"close": "Schließen",
|
||||
"textFormatting": "Textformatierung",
|
||||
"action": "Aktion",
|
||||
"paragraphFormatting": "Absatzformatierung",
|
||||
"documentStyle": "Dokumentenstil"
|
||||
"shortcuts":"Tastaturkürzel",
|
||||
"close":"Schließen",
|
||||
"textFormatting":"Textformatierung",
|
||||
"action":"Aktion",
|
||||
"paragraphFormatting":"Absatzformatierung",
|
||||
"documentStyle":"Dokumentenstil"
|
||||
},
|
||||
"history":{
|
||||
"undo": "Rückgängig",
|
||||
"redo": "Wiederholen"
|
||||
"undo":"Rückgängig",
|
||||
"redo":"Wiederholen"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user