diff --git a/.gitignore b/.gitignore index deefd2c21a..9574cb7ee2 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ /client /test.php /main.html +/frontend/client/css/bootstrap.css /tests/testData/cache/* composer.phar vendor/ diff --git a/Gruntfile.js b/Gruntfile.js index d2cfd1fb5c..a892636cf7 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -1,245 +1,245 @@ module.exports = function (grunt) { - var jsFilesToMinify = [ - 'client/lib/jquery-2.0.2.min.js', - 'client/lib/underscore-min.js', - 'client/lib/backbone-min.js', - 'client/lib/handlebars.js', - 'client/lib/base64.js', - 'client/lib/jquery-ui.min.js', - 'client/lib/moment.min.js', - 'client/lib/moment-timezone-with-data.min.js', - 'client/lib/jquery.timepicker.min.js', - 'client/lib/jquery.autocomplete.js', - 'client/lib/bootstrap.min.js', - 'client/lib/bootstrap-datepicker.js', - 'client/lib/bull.min.js', - 'client/src/namespace.js', - 'client/src/exceptions.js', - 'client/src/app.js', - 'client/src/utils.js', - 'client/src/storage.js', - 'client/src/loader.js', - 'client/src/pre-loader.js', - 'client/src/ui.js', - 'client/src/acl.js', - 'client/src/model.js', - 'client/src/model-offline.js', - 'client/src/metadata.js', - 'client/src/language.js', - 'client/src/cache.js', - 'client/src/controller.js', - 'client/src/router.js', - 'client/src/date-time.js', - 'client/src/field-manager.js', - 'client/src/search-manager.js', - 'client/src/collection.js', - 'client/src/multi-collection.js', - 'client/src/view-helper.js', - 'client/src/layout-manager.js', - 'client/src/model-factory.js', - 'client/src/collection-factory.js', - 'client/src/models/settings.js', - 'client/src/models/user.js', - 'client/src/models/preferences.js', - 'client/src/controllers/base.js', - 'client/src/view.js', - ]; - - grunt.initConfig({ - pkg: grunt.file.readJSON('package.json'), - - mkdir: { - tmp: { - options: { - mode: 0775, - create: [ - 'build/tmp', - ] - }, + var jsFilesToMinify = [ + 'client/lib/jquery-2.0.2.min.js', + 'client/lib/underscore-min.js', + 'client/lib/backbone-min.js', + 'client/lib/handlebars.js', + 'client/lib/base64.js', + 'client/lib/jquery-ui.min.js', + 'client/lib/moment.min.js', + 'client/lib/moment-timezone-with-data.min.js', + 'client/lib/jquery.timepicker.min.js', + 'client/lib/jquery.autocomplete.js', + 'client/lib/bootstrap.min.js', + 'client/lib/bootstrap-datepicker.js', + 'client/lib/bull.min.js', + 'client/src/namespace.js', + 'client/src/exceptions.js', + 'client/src/app.js', + 'client/src/utils.js', + 'client/src/storage.js', + 'client/src/loader.js', + 'client/src/pre-loader.js', + 'client/src/ui.js', + 'client/src/acl.js', + 'client/src/model.js', + 'client/src/model-offline.js', + 'client/src/metadata.js', + 'client/src/language.js', + 'client/src/cache.js', + 'client/src/controller.js', + 'client/src/router.js', + 'client/src/date-time.js', + 'client/src/field-manager.js', + 'client/src/search-manager.js', + 'client/src/collection.js', + 'client/src/multi-collection.js', + 'client/src/view-helper.js', + 'client/src/layout-manager.js', + 'client/src/model-factory.js', + 'client/src/collection-factory.js', + 'client/src/models/settings.js', + 'client/src/models/user.js', + 'client/src/models/preferences.js', + 'client/src/controllers/base.js', + 'client/src/view.js', + ]; + + grunt.initConfig({ + pkg: grunt.file.readJSON('package.json'), + + mkdir: { + tmp: { + options: { + mode: 0775, + create: [ + 'build/tmp', + ] + }, - } - }, - clean: { - start: ['build/*'], - final: ['build/tmp'], - }, - less: { - bootstrap: { - options: { - yuicompress: true, - }, - files: { - 'frontend/client/css/bootstrap.css': 'frontend/less/espo/main.less', - }, - }, - }, - cssmin: { - minify: { - files: { - 'build/tmp/client/css/espo.min.css': [ - 'frontend/client/css/bootstrap.css', - 'frontend/client/css/datepicker.css', - 'frontend/client/css/jquery.timepicker.css', - ] - } - }, - }, - uglify: { - options: { - mangle: false, - banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n', - }, - 'build/tmp/client/espo.min.js': jsFilesToMinify.map(function (item) { - return 'frontend/' + item; - }) - }, - copy: { - frontendFolders: { - expand: true, - cwd: 'frontend/client', - src: [ - 'src/**', - 'res/**', - 'fonts/**', - 'cfg/**', - 'modules/**', - 'img/**', - 'css/**', - ], - dest: 'build/tmp/client', - }, - frontendHtml: { - src: 'frontend/html/reset.html', - dest: 'build/tmp/reset.html' - }, - frontendLib: { - expand: true, - dot: true, - cwd: 'frontend/client/lib', - src: '**', - dest: 'build/tmp/client/lib/', - }, - backend: { - expand: true, - dot: true, - src: [ - 'api/**', - 'application/**', - 'custom/**', - 'data/.data', - 'install/**', - 'vendor/**', - 'bootstrap.php', - 'cron.php', - 'rebuild.php', - 'index.php', - 'LICENSE.txt', - '.htaccess', - 'web.config', - ], - dest: 'build/tmp/', - }, - final: { - expand: true, - dot: true, - src: '**', - cwd: 'build/tmp', - dest: 'build/EspoCRM-<%= pkg.version %>/', - }, - }, - chmod: { - options: { - mode: '755' - }, - php: { - options: { - mode: '644' - }, - src: [ - 'build/EspoCRM-<%= pkg.version %>/**/*.php', - 'build/EspoCRM-<%= pkg.version %>/**/*.json', - 'build/EspoCRM-<%= pkg.version %>/**/*.config', - 'build/EspoCRM-<%= pkg.version %>/**/.htaccess', - 'build/EspoCRM-<%= pkg.version %>/client/**/*.js', - 'build/EspoCRM-<%= pkg.version %>/client/**/*.css', - 'build/EspoCRM-<%= pkg.version %>/client/**/*.tpl', - 'build/EspoCRM-<%= pkg.version %>/**/*.html', - 'build/EspoCRM-<%= pkg.version %>/**/*.txt', - ] - } - }, - replace: { - timestamp: { - options: { - patterns: [ - { - match: 'timestamp', - replacement: '<%= new Date().getTime() %>' - } - ] - }, - files: [ - { - src: 'frontend/html/main.html', - dest: 'build/tmp/main.html' - } - ] - }, - version: { - options: { - patterns: [ - { - match: 'version', - replacement: '<%= pkg.version %>' - } - ] - }, - files: [ - { - src: 'build/tmp/application/Espo/Core/defaults/config.php', - dest: 'build/tmp/application/Espo/Core/defaults/config.php' - } - ] - } - }, - compress: { - final: { - options: { - archive: 'build/EspoCRM-<%= pkg.version %>.zip', - mode: 'zip' - }, - src: ['**'], - cwd: 'build/EspoCRM-<%= pkg.version %>', - dest: 'EspoCRM-<%= pkg.version %>' - } - } - }); + } + }, + clean: { + start: ['build/*'], + final: ['build/tmp'], + }, + less: { + bootstrap: { + options: { + yuicompress: true, + }, + files: { + 'frontend/client/css/bootstrap.css': 'frontend/less/espo/main.less', + }, + }, + }, + cssmin: { + minify: { + files: { + 'build/tmp/client/css/espo.min.css': [ + 'frontend/client/css/bootstrap.css', + 'frontend/client/css/datepicker.css', + 'frontend/client/css/jquery.timepicker.css', + ] + } + }, + }, + uglify: { + options: { + mangle: false, + banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n', + }, + 'build/tmp/client/espo.min.js': jsFilesToMinify.map(function (item) { + return 'frontend/' + item; + }) + }, + copy: { + frontendFolders: { + expand: true, + cwd: 'frontend/client', + src: [ + 'src/**', + 'res/**', + 'fonts/**', + 'cfg/**', + 'modules/**', + 'img/**', + 'css/**', + ], + dest: 'build/tmp/client', + }, + frontendHtml: { + src: 'frontend/html/reset.html', + dest: 'build/tmp/reset.html' + }, + frontendLib: { + expand: true, + dot: true, + cwd: 'frontend/client/lib', + src: '**', + dest: 'build/tmp/client/lib/', + }, + backend: { + expand: true, + dot: true, + src: [ + 'api/**', + 'application/**', + 'custom/**', + 'data/.data', + 'install/**', + 'vendor/**', + 'bootstrap.php', + 'cron.php', + 'rebuild.php', + 'index.php', + 'LICENSE.txt', + '.htaccess', + 'web.config', + ], + dest: 'build/tmp/', + }, + final: { + expand: true, + dot: true, + src: '**', + cwd: 'build/tmp', + dest: 'build/EspoCRM-<%= pkg.version %>/', + }, + }, + chmod: { + options: { + mode: '755' + }, + php: { + options: { + mode: '644' + }, + src: [ + 'build/EspoCRM-<%= pkg.version %>/**/*.php', + 'build/EspoCRM-<%= pkg.version %>/**/*.json', + 'build/EspoCRM-<%= pkg.version %>/**/*.config', + 'build/EspoCRM-<%= pkg.version %>/**/.htaccess', + 'build/EspoCRM-<%= pkg.version %>/client/**/*.js', + 'build/EspoCRM-<%= pkg.version %>/client/**/*.css', + 'build/EspoCRM-<%= pkg.version %>/client/**/*.tpl', + 'build/EspoCRM-<%= pkg.version %>/**/*.html', + 'build/EspoCRM-<%= pkg.version %>/**/*.txt', + ] + } + }, + replace: { + timestamp: { + options: { + patterns: [ + { + match: 'timestamp', + replacement: '<%= new Date().getTime() %>' + } + ] + }, + files: [ + { + src: 'frontend/html/main.html', + dest: 'build/tmp/main.html' + } + ] + }, + version: { + options: { + patterns: [ + { + match: 'version', + replacement: '<%= pkg.version %>' + } + ] + }, + files: [ + { + src: 'build/tmp/application/Espo/Core/defaults/config.php', + dest: 'build/tmp/application/Espo/Core/defaults/config.php' + } + ] + } + }, + compress: { + final: { + options: { + archive: 'build/EspoCRM-<%= pkg.version %>.zip', + mode: 'zip' + }, + src: ['**'], + cwd: 'build/EspoCRM-<%= pkg.version %>', + dest: 'EspoCRM-<%= pkg.version %>' + } + } + }); - grunt.loadNpmTasks('grunt-contrib-clean'); - grunt.loadNpmTasks('grunt-mkdir'); - grunt.loadNpmTasks('grunt-contrib-less'); - grunt.loadNpmTasks('grunt-contrib-cssmin'); - grunt.loadNpmTasks('grunt-contrib-uglify'); - grunt.loadNpmTasks('grunt-contrib-copy'); - grunt.loadNpmTasks('grunt-replace'); - grunt.loadNpmTasks('grunt-contrib-compress'); - grunt.loadNpmTasks('grunt-chmod'); + grunt.loadNpmTasks('grunt-contrib-clean'); + grunt.loadNpmTasks('grunt-mkdir'); + grunt.loadNpmTasks('grunt-contrib-less'); + grunt.loadNpmTasks('grunt-contrib-cssmin'); + grunt.loadNpmTasks('grunt-contrib-uglify'); + grunt.loadNpmTasks('grunt-contrib-copy'); + grunt.loadNpmTasks('grunt-replace'); + grunt.loadNpmTasks('grunt-contrib-compress'); + grunt.loadNpmTasks('grunt-chmod'); - grunt.registerTask('default', [ - 'clean:start', - 'mkdir:tmp', - 'less', - 'cssmin', - 'uglify', - 'copy:frontendFolders', - 'copy:frontendHtml', - 'copy:frontendLib', - 'copy:backend', - 'replace', - 'copy:final', - 'chmod', - 'clean:final', - ]); + grunt.registerTask('default', [ + 'clean:start', + 'mkdir:tmp', + 'less', + 'cssmin', + 'uglify', + 'copy:frontendFolders', + 'copy:frontendHtml', + 'copy:frontendLib', + 'copy:backend', + 'replace', + 'copy:final', + 'chmod', + 'clean:final', + ]); }; diff --git a/README.md b/README.md index 1afcc1ed63..ecf81b4435 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,16 @@ +## EspoCRM + EspoCRM is an Open Source CRM (Customer Relationship Management) software that allows you to see, enter and evaluate all your company relationships regardless of the type. People, companies or opportunities - all in an easy and intuitive interface. -### How to get started +It's a web application with a frontend designed as a single page application based on backbone.js and a RESTful backend written in PHP. + +Download the latest release from our [website](http://www.espocrm.com). + +### How to report bug + +Create an issue [here](https://github.com/espocrm/espocrm/issues) or post on our [forum](http://forum.espocrm.com/bug-reports?routestring=forum/bug-reports). + +### How to get started (for developers) 1. Clone repository to your local computer. 2. Change to the project's root directory. @@ -9,9 +19,9 @@ Never update composer dependencies if you are going to contribute code back. -Now you can build. +Now you can build. -If your repository is accessible via a web server then you can run EspoCRM by url `http://PROJECT_URL/frontend` w/o making a build. You will need to have proper data/config.php and existing database. +If your repository is accessible via a web server then you can run EspoCRM by url `http://PROJECT_URL/frontend`. To compose a proper config.php and populate database you can run install by opening `http(s)://{YOUR_CRM_URL}/install` location in a browser. Also you need to run build before to have compiled css. ### How to build diff --git a/application/Espo/Controllers/Admin.php b/application/Espo/Controllers/Admin.php index 9aa225f8a1..798990837c 100644 --- a/application/Espo/Controllers/Admin.php +++ b/application/Espo/Controllers/Admin.php @@ -27,60 +27,60 @@ use \Espo\Core\Exceptions\Error, class Admin extends \Espo\Core\Controllers\Base { - protected function checkControllerAccess() - { - if (!$this->getUser()->isAdmin()) { - throw new Forbidden(); - } - } + protected function checkControllerAccess() + { + if (!$this->getUser()->isAdmin()) { + throw new Forbidden(); + } + } - public function actionRebuild($params, $data) - { - $result = $this->getContainer()->get('dataManager')->rebuild(); + public function actionRebuild($params, $data) + { + $result = $this->getContainer()->get('dataManager')->rebuild(); - return $result; - } + return $result; + } - public function actionClearCache($params, $data) - { - $result = $this->getContainer()->get('dataManager')->clearCache(); + public function actionClearCache($params, $data) + { + $result = $this->getContainer()->get('dataManager')->clearCache(); - return $result; - } + return $result; + } - public function actionJobs() - { - $scheduledJob = $this->getContainer()->get('scheduledJob'); + public function actionJobs() + { + $scheduledJob = $this->getContainer()->get('scheduledJob'); - return $scheduledJob->getAllNamesOnly(); - } + return $scheduledJob->getAllNamesOnly(); + } - public function actionUploadUpgradePackage($params, $data) - { - $upgradeManager = new \Espo\Core\UpgradeManager($this->getContainer()); + public function actionUploadUpgradePackage($params, $data) + { + $upgradeManager = new \Espo\Core\UpgradeManager($this->getContainer()); - $upgradeId = $upgradeManager->upload($data); - $manifest = $upgradeManager->getManifest(); + $upgradeId = $upgradeManager->upload($data); + $manifest = $upgradeManager->getManifest(); - return array( - 'id' => $upgradeId, - 'version' => $manifest['version'], - ); - } + return array( + 'id' => $upgradeId, + 'version' => $manifest['version'], + ); + } - public function actionRunUpgrade($params, $data) - { - $upgradeManager = new \Espo\Core\UpgradeManager($this->getContainer()); + public function actionRunUpgrade($params, $data) + { + $upgradeManager = new \Espo\Core\UpgradeManager($this->getContainer()); - $upgradeManager->install($data['id']); + $upgradeManager->install($data['id']); - return true; - } + return true; + } - public function actionCronMessage($params, $data) - { - return $this->getContainer()->get('scheduledJob')->getSetupMessage(); - } + public function actionCronMessage($params, $data) + { + return $this->getContainer()->get('scheduledJob')->getSetupMessage(); + } } diff --git a/application/Espo/Controllers/App.php b/application/Espo/Controllers/App.php index 9feba226de..09ae50b1c9 100644 --- a/application/Espo/Controllers/App.php +++ b/application/Espo/Controllers/App.php @@ -26,25 +26,25 @@ use \Espo\Core\Exceptions\BadRequest; class App extends \Espo\Core\Controllers\Record { - public function actionUser() - { - return array( - 'user' => $this->getUser()->toArray(), - 'acl' => $this->getAcl()->toArray(), - 'preferences' => $this->getPreferences()->toArray(), - 'token' => $this->getUser()->get('token') - ); - } - - public function actionDestroyAuthToken($params, $data) - { - $token = $data['token']; - if (empty($token)) { - throw new BadRequest(); - } + public function actionUser() + { + return array( + 'user' => $this->getUser()->toArray(), + 'acl' => $this->getAcl()->toArray(), + 'preferences' => $this->getPreferences()->toArray(), + 'token' => $this->getUser()->get('token') + ); + } + + public function actionDestroyAuthToken($params, $data) + { + $token = $data['token']; + if (empty($token)) { + throw new BadRequest(); + } - $auth = new \Espo\Core\Utils\Auth($this->getContainer()); - return $auth->destroyAuthToken($token); - } + $auth = new \Espo\Core\Utils\Auth($this->getContainer()); + return $auth->destroyAuthToken($token); + } } diff --git a/application/Espo/Controllers/Attachment.php b/application/Espo/Controllers/Attachment.php index a2baabbc2f..49fd0157d1 100644 --- a/application/Espo/Controllers/Attachment.php +++ b/application/Espo/Controllers/Attachment.php @@ -25,19 +25,19 @@ namespace Espo\Controllers; class Attachment extends \Espo\Core\Controllers\Record { - public function actionUpload($params, $data) - { - list($prefix, $contents) = explode(',', $data); - $contents = base64_decode($contents); - - $attachment = $this->getEntityManager()->getEntity('Attachment'); - $this->getEntityManager()->saveEntity($attachment); - $this->getContainer()->get('fileManager')->putContents('data/upload/' . $attachment->id, $contents); - - return array( - 'attachmentId' => $attachment->id - ); - } + public function actionUpload($params, $data) + { + list($prefix, $contents) = explode(',', $data); + $contents = base64_decode($contents); + + $attachment = $this->getEntityManager()->getEntity('Attachment'); + $this->getEntityManager()->saveEntity($attachment); + $this->getContainer()->get('fileManager')->putContents('data/upload/' . $attachment->id, $contents); + + return array( + 'attachmentId' => $attachment->id + ); + } } diff --git a/application/Espo/Controllers/AuthToken.php b/application/Espo/Controllers/AuthToken.php index 6372aa703e..5c1b441542 100644 --- a/application/Espo/Controllers/AuthToken.php +++ b/application/Espo/Controllers/AuthToken.php @@ -25,42 +25,42 @@ namespace Espo\Controllers; use \Espo\Core\Exceptions\Forbidden; class AuthToken extends \Espo\Core\Controllers\Record -{ - protected function checkControllerAccess() - { - if (!$this->getUser()->isAdmin()) { - throw new Forbidden(); - } - } - - public function actionUpdate($params, $data) - { - throw new Forbidden(); - } - - public function actionCreate($params, $data) - { - throw new Forbidden(); - } - - public function actionListLinked($params, $data) - { - throw new Forbidden(); - } - - public function actionMassUpdate($params, $data) - { - throw new Forbidden(); - } - - public function actionCreateLink($params, $data) - { - throw new Forbidden(); - } - - public function actionRemoveLink($params, $data) - { - throw new Forbidden(); - } +{ + protected function checkControllerAccess() + { + if (!$this->getUser()->isAdmin()) { + throw new Forbidden(); + } + } + + public function actionUpdate($params, $data) + { + throw new Forbidden(); + } + + public function actionCreate($params, $data) + { + throw new Forbidden(); + } + + public function actionListLinked($params, $data) + { + throw new Forbidden(); + } + + public function actionMassUpdate($params, $data) + { + throw new Forbidden(); + } + + public function actionCreateLink($params, $data) + { + throw new Forbidden(); + } + + public function actionRemoveLink($params, $data) + { + throw new Forbidden(); + } } diff --git a/application/Espo/Controllers/Email.php b/application/Espo/Controllers/Email.php index 1763f4c71f..9bd4f36453 100644 --- a/application/Espo/Controllers/Email.php +++ b/application/Espo/Controllers/Email.php @@ -22,13 +22,45 @@ namespace Espo\Controllers; +use \Espo\Core\Exceptions\BadRequest; +use \Espo\Core\Exceptions\Forbidden; +use \Espo\Core\Exceptions\Error; + class Email extends \Espo\Core\Controllers\Record { - public function actionGetCopiedAttachments($params, $data, $request) - { - $id = $request->get('id'); - - return $this->getRecordService()->getCopiedAttachments($id); - } + public function actionGetCopiedAttachments($params, $data, $request) + { + $id = $request->get('id'); + + return $this->getRecordService()->getCopiedAttachments($id); + } + + public function actionSendTestEmail($params, $data, $request) + { + if (!$request->isPost()) { + throw new BadRequest(); + } + + if (empty($data['password'])) { + if ($data['type'] == 'preferences') { + if (!$this->getUser()->isAdmin() && $data['id'] != $this->getUser()->id) { + throw new Forbidden(); + } + $preferences = $this->getEntityManager()->getEntity('Preferences', $data['id']); + if (!$preferences) { + throw new Error(); + } + + $data['password'] = $this->getContainer()->get('crypt')->decrypt($preferences->get('smtpPassword')); + } else { + if (!$this->getUser()->isAdmin()) { + throw new Forbidden(); + } + $data['password'] = $this->getConfig()->get('smtpPassword'); + } + } + + return $this->getRecordService()->sendTestEmail($data); + } } diff --git a/application/Espo/Controllers/EmailAccount.php b/application/Espo/Controllers/EmailAccount.php index a765f9563e..3b60958642 100644 --- a/application/Espo/Controllers/EmailAccount.php +++ b/application/Espo/Controllers/EmailAccount.php @@ -22,19 +22,27 @@ 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') - )); +use \Espo\Core\Exceptions\Forbidden; - } +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') + )); + } + + protected function checkControllerAccess() + { + if (!$this->getAcl()->check('EmailAccountScope')) { + throw new Forbidden(); + } + } } diff --git a/application/Espo/Controllers/EmailAddress.php b/application/Espo/Controllers/EmailAddress.php index f990466aa0..c01652e3b6 100644 --- a/application/Espo/Controllers/EmailAddress.php +++ b/application/Espo/Controllers/EmailAddress.php @@ -24,14 +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); - } + 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); + } } diff --git a/application/Espo/Controllers/EmailTemplate.php b/application/Espo/Controllers/EmailTemplate.php index 1cc8687fa1..2c2e00485f 100644 --- a/application/Espo/Controllers/EmailTemplate.php +++ b/application/Espo/Controllers/EmailTemplate.php @@ -26,20 +26,20 @@ use \Espo\Core\Exceptions\Error; class EmailTemplate extends \Espo\Core\Controllers\Record { - public function actionParse($params, $data, $request) - { - $id = $request->get('id'); - $emailAddress = $request->get('emailAddress'); - if (empty($id)) { - throw new Error(); - } - - return $this->getRecordService()->parse($id, array( - 'emailAddress' => $request->get('emailAddress'), - 'parentType' => $request->get('parentType'), - 'parentId' => $request->get('parentId'), - ), true); - } + public function actionParse($params, $data, $request) + { + $id = $request->get('id'); + $emailAddress = $request->get('emailAddress'); + if (empty($id)) { + throw new Error(); + } + + return $this->getRecordService()->parse($id, array( + 'emailAddress' => $request->get('emailAddress'), + 'parentType' => $request->get('parentType'), + 'parentId' => $request->get('parentId'), + ), true); + } } diff --git a/application/Espo/Controllers/Extension.php b/application/Espo/Controllers/Extension.php index 0cab3b960a..57968eaa4c 100644 --- a/application/Espo/Controllers/Extension.php +++ b/application/Espo/Controllers/Extension.php @@ -27,105 +27,105 @@ use \Espo\Core\Exceptions\Forbidden; class Extension extends \Espo\Core\Controllers\Record { - protected function checkControllerAccess() - { - if (!$this->getUser()->isAdmin()) { - throw new Forbidden(); - } - } + protected function checkControllerAccess() + { + if (!$this->getUser()->isAdmin()) { + throw new Forbidden(); + } + } - public function actionUpload($params, $data, $request) - { - if (!$request->isPost()) { - throw new Forbidden(); - } + public function actionUpload($params, $data, $request) + { + if (!$request->isPost()) { + throw new Forbidden(); + } - $manager = new \Espo\Core\ExtensionManager($this->getContainer()); + $manager = new \Espo\Core\ExtensionManager($this->getContainer()); - $id = $manager->upload($data); - $manifest = $manager->getManifest(); + $id = $manager->upload($data); + $manifest = $manager->getManifest(); - return array( - 'id' => $id, - 'version' => $manifest['version'], - 'name' => $manifest['name'], - 'description' => $manifest['description'], - ); - } + return array( + 'id' => $id, + 'version' => $manifest['version'], + 'name' => $manifest['name'], + 'description' => $manifest['description'], + ); + } - public function actionInstall($params, $data, $request) - { - if (!$request->isPost()) { - throw new Forbidden(); - } + public function actionInstall($params, $data, $request) + { + if (!$request->isPost()) { + throw new Forbidden(); + } - $manager = new \Espo\Core\ExtensionManager($this->getContainer()); + $manager = new \Espo\Core\ExtensionManager($this->getContainer()); - $manager->install($data['id']); + $manager->install($data['id']); - return true; - } + return true; + } - public function actionUninstall($params, $data, $request) - { - if (!$request->isPost()) { - throw new Forbidden(); - } + public function actionUninstall($params, $data, $request) + { + if (!$request->isPost()) { + throw new Forbidden(); + } - $manager = new \Espo\Core\ExtensionManager($this->getContainer()); + $manager = new \Espo\Core\ExtensionManager($this->getContainer()); - $manager->uninstall($data['id']); + $manager->uninstall($data['id']); - return true; - } + return true; + } - public function actionCreate() - { - throw new Forbidden(); - } + public function actionCreate() + { + throw new Forbidden(); + } - public function actionUpdate() - { - throw new Forbidden(); - } + public function actionUpdate() + { + throw new Forbidden(); + } - public function actionPatch() - { - throw new Forbidden(); - } + public function actionPatch() + { + throw new Forbidden(); + } - public function actionListLinked() - { - throw new Forbidden(); - } + public function actionListLinked() + { + throw new Forbidden(); + } - public function actionDelete($params, $data, $request) - { - $manager = new \Espo\Core\ExtensionManager($this->getContainer()); + public function actionDelete($params, $data, $request) + { + $manager = new \Espo\Core\ExtensionManager($this->getContainer()); - $manager->delete($params['id']); + $manager->delete($params['id']); - return true; - } + return true; + } - public function actionMassUpdate() - { - throw new Forbidden(); - } + public function actionMassUpdate() + { + throw new Forbidden(); + } - public function actionMassDelete() - { - throw new Forbidden(); - } + public function actionMassDelete() + { + throw new Forbidden(); + } - public function actionCreateLink() - { - throw new Forbidden(); - } + public function actionCreateLink() + { + throw new Forbidden(); + } - public function actionRemoveLink() - { - throw new Forbidden(); - } + public function actionRemoveLink() + { + throw new Forbidden(); + } } diff --git a/application/Espo/Controllers/ExternalAccount.php b/application/Espo/Controllers/ExternalAccount.php index 38427406d1..7978f15464 100644 --- a/application/Espo/Controllers/ExternalAccount.php +++ b/application/Espo/Controllers/ExternalAccount.php @@ -27,98 +27,98 @@ 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 actionGetOAuth2Info($params, $data, $request) - { - $id = $request->get('id'); - list($integration, $userId) = explode('__', $id); - + 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 actionGetOAuth2Info($params, $data, $request) + { + $id = $request->get('id'); + list($integration, $userId) = explode('__', $id); + - 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', - 'isConnected' => $this->getRecordService()->ping($integration, $userId) - ); - } - } + 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', + 'isConnected' => $this->getRecordService()->ping($integration, $userId) + ); + } + } - public function actionRead($params, $data, $request) - { - list($integration, $userId) = explode('__', $params['id']); + public function actionRead($params, $data, $request) + { + list($integration, $userId) = explode('__', $params['id']); - 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()->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()->id != $userId) { - throw new Forbidden(); - } - - if (isset($data['enabled']) && !$data['enabled']) { - $data['data'] = null; - } - - $entity = $this->getEntityManager()->getEntity('ExternalAccount', $params['id']); - $entity->set($data); - $this->getEntityManager()->saveEntity($entity); - - return $entity->toArray(); - } - - public function actionAuthorizationCode($params, $data, $request) - { - if (!$request->isPost()) { - throw new Error('Bad HTTP method type.'); - } - - $id = $data['id']; - $code = $data['code']; - - list($integration, $userId) = explode('__', $id); + if ($this->getUser()->id != $userId) { + throw new Forbidden(); + } + + if (isset($data['enabled']) && !$data['enabled']) { + $data['data'] = null; + } + + $entity = $this->getEntityManager()->getEntity('ExternalAccount', $params['id']); + $entity->set($data); + $this->getEntityManager()->saveEntity($entity); + + return $entity->toArray(); + } + + public function actionAuthorizationCode($params, $data, $request) + { + if (!$request->isPost()) { + throw new Error('Bad HTTP method type.'); + } + + $id = $data['id']; + $code = $data['code']; + + list($integration, $userId) = explode('__', $id); - if ($this->getUser()->id != $userId) { - throw new Forbidden(); - } - - $service = $this->getRecordService(); - return $service->authorizationCode($integration, $userId, $code); - } + if ($this->getUser()->id != $userId) { + throw new Forbidden(); + } + + $service = $this->getRecordService(); + return $service->authorizationCode($integration, $userId, $code); + } } diff --git a/application/Espo/Controllers/FieldManager.php b/application/Espo/Controllers/FieldManager.php index eeef95b79e..4606d3c4bd 100644 --- a/application/Espo/Controllers/FieldManager.php +++ b/application/Espo/Controllers/FieldManager.php @@ -23,70 +23,70 @@ namespace Espo\Controllers; use \Espo\Core\Exceptions\Error, - \Espo\Core\Exceptions\Forbidden, - \Espo\Core\Exceptions\NotFound; + \Espo\Core\Exceptions\Forbidden, + \Espo\Core\Exceptions\NotFound; class FieldManager extends \Espo\Core\Controllers\Base { - protected function checkControllerAccess() - { - if (!$this->getUser()->isAdmin()) { - throw new Forbidden(); - } - } + protected function checkControllerAccess() + { + if (!$this->getUser()->isAdmin()) { + throw new Forbidden(); + } + } - public function actionRead($params, $data) - { - $data = $this->getContainer()->get('fieldManager')->read($params['name'], $params['scope']); + public function actionRead($params, $data) + { + $data = $this->getContainer()->get('fieldManager')->read($params['name'], $params['scope']); - if (!isset($data)) { - throw new NotFound(); - } + if (!isset($data)) { + throw new NotFound(); + } - return $data; - } + return $data; + } - public function actionCreate($params, $data) - { - if (empty($data['name'])) { - throw new Error("Field 'name' cannnot be empty"); - } + public function actionCreate($params, $data) + { + if (empty($data['name'])) { + throw new Error("Field 'name' cannnot be empty"); + } - $fieldManager = $this->getContainer()->get('fieldManager'); - $fieldManager->create($data['name'], $data, $params['scope']); + $fieldManager = $this->getContainer()->get('fieldManager'); + $fieldManager->create($data['name'], $data, $params['scope']); - try { - $this->getContainer()->get('dataManager')->rebuild($params['scope']); - } catch (Error $e) { - $fieldManager->delete($data['name'], $params['scope']); - throw new Error($e->getMessage()); - } + try { + $this->getContainer()->get('dataManager')->rebuild($params['scope']); + } catch (Error $e) { + $fieldManager->delete($data['name'], $params['scope']); + throw new Error($e->getMessage()); + } - return $fieldManager->read($data['name'], $params['scope']); - } + return $fieldManager->read($data['name'], $params['scope']); + } - public function actionUpdate($params, $data) - { - $fieldManager = $this->getContainer()->get('fieldManager'); - $fieldManager->update($params['name'], $data, $params['scope']); + public function actionUpdate($params, $data) + { + $fieldManager = $this->getContainer()->get('fieldManager'); + $fieldManager->update($params['name'], $data, $params['scope']); - if ($fieldManager->isChanged()) { - $this->getContainer()->get('dataManager')->rebuild($params['scope']); - } else { - $this->getContainer()->get('dataManager')->clearCache(); - } + if ($fieldManager->isChanged()) { + $this->getContainer()->get('dataManager')->rebuild($params['scope']); + } else { + $this->getContainer()->get('dataManager')->clearCache(); + } - return $fieldManager->read($params['name'], $params['scope']); - } + return $fieldManager->read($params['name'], $params['scope']); + } - public function actionDelete($params, $data) - { - $res = $this->getContainer()->get('fieldManager')->delete($params['name'], $params['scope']); + public function actionDelete($params, $data) + { + $res = $this->getContainer()->get('fieldManager')->delete($params['name'], $params['scope']); - $this->getContainer()->get('dataManager')->rebuildMetadata(); + $this->getContainer()->get('dataManager')->rebuildMetadata(); - return $res; - } + return $res; + } } diff --git a/application/Espo/Controllers/GlobalSearch.php b/application/Espo/Controllers/GlobalSearch.php index 23d8337b17..c4fcc72063 100644 --- a/application/Espo/Controllers/GlobalSearch.php +++ b/application/Espo/Controllers/GlobalSearch.php @@ -23,18 +23,18 @@ namespace Espo\Controllers; use \Espo\Core\Exceptions\Error, - \Espo\Core\Exceptions\Forbidden; + \Espo\Core\Exceptions\Forbidden; class GlobalSearch extends \Espo\Core\Controllers\Base { public function actionSearch($params, $data, $request) - { - $query = $params['query']; - - $offset = $request->get('offset'); - $maxSize = $request->get('maxSize'); - - return $this->getService('GlobalSearch')->find($query, $offset, $maxSize); - } + { + $query = $params['query']; + + $offset = $request->get('offset'); + $maxSize = $request->get('maxSize'); + + return $this->getService('GlobalSearch')->find($query, $offset, $maxSize); + } } diff --git a/application/Espo/Controllers/I18n.php b/application/Espo/Controllers/I18n.php index 1ec5cadf22..1072e0a960 100644 --- a/application/Espo/Controllers/I18n.php +++ b/application/Espo/Controllers/I18n.php @@ -26,7 +26,7 @@ class I18n extends \Espo\Core\Controllers\Base { public function actionRead($params, $data) - { - return $this->getContainer()->get('language')->getAll(); - } + { + return $this->getContainer()->get('language')->getAll(); + } } diff --git a/application/Espo/Controllers/Import.php b/application/Espo/Controllers/Import.php index 2c13a4e784..f4aa8dc666 100644 --- a/application/Espo/Controllers/Import.php +++ b/application/Espo/Controllers/Import.php @@ -27,61 +27,61 @@ use \Espo\Core\Exceptions\Error; use \Espo\Core\Exceptions\Forbidden; class Import extends \Espo\Core\Controllers\Base -{ - - protected function getFileManager() - { - return $this->getContainer()->get('fileManager'); - } - - protected function getEntityManager() - { - return $this->getContainer()->get('entityManager'); - } - - public function actionUploadFile($params, $data) - { - $contents = $data; - - $attachment = $this->getEntityManager()->getEntity('Attachment'); - $attachment->set('type', 'text/csv'); - $attachment->set('role', 'Import File'); - $this->getEntityManager()->saveEntity($attachment); - - $this->getFileManager()->putContents('data/upload/' . $attachment->id, $contents); - - return array( - 'attachmentId' => $attachment->id - ); - } - - public function actionRevert($params, $data) - { - return $this->getService('Import')->revert($data['entityType'], $data['idsToRemove']); - } - - public function actionCreate($params, $data) - { +{ + + protected function getFileManager() + { + return $this->getContainer()->get('fileManager'); + } + + protected function getEntityManager() + { + return $this->getContainer()->get('entityManager'); + } + + public function actionUploadFile($params, $data) + { + $contents = $data; + + $attachment = $this->getEntityManager()->getEntity('Attachment'); + $attachment->set('type', 'text/csv'); + $attachment->set('role', 'Import File'); + $this->getEntityManager()->saveEntity($attachment); + + $this->getFileManager()->putContents('data/upload/' . $attachment->id, $contents); + + return array( + 'attachmentId' => $attachment->id + ); + } + + public function actionRevert($params, $data) + { + return $this->getService('Import')->revert($data['entityType'], $data['idsToRemove']); + } + + public function actionCreate($params, $data) + { $importParams = array( - 'headerRow' => $data['headerRow'], - 'fieldDelimiter' => $data['fieldDelimiter'], - 'textQualifier' => $data['textQualifier'], - 'dateFormat' => $data['dateFormat'], - 'timeFormat' => $data['timeFormat'], - 'personNameFormat' => $data['personNameFormat'], - 'decimalMark' => $data['decimalMark'], - 'currency' => $data['currency'], - 'defaultValues' => $data['defaultValues'], - 'action' => $data['action'], + 'headerRow' => $data['headerRow'], + 'fieldDelimiter' => $data['fieldDelimiter'], + 'textQualifier' => $data['textQualifier'], + 'dateFormat' => $data['dateFormat'], + 'timeFormat' => $data['timeFormat'], + 'personNameFormat' => $data['personNameFormat'], + 'decimalMark' => $data['decimalMark'], + 'currency' => $data['currency'], + 'defaultValues' => $data['defaultValues'], + 'action' => $data['action'], ); $attachmentId = $data['attachmentId']; if (!$this->getAcl()->check($data['entityType'], 'edit')) { - throw new Forbidden(); + throw new Forbidden(); } - return $this->getService('Import')->import($data['entityType'], $data['fields'], $attachmentId, $importParams); - } + return $this->getService('Import')->import($data['entityType'], $data['fields'], $attachmentId, $importParams); + } } diff --git a/application/Espo/Controllers/Integration.php b/application/Espo/Controllers/Integration.php index 0e6b30e4ff..0e4a60576a 100644 --- a/application/Espo/Controllers/Integration.php +++ b/application/Espo/Controllers/Integration.php @@ -25,37 +25,37 @@ 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; - } +{ + 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(); - } + 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(); + } } diff --git a/application/Espo/Controllers/Layout.php b/application/Espo/Controllers/Layout.php index a14eaf149f..2053358d4a 100644 --- a/application/Espo/Controllers/Layout.php +++ b/application/Espo/Controllers/Layout.php @@ -30,33 +30,33 @@ use \Espo\Core\Exceptions\Forbidden; class Layout extends \Espo\Core\Controllers\Base { public function actionRead($params, $data) - { - $data = $this->getContainer()->get('layout')->get($params['scope'], $params['name']); - if (empty($data)) { - throw new NotFound("Layout " . $params['scope'] . ":" . $params['name'] . ' is not found'); - } - return $data; - } + { + $data = $this->getContainer()->get('layout')->get($params['scope'], $params['name']); + if (empty($data)) { + throw new NotFound("Layout " . $params['scope'] . ":" . $params['name'] . ' is not found'); + } + return $data; + } - public function actionUpdate($params, $data) - { + public function actionUpdate($params, $data) + { if (!$this->getUser()->isAdmin()) { - throw new Forbidden(); + throw new Forbidden(); } $result = $this->getContainer()->get('layout')->set($data, $params['scope'], $params['name']); - if ($result === false) { - throw new Error("Error while saving layout"); - } + if ($result === false) { + throw new Error("Error while saving layout"); + } - $this->getContainer()->get('dataManager')->updateCacheTimestamp(); + $this->getContainer()->get('dataManager')->updateCacheTimestamp(); - return $this->getContainer()->get('layout')->get($params['scope'], $params['name']); - } + return $this->getContainer()->get('layout')->get($params['scope'], $params['name']); + } - public function actionPatch($params, $data) - { + public function actionPatch($params, $data) + { return $this->actionUpdate($params, $data); - } + } } diff --git a/application/Espo/Controllers/Metadata.php b/application/Espo/Controllers/Metadata.php index d8effcfb78..3784c49413 100644 --- a/application/Espo/Controllers/Metadata.php +++ b/application/Espo/Controllers/Metadata.php @@ -26,7 +26,7 @@ class Metadata extends \Espo\Core\Controllers\Base { public function actionRead($params, $data) - { - return $this->getMetadata()->getAll(true); - } + { + return $this->getMetadata()->getAll(true); + } } diff --git a/application/Espo/Controllers/Notification.php b/application/Espo/Controllers/Notification.php index 03811feadf..51947dc17b 100644 --- a/application/Espo/Controllers/Notification.php +++ b/application/Espo/Controllers/Notification.php @@ -26,41 +26,41 @@ use \Espo\Core\Exceptions\Error; class Notification extends \Espo\Core\Controllers\Base { - public static $defaultAction = 'list'; + public static $defaultAction = 'list'; - public function actionList($params, $data, $request) - { - $scope = $params['scope']; - $id = $params['id']; - - $userId = $this->getUser()->id; - - $offset = intval($request->get('offset')); - $maxSize = intval($request->get('maxSize')); - - $params = array( - 'offset' => $offset, - 'maxSize' => $maxSize, - ); - - $result = $this->getService('Notification')->getList($userId, $params); - - return array( - 'total' => $result['total'], - 'list' => $result['collection']->toArray() - ); - } - - public function actionNotReadCount() - { - $userId = $this->getUser()->id; - return $this->getService('Notification')->getNotReadCount($userId); - } - - public function actionMarkAllRead($params, $data, $request) - { - $userId = $this->getUser()->id; - return $this->getService('Notification')->markAllRead($userId); - } + public function actionList($params, $data, $request) + { + $scope = $params['scope']; + $id = $params['id']; + + $userId = $this->getUser()->id; + + $offset = intval($request->get('offset')); + $maxSize = intval($request->get('maxSize')); + + $params = array( + 'offset' => $offset, + 'maxSize' => $maxSize, + ); + + $result = $this->getService('Notification')->getList($userId, $params); + + return array( + 'total' => $result['total'], + 'list' => $result['collection']->toArray() + ); + } + + public function actionNotReadCount() + { + $userId = $this->getUser()->id; + return $this->getService('Notification')->getNotReadCount($userId); + } + + public function actionMarkAllRead($params, $data, $request) + { + $userId = $this->getUser()->id; + return $this->getService('Notification')->markAllRead($userId); + } } diff --git a/application/Espo/Controllers/Preferences.php b/application/Espo/Controllers/Preferences.php index eb9a3ffedc..4e9518f64d 100644 --- a/application/Espo/Controllers/Preferences.php +++ b/application/Espo/Controllers/Preferences.php @@ -24,74 +24,95 @@ namespace Espo\Controllers; use \Espo\Core\Exceptions\Error; use \Espo\Core\Exceptions\Forbidden; +use \Espo\Core\Exceptions\BadRequest; use \Espo\Core\Exceptions\NotFound; class Preferences extends \Espo\Core\Controllers\Base -{ - protected function getPreferences() - { - return $this->getContainer()->get('preferences'); - } - - protected function getEntityManager() - { - return $this->getContainer()->get('entityManager'); - } - - protected function handleUserAccess($userId) - { - if (!$this->getUser()->isAdmin()) { - if ($this->getUser()->id != $userId) { - throw new Forbidden(); - } - } - } - - public function actionPatch($params, $data) - { - return $this->actionUpdate($params, $data); - } +{ + protected function getPreferences() + { + return $this->getContainer()->get('preferences'); + } + + protected function getEntityManager() + { + return $this->getContainer()->get('entityManager'); + } + + protected function getCrypt() + { + return $this->getContainer()->get('crypt'); + } + + protected function handleUserAccess($userId) + { + if (!$this->getUser()->isAdmin()) { + if ($this->getUser()->id != $userId) { + throw new Forbidden(); + } + } + } + + public function actionDelete($params, $data) + { + $userId = $params['id']; + if (empty($userId)) { + throw new BadRequest(); + } + $this->handleUserAccess($userId); + + return $this->getEntityManager()->getRepository('Preferences')->resetToDefaults($userId); + } + + public function actionPatch($params, $data) + { + return $this->actionUpdate($params, $data); + } - public function actionUpdate($params, $data) - { - $userId = $params['id']; - $this->handleUserAccess($userId); - - $user = $this->getEntityManager()->getEntity('User', $userId); + public function actionUpdate($params, $data) + { + $userId = $params['id']; + $this->handleUserAccess($userId); + + if (array_key_exists('smtpPassword', $data)) { + $data['smtpPassword'] = $this->getCrypt()->encrypt($data['smtpPassword']); + } + + $user = $this->getEntityManager()->getEntity('User', $userId); - $entity = $this->getEntityManager()->getEntity('Preferences', $userId); - - if ($entity) { - $entity->set($data); - $this->getEntityManager()->saveEntity($entity); - - $entity->set('smtpEmailAddress', $user->get('emailAddress')); - $entity->set('name', $user->get('name')); - - $entity->clear('smtpPassword'); - - return $entity->toArray(); - } - throw new Error(); - } + $entity = $this->getEntityManager()->getEntity('Preferences', $userId); + + if ($entity) { + $entity->set($data); + $this->getEntityManager()->saveEntity($entity); + + $entity->set('smtpEmailAddress', $user->get('emailAddress')); + $entity->set('name', $user->get('name')); + + $entity->clear('smtpPassword'); + + return $entity->toArray(); + } + throw new Error(); + } public function actionRead($params) - { - $userId = $params['id']; - $this->handleUserAccess($userId); + { + $userId = $params['id']; + $this->handleUserAccess($userId); - $entity = $this->getEntityManager()->getEntity('Preferences', $userId); - $user = $this->getEntityManager()->getEntity('User', $userId); - - $entity->set('smtpEmailAddress', $user->get('emailAddress')); - $entity->set('name', $user->get('name')); - - $entity->clear('smtpPassword'); - - if ($entity) { - return $entity->toArray(); - } - throw new NotFound(); - } + $entity = $this->getEntityManager()->getEntity('Preferences', $userId); + $user = $this->getEntityManager()->getEntity('User', $userId); + + $entity->set('smtpEmailAddress', $user->get('emailAddress')); + $entity->set('name', $user->get('name')); + + $entity->clear('smtpPassword'); + + if ($entity) { + return $entity->toArray(); + } + throw new NotFound(); + } } diff --git a/application/Espo/Controllers/ScheduledJob.php b/application/Espo/Controllers/ScheduledJob.php index f06407812b..50d7f623f6 100644 --- a/application/Espo/Controllers/ScheduledJob.php +++ b/application/Espo/Controllers/ScheduledJob.php @@ -24,11 +24,11 @@ namespace Espo\Controllers; class ScheduledJob extends \Espo\Core\Controllers\Record { - protected function checkControllerAccess() - { - if (!$this->getUser()->isAdmin()) { - throw new Forbidden(); - } - } + protected function checkControllerAccess() + { + if (!$this->getUser()->isAdmin()) { + throw new Forbidden(); + } + } } diff --git a/application/Espo/Controllers/ScheduledJobLogRecord.php b/application/Espo/Controllers/ScheduledJobLogRecord.php index 65483fa3ab..30b2e38835 100644 --- a/application/Espo/Controllers/ScheduledJobLogRecord.php +++ b/application/Espo/Controllers/ScheduledJobLogRecord.php @@ -24,11 +24,11 @@ namespace Espo\Controllers; class ScheduledJobLogRecord extends \Espo\Core\Controllers\Record { - protected function checkControllerAccess() - { - if (!$this->getUser()->isAdmin()) { - throw new Forbidden(); - } - } + protected function checkControllerAccess() + { + if (!$this->getUser()->isAdmin()) { + throw new Forbidden(); + } + } } diff --git a/application/Espo/Controllers/Settings.php b/application/Espo/Controllers/Settings.php index 5593787faa..d50a208fb4 100644 --- a/application/Espo/Controllers/Settings.php +++ b/application/Espo/Controllers/Settings.php @@ -27,48 +27,48 @@ use \Espo\Core\Exceptions\Forbidden; class Settings extends \Espo\Core\Controllers\Base { - protected function getConfigData() - { - $data = $this->getConfig()->getData($this->getUser()->isAdmin()); + protected function getConfigData() + { + $data = $this->getConfig()->getData($this->getUser()->isAdmin()); - $fieldDefs = $this->getMetadata()->get('entityDefs.Settings.fields'); + $fieldDefs = $this->getMetadata()->get('entityDefs.Settings.fields'); - foreach ($fieldDefs as $field => $d) { - if ($d['type'] == 'password') { - unset($data[$field]); - } - } - return $data; - } + foreach ($fieldDefs as $field => $d) { + if ($d['type'] == 'password') { + unset($data[$field]); + } + } + return $data; + } - public function actionRead($params, $data) - { - return $this->getConfigData(); - } + public function actionRead($params, $data) + { + return $this->getConfigData(); + } - public function actionUpdate($params, $data) - { - return $this->actionPatch($params, $data); - } + public function actionUpdate($params, $data) + { + return $this->actionPatch($params, $data); + } - public function actionPatch($params, $data) - { - if (!$this->getUser()->isAdmin()) { - throw new Forbidden(); - } + public function actionPatch($params, $data) + { + if (!$this->getUser()->isAdmin()) { + throw new Forbidden(); + } - $this->getConfig()->setData($data, $this->getUser()->isAdmin()); - $result = $this->getConfig()->save(); - if ($result === false) { - throw new Error('Cannot save settings'); - } + $this->getConfig()->setData($data, $this->getUser()->isAdmin()); + $result = $this->getConfig()->save(); + if ($result === false) { + throw new Error('Cannot save settings'); + } - /** Rebuild for Currency Settings */ - if (isset($data['baseCurrency']) || isset($data['currencyRates'])) { - $this->getContainer()->get('dataManager')->rebuildDatabase(array()); - } - /** END Rebuild for Currency Settings */ + /** Rebuild for Currency Settings */ + if (isset($data['baseCurrency']) || isset($data['currencyRates'])) { + $this->getContainer()->get('dataManager')->rebuildDatabase(array()); + } + /** END Rebuild for Currency Settings */ - return $this->getConfigData(); - } + return $this->getConfigData(); + } } diff --git a/application/Espo/Controllers/Stream.php b/application/Espo/Controllers/Stream.php index 6418c03252..4d1c136939 100644 --- a/application/Espo/Controllers/Stream.php +++ b/application/Espo/Controllers/Stream.php @@ -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\Controllers; @@ -26,38 +26,38 @@ use \Espo\Core\Exceptions\Error; class Stream extends \Espo\Core\Controllers\Base { - const MAX_SIZE_LIMIT = 400; - - public static $defaultAction = 'list'; + const MAX_SIZE_LIMIT = 400; + + public static $defaultAction = 'list'; public function actionList($params, $data, $request) - { - $scope = $params['scope']; - $id = isset($params['id']) ? $params['id'] : null; - - $offset = intval($request->get('offset')); - $maxSize = intval($request->get('maxSize')); - $after = $request->get('after'); - - $service = $this->getService('Stream'); - - if (empty($maxSize)) { - $maxSize = self::MAX_SIZE_LIMIT; - } - if (!empty($maxSize) && $maxSize > self::MAX_SIZE_LIMIT) { - throw new Forbidden(); - } - - $result = $service->find($scope, $id, array( - 'offset' => $offset, - 'maxSize' => $maxSize, - 'after' => $after, - )); - - return array( - 'total' => $result['total'], - 'list' => $result['collection']->toArray() - ); - } + { + $scope = $params['scope']; + $id = isset($params['id']) ? $params['id'] : null; + + $offset = intval($request->get('offset')); + $maxSize = intval($request->get('maxSize')); + $after = $request->get('after'); + + $service = $this->getService('Stream'); + + if (empty($maxSize)) { + $maxSize = self::MAX_SIZE_LIMIT; + } + if (!empty($maxSize) && $maxSize > self::MAX_SIZE_LIMIT) { + throw new Forbidden(); + } + + $result = $service->find($scope, $id, array( + 'offset' => $offset, + 'maxSize' => $maxSize, + 'after' => $after, + )); + + return array( + 'total' => $result['total'], + 'list' => $result['collection']->toArray() + ); + } } diff --git a/application/Espo/Controllers/Team.php b/application/Espo/Controllers/Team.php index af5d7f6c2e..b0cc25bd27 100644 --- a/application/Espo/Controllers/Team.php +++ b/application/Espo/Controllers/Team.php @@ -24,6 +24,6 @@ namespace Espo\Controllers; class Team extends \Espo\Core\Controllers\Record { - + } diff --git a/application/Espo/Controllers/User.php b/application/Espo/Controllers/User.php index e6d1605e33..17a7138d01 100644 --- a/application/Espo/Controllers/User.php +++ b/application/Espo/Controllers/User.php @@ -27,31 +27,31 @@ use \Espo\Core\Exceptions\NotFound; use \Espo\Core\Exceptions\Forbidden; class User extends \Espo\Core\Controllers\Record -{ - public function actionAcl($params, $data, $request) - { - $userId = $request->get('id'); - if (empty($userId)) { - throw new Error(); - } - - if (!$this->getUser()->isAdmin() && $this->getUser()->id != $userId) { - throw new Forbidden(); - } - - $user = $this->getEntityManager()->getEntity('User', $userId); - if (empty($user)) { - throw new NotFound(); - } - - $acl = new \Espo\Core\Acl($user, $this->getConfig(), $this->getContainer()->get('fileManager'), $this->getMetadata()); - - return $acl->toArray(); - } - - public function actionChangeOwnPassword($params, $data) - { - return $this->getService('User')->changePassword($this->getUser()->id, $data['password']); - } +{ + public function actionAcl($params, $data, $request) + { + $userId = $request->get('id'); + if (empty($userId)) { + throw new Error(); + } + + if (!$this->getUser()->isAdmin() && $this->getUser()->id != $userId) { + throw new Forbidden(); + } + + $user = $this->getEntityManager()->getEntity('User', $userId); + if (empty($user)) { + throw new NotFound(); + } + + $acl = new \Espo\Core\Acl($user, $this->getConfig(), $this->getContainer()->get('fileManager'), $this->getMetadata()); + + return $acl->toArray(); + } + + public function actionChangeOwnPassword($params, $data) + { + return $this->getService('User')->changePassword($this->getUser()->id, $data['password']); + } } diff --git a/application/Espo/Core/Acl.php b/application/Espo/Core/Acl.php index e9ab36dcd8..7dfd02d9f8 100644 --- a/application/Espo/Core/Acl.php +++ b/application/Espo/Core/Acl.php @@ -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; @@ -28,241 +28,254 @@ use \Espo\ORM\Entity; class Acl { - private $data = array(); + private $data = array(); - private $cacheFile; + private $cacheFile; - private $actionList = array('read', 'edit', 'delete'); + private $actionList = array('read', 'edit', 'delete'); - private $levelList = array('all', 'team', 'own', 'no'); - - protected $fileManager; - - protected $metadata; + private $levelList = array('all', 'team', 'own', 'no'); - public function __construct(\Espo\Entities\User $user, $config = null, $fileManager = null, $metadata = null) - { - $this->user = $user; - - $this->metadata = $metadata; - - if (!$this->user->isFetched()) { - throw new Error(); - } - - $this->user->loadLinkMultipleField('teams'); - - if ($fileManager) { - $this->fileManager = $fileManager; - } - - $this->cacheFile = 'data/cache/application/acl/' . $user->id . '.php'; - - if ($config && $config->get('useCache') && file_exists($this->cacheFile)) { - $cached = include $this->cacheFile; - $this->data = $cached; - $this->initSolid(); - } else { - $this->load(); - $this->initSolid(); - if ($config && $fileManager && $config->get('useCache')) { - $this->buildCache(); - } - } + protected $fileManager; - } - - public function checkScope($scope, $action = null, $isOwner = null, $inTeam = null, $entity = null) - { - if (array_key_exists($scope, $this->data)) { - if ($this->data[$scope] === false) { - return false; - } - if ($this->data[$scope] === true) { - return true; - } - if (!is_null($action)) { - if (array_key_exists($action, $this->data[$scope])) { - $value = $this->data[$scope][$action]; - - if ($value === 'all' || $value === true) { - return true; - } - - if (!$value || $value === 'no') { - return false; - } - - if (is_null($isOwner)) { - return true; - } - - if ($isOwner) { - if ($value === 'own' || $value === 'team') { - return true; - } - } - if ($inTeam === null && $entity) { - $inTeam = $this->checkInTeam($entity); - } - - if ($inTeam) { - if ($value === 'team') { - return true; - } - } - - return false; - } - } - return true; - } - return true; - } - - public function toArray() - { - return $this->data; - } + protected $metadata; - public function check($subject, $action = null, $isOwner = null, $inTeam = null) - { - if ($this->user->isAdmin()) { - return true; - } - if (is_string($subject)) { - return $this->checkScope($subject, $action, $isOwner, $inTeam); - } else { - $entity = $subject; - if ($entity instanceof Entity) { - $entityName = $entity->getEntityName(); - return $this->checkScope($entityName, $action, $this->checkIsOwner($entity), $inTeam, $entity); - } - } - } - - public function checkReadOnlyTeam($scope) - { - if (isset($this->data[$scope]) && isset($this->data[$scope]['read'])) { - return $this->data[$scope]['read'] === 'team'; - } - return false; - } - - public function checkReadOnlyOwn($scope) - { - if ($this->user->isAdmin()) { - return false; - } - if (isset($this->data[$scope]) && isset($this->data[$scope]['read'])) { - return $this->data[$scope]['read'] === 'own'; - } - return false; - } - - public function checkIsOwner($entity) - { - if ($this->user->isAdmin()) { - return false; - } - $userId = $this->user->id; - if ($userId === $entity->get('assignedUserId') || $userId === $entity->get('createdById')) { - return true; - } - return false; - } - - public function checkInTeam($entity) - { - $userTeamIds = $this->user->get('teamsIds'); - - if (!$entity->hasRelation('teams') || !$entity->hasField('teamsIds')) { - return false; - } - - if (!$entity->has('teamsIds')) { - $entity->loadLinkMultipleField('teams'); - } - - $teamIds = $entity->get('teamsIds'); - - if (empty($teamIds)) { - return false; - } - - foreach ($userTeamIds as $id) { - if (in_array($id, $teamIds)) { - return true; - } - } - return false; - } + public function __construct(\Espo\Entities\User $user, $config = null, $fileManager = null, $metadata = null) + { + $this->user = $user; - private function load() - { - $aclTables = array(); + $this->metadata = $metadata; - $userRoles = $this->user->get('roles'); - - foreach ($userRoles as $role) { - $aclTables[] = json_decode($role->get('data')); - } + if (!$this->user->isFetched()) { + throw new Error(); + } - $teams = $this->user->get('teams'); - foreach ($teams as $team) { - $teamRoles = $team->get('roles'); - foreach ($teamRoles as $role) { - $aclTables[] = json_decode($role->get('data')); - } - } + $this->user->loadLinkMultipleField('teams'); - $this->data = $this->merge($aclTables); - } - - private function initSolid() - { - $data = $this->metadata->get('app.acl.solid', array()); - - foreach ($data as $entityName => $item) { - $this->data[$entityName] = $item; - } - } + if ($fileManager) { + $this->fileManager = $fileManager; + } - private function merge($tables) - { - $data = array(); - foreach ($tables as $table) { - foreach ($table as $scope => $row) { - if ($row == false) { - if (!isset($data[$scope])) { - $data[$scope] = false; - } - } else { - if (!isset($data[$scope])) { - $data[$scope] = array(); - } - if ($data[$scope] == false) { - $data[$scope] = array(); - } - foreach ($row as $action => $level) { - if (!isset($data[$scope][$action])) { - $data[$scope][$action] = $level; - } else { - if (array_search($data[$scope][$action], $this->levelList) > array_search($level, $this->levelList)) { - $data[$scope][$action] = $level; - } - } - } - } - } - } - return $data; - } + $this->cacheFile = 'data/cache/application/acl/' . $user->id . '.php'; - private function buildCache() - { - $contents = '<' . '?'. 'php return ' . var_export($this->data, true) . ';'; - $this->fileManager->putContents($this->cacheFile, $contents); - } + if ($config && $config->get('useCache') && file_exists($this->cacheFile)) { + $cached = include $this->cacheFile; + $this->data = $cached; + $this->initSolid(); + } else { + $this->load(); + $this->initSolid(); + if ($config && $fileManager && $config->get('useCache')) { + $this->buildCache(); + } + } + + } + + public function checkScope($scope, $action = null, $isOwner = null, $inTeam = null, $entity = null) + { + if (array_key_exists($scope, $this->data)) { + if ($this->data[$scope] === false) { + return false; + } + if ($this->data[$scope] === true) { + return true; + } + if (!is_null($action)) { + if (array_key_exists($action, $this->data[$scope])) { + $value = $this->data[$scope][$action]; + + if ($value === 'all' || $value === true) { + return true; + } + + if (!$value || $value === 'no') { + return false; + } + + if (is_null($isOwner)) { + return true; + } + + if ($isOwner) { + if ($value === 'own' || $value === 'team') { + return true; + } + } + if ($inTeam === null && $entity) { + $inTeam = $this->checkInTeam($entity); + } + + if ($inTeam) { + if ($value === 'team') { + return true; + } + } + + return false; + } + } + return true; + } + return true; + } + + public function toArray() + { + return $this->data; + } + + public function getLevel($scope, $action) + { + if ($this->user->isAdmin()) { + return 'all'; + } + if (array_key_exists($scope, $this->data)) { + if (array_key_exists($action, $this->data[$scope])) { + return $this->data[$scope][$action]; + } + } + return false; + } + + public function check($subject, $action = null, $isOwner = null, $inTeam = null) + { + if ($this->user->isAdmin()) { + return true; + } + if (is_string($subject)) { + return $this->checkScope($subject, $action, $isOwner, $inTeam); + } else { + $entity = $subject; + if ($entity instanceof Entity) { + $entityName = $entity->getEntityName(); + return $this->checkScope($entityName, $action, $this->checkIsOwner($entity), $inTeam, $entity); + } + } + } + + public function checkReadOnlyTeam($scope) + { + if (isset($this->data[$scope]) && isset($this->data[$scope]['read'])) { + return $this->data[$scope]['read'] === 'team'; + } + return false; + } + + public function checkReadOnlyOwn($scope) + { + if ($this->user->isAdmin()) { + return false; + } + if (isset($this->data[$scope]) && isset($this->data[$scope]['read'])) { + return $this->data[$scope]['read'] === 'own'; + } + return false; + } + + public function checkIsOwner($entity) + { + if ($this->user->isAdmin()) { + return false; + } + $userId = $this->user->id; + if ($userId === $entity->get('assignedUserId') || $userId === $entity->get('createdById')) { + return true; + } + return false; + } + + public function checkInTeam($entity) + { + $userTeamIds = $this->user->get('teamsIds'); + + if (!$entity->hasRelation('teams') || !$entity->hasField('teamsIds')) { + return false; + } + + if (!$entity->has('teamsIds')) { + $entity->loadLinkMultipleField('teams'); + } + + $teamIds = $entity->get('teamsIds'); + + if (empty($teamIds)) { + return false; + } + + foreach ($userTeamIds as $id) { + if (in_array($id, $teamIds)) { + return true; + } + } + return false; + } + + private function load() + { + $aclTables = array(); + + $userRoles = $this->user->get('roles'); + + foreach ($userRoles as $role) { + $aclTables[] = json_decode($role->get('data')); + } + + $teams = $this->user->get('teams'); + foreach ($teams as $team) { + $teamRoles = $team->get('roles'); + foreach ($teamRoles as $role) { + $aclTables[] = json_decode($role->get('data')); + } + } + + $this->data = $this->merge($aclTables); + } + + private function initSolid() + { + $data = $this->metadata->get('app.acl.solid', array()); + + foreach ($data as $entityName => $item) { + $this->data[$entityName] = $item; + } + } + + private function merge($tables) + { + $data = array(); + foreach ($tables as $table) { + foreach ($table as $scope => $row) { + if ($row == false) { + if (!isset($data[$scope])) { + $data[$scope] = false; + } + } else { + if (!isset($data[$scope])) { + $data[$scope] = array(); + } + if ($data[$scope] == false) { + $data[$scope] = array(); + } + foreach ($row as $action => $level) { + if (!isset($data[$scope][$action])) { + $data[$scope][$action] = $level; + } else { + if (array_search($data[$scope][$action], $this->levelList) > array_search($level, $this->levelList)) { + $data[$scope][$action] = $level; + } + } + } + } + } + } + return $data; + } + + private function buildCache() + { + $contents = '<' . '?'. 'php return ' . var_export($this->data, true) . ';'; + $this->fileManager->putContents($this->cacheFile, $contents); + } } diff --git a/application/Espo/Core/Application.php b/application/Espo/Core/Application.php index 95f3b97b8c..29dee4f3a4 100644 --- a/application/Espo/Core/Application.php +++ b/application/Espo/Core/Application.php @@ -25,54 +25,54 @@ namespace Espo\Core; class Application { - private $metadata; + private $metadata; - private $container; + private $container; - private $slim; + private $slim; - private $auth; + private $auth; - /** + /** * Constructor */ public function __construct() { - $this->container = new Container(); + $this->container = new Container(); - date_default_timezone_set('UTC'); + date_default_timezone_set('UTC'); - $GLOBALS['log'] = $this->container->get('log'); + $GLOBALS['log'] = $this->container->get('log'); } - public function getSlim() - { - if (empty($this->slim)) { - $this->slim = $this->container->get('slim'); - } - return $this->slim; - } + public function getSlim() + { + if (empty($this->slim)) { + $this->slim = $this->container->get('slim'); + } + return $this->slim; + } - public function getMetadata() - { - if (empty($this->metadata)) { - $this->metadata = $this->container->get('metadata'); - } - return $this->metadata; - } + public function getMetadata() + { + if (empty($this->metadata)) { + $this->metadata = $this->container->get('metadata'); + } + return $this->metadata; + } protected function getAuth() { - if (empty($this->auth)) { - $this->auth = new \Espo\Core\Utils\Auth($this->container); - } - return $this->auth; + if (empty($this->auth)) { + $this->auth = new \Espo\Core\Utils\Auth($this->container); + } + return $this->auth; } - public function getContainer() - { - return $this->container; - } + public function getContainer() + { + return $this->container; + } public function run($name = 'default') { @@ -83,160 +83,160 @@ class Application public function runClient() { - $config = $this->getContainer()->get('config'); + $config = $this->getContainer()->get('config'); - $html = file_get_contents('main.html'); - $html = str_replace('{{cacheTimestamp}}', $config->get('cacheTimestamp', 0), $html); - $html = str_replace('{{useCache}}', $config->get('useCache') ? 'true' : 'false' , $html); - echo $html; - exit; + $html = file_get_contents('main.html'); + $html = str_replace('{{cacheTimestamp}}', $config->get('cacheTimestamp', 0), $html); + $html = str_replace('{{useCache}}', $config->get('useCache') ? 'true' : 'false' , $html); + echo $html; + exit; } public function runEntryPoint($entryPoint) { - if (empty($entryPoint)) { - throw new \Error(); - } + if (empty($entryPoint)) { + throw new \Error(); + } - $slim = $this->getSlim(); - $container = $this->getContainer(); + $slim = $this->getSlim(); + $container = $this->getContainer(); - $slim->get('/', function() {}); + $slim->get('/', function() {}); - $entryPointManager = new \Espo\Core\EntryPointManager($container); + $entryPointManager = new \Espo\Core\EntryPointManager($container); - $auth = $this->getAuth(); - $apiAuth = new \Espo\Core\Utils\Api\Auth($auth, $entryPointManager->checkAuthRequired($entryPoint), true); - $slim->add($apiAuth); + $auth = $this->getAuth(); + $apiAuth = new \Espo\Core\Utils\Api\Auth($auth, $entryPointManager->checkAuthRequired($entryPoint), true); + $slim->add($apiAuth); - $slim->hook('slim.before.dispatch', function () use ($entryPoint, $entryPointManager, $container) { - try { - $entryPointManager->run($entryPoint); - } catch (\Exception $e) { - $container->get('output')->processError($e->getMessage(), $e->getCode(), true); - } - }); + $slim->hook('slim.before.dispatch', function () use ($entryPoint, $entryPointManager, $container) { + try { + $entryPointManager->run($entryPoint); + } catch (\Exception $e) { + $container->get('output')->processError($e->getMessage(), $e->getCode(), true); + } + }); - $slim->run(); + $slim->run(); } public function runCron() { - $auth = $this->getAuth(); - $auth->useNoAuth(true); + $auth = $this->getAuth(); + $auth->useNoAuth(true); - $cronManager = new \Espo\Core\CronManager($this->container); - $cronManager->run(); + $cronManager = new \Espo\Core\CronManager($this->container); + $cronManager->run(); } public function runRebuild() { - $dataManager = $this->getContainer()->get('dataManager'); - $dataManager->rebuild(); + $dataManager = $this->getContainer()->get('dataManager'); + $dataManager->rebuild(); } public function isInstalled() { - $config = $this->getContainer()->get('config'); + $config = $this->getContainer()->get('config'); - if (file_exists($config->getConfigPath()) && $config->get('isInstalled')) { - return true; - } + if (file_exists($config->getConfigPath()) && $config->get('isInstalled')) { + return true; + } - return false; + return false; } - protected function routeHooks() - { - $container = $this->getContainer(); - $slim = $this->getSlim(); + protected function routeHooks() + { + $container = $this->getContainer(); + $slim = $this->getSlim(); - $auth = $this->getAuth(); + $auth = $this->getAuth(); - $apiAuth = new \Espo\Core\Utils\Api\Auth($auth); - $this->getSlim()->add($apiAuth); + $apiAuth = new \Espo\Core\Utils\Api\Auth($auth); + $this->getSlim()->add($apiAuth); - $this->getSlim()->hook('slim.before.dispatch', function () use ($slim, $container) { + $this->getSlim()->hook('slim.before.dispatch', function () use ($slim, $container) { - $route = $slim->router()->getCurrentRoute(); - $conditions = $route->getConditions(); + $route = $slim->router()->getCurrentRoute(); + $conditions = $route->getConditions(); - if (isset($conditions['useController']) && $conditions['useController'] == false) { - return; - } + if (isset($conditions['useController']) && $conditions['useController'] == false) { + return; + } - $routeOptions = call_user_func($route->getCallable()); - $routeKeys = is_array($routeOptions) ? array_keys($routeOptions) : array(); + $routeOptions = call_user_func($route->getCallable()); + $routeKeys = is_array($routeOptions) ? array_keys($routeOptions) : array(); - if (!in_array('controller', $routeKeys, true)) { - return $container->get('output')->render($routeOptions); - } + if (!in_array('controller', $routeKeys, true)) { + return $container->get('output')->render($routeOptions); + } - $params = $route->getParams(); - $data = $slim->request()->getBody(); + $params = $route->getParams(); + $data = $slim->request()->getBody(); - foreach ($routeOptions as $key => $value) { - if (strstr($value, ':')) { - $paramName = str_replace(':', '', $value); - $value = $params[$paramName]; - } - $controllerParams[$key] = $value; - } + foreach ($routeOptions as $key => $value) { + if (strstr($value, ':')) { + $paramName = str_replace(':', '', $value); + $value = $params[$paramName]; + } + $controllerParams[$key] = $value; + } - $params = array_merge($params, $controllerParams); + $params = array_merge($params, $controllerParams); - $controllerName = ucfirst($controllerParams['controller']); + $controllerName = ucfirst($controllerParams['controller']); - if (!empty($controllerParams['action'])) { - $actionName = $controllerParams['action']; - } else { - $httpMethod = strtolower($slim->request()->getMethod()); - $crudList = $container->get('config')->get('crud'); - $actionName = $crudList[$httpMethod]; - } + if (!empty($controllerParams['action'])) { + $actionName = $controllerParams['action']; + } else { + $httpMethod = strtolower($slim->request()->getMethod()); + $crudList = $container->get('config')->get('crud'); + $actionName = $crudList[$httpMethod]; + } - try { - $controllerManager = new \Espo\Core\ControllerManager($container); - $result = $controllerManager->process($controllerName, $actionName, $params, $data, $slim->request()); - $container->get('output')->render($result); - } catch (\Exception $e) { - $container->get('output')->processError($e->getMessage(), $e->getCode()); - } - }); + try { + $controllerManager = new \Espo\Core\ControllerManager($container); + $result = $controllerManager->process($controllerName, $actionName, $params, $data, $slim->request()); + $container->get('output')->render($result); + } catch (\Exception $e) { + $container->get('output')->processError($e->getMessage(), $e->getCode()); + } + }); - $this->getSlim()->hook('slim.after.router', function () use (&$slim) { - $slim->contentType('application/json'); + $this->getSlim()->hook('slim.after.router', function () use (&$slim) { + $slim->contentType('application/json'); - $res = $slim->response(); - $res->header('Expires', '0'); - $res->header('Last-Modified', gmdate("D, d M Y H:i:s") . " GMT"); - $res->header('Cache-Control', 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0'); - $res->header('Pragma', 'no-cache'); - }); - } + $res = $slim->response(); + $res->header('Expires', '0'); + $res->header('Last-Modified', gmdate("D, d M Y H:i:s") . " GMT"); + $res->header('Cache-Control', 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0'); + $res->header('Pragma', 'no-cache'); + }); + } - protected function initRoutes() - { - $routes = new \Espo\Core\Utils\Route($this->getContainer()->get('config'), $this->getMetadata(), $this->getContainer()->get('fileManager')); - $crudList = array_keys( $this->getContainer()->get('config')->get('crud') ); + protected function initRoutes() + { + $routes = new \Espo\Core\Utils\Route($this->getContainer()->get('config'), $this->getMetadata(), $this->getContainer()->get('fileManager')); + $crudList = array_keys( $this->getContainer()->get('config')->get('crud') ); - foreach ($routes->getAll() as $route) { + foreach ($routes->getAll() as $route) { - $method = strtolower($route['method']); - if (!in_array($method, $crudList)) { - $GLOBALS['log']->error('Route: Method ['.$method.'] does not exist. Please check your route ['.$route['route'].']'); - continue; - } + $method = strtolower($route['method']); + if (!in_array($method, $crudList)) { + $GLOBALS['log']->error('Route: Method ['.$method.'] does not exist. Please check your route ['.$route['route'].']'); + continue; + } $currentRoute = $this->getSlim()->$method($route['route'], function() use ($route) { //todo change "use" for php 5.4 - return $route['params']; - }); + return $route['params']; + }); - if (isset($route['conditions'])) { - $currentRoute->conditions($route['conditions']); - } - } - } + if (isset($route['conditions'])) { + $currentRoute->conditions($route['conditions']); + } + } + } } diff --git a/application/Espo/Core/Container.php b/application/Espo/Core/Container.php index 0fd76577bf..b52b161e48 100644 --- a/application/Espo/Core/Container.php +++ b/application/Espo/Core/Container.php @@ -25,10 +25,10 @@ namespace Espo\Core; class Container { - private $data = array(); + private $data = array(); - /** + /** * Constructor */ public function __construct() @@ -38,38 +38,43 @@ class Container public function get($name) { - if (empty($this->data[$name])) { - $this->load($name); - } - return $this->data[$name]; + if (empty($this->data[$name])) { + $this->load($name); + } + return $this->data[$name]; } private function load($name) { - $loadMethod = 'load' . ucfirst($name); - if (method_exists($this, $loadMethod)) { - $obj = $this->$loadMethod(); - $this->data[$name] = $obj; - } else { - $className = '\Espo\Custom\Core\Loaders\\'.ucfirst($name); + $loadMethod = 'load' . ucfirst($name); + if (method_exists($this, $loadMethod)) { + $obj = $this->$loadMethod(); + $this->data[$name] = $obj; + } else { + $className = '\Espo\Custom\Core\Loaders\\'.ucfirst($name); if (!class_exists($className)) { - $className = '\Espo\Core\Loaders\\'.ucfirst($name); + $className = '\Espo\Core\Loaders\\'.ucfirst($name); } - if (class_exists($className)) { - $loadClass = new $className($this); - $this->data[$name] = $loadClass->load(); - } - } + if (class_exists($className)) { + $loadClass = new $className($this); + $this->data[$name] = $loadClass->load(); + } + } - return null; + return null; } protected function getServiceClassName($name, $default) { - $metadata = $this->get('metadata'); - $className = $metadata->get('app.serviceContainer.classNames.' . $name, $default); - return $className; + $metadata = $this->get('metadata'); + $className = $metadata->get('app.serviceContainer.classNames.' . $name, $default); + return $className; + } + + protected function loadContainer() + { + return $this; } private function loadSlim() @@ -77,154 +82,161 @@ class Container return new \Espo\Core\Utils\Api\Slim(); } - private function loadFileManager() + private function loadFileManager() { - return new \Espo\Core\Utils\File\Manager( - $this->get('config') - ); + return new \Espo\Core\Utils\File\Manager( + $this->get('config') + ); } - private function loadPreferences() + private function loadPreferences() { - return $this->get('entityManager')->getEntity('Preferences', $this->get('user')->id); + return $this->get('entityManager')->getEntity('Preferences', $this->get('user')->id); } - private function loadConfig() + private function loadConfig() { - return new \Espo\Core\Utils\Config( - new \Espo\Core\Utils\File\Manager() - ); + return new \Espo\Core\Utils\Config( + new \Espo\Core\Utils\File\Manager() + ); } - private function loadHookManager() + private function loadHookManager() { - return new \Espo\Core\HookManager( - $this - ); + return new \Espo\Core\HookManager( + $this + ); } - private function loadOutput() + private function loadOutput() { - return new \Espo\Core\Utils\Api\Output( - $this->get('slim') - ); + return new \Espo\Core\Utils\Api\Output( + $this->get('slim') + ); } - private function loadMailSender() + private function loadMailSender() { - $className = $this->getServiceClassName('mailSernder', '\\Espo\\Core\\Mail\\Sender'); - return new $className( - $this->get('config') - ); + $className = $this->getServiceClassName('mailSernder', '\\Espo\\Core\\Mail\\Sender'); + return new $className( + $this->get('config') + ); } - private function loadDateTime() + private function loadDateTime() { - return new \Espo\Core\Utils\DateTime( - $this->get('config')->get('dateFormat'), - $this->get('config')->get('timeFormat'), - $this->get('config')->get('timeZone') - ); + return new \Espo\Core\Utils\DateTime( + $this->get('config')->get('dateFormat'), + $this->get('config')->get('timeFormat'), + $this->get('config')->get('timeZone') + ); } - private function loadServiceFactory() + private function loadServiceFactory() { - return new \Espo\Core\ServiceFactory( - $this - ); + return new \Espo\Core\ServiceFactory( + $this + ); } - private function loadSelectManagerFactory() + private function loadSelectManagerFactory() { - return new \Espo\Core\SelectManagerFactory( - $this->get('entityManager'), - $this->get('user'), - $this->get('acl'), - $this->get('metadata') - ); + return new \Espo\Core\SelectManagerFactory( + $this->get('entityManager'), + $this->get('user'), + $this->get('acl'), + $this->get('metadata') + ); } - private function loadMetadata() + private function loadMetadata() { - return new \Espo\Core\Utils\Metadata( - $this->get('config'), - $this->get('fileManager') - ); + return new \Espo\Core\Utils\Metadata( + $this->get('config'), + $this->get('fileManager') + ); } - private function loadLayout() + private function loadLayout() { - return new \Espo\Core\Utils\Layout( - $this->get('fileManager'), - $this->get('metadata') - ); + return new \Espo\Core\Utils\Layout( + $this->get('fileManager'), + $this->get('metadata') + ); } - private function loadAcl() - { - $className = $this->getServiceClassName('acl', '\\Espo\\Core\\Acl'); - return new $className( - $this->get('user'), - $this->get('config'), - $this->get('fileManager'), - $this->get('metadata') - ); - } + private function loadAcl() + { + $className = $this->getServiceClassName('acl', '\\Espo\\Core\\Acl'); + return new $className( + $this->get('user'), + $this->get('config'), + $this->get('fileManager'), + $this->get('metadata') + ); + } - private function loadSchema() - { - return new \Espo\Core\Utils\Database\Schema\Schema( - $this->get('config'), - $this->get('metadata'), - $this->get('fileManager'), - $this->get('entityManager'), - $this->get('classParser') - ); - } + private function loadSchema() + { + return new \Espo\Core\Utils\Database\Schema\Schema( + $this->get('config'), + $this->get('metadata'), + $this->get('fileManager'), + $this->get('entityManager'), + $this->get('classParser') + ); + } - private function loadClassParser() - { - return new \Espo\Core\Utils\File\ClassParser( - $this->get('fileManager'), - $this->get('config'), - $this->get('metadata') - ); - } + private function loadClassParser() + { + return new \Espo\Core\Utils\File\ClassParser( + $this->get('fileManager'), + $this->get('config'), + $this->get('metadata') + ); + } - private function loadLanguage() - { - return new \Espo\Core\Utils\Language( - $this->get('fileManager'), - $this->get('config'), - $this->get('preferences') - ); - } + private function loadLanguage() + { + return new \Espo\Core\Utils\Language( + $this->get('fileManager'), + $this->get('config'), + $this->get('preferences') + ); + } + + private function loadCrypt() + { + return new \Espo\Core\Utils\Crypt( + $this->get('config') + ); + } - private function loadScheduledJob() - { - return new \Espo\Core\Cron\ScheduledJob( - $this - ); - } + private function loadScheduledJob() + { + return new \Espo\Core\Cron\ScheduledJob( + $this + ); + } - private function loadDataManager() - { - return new \Espo\Core\DataManager( - $this - ); - } + private function loadDataManager() + { + return new \Espo\Core\DataManager( + $this + ); + } - private function loadFieldManager() - { - return new \Espo\Core\Utils\FieldManager( - $this->get('metadata'), - $this->get('language') - ); - } + private function loadFieldManager() + { + return new \Espo\Core\Utils\FieldManager( + $this->get('metadata'), + $this->get('language') + ); + } - public function setUser($user) - { - $this->data['user'] = $user; - } + public function setUser($user) + { + $this->data['user'] = $user; + } } diff --git a/application/Espo/Core/ControllerManager.php b/application/Espo/Core/ControllerManager.php index 6c6b796c06..ee92f71c07 100644 --- a/application/Espo/Core/ControllerManager.php +++ b/application/Espo/Core/ControllerManager.php @@ -27,88 +27,88 @@ use \Espo\Core\Exceptions\NotFound; class ControllerManager { - private $config; + private $config; - private $metadata; + private $metadata; - private $container; + private $container; - public function __construct(\Espo\Core\Container $container) - { - $this->container = $container; + public function __construct(\Espo\Core\Container $container) + { + $this->container = $container; - $this->config = $this->container->get('config'); - $this->metadata = $this->container->get('metadata'); - } + $this->config = $this->container->get('config'); + $this->metadata = $this->container->get('metadata'); + } protected function getConfig() - { - return $this->config; - } + { + return $this->config; + } - protected function getMetadata() - { - return $this->metadata; - } + protected function getMetadata() + { + return $this->metadata; + } - public function process($controllerName, $actionName, $params, $data, $request) - { - $customeClassName = '\\Espo\\Custom\\Controllers\\' . Util::normilizeClassName($controllerName); - if (class_exists($customeClassName)) { - $controllerClassName = $customeClassName; - } else { - $moduleName = $this->metadata->getScopeModuleName($controllerName); - if ($moduleName) { - $controllerClassName = '\\Espo\\Modules\\' . $moduleName . '\\Controllers\\' . Util::normilizeClassName($controllerName); - } else { - $controllerClassName = '\\Espo\\Controllers\\' . Util::normilizeClassName($controllerName); - } - } + public function process($controllerName, $actionName, $params, $data, $request) + { + $customeClassName = '\\Espo\\Custom\\Controllers\\' . Util::normilizeClassName($controllerName); + if (class_exists($customeClassName)) { + $controllerClassName = $customeClassName; + } else { + $moduleName = $this->metadata->getScopeModuleName($controllerName); + if ($moduleName) { + $controllerClassName = '\\Espo\\Modules\\' . $moduleName . '\\Controllers\\' . Util::normilizeClassName($controllerName); + } else { + $controllerClassName = '\\Espo\\Controllers\\' . Util::normilizeClassName($controllerName); + } + } - if ($data && stristr($request->getContentType(), 'application/json')) { - $data = json_decode($data); - } + if ($data && stristr($request->getContentType(), 'application/json')) { + $data = json_decode($data); + } - if ($data instanceof \stdClass) { - $data = get_object_vars($data); - } + if ($data instanceof \stdClass) { + $data = get_object_vars($data); + } - if (!class_exists($controllerClassName)) { - throw new NotFound("Controller '$controllerName' is not found"); - } + if (!class_exists($controllerClassName)) { + throw new NotFound("Controller '$controllerName' is not found"); + } - $controller = new $controllerClassName($this->container, $request->getMethod()); + $controller = new $controllerClassName($this->container, $request->getMethod()); - if ($actionName == 'index') { - $actionName = $controllerClassName::$defaultAction; - } + if ($actionName == 'index') { + $actionName = $controllerClassName::$defaultAction; + } - $actionNameUcfirst = ucfirst($actionName); + $actionNameUcfirst = ucfirst($actionName); - $beforeMethodName = 'before' . $actionNameUcfirst; - if (method_exists($controller, $beforeMethodName)) { - $controller->$beforeMethodName($params, $data, $request); - } - $actionMethodName = 'action' . $actionNameUcfirst; + $beforeMethodName = 'before' . $actionNameUcfirst; + if (method_exists($controller, $beforeMethodName)) { + $controller->$beforeMethodName($params, $data, $request); + } + $actionMethodName = 'action' . $actionNameUcfirst; - if (!method_exists($controller, $actionMethodName)) { - throw new NotFound("Action '$actionMethodName' does not exist in controller '$controller'"); - } + if (!method_exists($controller, $actionMethodName)) { + throw new NotFound("Action '$actionMethodName' does not exist in controller '$controller'"); + } - $result = $controller->$actionMethodName($params, $data, $request); + $result = $controller->$actionMethodName($params, $data, $request); - $afterMethodName = 'after' . $actionNameUcfirst; - if (method_exists($controller, $afterMethodName)) { - $controller->$afterMethodName($params, $data, $request); - } + $afterMethodName = 'after' . $actionNameUcfirst; + if (method_exists($controller, $afterMethodName)) { + $controller->$afterMethodName($params, $data, $request); + } - if (is_array($result) || is_bool($result)) { - return \Espo\Core\Utils\Json::encode($result); - } + if (is_array($result) || is_bool($result)) { + return \Espo\Core\Utils\Json::encode($result); + } - return $result; - } + return $result; + } } diff --git a/application/Espo/Core/Controllers/Base.php b/application/Espo/Core/Controllers/Base.php index cf8f1703fd..7c49730251 100644 --- a/application/Espo/Core/Controllers/Base.php +++ b/application/Espo/Core/Controllers/Base.php @@ -28,91 +28,91 @@ use \Espo\Core\Utils\Util; abstract class Base { - protected $name; + protected $name; - private $container; + private $container; - private $requestMethod; + private $requestMethod; - public static $defaultAction = 'index'; + public static $defaultAction = 'index'; - public function __construct(Container $container, $requestMethod = null) - { - $this->container = $container; + public function __construct(Container $container, $requestMethod = null) + { + $this->container = $container; - if (isset($requestMethod)) { - $this->setRequestMethod($requestMethod); - } + if (isset($requestMethod)) { + $this->setRequestMethod($requestMethod); + } - if (empty($this->name)) { - $name = get_class($this); - if (preg_match('@\\\\([\w]+)$@', $name, $matches)) { - $name = $matches[1]; - } - $this->name = $name; - } + if (empty($this->name)) { + $name = get_class($this); + if (preg_match('@\\\\([\w]+)$@', $name, $matches)) { + $name = $matches[1]; + } + $this->name = $name; + } - $this->checkControllerAccess(); - } + $this->checkControllerAccess(); + } - protected function checkControllerAccess() - { - return; - } + protected function checkControllerAccess() + { + return; + } - protected function getContainer() - { - return $this->container; - } + protected function getContainer() + { + return $this->container; + } - /** - * Get request method name (Uppercase) - * - * @return string - */ - protected function getRequestMethod() - { - return $this->requestMethod; - } + /** + * Get request method name (Uppercase) + * + * @return string + */ + protected function getRequestMethod() + { + return $this->requestMethod; + } - protected function setRequestMethod($requestMethod) - { - $this->requestMethod = strtoupper($requestMethod); - } + protected function setRequestMethod($requestMethod) + { + $this->requestMethod = strtoupper($requestMethod); + } - protected function getUser() - { - return $this->container->get('user'); - } + protected function getUser() + { + return $this->container->get('user'); + } - protected function getAcl() - { - return $this->container->get('acl'); - } + protected function getAcl() + { + return $this->container->get('acl'); + } - protected function getConfig() - { - return $this->container->get('config'); - } + protected function getConfig() + { + return $this->container->get('config'); + } - protected function getPreferences() - { - return $this->container->get('preferences'); - } + protected function getPreferences() + { + return $this->container->get('preferences'); + } - protected function getMetadata() - { - return $this->container->get('metadata'); - } + protected function getMetadata() + { + return $this->container->get('metadata'); + } - protected function getServiceFactory() - { - return $this->container->get('serviceFactory'); - } + protected function getServiceFactory() + { + return $this->container->get('serviceFactory'); + } - protected function getService($name) - { - return $this->getServiceFactory()->create($name); - } + protected function getService($name) + { + return $this->getServiceFactory()->create($name); + } } diff --git a/application/Espo/Core/Controllers/Record.php b/application/Espo/Core/Controllers/Record.php index 0f20ea26c6..4601e8b6d9 100644 --- a/application/Espo/Core/Controllers/Record.php +++ b/application/Espo/Core/Controllers/Record.php @@ -18,7 +18,7 @@ * * You should have received a copy of the GNU General Public License * along with EspoCRM. If not, see http://www.gnu.org/licenses/. - ************************************************************************/ + ************************************************************************/ namespace Espo\Core\Controllers; @@ -29,277 +29,277 @@ use \Espo\Core\Utils\Util; class Record extends Base { - const MAX_SIZE_LIMIT = 200; - - public static $defaultAction = 'list'; - - protected function getEntityManager() - { - return $this->getContainer()->get('entityManager'); - } - - protected function getRecordService($name = null) - { - if (empty($name)) { - $name = $this->name; - } - - if ($this->getServiceFactory()->checkExists($name)) { - $service = $this->getServiceFactory()->create($name); - } else { - $service = $this->getServiceFactory()->create('Record'); - $service->setEntityName($name); - } - - return $service; - } + const MAX_SIZE_LIMIT = 200; - public function actionRead($params) - { - $id = $params['id']; - $entity = $this->getRecordService()->getEntity($id); - - if (empty($entity)) { - throw new NotFound(); - } + public static $defaultAction = 'list'; - return $entity->toArray(); - } - - public function actionPatch($params, $data) - { - return $this->actionUpdate($params, $data); - } - - public function actionCreate($params, $data) - { - if (!$this->getAcl()->check($this->name, 'edit')) { - throw new Forbidden(); - } + protected function getEntityManager() + { + return $this->getContainer()->get('entityManager'); + } - $service = $this->getRecordService(); - - if ($entity = $service->createEntity($data)) { - return $entity->toArray(); - } + protected function getRecordService($name = null) + { + if (empty($name)) { + $name = $this->name; + } - throw new Error(); - } + if ($this->getServiceFactory()->checkExists($name)) { + $service = $this->getServiceFactory()->create($name); + } else { + $service = $this->getServiceFactory()->create('Record'); + $service->setEntityName($name); + } - public function actionUpdate($params, $data) - { - if (!$this->getAcl()->check($this->name, 'edit')) { - throw new Forbidden(); - } - - $id = $params['id']; - - if ($entity = $this->getRecordService()->updateEntity($id, $data)) { - return $entity->toArray(); - } + return $service; + } - throw new Error(); - } + public function actionRead($params) + { + $id = $params['id']; + $entity = $this->getRecordService()->getEntity($id); - public function actionList($params, $data, $request) - { - if (!$this->getAcl()->check($this->name, 'read')) { - throw new Forbidden(); - } + if (empty($entity)) { + throw new NotFound(); + } - $where = $request->get('where'); - $offset = $request->get('offset'); - $maxSize = $request->get('maxSize'); - $asc = $request->get('asc') === 'true'; - $sortBy = $request->get('sortBy'); - $q = $request->get('q'); - - if (empty($maxSize)) { - $maxSize = self::MAX_SIZE_LIMIT; - } - if (!empty($maxSize) && $maxSize > self::MAX_SIZE_LIMIT) { - throw new Forbidden(); - } + return $entity->toArray(); + } - $result = $this->getRecordService()->findEntities(array( - 'where' => $where, - 'offset' => $offset, - 'maxSize' => $maxSize, - 'asc' => $asc, - 'sortBy' => $sortBy, - 'q' => $q, - )); - - return array( - 'total' => $result['total'], - 'list' => $result['collection']->toArray() - ); - } - - public function actionListLinked($params, $data, $request) - { - $id = $params['id']; - $link = $params['link']; + public function actionPatch($params, $data) + { + return $this->actionUpdate($params, $data); + } - $where = $request->get('where'); - $offset = $request->get('offset'); - $maxSize = $request->get('maxSize'); - $asc = $request->get('asc') === 'true'; - $sortBy = $request->get('sortBy'); - $q = $request->get('q'); - - if (empty($maxSize)) { - $maxSize = self::MAX_SIZE_LIMIT; - } - if (!empty($maxSize) && $maxSize > self::MAX_SIZE_LIMIT) { - throw new Forbidden(); - } + public function actionCreate($params, $data) + { + if (!$this->getAcl()->check($this->name, 'edit')) { + throw new Forbidden(); + } - $result = $this->getRecordService()->findLinkedEntities($id, $link, array( - 'where' => $where, - 'offset' => $offset, - 'maxSize' => $maxSize, - 'asc' => $asc, - 'sortBy' => $sortBy, - 'q' => $q, - )); - - - return array( - 'total' => $result['total'], - 'list' => $result['collection']->toArray() - ); - } + $service = $this->getRecordService(); - public function actionDelete($params) - { - $id = $params['id']; + if ($entity = $service->createEntity($data)) { + return $entity->toArray(); + } - if ($this->getRecordService()->deleteEntity($id)) { - return true; - } - throw new Error(); - } - - public function actionExport($params, $data, $request) - { - if ($this->getConfig()->get('disableExport') && !$this->getUser()->isAdmin()) { - throw new Forbidden(); - } - - if (!$this->getAcl()->check($this->name, 'read')) { - throw new Forbidden(); - } - - $ids = $request->get('ids'); - $where = $request->get('where'); - - return array( - 'id' => $this->getRecordService()->export($ids, $where) - ); - } + throw new Error(); + } - public function actionMassUpdate($params, $data) - { - if (!$this->getAcl()->check($this->name, 'edit')) { - throw new Forbidden(); - } + public function actionUpdate($params, $data) + { + if (!$this->getAcl()->check($this->name, 'edit')) { + throw new Forbidden(); + } - $ids = $data['ids']; - $where = $data['where']; - $attributes = $data['attributes']; + $id = $params['id']; - $idsUpdated = $this->getRecordService()->massUpdate($attributes, $ids, $where); + if ($entity = $this->getRecordService()->updateEntity($id, $data)) { + return $entity->toArray(); + } - return $idsUpdated; - } + throw new Error(); + } - public function actionMassDelete($params, $data) - { - if (!$this->getAcl()->check($this->name, 'delete')) { - throw new Forbidden(); - } + public function actionList($params, $data, $request) + { + if (!$this->getAcl()->check($this->name, 'read')) { + throw new Forbidden(); + } - $ids = $data['ids']; - $where = $data['where']; + $where = $request->get('where'); + $offset = $request->get('offset'); + $maxSize = $request->get('maxSize'); + $asc = $request->get('asc') === 'true'; + $sortBy = $request->get('sortBy'); + $q = $request->get('q'); - $idsDeleted = $this->getRecordService()->massDelete($ids, $where); + if (empty($maxSize)) { + $maxSize = self::MAX_SIZE_LIMIT; + } + if (!empty($maxSize) && $maxSize > self::MAX_SIZE_LIMIT) { + throw new Forbidden(); + } - return $idsDeleted; - } + $result = $this->getRecordService()->findEntities(array( + 'where' => $where, + 'offset' => $offset, + 'maxSize' => $maxSize, + 'asc' => $asc, + 'sortBy' => $sortBy, + 'q' => $q, + )); - public function actionCreateLink($params, $data) - { - $id = $params['id']; - $link = $params['link']; - - $foreignIds = array(); - if (isset($data['id'])) { - $foreignIds[] = $data['id']; - } - if (isset($data['ids']) && is_array($data['ids'])) { - foreach ($data['ids'] as $foreignId) { - $foreignIds[] = $foreignId; - } - } - - $result = false; - foreach ($foreignIds as $foreignId) { - if ($this->getRecordService()->linkEntity($id, $link, $foreignId)) { - $result = $result || true; - } - } - if ($result) { - return true; - } - - throw new Error(); - } - - public function actionRemoveLink($params, $data) - { - $id = $params['id']; - $link = $params['link']; - - $foreignIds = array(); - if (isset($data['id'])) { - $foreignIds[] = $data['id']; - } - if (isset($data['ids']) && is_array($data['ids'])) { - foreach ($data['ids'] as $foreignId) { - $foreignIds[] = $foreignId; - } - } - - $result = false; - foreach ($foreignIds as $foreignId) { - if ($this->getRecordService()->unlinkEntity($id, $link, $foreignId)) { - $result = $result || true; - } - } - if ($result) { - return true; - } - - throw new Error(); - } - - public function actionFollow($params) - { - if (!$this->getAcl()->check($this->name, 'read')) { - throw new Forbidden(); - } - $id = $params['id']; - return $this->getRecordService()->follow($id); - } - - public function actionUnfollow($params) - { - if (!$this->getAcl()->check($this->name, 'read')) { - throw new Forbidden(); - } - $id = $params['id']; - return $this->getRecordService()->unfollow($id); - } + return array( + 'total' => $result['total'], + 'list' => $result['collection']->toArray() + ); + } + + public function actionListLinked($params, $data, $request) + { + $id = $params['id']; + $link = $params['link']; + + $where = $request->get('where'); + $offset = $request->get('offset'); + $maxSize = $request->get('maxSize'); + $asc = $request->get('asc') === 'true'; + $sortBy = $request->get('sortBy'); + $q = $request->get('q'); + + if (empty($maxSize)) { + $maxSize = self::MAX_SIZE_LIMIT; + } + if (!empty($maxSize) && $maxSize > self::MAX_SIZE_LIMIT) { + throw new Forbidden(); + } + + $result = $this->getRecordService()->findLinkedEntities($id, $link, array( + 'where' => $where, + 'offset' => $offset, + 'maxSize' => $maxSize, + 'asc' => $asc, + 'sortBy' => $sortBy, + 'q' => $q, + )); + + + return array( + 'total' => $result['total'], + 'list' => $result['collection']->toArray() + ); + } + + public function actionDelete($params) + { + $id = $params['id']; + + if ($this->getRecordService()->deleteEntity($id)) { + return true; + } + throw new Error(); + } + + public function actionExport($params, $data, $request) + { + if ($this->getConfig()->get('disableExport') && !$this->getUser()->isAdmin()) { + throw new Forbidden(); + } + + if (!$this->getAcl()->check($this->name, 'read')) { + throw new Forbidden(); + } + + $ids = $request->get('ids'); + $where = $request->get('where'); + + return array( + 'id' => $this->getRecordService()->export($ids, $where) + ); + } + + public function actionMassUpdate($params, $data, $request) + { + if (!$this->getAcl()->check($this->name, 'edit')) { + throw new Forbidden(); + } + + $ids = $data['ids']; + $where = $data['where']; + $attributes = $data['attributes']; + + $idsUpdated = $this->getRecordService()->massUpdate($attributes, $ids, $where); + + return $idsUpdated; + } + + public function actionMassDelete($params, $data, $request) + { + if (!$this->getAcl()->check($this->name, 'delete')) { + throw new Forbidden(); + } + + $ids = $data['ids']; + $where = $data['where']; + + $idsRemoved = $this->getRecordService()->massRemove($ids, $where); + + return $idsRemoved; + } + + public function actionCreateLink($params, $data) + { + $id = $params['id']; + $link = $params['link']; + + $foreignIds = array(); + if (isset($data['id'])) { + $foreignIds[] = $data['id']; + } + if (isset($data['ids']) && is_array($data['ids'])) { + foreach ($data['ids'] as $foreignId) { + $foreignIds[] = $foreignId; + } + } + + $result = false; + foreach ($foreignIds as $foreignId) { + if ($this->getRecordService()->linkEntity($id, $link, $foreignId)) { + $result = $result || true; + } + } + if ($result) { + return true; + } + + throw new Error(); + } + + public function actionRemoveLink($params, $data) + { + $id = $params['id']; + $link = $params['link']; + + $foreignIds = array(); + if (isset($data['id'])) { + $foreignIds[] = $data['id']; + } + if (isset($data['ids']) && is_array($data['ids'])) { + foreach ($data['ids'] as $foreignId) { + $foreignIds[] = $foreignId; + } + } + + $result = false; + foreach ($foreignIds as $foreignId) { + if ($this->getRecordService()->unlinkEntity($id, $link, $foreignId)) { + $result = $result || true; + } + } + if ($result) { + return true; + } + + throw new Error(); + } + + public function actionFollow($params) + { + if (!$this->getAcl()->check($this->name, 'read')) { + throw new Forbidden(); + } + $id = $params['id']; + return $this->getRecordService()->follow($id); + } + + public function actionUnfollow($params) + { + if (!$this->getAcl()->check($this->name, 'read')) { + throw new Forbidden(); + } + $id = $params['id']; + return $this->getRecordService()->unfollow($id); + } } diff --git a/application/Espo/Core/Cron/ScheduledJob.php b/application/Espo/Core/Cron/ScheduledJob.php index 22fa69ad81..886dfd0b70 100644 --- a/application/Espo/Core/Cron/ScheduledJob.php +++ b/application/Espo/Core/Cron/ScheduledJob.php @@ -23,163 +23,163 @@ namespace Espo\Core\Cron; use Espo\Core\Exceptions\NotFound, - Espo\Core\Utils\Util; + Espo\Core\Utils\Util; class ScheduledJob { - private $container; - private $systemUtil; + private $container; + private $systemUtil; - protected $data = null; + protected $data = null; - protected $cacheFile = 'data/cache/application/jobs.php'; + protected $cacheFile = 'data/cache/application/jobs.php'; - protected $cronFile = 'cron.php'; + protected $cronFile = 'cron.php'; - protected $allowedMethod = 'run'; + protected $allowedMethod = 'run'; - /** - * @var array - path to cron job files - */ - private $paths = array( - 'corePath' => 'application/Espo/Jobs', - 'modulePath' => 'application/Espo/Modules/{*}/Jobs', - 'customPath' => 'custom/Espo/Custom/Jobs', - ); + /** + * @var array - path to cron job files + */ + private $paths = array( + 'corePath' => 'application/Espo/Jobs', + 'modulePath' => 'application/Espo/Modules/{*}/Jobs', + 'customPath' => 'custom/Espo/Custom/Jobs', + ); - protected $cronSetup = array( - 'linux' => '* * * * * {PHP-BIN-DIR} -f {CRON-FILE} > /dev/null 2>&1', - 'windows' => '{PHP-BIN-DIR}.exe -f {CRON-FILE}', - 'mac' => '* * * * * {PHP-BIN-DIR} -f {CRON-FILE} > /dev/null 2>&1', - 'default' => '* * * * * {PHP-BIN-DIR} -f {CRON-FILE}', - ); + protected $cronSetup = array( + 'linux' => '* * * * * {PHP-BIN-DIR} -f {CRON-FILE} > /dev/null 2>&1', + 'windows' => '{PHP-BIN-DIR}.exe -f {CRON-FILE}', + 'mac' => '* * * * * {PHP-BIN-DIR} -f {CRON-FILE} > /dev/null 2>&1', + 'default' => '* * * * * {PHP-BIN-DIR} -f {CRON-FILE}', + ); - public function __construct(\Espo\Core\Container $container) - { - $this->container = $container; - $this->systemUtil = new \Espo\Core\Utils\System(); - } + public function __construct(\Espo\Core\Container $container) + { + $this->container = $container; + $this->systemUtil = new \Espo\Core\Utils\System(); + } - protected function getContainer() - { - return $this->container; - } + protected function getContainer() + { + return $this->container; + } - protected function getEntityManager() - { - return $this->container->get('entityManager'); - } + protected function getEntityManager() + { + return $this->container->get('entityManager'); + } - protected function getSystemUtil() - { - return $this->systemUtil; - } + protected function getSystemUtil() + { + return $this->systemUtil; + } - public function run(array $job) - { - $jobName = $job['method']; + public function run(array $job) + { + $jobName = $job['method']; - $className = $this->getClassName($jobName); - if ($className === false) { - throw new NotFound(); - } + $className = $this->getClassName($jobName); + if ($className === false) { + throw new NotFound(); + } - $jobClass = new $className($this->container); - $method = $this->allowedMethod; + $jobClass = new $className($this->container); + $method = $this->allowedMethod; - $jobClass->$method(); - } + $jobClass->$method(); + } - /** - * Get list of all jobs - * - * @return array - */ - public function getAll() - { - if (!isset($this->data)) { - $this->init(); - } + /** + * Get list of all jobs + * + * @return array + */ + public function getAll() + { + if (!isset($this->data)) { + $this->init(); + } - return $this->data; - } + return $this->data; + } - /** - * Get class name of a job by name - * - * @param string $name - * @return string - */ - public function get($name) - { - return $this->getClassName($name); - } + /** + * Get class name of a job by name + * + * @param string $name + * @return string + */ + public function get($name) + { + return $this->getClassName($name); + } - /** - * Get list of all job names - * - * @return array - */ - public function getAllNamesOnly() - { - $data = $this->getAll(); + /** + * Get list of all job names + * + * @return array + */ + public function getAllNamesOnly() + { + $data = $this->getAll(); - $namesOnly = array_keys($data); + $namesOnly = array_keys($data); - return $namesOnly; - } + return $namesOnly; + } - /** - * Get class name of a job - * - * @param string $name - * @return string - */ - protected function getClassName($name) - { - $name = Util::normilizeClassName($name); + /** + * Get class name of a job + * + * @param string $name + * @return string + */ + protected function getClassName($name) + { + $name = Util::normilizeClassName($name); - $data = $this->getAll(); + $data = $this->getAll(); - $name = ucfirst($name); - if (isset($data[$name])) { - return $data[$name]; - } + $name = ucfirst($name); + if (isset($data[$name])) { + return $data[$name]; + } - return false; - } + return false; + } - /** - * Load scheduler classes. It loads from ...Jobs, ex. \Espo\Jobs - * @return null - */ - protected function init() - { - $classParser = $this->getContainer()->get('classParser'); - $classParser->setAllowedMethods( array($this->allowedMethod) ); - $this->data = $classParser->getData($this->paths, $this->cacheFile); - } + /** + * Load scheduler classes. It loads from ...Jobs, ex. \Espo\Jobs + * @return null + */ + protected function init() + { + $classParser = $this->getContainer()->get('classParser'); + $classParser->setAllowedMethods( array($this->allowedMethod) ); + $this->data = $classParser->getData($this->paths, $this->cacheFile); + } - public function getSetupMessage() - { - $language = $this->getContainer()->get('language'); + public function getSetupMessage() + { + $language = $this->getContainer()->get('language'); - $OS = $this->getSystemUtil()->getOS(); - $phpBin = $this->getSystemUtil()->getPhpBin(); - $cronFile = Util::concatPath($this->getSystemUtil()->getRootDir(), $this->cronFile); - $desc = $language->translate('cronSetup', 'options', 'ScheduledJob'); + $OS = $this->getSystemUtil()->getOS(); + $phpBin = $this->getSystemUtil()->getPhpBin(); + $cronFile = Util::concatPath($this->getSystemUtil()->getRootDir(), $this->cronFile); + $desc = $language->translate('cronSetup', 'options', 'ScheduledJob'); - $message = isset($desc[$OS]) ? $desc[$OS] : $desc['default']; + $message = isset($desc[$OS]) ? $desc[$OS] : $desc['default']; - $command = isset($this->cronSetup[$OS]) ? $this->cronSetup[$OS] : $this->cronSetup['default']; - $command = str_replace(array('{PHP-BIN-DIR}', '{CRON-FILE}'), array($phpBin, $cronFile), $command); + $command = isset($this->cronSetup[$OS]) ? $this->cronSetup[$OS] : $this->cronSetup['default']; + $command = str_replace(array('{PHP-BIN-DIR}', '{CRON-FILE}'), array($phpBin, $cronFile), $command); - return array( - 'message' => $message, - 'command' => $command, - ); - } + return array( + 'message' => $message, + 'command' => $command, + ); + } } diff --git a/application/Espo/Core/Cron/Service.php b/application/Espo/Core/Cron/Service.php index 7ffa3a2ca6..cb969e1b53 100644 --- a/application/Espo/Core/Cron/Service.php +++ b/application/Espo/Core/Cron/Service.php @@ -23,45 +23,45 @@ namespace Espo\Core\Cron; use Espo\Core\Utils\Json, - Espo\Core\Exceptions\NotFound; + Espo\Core\Exceptions\NotFound; class Service { - private $serviceFactory; + private $serviceFactory; - public function __construct(\Espo\Core\ServiceFactory $serviceFactory) - { - $this->serviceFactory = $serviceFactory; - } + public function __construct(\Espo\Core\ServiceFactory $serviceFactory) + { + $this->serviceFactory = $serviceFactory; + } - protected function getServiceFactory() - { - return $this->serviceFactory; - } + protected function getServiceFactory() + { + return $this->serviceFactory; + } - public function run($job) - { - $serviceName = $job['service_name']; + public function run($job) + { + $serviceName = $job['service_name']; - if (!$this->getServiceFactory()->checkExists($serviceName)) { - throw new NotFound(); - } + if (!$this->getServiceFactory()->checkExists($serviceName)) { + 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(); - } + if (!method_exists($service, $serviceMethod)) { + throw new NotFound(); + } - $data = $job['data']; - if (Json::isJSON($data)) { - $data = Json::decode($data, true); - } + $data = $job['data']; + if (Json::isJSON($data)) { + $data = Json::decode($data, true); + } - $service->$serviceMethod($data); - } + $service->$serviceMethod($data); + } } \ No newline at end of file diff --git a/application/Espo/Core/CronManager.php b/application/Espo/Core/CronManager.php index 6c5cb13063..059ec4d059 100644 --- a/application/Espo/Core/CronManager.php +++ b/application/Espo/Core/CronManager.php @@ -24,192 +24,192 @@ namespace Espo\Core; class CronManager { - private $container; - private $config; - private $fileManager; + private $container; + private $config; + private $fileManager; - private $scheduledJobCron; - private $serviceCron; + private $scheduledJobCron; + private $serviceCron; - private $jobService; - private $scheduledJobService; + private $jobService; + private $scheduledJobService; - const PENDING = 'Pending'; - const RUNNING = 'Running'; - const SUCCESS = 'Success'; - const FAILED = 'Failed'; + const PENDING = 'Pending'; + const RUNNING = 'Running'; + const SUCCESS = 'Success'; + const FAILED = 'Failed'; - protected $lastRunTime = 'data/cache/application/cronLastRunTime.php'; + protected $lastRunTime = 'data/cache/application/cronLastRunTime.php'; - public function __construct(\Espo\Core\Container $container) - { - $this->container = $container; + public function __construct(\Espo\Core\Container $container) + { + $this->container = $container; - $this->config = $this->container->get('config'); - $this->fileManager = $this->container->get('fileManager'); + $this->config = $this->container->get('config'); + $this->fileManager = $this->container->get('fileManager'); - $this->scheduledJobCron = $this->container->get('scheduledJob'); - $this->serviceCron = new \Espo\Core\Cron\Service( $this->container->get('serviceFactory')); + $this->scheduledJobCron = $this->container->get('scheduledJob'); + $this->serviceCron = new \Espo\Core\Cron\Service( $this->container->get('serviceFactory')); - $this->jobService = $this->container->get('serviceFactory')->create('job'); - $this->scheduledJobService = $this->container->get('serviceFactory')->create('scheduledJob'); - } + $this->jobService = $this->container->get('serviceFactory')->create('job'); + $this->scheduledJobService = $this->container->get('serviceFactory')->create('scheduledJob'); + } - protected function getContainer() - { - return $this->container; - } + protected function getContainer() + { + return $this->container; + } - protected function getConfig() - { - return $this->config; - } + protected function getConfig() + { + return $this->config; + } - protected function getFileManager() - { - return $this->fileManager; - } + protected function getFileManager() + { + return $this->fileManager; + } - protected function getJobService() - { - return $this->jobService; - } + protected function getJobService() + { + return $this->jobService; + } - protected function getScheduledJobService() - { - return $this->scheduledJobService; - } + protected function getScheduledJobService() + { + return $this->scheduledJobService; + } - protected function getScheduledJobCron() - { - return $this->scheduledJobCron; - } + protected function getScheduledJobCron() + { + return $this->scheduledJobCron; + } - protected function getServiceCron() - { - return $this->serviceCron; - } + protected function getServiceCron() + { + return $this->serviceCron; + } - protected function getLastRunTime() - { - $lastRunTime = $this->getFileManager()->getContents($this->lastRunTime); - if (!is_int($lastRunTime)) { - $lastRunTime = time() - (intval($this->getConfig()->get('cron.minExecutionTime')) + 60); - } + protected function getLastRunTime() + { + $lastRunTime = $this->getFileManager()->getContents($this->lastRunTime); + if (!is_int($lastRunTime)) { + $lastRunTime = time() - (intval($this->getConfig()->get('cron.minExecutionTime')) + 60); + } - return $lastRunTime; - } + return $lastRunTime; + } - protected function setLastRunTime($time) - { - return $this->getFileManager()->putContentsPHP($this->lastRunTime, $time); - } + protected function setLastRunTime($time) + { + return $this->getFileManager()->putContentsPHP($this->lastRunTime, $time); + } - protected function checkLastRunTime() - { - $currentTime = time(); - $lastRunTime = $this->getLastRunTime(); - $minTime = $this->getConfig()->get('cron.minExecutionTime'); + protected function checkLastRunTime() + { + $currentTime = time(); + $lastRunTime = $this->getLastRunTime(); + $minTime = $this->getConfig()->get('cron.minExecutionTime'); - if ($currentTime > ($lastRunTime + $minTime) ) { - return true; - } + if ($currentTime > ($lastRunTime + $minTime) ) { + return true; + } - return false; - } + return false; + } - public function run() - { - if (!$this->checkLastRunTime()) { - $GLOBALS['log']->info('Cron Manager: Stop cron running, too frequency execution'); - return; //stop cron running, too frequency execution - } + public function run() + { + if (!$this->checkLastRunTime()) { + $GLOBALS['log']->info('Cron Manager: Stop cron running, too frequency execution'); + return; //stop cron running, too frequency execution + } - $this->setLastRunTime(time()); + $this->setLastRunTime(time()); - //Check scheduled jobs and create related jobs - $this->createJobsFromScheduledJobs(); + //Check scheduled jobs and create related jobs + $this->createJobsFromScheduledJobs(); - $pendingJobs = $this->getJobService()->getPendingJobs(); + $pendingJobs = $this->getJobService()->getPendingJobs(); - foreach ($pendingJobs as $job) { + foreach ($pendingJobs as $job) { - $this->getJobService()->updateEntity($job['id'], array( - 'status' => self::RUNNING, - )); + $this->getJobService()->updateEntity($job['id'], array( + 'status' => self::RUNNING, + )); - $isSuccess = true; + $isSuccess = true; - try { - if (!empty($job['scheduled_job_id'])) { - $this->getScheduledJobCron()->run($job); - } else { - $this->getServiceCron()->run($job); - } - } catch (\Exception $e) { - $isSuccess = false; - $GLOBALS['log']->error('Failed job running, job ['.$job['id'].']. Error Details: '.$e->getMessage()); - } + try { + if (!empty($job['scheduled_job_id'])) { + $this->getScheduledJobCron()->run($job); + } else { + $this->getServiceCron()->run($job); + } + } catch (\Exception $e) { + $isSuccess = false; + $GLOBALS['log']->error('Failed job running, job ['.$job['id'].']. Error Details: '.$e->getMessage()); + } - $status = $isSuccess ? self::SUCCESS : self::FAILED; + $status = $isSuccess ? self::SUCCESS : self::FAILED; - $this->getJobService()->updateEntity($job['id'], array( - 'status' => $status, - )); + $this->getJobService()->updateEntity($job['id'], array( + 'status' => $status, + )); - //set status in the schedulerJobLog - if (!empty($job['scheduled_job_id'])) { - $this->getScheduledJobService()->addLogRecord($job['scheduled_job_id'], $status); - } - } + //set status in the schedulerJobLog + if (!empty($job['scheduled_job_id'])) { + $this->getScheduledJobService()->addLogRecord($job['scheduled_job_id'], $status); + } + } - } + } - /** - * Check scheduled jobs and create related jobs - * @return array List of created Jobs - */ - protected function createJobsFromScheduledJobs() - { - $activeScheduledJobs = $this->getScheduledJobService()->getActiveJobs(); + /** + * Check scheduled jobs and create related jobs + * @return array List of created Jobs + */ + protected function createJobsFromScheduledJobs() + { + $activeScheduledJobs = $this->getScheduledJobService()->getActiveJobs(); - $createdJobs = array(); - foreach ($activeScheduledJobs as $scheduledJob) { + $createdJobs = array(); + foreach ($activeScheduledJobs as $scheduledJob) { - $scheduling = $scheduledJob['scheduling']; + $scheduling = $scheduledJob['scheduling']; - $cronExpression = \Cron\CronExpression::factory($scheduling); + $cronExpression = \Cron\CronExpression::factory($scheduling); - try { - $prevDate = $cronExpression->getPreviousRunDate()->format('Y-m-d H:i:s'); - } catch (\Exception $e) { - $GLOBALS['log']->error('ScheduledJob ['.$scheduledJob['id'].']: CronExpression - Impossible CRON expression ['.$scheduling.']'); - continue; - } + try { + $prevDate = $cronExpression->getPreviousRunDate()->format('Y-m-d H:i:s'); + } catch (\Exception $e) { + $GLOBALS['log']->error('ScheduledJob ['.$scheduledJob['id'].']: CronExpression - Impossible CRON expression ['.$scheduling.']'); + continue; + } - if ($cronExpression->isDue()) { - $prevDate = date('Y-m-d H:i:00'); - } + if ($cronExpression->isDue()) { + $prevDate = date('Y-m-d H:i:00'); + } - $existsJob = $this->getJobService()->getJobByScheduledJob($scheduledJob['id'], $prevDate); + $existsJob = $this->getJobService()->getJobByScheduledJob($scheduledJob['id'], $prevDate); - if (!isset($existsJob) || empty($existsJob)) { - //create a job - $data = array( - 'name' => $scheduledJob['name'], - 'status' => self::PENDING, - 'scheduledJobId' => $scheduledJob['id'], - 'executeTime' => $prevDate, - 'method' => $scheduledJob['job'], - ); - $createdJobs[] = $this->getJobService()->createEntity($data); - } - } + if (!isset($existsJob) || empty($existsJob)) { + //create a job + $data = array( + 'name' => $scheduledJob['name'], + 'status' => self::PENDING, + 'scheduledJobId' => $scheduledJob['id'], + 'executeTime' => $prevDate, + 'method' => $scheduledJob['job'], + ); + $createdJobs[] = $this->getJobService()->createEntity($data); + } + } - return $createdJobs; - } + return $createdJobs; + } } diff --git a/application/Espo/Core/DataManager.php b/application/Espo/Core/DataManager.php index 65ee595dd7..44525ff57e 100644 --- a/application/Espo/Core/DataManager.php +++ b/application/Espo/Core/DataManager.php @@ -24,106 +24,106 @@ namespace Espo\Core; class DataManager { - private $container; + private $container; - private $cachePath = 'data/cache'; + private $cachePath = 'data/cache'; - public function __construct(Container $container) - { - $this->container = $container; - } + public function __construct(Container $container) + { + $this->container = $container; + } - protected function getContainer() - { - return $this->container; - } + protected function getContainer() + { + return $this->container; + } - /** - * Rebuild the system with metadata, database and cache clearing - * - * @return bool - */ - public function rebuild($entityList = null) - { - $result = $this->clearCache(); + /** + * Rebuild the system with metadata, database and cache clearing + * + * @return bool + */ + public function rebuild($entityList = null) + { + $result = $this->clearCache(); - $result &= $this->rebuildMetadata(); + $result &= $this->rebuildMetadata(); - $result &= $this->rebuildDatabase($entityList); + $result &= $this->rebuildDatabase($entityList); - return $result; - } + return $result; + } - /** - * Clear a cache - * - * @return bool - */ - public function clearCache() - { - $result = $this->getContainer()->get('fileManager')->removeInDir($this->cachePath); + /** + * Clear a cache + * + * @return bool + */ + public function clearCache() + { + $result = $this->getContainer()->get('fileManager')->removeInDir($this->cachePath); - if ($result === false) { - throw new Exceptions\Error("Error while clearing cache"); - } + if ($result != true) { + throw new Exceptions\Error("Error while clearing cache"); + } - $this->updateCacheTimestamp(); + $this->updateCacheTimestamp(); - return $result; - } + return $result; + } - /** - * Rebuild database - * - * @return bool - */ - public function rebuildDatabase($entityList = null) - { - try { - $result = $this->getContainer()->get('schema')->rebuild($entityList); - } catch (\Exception $e) { - $result = false; - $GLOBALS['log']->error('Fault to rebuild database schema'.'. Details: '.$e->getMessage()); - } + /** + * Rebuild database + * + * @return bool + */ + public function rebuildDatabase($entityList = null) + { + try { + $result = $this->getContainer()->get('schema')->rebuild($entityList); + } catch (\Exception $e) { + $result = false; + $GLOBALS['log']->error('Fault to rebuild database schema'.'. Details: '.$e->getMessage()); + } - if ($result === false) { - throw new Exceptions\Error("Error while rebuilding database. See log file for details."); - } + if ($result != true) { + throw new Exceptions\Error("Error while rebuilding database. See log file for details."); + } - $this->updateCacheTimestamp(); + $this->updateCacheTimestamp(); - return $result; - } + return $result; + } - /** - * Rebuild metadata - * - * @return bool - */ - public function rebuildMetadata() - { - $metadata = $this->getContainer()->get('metadata'); + /** + * Rebuild metadata + * + * @return bool + */ + public function rebuildMetadata() + { + $metadata = $this->getContainer()->get('metadata'); - $metadata->init(true); + $metadata->init(true); - $ormMeta = $metadata->getOrmMetadata(true); + $ormMeta = $metadata->getOrmMetadata(true); - $this->updateCacheTimestamp(); + $this->updateCacheTimestamp(); - return empty($ormMeta) ? false : true; - } + return empty($ormMeta) ? false : true; + } - /** - * Update cache timestamp - * - * @return bool - */ - public function updateCacheTimestamp() - { - $this->getContainer()->get('config')->updateCacheTimestamp(); - $this->getContainer()->get('config')->save(); - return true; - } + /** + * Update cache timestamp + * + * @return bool + */ + public function updateCacheTimestamp() + { + $this->getContainer()->get('config')->updateCacheTimestamp(); + $this->getContainer()->get('config')->save(); + return true; + } } diff --git a/application/Espo/Core/Entities/Person.php b/application/Espo/Core/Entities/Person.php index 38de106a55..6c6d8f08cc 100644 --- a/application/Espo/Core/Entities/Person.php +++ b/application/Espo/Core/Entities/Person.php @@ -24,30 +24,30 @@ namespace Espo\Core\Entities; class Person extends \Espo\Core\ORM\Entity { - public static $person = true; - - public function setLastName($value) - { - $this->_setValue('lastName', $value); - - $firstName = $this->get('firstName'); - if (empty($firstName)) { - $this->_setValue('name', $value); - } else { - $this->_setValue('name', $firstName . ' ' . $value); - } - } - - public function setFirstName($value) - { - $this->_setValue('firstName', $value); - - $lastName = $this->get('lastName'); - if (empty($lastName)) { - $this->_setValue('name', $value); - } else { - $this->_setValue('name', $value . ' ' . $lastName); - } - } + public static $person = true; + + public function _setLastName($value) + { + $this->setValue('lastName', $value); + + $firstName = $this->get('firstName'); + if (empty($firstName)) { + $this->setValue('name', $value); + } else { + $this->setValue('name', $firstName . ' ' . $value); + } + } + + public function _setFirstName($value) + { + $this->setValue('firstName', $value); + + $lastName = $this->get('lastName'); + if (empty($lastName)) { + $this->setValue('name', $value); + } else { + $this->setValue('name', $value . ' ' . $lastName); + } + } } diff --git a/application/Espo/Core/EntryPointManager.php b/application/Espo/Core/EntryPointManager.php index fa24a67fa5..271bcdabf3 100644 --- a/application/Espo/Core/EntryPointManager.php +++ b/application/Espo/Core/EntryPointManager.php @@ -23,93 +23,93 @@ namespace Espo\Core; use \Espo\Core\Exceptions\NotFound, - \Espo\Core\Utils\Util; + \Espo\Core\Utils\Util; class EntryPointManager { - private $container; - - private $fileManager; + private $container; + + private $fileManager; - protected $data = null; + protected $data = null; - protected $cacheFile = 'data/cache/application/entryPoints.php'; + protected $cacheFile = 'data/cache/application/entryPoints.php'; - protected $allowedMethods = array( - 'run', - ); + protected $allowedMethods = array( + 'run', + ); - /** + /** * @var array - path to entryPoint files */ - private $paths = array( - 'corePath' => 'application/Espo/EntryPoints', - 'modulePath' => 'application/Espo/Modules/{*}/EntryPoints', - 'customPath' => 'custom/Espo/Custom/EntryPoints', - ); + private $paths = array( + 'corePath' => 'application/Espo/EntryPoints', + 'modulePath' => 'application/Espo/Modules/{*}/EntryPoints', + 'customPath' => 'custom/Espo/Custom/EntryPoints', + ); - public function __construct(\Espo\Core\Container $container) - { - $this->container = $container; - $this->fileManager = $container->get('fileManager'); - } + public function __construct(\Espo\Core\Container $container) + { + $this->container = $container; + $this->fileManager = $container->get('fileManager'); + } - protected function getContainer() - { - return $this->container; - } + protected function getContainer() + { + return $this->container; + } - protected function getFileManager() - { - return $this->fileManager; - } + protected function getFileManager() + { + return $this->fileManager; + } - public function checkAuthRequired($name) - { - $className = $this->getClassName($name); - if ($className === false) { - throw new NotFound(); - } - return $className::$authRequired; - } + public function checkAuthRequired($name) + { + $className = $this->getClassName($name); + if ($className === false) { + throw new NotFound(); + } + return $className::$authRequired; + } - public function run($name) - { - $className = $this->getClassName($name); - if ($className === false) { - throw new NotFound(); - } - $entryPoint = new $className($this->container); + public function run($name) + { + $className = $this->getClassName($name); + if ($className === false) { + throw new NotFound(); + } + $entryPoint = new $className($this->container); - $entryPoint->run(); - } + $entryPoint->run(); + } - protected function getClassName($name) - { - $name = Util::normilizeClassName($name); - - if (!isset($this->data)) { - $this->init(); - } + protected function getClassName($name) + { + $name = Util::normilizeClassName($name); + + if (!isset($this->data)) { + $this->init(); + } - $name = ucfirst($name); - if (isset($this->data[$name])) { - return $this->data[$name]; - } - + $name = ucfirst($name); + if (isset($this->data[$name])) { + return $this->data[$name]; + } + return false; - } + } - protected function init() - { - $classParser = $this->getContainer()->get('classParser'); - $classParser->setAllowedMethods($this->allowedMethods); - $this->data = $classParser->getData($this->paths, $this->cacheFile); - } - + protected function init() + { + $classParser = $this->getContainer()->get('classParser'); + $classParser->setAllowedMethods($this->allowedMethods); + $this->data = $classParser->getData($this->paths, $this->cacheFile); + } + } diff --git a/application/Espo/Core/EntryPoints/Base.php b/application/Espo/Core/EntryPoints/Base.php index 52c668b8e7..d62598a66f 100644 --- a/application/Espo/Core/EntryPoints/Base.php +++ b/application/Espo/Core/EntryPoints/Base.php @@ -28,51 +28,51 @@ use \Espo\Core\Exceptions\Forbidden; abstract class Base { - private $container; - - public static $authRequired = true; - - protected function getContainer() - { - return $this->container; - } - - protected function getUser() - { - return $this->getContainer()->get('user'); - } - - protected function getAcl() - { - return $this->getContainer()->get('acl'); - } - - protected function getEntityManager() - { - return $this->getContainer()->get('entityManager'); - } - - protected function getServiceFactory() - { - return $this->getContainer()->get('serviceFactory'); - } - - protected function getConfig() - { - return $this->getContainer()->get('config'); - } - - protected function getMetadata() - { - return $this->getContainer()->get('metadata'); - } - - public function __construct(Container $container) - { - $this->container = $container; - } - - abstract public function run(); + private $container; + + public static $authRequired = true; + + protected function getContainer() + { + return $this->container; + } + + protected function getUser() + { + return $this->getContainer()->get('user'); + } + + protected function getAcl() + { + return $this->getContainer()->get('acl'); + } + + protected function getEntityManager() + { + return $this->getContainer()->get('entityManager'); + } + + protected function getServiceFactory() + { + return $this->getContainer()->get('serviceFactory'); + } + + protected function getConfig() + { + return $this->getContainer()->get('config'); + } + + protected function getMetadata() + { + return $this->getContainer()->get('metadata'); + } + + public function __construct(Container $container) + { + $this->container = $container; + } + + abstract public function run(); } diff --git a/application/Espo/Core/Exceptions/BadRequest.php b/application/Espo/Core/Exceptions/BadRequest.php index d12197cb01..e27d485b5f 100644 --- a/application/Espo/Core/Exceptions/BadRequest.php +++ b/application/Espo/Core/Exceptions/BadRequest.php @@ -24,7 +24,7 @@ namespace Espo\Core\Exceptions; class BadRequest extends \Exception { - protected $code = 400; + protected $code = 400; } diff --git a/application/Espo/Core/Exceptions/Conflict.php b/application/Espo/Core/Exceptions/Conflict.php index 0433a62160..d749eab336 100644 --- a/application/Espo/Core/Exceptions/Conflict.php +++ b/application/Espo/Core/Exceptions/Conflict.php @@ -24,7 +24,7 @@ namespace Espo\Core\Exceptions; class Conflict extends \Exception { - protected $code = 409; + protected $code = 409; } diff --git a/application/Espo/Core/Exceptions/Forbidden.php b/application/Espo/Core/Exceptions/Forbidden.php index 2fdf613a23..edf5350b55 100644 --- a/application/Espo/Core/Exceptions/Forbidden.php +++ b/application/Espo/Core/Exceptions/Forbidden.php @@ -24,7 +24,7 @@ namespace Espo\Core\Exceptions; class Forbidden extends \Exception { - protected $code = 403; + protected $code = 403; } diff --git a/application/Espo/Core/Exceptions/InternalServerError.php b/application/Espo/Core/Exceptions/InternalServerError.php index d3f0b80706..7a28a14b69 100644 --- a/application/Espo/Core/Exceptions/InternalServerError.php +++ b/application/Espo/Core/Exceptions/InternalServerError.php @@ -24,6 +24,6 @@ namespace Espo\Core\Exceptions; class InternalServerError extends \Exception { - protected $code = 500; + protected $code = 500; } diff --git a/application/Espo/Core/Exceptions/NotFound.php b/application/Espo/Core/Exceptions/NotFound.php index 4371ca19e6..836f774be9 100644 --- a/application/Espo/Core/Exceptions/NotFound.php +++ b/application/Espo/Core/Exceptions/NotFound.php @@ -24,7 +24,7 @@ namespace Espo\Core\Exceptions; class NotFound extends \Exception { - protected $code = 404; + protected $code = 404; } diff --git a/application/Espo/Core/Exceptions/Unauthorized.php b/application/Espo/Core/Exceptions/Unauthorized.php index 6c8b403ebc..99b784657c 100644 --- a/application/Espo/Core/Exceptions/Unauthorized.php +++ b/application/Espo/Core/Exceptions/Unauthorized.php @@ -24,7 +24,7 @@ namespace Espo\Core\Exceptions; class Unauthorized extends \Exception { - protected $code = 401; + protected $code = 401; } diff --git a/application/Espo/Core/ExtensionManager.php b/application/Espo/Core/ExtensionManager.php index d9b848c0ed..ce01895275 100644 --- a/application/Espo/Core/ExtensionManager.php +++ b/application/Espo/Core/ExtensionManager.php @@ -24,18 +24,18 @@ namespace Espo\Core; class ExtensionManager extends Upgrades\Base { - protected $name = 'Extension'; + protected $name = 'Extension'; - protected $params = array( - 'packagePath' => 'data/upload/extensions', + protected $params = array( + 'packagePath' => 'data/upload/extensions', - 'backupPath' => 'data/.backup/extensions', + 'backupPath' => 'data/.backup/extensions', - 'scriptNames' => array( - 'before' => 'BeforeInstall', - 'after' => 'AfterInstall', - 'beforeUninstall' => 'BeforeUninstall', - 'afterUninstall' => 'AfterUninstall', - ) - ); + 'scriptNames' => array( + 'before' => 'BeforeInstall', + 'after' => 'AfterInstall', + 'beforeUninstall' => 'BeforeUninstall', + 'afterUninstall' => 'AfterUninstall', + ) + ); } diff --git a/application/Espo/Core/ExternalAccount/ClientManager.php b/application/Espo/Core/ExternalAccount/ClientManager.php index 7d5dcd59bb..7f5ef2a55f 100644 --- a/application/Espo/Core/ExternalAccount/ClientManager.php +++ b/application/Espo/Core/ExternalAccount/ClientManager.php @@ -28,98 +28,98 @@ use \Espo\Core\Exceptions\NotFound; class ClientManager { - protected $entityManager; - - protected $metadata; - - protected $clientMap = array(); - - public function __construct($entityManager, $metadata, $config) - { - $this->entityManager = $entityManager; - $this->metadata = $metadata; - $this->config = $config; - } - - protected function getMetadata() - { - return $this->metadata; - } - - protected function getEntityManager() - { - return $this->entityManager; - } - - protected function getConfig() - { - return $this->config; - } - - public function storeAccessToken($hash, $data) - { - if (!empty($this->clientMap[$hash]) && !empty($this->clientMap[$hash]['externalAccountEntity'])) { - $externalAccountEntity = $this->clientMap[$hash]['externalAccountEntity']; - $externalAccountEntity->set('accessToken', $data['accessToken']); - $externalAccountEntity->set('tokenType', $data['tokenType']); - $this->getEntityManager()->saveEntity($externalAccountEntity); - } - } - - public function create($integration, $userId) - { - $authMethod = $this->getMetadata()->get("integrations.{$integration}.authMethod"); - $methodName = 'create' . ucfirst($authMethod); - return $this->$methodName($integration, $userId); - } - - protected function createOAuth2($integration, $userId) - { - $integrationEntity = $this->getEntityManager()->getEntity('Integration', $integration); - $externalAccountEntity = $this->getEntityManager()->getEntity('ExternalAccount', $integration . '__' . $userId); - - $className = $this->getMetadata()->get("integrations.{$integration}.clientClassName"); - - $redirectUri = $this->getConfig()->get('siteUrl') . '/oauthcallback'; // TODO move to client class - - if (!$externalAccountEntity) { - throw new Error("External Account {$integration} not found for {$userId}"); - } - - if (!$integrationEntity->get('enabled')) { - return null; - } - if (!$externalAccountEntity->get('enabled')) { - return null; - } - - $oauth2Client = new \Espo\Core\ExternalAccount\OAuth2\Client(); - - $client = new $className($oauth2Client, array( - 'endpoint' => $this->getMetadata()->get("integrations.{$integration}.params.endpoint"), - 'tokenEndpoint' => $this->getMetadata()->get("integrations.{$integration}.params.tokenEndpoint"), - 'clientId' => $integrationEntity->get('clientId'), - 'clientSecret' => $integrationEntity->get('clientSecret'), - 'redirectUri' => $redirectUri, - 'accessToken' => $externalAccountEntity->get('accessToken'), - 'refreshToken' => $externalAccountEntity->get('refreshToken'), - 'tokenType' => $externalAccountEntity->get('tokenType'), - ), $this); - - $this->addToClientMap($client, $integrationEntity, $externalAccountEntity, $userId); - - return $client; - } - - protected function addToClientMap($client, $integrationEntity, $externalAccountEntity, $userId) - { - $this->clientMap[spl_object_hash($client)] = array( - 'client' => $client, - 'userId' => $userId, - 'integration' => $integrationEntity->id, - 'integrationEntity' => $integrationEntity, - 'externalAccountEntity' => $externalAccountEntity, - ); - } + protected $entityManager; + + protected $metadata; + + protected $clientMap = array(); + + public function __construct($entityManager, $metadata, $config) + { + $this->entityManager = $entityManager; + $this->metadata = $metadata; + $this->config = $config; + } + + protected function getMetadata() + { + return $this->metadata; + } + + protected function getEntityManager() + { + return $this->entityManager; + } + + protected function getConfig() + { + return $this->config; + } + + public function storeAccessToken($hash, $data) + { + if (!empty($this->clientMap[$hash]) && !empty($this->clientMap[$hash]['externalAccountEntity'])) { + $externalAccountEntity = $this->clientMap[$hash]['externalAccountEntity']; + $externalAccountEntity->set('accessToken', $data['accessToken']); + $externalAccountEntity->set('tokenType', $data['tokenType']); + $this->getEntityManager()->saveEntity($externalAccountEntity); + } + } + + public function create($integration, $userId) + { + $authMethod = $this->getMetadata()->get("integrations.{$integration}.authMethod"); + $methodName = 'create' . ucfirst($authMethod); + return $this->$methodName($integration, $userId); + } + + protected function createOAuth2($integration, $userId) + { + $integrationEntity = $this->getEntityManager()->getEntity('Integration', $integration); + $externalAccountEntity = $this->getEntityManager()->getEntity('ExternalAccount', $integration . '__' . $userId); + + $className = $this->getMetadata()->get("integrations.{$integration}.clientClassName"); + + $redirectUri = $this->getConfig()->get('siteUrl') . '/oauthcallback'; // TODO move to client class + + if (!$externalAccountEntity) { + throw new Error("External Account {$integration} not found for {$userId}"); + } + + if (!$integrationEntity->get('enabled')) { + return null; + } + if (!$externalAccountEntity->get('enabled')) { + return null; + } + + $oauth2Client = new \Espo\Core\ExternalAccount\OAuth2\Client(); + + $client = new $className($oauth2Client, array( + 'endpoint' => $this->getMetadata()->get("integrations.{$integration}.params.endpoint"), + 'tokenEndpoint' => $this->getMetadata()->get("integrations.{$integration}.params.tokenEndpoint"), + 'clientId' => $integrationEntity->get('clientId'), + 'clientSecret' => $integrationEntity->get('clientSecret'), + 'redirectUri' => $redirectUri, + 'accessToken' => $externalAccountEntity->get('accessToken'), + 'refreshToken' => $externalAccountEntity->get('refreshToken'), + 'tokenType' => $externalAccountEntity->get('tokenType'), + ), $this); + + $this->addToClientMap($client, $integrationEntity, $externalAccountEntity, $userId); + + return $client; + } + + protected function addToClientMap($client, $integrationEntity, $externalAccountEntity, $userId) + { + $this->clientMap[spl_object_hash($client)] = array( + 'client' => $client, + 'userId' => $userId, + 'integration' => $integrationEntity->id, + 'integrationEntity' => $integrationEntity, + 'externalAccountEntity' => $externalAccountEntity, + ); + } } diff --git a/application/Espo/Core/ExternalAccount/Clients/Google.php b/application/Espo/Core/ExternalAccount/Clients/Google.php index 089b5f5e31..e6713a2767 100644 --- a/application/Espo/Core/ExternalAccount/Clients/Google.php +++ b/application/Espo/Core/ExternalAccount/Clients/Google.php @@ -26,9 +26,9 @@ use \Espo\Core\Exceptions\Error; class Google extends OAuth2Abstract { - protected function getPingUrl() - { - return 'https://www.googleapis.com/calendar/v3/users/me/calendarList'; - } + protected function getPingUrl() + { + return 'https://www.googleapis.com/calendar/v3/users/me/calendarList'; + } } diff --git a/application/Espo/Core/ExternalAccount/Clients/IClient.php b/application/Espo/Core/ExternalAccount/Clients/IClient.php index 978d9835a3..37e31a6673 100644 --- a/application/Espo/Core/ExternalAccount/Clients/IClient.php +++ b/application/Espo/Core/ExternalAccount/Clients/IClient.php @@ -24,12 +24,12 @@ namespace Espo\Core\ExternalAccount\Clients; interface IClient { - public function getParam($name); - - public function setParam($name, $value); - - public function setParams(array $params); + public function getParam($name); + + public function setParam($name, $value); + + public function setParams(array $params); - public function ping(); + public function ping(); } diff --git a/application/Espo/Core/ExternalAccount/Clients/OAuth2Abstract.php b/application/Espo/Core/ExternalAccount/Clients/OAuth2Abstract.php index de0a7e837e..76f79fceff 100644 --- a/application/Espo/Core/ExternalAccount/Clients/OAuth2Abstract.php +++ b/application/Espo/Core/ExternalAccount/Clients/OAuth2Abstract.php @@ -28,182 +28,182 @@ use \Espo\Core\ExternalAccount\OAuth2\Client; abstract class OAuth2Abstract implements IClient { - protected $client = null; - - protected $manager = null; - - protected $paramList = array( - 'endpoint', - 'tokenEndpoint', - 'clientId', - 'clientSecret', - 'tokenType', - 'accessToken', - 'refreshToken', - 'redirectUri', - ); - - protected $clientId = null; - - protected $clientSecret = null; - - protected $accessToken = null; - - protected $refreshToken = null; - - protected $redirectUri = null; - - public function __construct($client, array $params = array(), $manager = null) - { - $this->client = $client; + protected $client = null; + + protected $manager = null; + + protected $paramList = array( + 'endpoint', + 'tokenEndpoint', + 'clientId', + 'clientSecret', + 'tokenType', + 'accessToken', + 'refreshToken', + 'redirectUri', + ); + + protected $clientId = null; + + protected $clientSecret = null; + + protected $accessToken = null; + + protected $refreshToken = null; + + protected $redirectUri = null; + + public function __construct($client, array $params = array(), $manager = null) + { + $this->client = $client; - $this->setParams($params); - - $this->manager = $manager; - } - - public function getParam($name) - { - if (in_array($name, $this->paramList)) { - return $this->$name; - } - } - - public function setParam($name, $value) - { - if (in_array($name, $this->paramList)) { - $methodName = 'set' . ucfirst($name); - if (method_exists($this->client, $methodName)) { - $this->client->$methodName($value); - } - $this->$name = $value; - } - } - - public function setParams(array $params) - { - foreach ($this->paramList as $name) { - if (!empty($params[$name])) { - $this->setParam($name, $params[$name]); - } - } - } - - protected function afterTokenRefreshed($data) - { - if ($this->manager) { - $this->manager->storeAccessToken(spl_object_hash($this), $data); - } - } - - public function getAccessTokenFromAuthorizationCode($code) - { - $r = $this->client->getAccessToken($this->getParam('tokenEndpoint'), Client::GRANT_TYPE_AUTHORIZATION_CODE, array( - 'code' => $code, - 'redirect_uri' => $this->getParam('redirectUri') - )); - - - if ($r['code'] == 200) { - $data = array(); - if (!empty($r['result'])) { - $data['accessToken'] = $r['result']['access_token']; - $data['tokenType'] = $r['result']['token_type']; - $data['refreshToken'] = $r['result']['refresh_token']; - } - return $data; - } - return null; - } - - abstract protected function getPingUrl(); - - public function ping() - { - if (empty($this->accessToken) || empty($this->clientId) || empty($this->clientSecret)) { - return false; - } - - $url = $this->getPingUrl(); + $this->setParams($params); + + $this->manager = $manager; + } + + public function getParam($name) + { + if (in_array($name, $this->paramList)) { + return $this->$name; + } + } + + public function setParam($name, $value) + { + if (in_array($name, $this->paramList)) { + $methodName = 'set' . ucfirst($name); + if (method_exists($this->client, $methodName)) { + $this->client->$methodName($value); + } + $this->$name = $value; + } + } + + public function setParams(array $params) + { + foreach ($this->paramList as $name) { + if (!empty($params[$name])) { + $this->setParam($name, $params[$name]); + } + } + } + + protected function afterTokenRefreshed($data) + { + if ($this->manager) { + $this->manager->storeAccessToken(spl_object_hash($this), $data); + } + } + + public function getAccessTokenFromAuthorizationCode($code) + { + $r = $this->client->getAccessToken($this->getParam('tokenEndpoint'), Client::GRANT_TYPE_AUTHORIZATION_CODE, array( + 'code' => $code, + 'redirect_uri' => $this->getParam('redirectUri') + )); + + + if ($r['code'] == 200) { + $data = array(); + if (!empty($r['result'])) { + $data['accessToken'] = $r['result']['access_token']; + $data['tokenType'] = $r['result']['token_type']; + $data['refreshToken'] = $r['result']['refresh_token']; + } + return $data; + } + return null; + } + + abstract protected function getPingUrl(); + + public function ping() + { + if (empty($this->accessToken) || empty($this->clientId) || empty($this->clientSecret)) { + return false; + } + + $url = $this->getPingUrl(); - try { - $this->request($url); - return true; - } catch (\Exception $e) { - return false; - } - } - - public function request($url, $params = array(), $httpMethod = Client::HTTP_METHOD_GET, $allowRenew = true) - { - $r = $this->client->request($url, $params, $httpMethod); - - $code = null; - if (!empty($r['code'])) { - $code = $r['code']; - } - - if ($code == 200) { - return $r['result']; - } else { - $handledData = $this->handleErrorResponse($r); - - if ($allowRenew && is_array($handledData)) { - if ($handledData['action'] == 'refreshToken') { - if ($this->refreshToken()) { - return $this->request($url, $params, $httpMethod, false); - } - } else if ($handledData['action'] == 'renew') { - return $this->request($url, $params, $httpMethod, false); - } - } - } - - throw new Error("Error after requesting {$httpMethod} {$url}.", $code); - } - - protected function refreshToken() - { - if (!empty($this->refreshToken)) { - $r = $this->client->getAccessToken($this->getParam('tokenEndpoint'), Client::GRANT_TYPE_REFRESH_TOKEN, array( - 'refresh_token' => $this->refreshToken, - )); - if ($r['code'] == 200) { - if (is_array($r['result'])) { - if (!empty($r['result']['access_token'])) { - $data = array(); - $data['accessToken'] = $r['result']['access_token']; - $data['tokenType'] = $r['result']['token_type']; + try { + $this->request($url); + return true; + } catch (\Exception $e) { + return false; + } + } + + public function request($url, $params = array(), $httpMethod = Client::HTTP_METHOD_GET, $allowRenew = true) + { + $r = $this->client->request($url, $params, $httpMethod); + + $code = null; + if (!empty($r['code'])) { + $code = $r['code']; + } + + if ($code == 200) { + return $r['result']; + } else { + $handledData = $this->handleErrorResponse($r); + + if ($allowRenew && is_array($handledData)) { + if ($handledData['action'] == 'refreshToken') { + if ($this->refreshToken()) { + return $this->request($url, $params, $httpMethod, false); + } + } else if ($handledData['action'] == 'renew') { + return $this->request($url, $params, $httpMethod, false); + } + } + } + + throw new Error("Error after requesting {$httpMethod} {$url}.", $code); + } + + protected function refreshToken() + { + if (!empty($this->refreshToken)) { + $r = $this->client->getAccessToken($this->getParam('tokenEndpoint'), Client::GRANT_TYPE_REFRESH_TOKEN, array( + 'refresh_token' => $this->refreshToken, + )); + if ($r['code'] == 200) { + if (is_array($r['result'])) { + if (!empty($r['result']['access_token'])) { + $data = array(); + $data['accessToken'] = $r['result']['access_token']; + $data['tokenType'] = $r['result']['token_type']; - $this->setParams($data); - $this->afterTokenRefreshed($data); - return true; - } - } - } - } - } - - protected function handleErrorResponse($r) - { - if ($r['code'] == 401 && !empty($r['result'])) { - $result = $r['result']; - if (strpos($r['header'], 'error=invalid_token') !== false) { - return array( - 'action' => 'refreshToken' - ); - } else { - return array( - 'action' => 'renew' - ); - } - } else if ($r['code'] == 400 && !empty($r['result'])) { - if ($r['result']['error'] == 'invalid_token') { - return array( - 'action' => 'refreshToken' - ); - } - } - } + $this->setParams($data); + $this->afterTokenRefreshed($data); + return true; + } + } + } + } + } + + protected function handleErrorResponse($r) + { + if ($r['code'] == 401 && !empty($r['result'])) { + $result = $r['result']; + if (strpos($r['header'], 'error=invalid_token') !== false) { + return array( + 'action' => 'refreshToken' + ); + } else { + return array( + 'action' => 'renew' + ); + } + } else if ($r['code'] == 400 && !empty($r['result'])) { + if ($r['result']['error'] == 'invalid_token') { + return array( + 'action' => 'refreshToken' + ); + } + } + } } diff --git a/application/Espo/Core/ExternalAccount/OAuth2/Client.php b/application/Espo/Core/ExternalAccount/OAuth2/Client.php index dea4caf0a8..b96c2a42a0 100644 --- a/application/Espo/Core/ExternalAccount/OAuth2/Client.php +++ b/application/Espo/Core/ExternalAccount/OAuth2/Client.php @@ -24,225 +24,225 @@ namespace Espo\Core\ExternalAccount\OAuth2; class Client { - const AUTH_TYPE_URI = 0; - const AUTH_TYPE_AUTHORIZATION_BASIC = 1; - const AUTH_TYPE_FORM = 2; + const AUTH_TYPE_URI = 0; + const AUTH_TYPE_AUTHORIZATION_BASIC = 1; + const AUTH_TYPE_FORM = 2; - const TOKEN_TYPE_URI = 'Uri'; - const TOKEN_TYPE_BEARER = 'Bearer'; - const TOKEN_TYPE_OAUTH = 'OAuth'; + const TOKEN_TYPE_URI = 'Uri'; + const TOKEN_TYPE_BEARER = 'Bearer'; + const TOKEN_TYPE_OAUTH = 'OAuth'; - const CONTENT_TYPE_APPLICATION = 0; - const CONTENT_TYPE_MULTIPART = 1; + const CONTENT_TYPE_APPLICATION = 0; + const CONTENT_TYPE_MULTIPART = 1; - const HTTP_METHOD_GET = 'GET'; - const HTTP_METHOD_POST = 'POST'; - const HTTP_METHOD_PUT = 'PUT'; + const HTTP_METHOD_GET = 'GET'; + const HTTP_METHOD_POST = 'POST'; + const HTTP_METHOD_PUT = 'PUT'; - const HTTP_METHOD_DELETE = 'DELETE'; - const HTTP_METHOD_HEAD = 'HEAD'; - const HTTP_METHOD_PATCH = 'PATCH'; + const HTTP_METHOD_DELETE = 'DELETE'; + const HTTP_METHOD_HEAD = 'HEAD'; + const HTTP_METHOD_PATCH = 'PATCH'; - const GRANT_TYPE_AUTHORIZATION_CODE = 'authorization_code'; - const GRANT_TYPE_REFRESH_TOKEN = 'refresh_token'; - const GRANT_TYPE_PASSWORD = 'password'; - const GRANT_TYPE_CLIENT_CREDENTIALS = 'client_credentials'; + const GRANT_TYPE_AUTHORIZATION_CODE = 'authorization_code'; + const GRANT_TYPE_REFRESH_TOKEN = 'refresh_token'; + const GRANT_TYPE_PASSWORD = 'password'; + const GRANT_TYPE_CLIENT_CREDENTIALS = 'client_credentials'; - protected $clientId = null; + protected $clientId = null; - protected $clientSecret = null; + protected $clientSecret = null; - protected $accessToken = null; + protected $accessToken = null; - protected $authType = self::AUTH_TYPE_URI; + protected $authType = self::AUTH_TYPE_URI; - protected $tokenType = self::TOKEN_TYPE_URI; + protected $tokenType = self::TOKEN_TYPE_URI; - protected $accessTokenSecret = null; + protected $accessTokenSecret = null; - protected $accessTokenParamName = 'access_token'; + protected $accessTokenParamName = 'access_token'; - protected $certificateFile = null; + protected $certificateFile = null; - protected $curlOptions = array(); + protected $curlOptions = array(); - public function __construct(array $params = array()) - { - if (!extension_loaded('curl')) { - throw new \Exception('CURL extension not found.'); - } - } + public function __construct(array $params = array()) + { + if (!extension_loaded('curl')) { + throw new \Exception('CURL extension not found.'); + } + } - public function setClientId($clientId) - { - $this->clientId = $clientId; - } + public function setClientId($clientId) + { + $this->clientId = $clientId; + } - public function setClientSecret($clientSecret) - { - $this->clientSecret = $clientSecret; - } + public function setClientSecret($clientSecret) + { + $this->clientSecret = $clientSecret; + } - public function setAccessToken($accessToken) - { - $this->accessToken = $accessToken; - } + public function setAccessToken($accessToken) + { + $this->accessToken = $accessToken; + } - public function setAuthType($authType) - { - $this->authType = $authType; - } + public function setAuthType($authType) + { + $this->authType = $authType; + } - public function setCertificateFile($certificateFile) - { - $this->certificateFile = $certificateFile; - } + public function setCertificateFile($certificateFile) + { + $this->certificateFile = $certificateFile; + } - public function setCurlOption($option, $value) - { - $this->curlOptions[$option] = $value; - } + public function setCurlOption($option, $value) + { + $this->curlOptions[$option] = $value; + } - public function setCurlOptions($options) - { - $this->curlOptions = array_merge($this->curlOptions, $options); - } + public function setCurlOptions($options) + { + $this->curlOptions = array_merge($this->curlOptions, $options); + } - public function setTokenType($tokenType) - { - $this->tokenType = $tokenType; - } + public function setTokenType($tokenType) + { + $this->tokenType = $tokenType; + } - public function setAccessTokenSecret($accessTokenSecret) - { - $this->accessTokenSecret = $accessTokenSecret; - } + public function setAccessTokenSecret($accessTokenSecret) + { + $this->accessTokenSecret = $accessTokenSecret; + } - public function request($url, $params = array(), $httpMethod = self::HTTP_METHOD_GET, array $httpHeaders = array(), $contentType = self::CONTENT_TYPE_MULTIPART) - { - if ($this->accessToken) { - switch ($this->tokenType) { - case self::TOKEN_TYPE_URI: - $params[$this->accessTokenParamName] = $this->accessToken; - break; - case self::TOKEN_TYPE_BEARER: - $httpHeaders['Authorization'] = 'Bearer ' . $this->accessToken; - break; - case self::TOKEN_TYPE_OAUTH: - $httpHeaders['Authorization'] = 'OAuth ' . $this->accessToken; - break; - default: - throw new \Exception('Unknown access token type.'); + public function request($url, $params = array(), $httpMethod = self::HTTP_METHOD_GET, array $httpHeaders = array(), $contentType = self::CONTENT_TYPE_MULTIPART) + { + if ($this->accessToken) { + switch ($this->tokenType) { + case self::TOKEN_TYPE_URI: + $params[$this->accessTokenParamName] = $this->accessToken; + break; + case self::TOKEN_TYPE_BEARER: + $httpHeaders['Authorization'] = 'Bearer ' . $this->accessToken; + break; + case self::TOKEN_TYPE_OAUTH: + $httpHeaders['Authorization'] = 'OAuth ' . $this->accessToken; + break; + default: + throw new \Exception('Unknown access token type.'); - } - } + } + } - return $this->execute($url, $params, $httpMethod, $httpHeaders, $contentType); - } + return $this->execute($url, $params, $httpMethod, $httpHeaders, $contentType); + } - private function execute($url, $params = array(), $httpMethod, array $httpHeaders = array(), $contentType = self::CONTENT_TYPE_MULTIPART) - { - $curlOptions = array( - CURLOPT_RETURNTRANSFER => true, - CURLOPT_SSL_VERIFYPEER => true, - CURLOPT_CUSTOMREQUEST => $httpMethod - ); + private function execute($url, $params = array(), $httpMethod, array $httpHeaders = array(), $contentType = self::CONTENT_TYPE_MULTIPART) + { + $curlOptions = array( + CURLOPT_RETURNTRANSFER => true, + CURLOPT_SSL_VERIFYPEER => true, + CURLOPT_CUSTOMREQUEST => $httpMethod + ); - switch ($httpMethod) { - case self::HTTP_METHOD_POST: - $curlOptions[CURLOPT_POST] = true; - case self::HTTP_METHOD_PUT: - case self::HTTP_METHOD_PATCH: - if (self::CONTENT_TYPE_APPLICATION === $contentType) { - $postFields = http_build_query($params, null, '&'); - } - $curlOptions[CURLOPT_POSTFIELDS] = $postFields; - break; - case self::HTTP_METHOD_HEAD: - $curlOptions[CURLOPT_NOBODY] = true; - case self::HTTP_METHOD_DELETE: - case self::HTTP_METHOD_GET: - if (strpos($url, '?') === false) { - $url .= '?'; - } - $url .= http_build_query($params, null, '&'); - break; - default: - break; - } + switch ($httpMethod) { + case self::HTTP_METHOD_POST: + $curlOptions[CURLOPT_POST] = true; + case self::HTTP_METHOD_PUT: + case self::HTTP_METHOD_PATCH: + if (self::CONTENT_TYPE_APPLICATION === $contentType) { + $postFields = http_build_query($params, null, '&'); + } + $curlOptions[CURLOPT_POSTFIELDS] = $postFields; + break; + case self::HTTP_METHOD_HEAD: + $curlOptions[CURLOPT_NOBODY] = true; + case self::HTTP_METHOD_DELETE: + case self::HTTP_METHOD_GET: + if (strpos($url, '?') === false) { + $url .= '?'; + } + $url .= http_build_query($params, null, '&'); + break; + default: + break; + } - $curlOptions[CURLOPT_URL] = $url; + $curlOptions[CURLOPT_URL] = $url; - $curlOptHttpHeader = array(); - foreach ($httpHeaders as $key => $value) { - $curlOptHttpHeader[] = "{$key}: {$value}"; - } - $curlOptions[CURLOPT_HTTPHEADER] = $curlOptHttpHeader; + $curlOptHttpHeader = array(); + foreach ($httpHeaders as $key => $value) { + $curlOptHttpHeader[] = "{$key}: {$value}"; + } + $curlOptions[CURLOPT_HTTPHEADER] = $curlOptHttpHeader; - $ch = curl_init(); - curl_setopt_array($ch, $curlOptions); + $ch = curl_init(); + curl_setopt_array($ch, $curlOptions); - curl_setopt($ch, CURLOPT_HEADER, 1); + curl_setopt($ch, CURLOPT_HEADER, 1); - if (!empty($this->certificateFile)) { - curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); - curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); - curl_setopt($ch, CURLOPT_CAINFO, $this->certificateFile); - } else { - curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); - curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); - } + if (!empty($this->certificateFile)) { + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); + curl_setopt($ch, CURLOPT_CAINFO, $this->certificateFile); + } else { + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); + } - if (!empty($this->curlOptions)) { - curl_setopt_array($ch, $this->curlOptions); - } + if (!empty($this->curlOptions)) { + curl_setopt_array($ch, $this->curlOptions); + } - $response = curl_exec($ch); + $response = curl_exec($ch); - $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); - $contentType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE); - $headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + $contentType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE); + $headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE); - $responceHeader = substr($response, 0, $headerSize); - $responceBody = substr($response, $headerSize); + $responceHeader = substr($response, 0, $headerSize); + $responceBody = substr($response, $headerSize); - $resultArray = null; + $resultArray = null; - if ($curlError = curl_error($ch)) { - throw new \Exception($curlError); - } else { - $resultArray = json_decode($responceBody, true); - } - curl_close($ch); + if ($curlError = curl_error($ch)) { + throw new \Exception($curlError); + } else { + $resultArray = json_decode($responceBody, true); + } + curl_close($ch); - return array( - 'result' => (null !== $resultArray) ? $resultArray: $responceBody, - 'code' => intval($httpCode), - 'contentType' => $contentType, - 'header' => $responceHeader, - ); - } + return array( + 'result' => (null !== $resultArray) ? $resultArray: $responceBody, + 'code' => intval($httpCode), + 'contentType' => $contentType, + 'header' => $responceHeader, + ); + } - public function getAccessToken($url, $grantType, array $params) - { - $params['grant_type'] = $grantType; + public function getAccessToken($url, $grantType, array $params) + { + $params['grant_type'] = $grantType; - $httpHeaders = array(); - switch ($this->clientAuth) { - case self::AUTH_TYPE_URI: - case self::AUTH_TYPE_FORM: - $params['client_id'] = $this->clientId; - $params['client_secret'] = $this->clientSecret; - break; - case self::AUTH_TYPE_AUTHORIZATION_BASIC: - $params['client_id'] = $this->clientId; - $httpHeaders['Authorization'] = 'Basic ' . base64_encode($this->clientId . ':' . $this->clientSecret); - break; - default: - throw new \Exception(); - } + $httpHeaders = array(); + switch ($this->clientAuth) { + case self::AUTH_TYPE_URI: + case self::AUTH_TYPE_FORM: + $params['client_id'] = $this->clientId; + $params['client_secret'] = $this->clientSecret; + break; + case self::AUTH_TYPE_AUTHORIZATION_BASIC: + $params['client_id'] = $this->clientId; + $httpHeaders['Authorization'] = 'Basic ' . base64_encode($this->clientId . ':' . $this->clientSecret); + break; + default: + throw new \Exception(); + } - return $this->execute($url, $params, self::HTTP_METHOD_POST, $httpHeaders, self::CONTENT_TYPE_APPLICATION); - } + return $this->execute($url, $params, self::HTTP_METHOD_POST, $httpHeaders, self::CONTENT_TYPE_APPLICATION); + } } diff --git a/application/Espo/Core/HookManager.php b/application/Espo/Core/HookManager.php index 2e1073376d..7f3e98b397 100644 --- a/application/Espo/Core/HookManager.php +++ b/application/Espo/Core/HookManager.php @@ -23,162 +23,162 @@ namespace Espo\Core; use \Espo\Core\Exceptions\Error, - \Espo\Core\Utils\Util; + \Espo\Core\Utils\Util; class HookManager { - private $container; + private $container; - private $data; + private $data; - private $hooks; + private $hooks; - protected $cacheFile = 'data/cache/application/hooks.php'; + protected $cacheFile = 'data/cache/application/hooks.php'; - /** + /** * List of defined hooks * * @var array */ - protected $hookList = array( - 'beforeSave', - 'afterSave', - 'beforeRemove', - 'afterRemove', - ); + protected $hookList = array( + 'beforeSave', + 'afterSave', + 'beforeRemove', + 'afterRemove', + ); - protected $paths = array( - 'corePath' => 'application/Espo/Hooks', - 'modulePath' => 'application/Espo/Modules/{*}/Hooks', - 'customPath' => 'custom/Espo/Custom/Hooks', - ); + protected $paths = array( + 'corePath' => 'application/Espo/Hooks', + 'modulePath' => 'application/Espo/Modules/{*}/Hooks', + 'customPath' => 'custom/Espo/Custom/Hooks', + ); public function __construct(Container $container) { - $this->container = $container; - $this->loadHooks(); + $this->container = $container; + $this->loadHooks(); } protected function getConfig() { - return $this->container->get('config'); + return $this->container->get('config'); } - protected function getFileManager() - { - return $this->container->get('fileManager'); - } + protected function getFileManager() + { + return $this->container->get('fileManager'); + } protected function loadHooks() { - if ($this->getConfig()->get('useCache') && file_exists($this->cacheFile)) { - $this->data = $this->getFileManager()->getContents($this->cacheFile); - return; - } + if ($this->getConfig()->get('useCache') && file_exists($this->cacheFile)) { + $this->data = $this->getFileManager()->getContents($this->cacheFile); + return; + } - $metadata = $this->container->get('metadata'); + $metadata = $this->container->get('metadata'); - $this->data = $this->getHookData($this->paths['corePath']); + $this->data = $this->getHookData($this->paths['corePath']); - foreach ($metadata->getModuleList() as $moduleName) { - $modulePath = str_replace('{*}', $moduleName, $this->paths['modulePath']); - $this->data = array_merge($this->data, $this->getHookData($modulePath)); - } + foreach ($metadata->getModuleList() as $moduleName) { + $modulePath = str_replace('{*}', $moduleName, $this->paths['modulePath']); + $this->data = array_merge($this->data, $this->getHookData($modulePath)); + } - $this->data = array_merge($this->data, $this->getHookData($this->paths['customPath'])); + $this->data = array_merge($this->data, $this->getHookData($this->paths['customPath'])); - if ($this->getConfig()->get('useCache')) { - $this->getFileManager()->putContentsPHP($this->cacheFile, $this->data); - } + if ($this->getConfig()->get('useCache')) { + $this->getFileManager()->putContentsPHP($this->cacheFile, $this->data); + } } public function process($scope, $hookName, $injection = null) { - if ($scope != 'Common') { - $this->process('Common', $hookName, $injection); - } + if ($scope != 'Common') { + $this->process('Common', $hookName, $injection); + } - if (!empty($this->data[$scope])) { - if (!empty($this->data[$scope][$hookName])) { - foreach ($this->data[$scope][$hookName] as $className) { - if (empty($this->hooks[$className])) { - $this->hooks[$className] = $this->createHookByClassName($className); - } - $hook = $this->hooks[$className]; - $hook->$hookName($injection); - } - } - } + if (!empty($this->data[$scope])) { + if (!empty($this->data[$scope][$hookName])) { + foreach ($this->data[$scope][$hookName] as $className) { + if (empty($this->hooks[$className])) { + $this->hooks[$className] = $this->createHookByClassName($className); + } + $hook = $this->hooks[$className]; + $hook->$hookName($injection); + } + } + } } - public function createHookByClassName($className) - { - if (class_exists($className)) { - $hook = new $className(); - $dependencies = $hook->getDependencyList(); - foreach ($dependencies as $name) { - $hook->inject($name, $this->container->get($name)); - } - return $hook; - } - throw new Error("Class '$className' does not exist"); - } + public function createHookByClassName($className) + { + if (class_exists($className)) { + $hook = new $className(); + $dependencies = $hook->getDependencyList(); + foreach ($dependencies as $name) { + $hook->inject($name, $this->container->get($name)); + } + return $hook; + } + throw new Error("Class '$className' does not exist"); + } /** * Get and merge hook data by checking the files exist in $hookDirs - * - * @param array $hookDirs - it can be an array('Espo/Hooks', 'Espo/Custom/Hooks', 'Espo/Modules/Crm/Hooks') - * - * @return array - */ - protected function getHookData($hookDirs) - { - if (is_string($hookDirs)) { - $hookDirs = (array) $hookDirs; - } + * + * @param array $hookDirs - it can be an array('Espo/Hooks', 'Espo/Custom/Hooks', 'Espo/Modules/Crm/Hooks') + * + * @return array + */ + protected function getHookData($hookDirs) + { + if (is_string($hookDirs)) { + $hookDirs = (array) $hookDirs; + } - $hooks = array(); + $hooks = array(); - foreach ($hookDirs as $hookDir) { + foreach ($hookDirs as $hookDir) { - if (file_exists($hookDir)) { - $fileList = $this->getFileManager()->getFileList($hookDir, 1, '\.php$', 'file'); + if (file_exists($hookDir)) { + $fileList = $this->getFileManager()->getFileList($hookDir, 1, '\.php$', true); - foreach ($fileList as $scopeName => $hookFiles) { + foreach ($fileList as $scopeName => $hookFiles) { - $hookScopeDirPath = Util::concatPath($hookDir, $scopeName); + $hookScopeDirPath = Util::concatPath($hookDir, $scopeName); - $scopeHooks = array(); - foreach($hookFiles as $hookFile) { - $hookFilePath = Util::concatPath($hookScopeDirPath, $hookFile); - $className = Util::getClassName($hookFilePath); + $scopeHooks = array(); + foreach($hookFiles as $hookFile) { + $hookFilePath = Util::concatPath($hookScopeDirPath, $hookFile); + $className = Util::getClassName($hookFilePath); - foreach($this->hookList as $hookName) { - if (method_exists($className, $hookName)) { - $scopeHooks[$hookName][$className::$order][] = $className; - } - } - } + foreach($this->hookList as $hookName) { + if (method_exists($className, $hookName)) { + $scopeHooks[$hookName][$className::$order][] = $className; + } + } + } - //sort hooks by order - foreach ($scopeHooks as $hookName => $hookList) { - ksort($hookList); + //sort hooks by order + foreach ($scopeHooks as $hookName => $hookList) { + ksort($hookList); - $sortedHookList = array(); - foreach($hookList as $hookDetails) { - $sortedHookList = array_merge($sortedHookList, $hookDetails); - } + $sortedHookList = array(); + foreach($hookList as $hookDetails) { + $sortedHookList = array_merge($sortedHookList, $hookDetails); + } $hooks[$scopeName][$hookName] = isset($hooks[$scopeName][$hookName]) ? array_merge($hooks[$scopeName][$hookName], $sortedHookList) : $sortedHookList; - } - } - } + } + } + } - } + } - return $hooks; - } + return $hooks; + } } diff --git a/application/Espo/Core/Hooks/Base.php b/application/Espo/Core/Hooks/Base.php index e3627788be..ae6baeb3c4 100644 --- a/application/Espo/Core/Hooks/Base.php +++ b/application/Espo/Core/Hooks/Base.php @@ -26,70 +26,70 @@ use \Espo\Core\Interfaces\Injectable; class Base implements Injectable { - protected $dependencies = array( - 'entityManager', - 'config', - 'metadata', - 'acl', - 'user', - ); + protected $dependencies = array( + 'entityManager', + 'config', + 'metadata', + 'acl', + 'user', + ); - protected $injections = array(); + protected $injections = array(); - public static $order = 9; + public static $order = 9; - public function __construct() - { - $this->init(); - } + public function __construct() + { + $this->init(); + } - protected function init() - { - } + protected function init() + { + } - public function getDependencyList() - { - return $this->dependencies; - } + public function getDependencyList() + { + return $this->dependencies; + } - protected function getInjection($name) - { - return $this->injections[$name]; - } + protected function getInjection($name) + { + return $this->injections[$name]; + } - public function inject($name, $object) - { - $this->injections[$name] = $object; - } + public function inject($name, $object) + { + $this->injections[$name] = $object; + } - protected function getEntityManager() - { - return $this->injections['entityManager']; - } + protected function getEntityManager() + { + return $this->injections['entityManager']; + } - protected function getUser() - { - return $this->injections['user']; - } + protected function getUser() + { + return $this->injections['user']; + } - protected function getAcl() - { - return $this->injections['acl']; - } + protected function getAcl() + { + return $this->injections['acl']; + } - protected function getConfig() - { - return $this->injections['config']; - } + protected function getConfig() + { + return $this->injections['config']; + } - protected function getMetadata() - { - return $this->injections['metadata']; - } + protected function getMetadata() + { + return $this->injections['metadata']; + } - protected function getRepository() - { - return $this->getEntityManager()->getRepository($this->entityName); - } + protected function getRepository() + { + return $this->getEntityManager()->getRepository($this->entityName); + } } diff --git a/application/Espo/Core/Interfaces/Injectable.php b/application/Espo/Core/Interfaces/Injectable.php index 9185de91d8..7ccae942e1 100644 --- a/application/Espo/Core/Interfaces/Injectable.php +++ b/application/Espo/Core/Interfaces/Injectable.php @@ -24,8 +24,8 @@ namespace Espo\Core\Interfaces; interface Injectable { - public function getDependencyList(); - - public function inject($name, $object); + public function getDependencyList(); + + public function inject($name, $object); } diff --git a/application/Espo/Core/Loaders/Loader.php b/application/Espo/Core/Interfaces/Loader.php similarity index 94% rename from application/Espo/Core/Loaders/Loader.php rename to application/Espo/Core/Interfaces/Loader.php index 971290c6a0..c3a9e9ad2e 100644 --- a/application/Espo/Core/Loaders/Loader.php +++ b/application/Espo/Core/Interfaces/Loader.php @@ -20,12 +20,10 @@ * along with EspoCRM. If not, see http://www.gnu.org/licenses/. ************************************************************************/ -namespace Espo\Core\Loaders; - +namespace Espo\Core\Interfaces; interface Loader { - public function load(); - + public function load(); } diff --git a/application/Espo/Core/Jobs/Base.php b/application/Espo/Core/Jobs/Base.php index 975dd5fa1d..9256cd997b 100644 --- a/application/Espo/Core/Jobs/Base.php +++ b/application/Espo/Core/Jobs/Base.php @@ -27,44 +27,44 @@ use \Espo\Core\Container; abstract class Base { - private $container; + private $container; - protected function getContainer() - { - return $this->container; - } + protected function getContainer() + { + return $this->container; + } - protected function getEntityManager() - { - return $this->getContainer()->get('entityManager'); - } + protected function getEntityManager() + { + return $this->getContainer()->get('entityManager'); + } - protected function getServiceFactory() - { - return $this->getContainer()->get('serviceFactory'); - } + protected function getServiceFactory() + { + return $this->getContainer()->get('serviceFactory'); + } - protected function getConfig() - { - return $this->getContainer()->get('config'); - } + protected function getConfig() + { + return $this->getContainer()->get('config'); + } - protected function getMetadata() - { - return $this->getContainer()->get('metadata'); - } + protected function getMetadata() + { + return $this->getContainer()->get('metadata'); + } - protected function getUser() - { - return $this->getContainer()->get('user'); - } + protected function getUser() + { + return $this->getContainer()->get('user'); + } - public function __construct(Container $container) - { - $this->container = $container; - } + public function __construct(Container $container) + { + $this->container = $container; + } - abstract public function run(); + abstract public function run(); } diff --git a/application/Espo/Core/Loaders/Base.php b/application/Espo/Core/Loaders/Base.php new file mode 100644 index 0000000000..9ac545d77f --- /dev/null +++ b/application/Espo/Core/Loaders/Base.php @@ -0,0 +1,38 @@ +container = $container; + } + + protected function getContainer() + { + return $this->container; + } +} \ No newline at end of file diff --git a/application/Espo/Core/Loaders/EntityManager.php b/application/Espo/Core/Loaders/EntityManager.php index 66e05872f0..0d24be18f3 100644 --- a/application/Espo/Core/Loaders/EntityManager.php +++ b/application/Espo/Core/Loaders/EntityManager.php @@ -22,43 +22,28 @@ namespace Espo\Core\Loaders; -use Doctrine\ORM\Tools\Setup, - Espo\Core\Doctrine\ORM\Mapping\Driver\EspoPHPDriver; - -class EntityManager implements Loader +class EntityManager extends Base { - private $container; + public function load() + { + $config = $this->getContainer()->get('config'); - public function __construct(\Espo\Core\Container $container) - { - $this->container = $container; - } + $params = array( + 'host' => $config->get('database.host'), + 'port' => $config->get('database.port'), + 'dbname' => $config->get('database.dbname'), + 'user' => $config->get('database.user'), + 'password' => $config->get('database.password'), + 'metadata' => $this->getContainer()->get('metadata')->getOrmMetadata(), + 'repositoryFactoryClassName' => '\\Espo\\Core\\ORM\\RepositoryFactory', + ); - protected function getContainer() - { - return $this->container; - } + $entityManager = new \Espo\Core\ORM\EntityManager($params); + $entityManager->setEspoMetadata($this->getContainer()->get('metadata')); + $entityManager->setHookManager($this->getContainer()->get('hookManager')); + $entityManager->setContainer($this->getContainer()); - public function load() - { - $config = $this->getContainer()->get('config'); - - $params = array( - 'host' => $config->get('database.host'), - 'port' => $config->get('database.port'), - 'dbname' => $config->get('database.dbname'), - 'user' => $config->get('database.user'), - 'password' => $config->get('database.password'), - 'metadata' => $this->getContainer()->get('metadata')->getOrmMetadata(), - 'repositoryFactoryClassName' => '\\Espo\\Core\\ORM\\RepositoryFactory', - ); - - $entityManager = new \Espo\Core\ORM\EntityManager($params); - $entityManager->setEspoMetadata($this->getContainer()->get('metadata')); - $entityManager->setHookManager($this->getContainer()->get('hookManager')); - $entityManager->setContainer($this->getContainer()); - - return $entityManager; - } + return $entityManager; + } } diff --git a/application/Espo/Core/Loaders/Log.php b/application/Espo/Core/Loaders/Log.php index 764eaad4ce..134cfb6fac 100644 --- a/application/Espo/Core/Loaders/Log.php +++ b/application/Espo/Core/Loaders/Log.php @@ -23,42 +23,30 @@ namespace Espo\Core\Loaders; use Espo\Core\Utils, - Espo\Core\Utils\Log\Monolog\Handler; + Espo\Core\Utils\Log\Monolog\Handler; -class Log implements Loader +class Log extends Base { - private $container; + public function load() + { + $logConfig = $this->getContainer()->get('config')->get('logger'); - public function __construct(\Espo\Core\Container $container) - { - $this->container = $container; - } + $log = new Utils\Log('Espo'); - protected function getContainer() - { - return $this->container; - } + $levelCode = $log->getLevelCode($logConfig['level']); - public function load() - { - $logConfig = $this->getContainer()->get('config')->get('logger'); + if ($logConfig['isRotate']) { + $handler = new Handler\RotatingFileHandler($logConfig['path'], $logConfig['maxRotateFiles'], $levelCode); + } else { + $handler = new Handler\StreamHandler($logConfig['path'], $levelCode); + } + $log->pushHandler($handler); - $log = new Utils\Log('Espo'); + $errorHandler = new \Monolog\ErrorHandler($log); + $errorHandler->registerExceptionHandler(null, false); + $errorHandler->registerErrorHandler(array(), false); - $levelCode = $log->getLevelCode($logConfig['level']); - - if ($logConfig['isRotate']) { - $handler = new Handler\RotatingFileHandler($logConfig['path'], $logConfig['maxRotateFiles'], $levelCode); - } else { - $handler = new Handler\StreamHandler($logConfig['path'], $levelCode); - } - $log->pushHandler($handler); - - $errorHandler = new \Monolog\ErrorHandler($log); - $errorHandler->registerExceptionHandler(null, false); - $errorHandler->registerErrorHandler(array(), false); - - return $log; - } + return $log; + } } diff --git a/application/Espo/Core/Mail/Importer.php b/application/Espo/Core/Mail/Importer.php index a6ae800231..ed338f9484 100644 --- a/application/Espo/Core/Mail/Importer.php +++ b/application/Espo/Core/Mail/Importer.php @@ -5,240 +5,245 @@ 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; - } +{ + 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'); + + $subject = $message->subject; + if ($subject !== '0' && empty($subject)) { + $subject = '--empty--'; + } + + $email->set('isHtml', false); + $email->set('name', $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); - } + 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; - } + $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; + } } diff --git a/application/Espo/Core/Mail/Sender.php b/application/Espo/Core/Mail/Sender.php index 777c97a595..287ac98084 100644 --- a/application/Espo/Core/Mail/Sender.php +++ b/application/Espo/Core/Mail/Sender.php @@ -36,239 +36,247 @@ use \Espo\Core\Exceptions\Error; class Sender { - protected $config; + protected $config; - protected $transport; + protected $transport; - protected $isGlobal = false; + protected $isGlobal = false; - protected $params = array(); + protected $params = array(); - public function __construct($config) - { - $this->config = $config; - $this->useGlobal(); - } + public function __construct($config) + { + $this->config = $config; + $this->useGlobal(); + } - public function resetParams() - { - $this->params = array(); - return $this; - } + public function resetParams() + { + $this->params = array(); + return $this; + } - public function setParams(array $params = array()) - { - $this->params = array_merge($this->params, $params); - return $this; - } + public function setParams(array $params = array()) + { + $this->params = array_merge($this->params, $params); + return $this; + } - public function useSmtp(array $params = array()) - { - $this->isGlobal = false; - $this->params = $params; + public function useSmtp(array $params = array()) + { + $this->isGlobal = false; + $this->params = $params; - $this->transport = new SmtpTransport(); + $this->transport = new SmtpTransport(); + + $opts = array( + 'name' => 'admin', + 'host' => $params['server'], + 'port' => $params['port'], + 'connection_config' => array() + ); + if ($params['auth']) { + $opts['connection_class'] = 'login'; + $opts['connection_config']['username'] = $params['username']; + $opts['connection_config']['password'] = $params['password']; + } + if ($params['security']) { + $opts['connection_config']['ssl'] = strtolower($params['security']); + } + + if (in_array('fromName', $params)) { + $this->params['fromName'] = $params['fromName']; + } + if (in_array('fromAddress', $params)) { + $this->params['fromAddress'] = $params['fromAddress']; + } + + $options = new SmtpOptions($opts); + $this->transport->setOptions($options); - $opts = array( - 'name' => 'admin', - 'host' => $params['server'], - 'port' => $params['port'], - 'connection_config' => array() - ); - if ($params['auth']) { - $opts['connection_class'] = 'login'; - $opts['connection_config']['username'] = $params['username']; - $opts['connection_config']['password'] = $params['password']; - } - if ($params['security']) { - $opts['connection_config']['ssl'] = strtolower($params['security']); - } + return $this; + } - $options = new SmtpOptions($opts); - $this->transport->setOptions($options); + public function useGlobal() + { + $this->params = array(); + if ($this->isGlobal) { + return $this; + } - return $this; - } + $this->transport = new SmtpTransport(); - public function useGlobal() - { - $this->params = array(); - if ($this->isGlobal) { - return $this; - } + $config = $this->config; - $this->transport = new SmtpTransport(); + $opts = array( + 'name' => 'admin', + 'host' => $config->get('smtpServer'), + 'port' => $config->get('smtpPort'), + 'connection_config' => array() + ); + if ($config->get('smtpAuth')) { + $opts['connection_class'] = 'login'; + $opts['connection_config']['username'] = $config->get('smtpUsername'); + $opts['connection_config']['password'] = $config->get('smtpPassword'); + } + if ($config->get('smtpSecurity')) { + $opts['connection_config']['ssl'] = strtolower($config->get('smtpSecurity')); + } - $config = $this->config; + $options = new SmtpOptions($opts); + $this->transport->setOptions($options); - $opts = array( - 'name' => 'admin', - 'host' => $config->get('smtpServer'), - 'port' => $config->get('smtpPort'), - 'connection_config' => array() - ); - if ($config->get('smtpAuth')) { - $opts['connection_class'] = 'login'; - $opts['connection_config']['username'] = $config->get('smtpUsername'); - $opts['connection_config']['password'] = $config->get('smtpPassword'); - } - if ($config->get('smtpSecurity')) { - $opts['connection_config']['ssl'] = strtolower($config->get('smtpSecurity')); - } + $this->isGlobal = true; - $options = new SmtpOptions($opts); - $this->transport->setOptions($options); + return $this; + } - $this->isGlobal = true; + public function send(Email $email, $params = array()) + { + $message = new Message(); + $config = $this->config; + $params = $this->params + $params; - return $this; - } + if ($email->get('from')) { + $fromName = null; + if (!empty($params['fromName'])) { + $fromName = $params['fromName']; + } else { + $fromName = $config->get('outboundEmailFromName'); + } + $message->addFrom(trim($email->get('from')), $fromName); + } else { + if (!empty($params['fromAddress'])) { + $fromAddress = $params['fromAddress']; + } else { + if (!$config->get('outboundEmailFromAddress')) { + throw new Error('outboundEmailFromAddress is not specified in config.'); + } + $fromAddress = $config->get('outboundEmailFromAddress'); + } - public function send(Email $email, $params = array()) - { - $message = new Message(); + if (!empty($params['fromName'])) { + $fromName = $params['fromName']; + } else { + $fromName = $config->get('outboundEmailFromName'); + } + + $message->addFrom($fromAddress, $fromName); + } + + if (!empty($params['replyToAddress'])) { + $replyToName = null; + if (!empty($params['replyToName'])) { + $replyToName = $params['replyToName']; + } + $message->setReplyTo($params['replyToAddress'], $replyToName); + } - $config = $this->config; - - $params = $this->params + $params; + $value = $email->get('to'); + if ($value) { + $arr = explode(';', $value); + if (is_array($arr)) { + foreach ($arr as $address) { + $message->addTo(trim($address)); + } + } + } - if ($email->get('from')) { - $fromName = null; - if (!empty($params['fromName'])) { - $fromName = $params['fromName']; - } else { - $fromName = $config->get('outboundEmailFromName'); - } - $message->addFrom(trim($email->get('from')), $fromName); - } else { - if (!empty($params['fromAddress'])) { - $fromAddress = $params['fromAddress']; - } else { - if (!$config->get('outboundEmailFromAddress')) { - throw new Error('outboundEmailFromAddress is not specified in config.'); - } - $fromAddress = $config->get('outboundEmailFromAddress'); - } + $value = $email->get('cc'); + if ($value) { + $arr = explode(';', $value); + if (is_array($arr)) { + foreach ($arr as $address) { + $message->addCC(trim($address)); + } + } + } - if (!empty($params['fromName'])) { - $fromName = $params['fromName']; - } else { - $fromName = $config->get('outboundEmailFromName'); - } + $value = $email->get('bcc'); + if ($value) { + $arr = explode(';', $value); + if (is_array($arr)) { + foreach ($arr as $address) { + $message->addBCC(trim($address)); + } + } + } - $message->addFrom($fromAddress, $fromName); - } - - if (!empty($params['replyToAddress'])) { - $replyToName = null; - if (!empty($params['replyToName'])) { - $replyToName = $params['replyToName']; - } - $message->setReplyTo($params['replyToAddress'], $replyToName); - } + $message->setSubject($email->get('name')); - $value = $email->get('to'); - if ($value) { - $arr = explode(';', $value); - if (is_array($arr)) { - foreach ($arr as $address) { - $message->addTo(trim($address)); - } - } - } + $body = new MimeMessage; + $parts = array(); + - $value = $email->get('cc'); - if ($value) { - $arr = explode(';', $value); - if (is_array($arr)) { - foreach ($arr as $address) { - $message->addCC(trim($address)); - } - } - } + $bodyPart = new MimePart($email->getBodyPlainForSending()); + $bodyPart->type = 'text/plain'; + $bodyPart->charset = 'utf-8'; + $parts[] = $bodyPart; - $value = $email->get('bcc'); - if ($value) { - $arr = explode(';', $value); - if (is_array($arr)) { - foreach ($arr as $address) { - $message->addBCC(trim($address)); - } - } - } + + if ($email->get('isHtml')) { + $bodyPart = new MimePart($email->getBodyForSending()); + $bodyPart->type = 'text/html'; + $bodyPart->charset = 'utf-8'; + $parts[] = $bodyPart; + } + - $message->setSubject($email->get('name')); + $aCollection = $email->get('attachments'); + if (!empty($aCollection)) { + foreach ($aCollection as $a) { + $fileName = 'data/upload/' . $a->id; + $attachment = new MimePart(file_get_contents($fileName)); + $attachment->disposition = Mime::DISPOSITION_ATTACHMENT; + $attachment->encoding = Mime::ENCODING_BASE64; + $attachment->filename = $a->get('name'); + if ($a->get('type')) { + $attachment->type = $a->get('type'); + } + $parts[] = $attachment; + } + } + + $aCollection = $email->getInlineAttachments(); + if (!empty($aCollection)) { + foreach ($aCollection as $a) { + $fileName = 'data/upload/' . $a->id; + $attachment = new MimePart(file_get_contents($fileName)); + $attachment->disposition = Mime::DISPOSITION_INLINE; + $attachment->encoding = Mime::ENCODING_BASE64; + $attachment->id = $a->id; + if ($a->get('type')) { + $attachment->type = $a->get('type'); + } + $parts[] = $attachment; + } + } - $body = new MimeMessage; - $parts = array(); - + $body->setParts($parts); + $message->setBody($body); + + if ($email->get('isHtml')) { + $message->getHeaders()->get('content-type')->setType('multipart/alternative'); + } - $bodyPart = new MimePart($email->getBodyPlainForSending()); - $bodyPart->type = 'text/plain'; - $bodyPart->charset = 'utf-8'; - $parts[] = $bodyPart; + try { + if ($email->get('parentType') && $email->get('parentId')) { + $messageId = '<' . $email->get('parentType') .'/' . $email->get('parentId') . '/' . time() . '@espo>'; + } else { + $messageId = '<' . md5($email->get('name')) . '/' . time() . '@espo>'; + } + $message->getHeaders()->addHeaderLine('Message-Id', $messageId); - - if ($email->get('isHtml')) { - $bodyPart = new MimePart($email->getBodyForSending()); - $bodyPart->type = 'text/html'; - $bodyPart->charset = 'utf-8'; - $parts[] = $bodyPart; - } - + $this->transport->send($message); - $aCollection = $email->get('attachments'); - if (!empty($aCollection)) { - foreach ($aCollection as $a) { - $fileName = 'data/upload/' . $a->id; - $attachment = new MimePart(file_get_contents($fileName)); - $attachment->disposition = Mime::DISPOSITION_ATTACHMENT; - $attachment->encoding = Mime::ENCODING_BASE64; - $attachment->filename = $a->get('name'); - if ($a->get('type')) { - $attachment->type = $a->get('type'); - } - $parts[] = $attachment; - } - } - - $aCollection = $email->getInlineAttachments(); - if (!empty($aCollection)) { - foreach ($aCollection as $a) { - $fileName = 'data/upload/' . $a->id; - $attachment = new MimePart(file_get_contents($fileName)); - $attachment->disposition = Mime::DISPOSITION_INLINE; - $attachment->encoding = Mime::ENCODING_BASE64; - $attachment->id = $a->id; - if ($a->get('type')) { - $attachment->type = $a->get('type'); - } - $parts[] = $attachment; - } - } + $email->set('messageId', $message_id); + $email->set('status', 'Sent'); + $email->set('dateSent', date("Y-m-d H:i:s")); + } catch (\Exception $e) { + throw new Error($e->getMessage(), 500); + } - $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) { - throw new Error($e->getMessage(), 500); - } - - $this->useGlobal(); - } + $this->useGlobal(); + } } diff --git a/application/Espo/Core/Mail/Storage/Imap.php b/application/Espo/Core/Mail/Storage/Imap.php index 65a9ded66b..494ad94e6a 100644 --- a/application/Espo/Core/Mail/Storage/Imap.php +++ b/application/Espo/Core/Mail/Storage/Imap.php @@ -3,17 +3,17 @@ 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 . '"')); - } - +{ + 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 . '"')); + } + } diff --git a/application/Espo/Core/ORM/DB/MysqlMapper.php b/application/Espo/Core/ORM/DB/MysqlMapper.php index 78ef574046..912c28777c 100644 --- a/application/Espo/Core/ORM/DB/MysqlMapper.php +++ b/application/Espo/Core/ORM/DB/MysqlMapper.php @@ -18,12 +18,12 @@ * * 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\ORM\DB; class MysqlMapper extends \Espo\ORM\DB\MysqlMapper { - protected $returnCollection = false; + protected $returnCollection = false; } diff --git a/application/Espo/Core/ORM/Entity.php b/application/Espo/Core/ORM/Entity.php index e279f94be9..e96292c6ee 100644 --- a/application/Espo/Core/ORM/Entity.php +++ b/application/Espo/Core/ORM/Entity.php @@ -18,46 +18,46 @@ * * 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\ORM; class Entity extends \Espo\ORM\Entity { - public function loadLinkMultipleField($field, $columns = null) - { - if ($this->hasRelation($field) && $this->hasField($field . 'Ids')) { - - $defs = array(); - if (!empty($columns)) { - $defs['additionalColumns'] = $columns; - } - - $collection = $this->get($field, $defs); - $ids = array(); - $names = new \stdClass(); - if (!empty($columns)) { - $columnsData = new \stdClass(); - } - - foreach ($collection as $e) { - $id = $e->id; - $ids[] = $id; - $names->$id = $e->get('name'); - if (!empty($columns)) { - $columnsData->$id = new \stdClass(); - foreach ($columns as $column => $f) { - $columnsData->$id->$column = $e->get($f); - } - } - } - $this->set($field . 'Ids', $ids); - $this->set($field . 'Names', $names); - if (!empty($columns)) { - $this->set($field . 'Columns', $columnsData); - } - - } - } + + public function loadLinkMultipleField($field, $columns = null) + { + if ($this->hasRelation($field) && $this->hasField($field . 'Ids')) { + + $defs = array(); + if (!empty($columns)) { + $defs['additionalColumns'] = $columns; + } + + $collection = $this->get($field, $defs); + $ids = array(); + $names = new \stdClass(); + if (!empty($columns)) { + $columnsData = new \stdClass(); + } + + foreach ($collection as $e) { + $id = $e->id; + $ids[] = $id; + $names->$id = $e->get('name'); + if (!empty($columns)) { + $columnsData->$id = new \stdClass(); + foreach ($columns as $column => $f) { + $columnsData->$id->$column = $e->get($f); + } + } + } + $this->set($field . 'Ids', $ids); + $this->set($field . 'Names', $names); + if (!empty($columns)) { + $this->set($field . 'Columns', $columnsData); + } + } + } } diff --git a/application/Espo/Core/ORM/EntityManager.php b/application/Espo/Core/ORM/EntityManager.php index 555e6875b8..7fde769740 100644 --- a/application/Espo/Core/ORM/EntityManager.php +++ b/application/Espo/Core/ORM/EntityManager.php @@ -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\ORM; @@ -26,80 +26,80 @@ use \Espo\Core\Utils\Util; class EntityManager extends \Espo\ORM\EntityManager { - protected $espoMetadata; - - private $hookManager; - - protected $user; - - protected $container; - - private $repositoryClassNameHash = array(); - - private $entityClassNameHash = array(); - - public function setContainer(\Espo\Core\Container $container) - { - $this->container = $container; - } - - public function getContainer() - { - return $this->container; - } - - public function setUser($user) - { - $this->user = $user; - } - - public function getUser() - { - return $this->user; - } - - public function getEspoMetadata() - { - return $this->espoMetadata; - } + protected $espoMetadata; - public function setEspoMetadata($espoMetadata) - { - $this->espoMetadata = $espoMetadata; - } - - public function setHookManager(\Espo\Core\HookManager $hookManager) - { - $this->hookManager = $hookManager; - } - - public function getHookManager() - { - return $this->hookManager; - } + private $hookManager; - public function normalizeRepositoryName($name) - { - if (empty($this->repositoryClassNameHash[$name])) { - $className = '\\Espo\\Custom\\Repositories\\' . Util::normilizeClassName($name); - if (!class_exists($className)) { - $className = $this->espoMetadata->getRepositoryPath($name); - } - $this->repositoryClassNameHash[$name] = $className; - } - return $this->repositoryClassNameHash[$name]; - } - - public function normalizeEntityName($name) - { - if (empty($this->entityClassNameHash[$name])) { - $className = '\\Espo\\Custom\\Entities\\' . Util::normilizeClassName($name); - if (!class_exists($className)) { - $className = $this->espoMetadata->getEntityPath($name); - } - $this->entityClassNameHash[$name] = $className; - } - return $this->entityClassNameHash[$name]; - } + protected $user; + + protected $container; + + private $repositoryClassNameHash = array(); + + private $entityClassNameHash = array(); + + public function setContainer(\Espo\Core\Container $container) + { + $this->container = $container; + } + + public function getContainer() + { + return $this->container; + } + + public function setUser($user) + { + $this->user = $user; + } + + public function getUser() + { + return $this->user; + } + + public function getEspoMetadata() + { + return $this->espoMetadata; + } + + public function setEspoMetadata($espoMetadata) + { + $this->espoMetadata = $espoMetadata; + } + + public function setHookManager(\Espo\Core\HookManager $hookManager) + { + $this->hookManager = $hookManager; + } + + public function getHookManager() + { + return $this->hookManager; + } + + public function normalizeRepositoryName($name) + { + if (empty($this->repositoryClassNameHash[$name])) { + $className = '\\Espo\\Custom\\Repositories\\' . Util::normilizeClassName($name); + if (!class_exists($className)) { + $className = $this->espoMetadata->getRepositoryPath($name); + } + $this->repositoryClassNameHash[$name] = $className; + } + return $this->repositoryClassNameHash[$name]; + } + + public function normalizeEntityName($name) + { + if (empty($this->entityClassNameHash[$name])) { + $className = '\\Espo\\Custom\\Entities\\' . Util::normilizeClassName($name); + if (!class_exists($className)) { + $className = $this->espoMetadata->getEntityPath($name); + } + $this->entityClassNameHash[$name] = $className; + } + return $this->entityClassNameHash[$name]; + } } diff --git a/application/Espo/Core/ORM/Repositories/RDB.php b/application/Espo/Core/ORM/Repositories/RDB.php index 0023ee6f9b..0031d8aa38 100644 --- a/application/Espo/Core/ORM/Repositories/RDB.php +++ b/application/Espo/Core/ORM/Repositories/RDB.php @@ -32,282 +32,284 @@ use \Espo\Core\Interfaces\Injectable; class RDB extends \Espo\ORM\Repositories\RDB implements Injectable { - public static $mapperClassName = '\\Espo\\Core\\ORM\\DB\\MysqlMapper'; + public static $mapperClassName = '\\Espo\\Core\\ORM\\DB\\MysqlMapper'; - protected $dependencies = array( - 'metadata' - ); + protected $dependencies = array( + 'metadata' + ); - protected $injections = array(); + protected $injections = array(); - public function inject($name, $object) - { - $this->injections[$name] = $object; - } + public function inject($name, $object) + { + $this->injections[$name] = $object; + } - protected function getInjection($name) - { - return $this->injections[$name]; - } + protected function getInjection($name) + { + return $this->injections[$name]; + } - public function getDependencyList() - { - return $this->dependencies; - } + public function getDependencyList() + { + return $this->dependencies; + } - protected function getMetadata() - { - return $this->getInjection('metadata'); - } + protected function getMetadata() + { + return $this->getInjection('metadata'); + } - public function handleSelectParams(&$params) - { - $this->handleEmailAddressParams($params); - $this->handlePhoneNumberParams($params); - $this->handleCurrencyParams($params); - } - - protected function handleCurrencyParams(&$params) - { - $entityName = $this->entityName; - - $metadata = $this->getMetadata(); - - if (!$metadata) { - return; - } - - $defs = $metadata->get('entityDefs.' . $entityName); + public function handleSelectParams(&$params) + { + $this->handleEmailAddressParams($params); + $this->handlePhoneNumberParams($params); + $this->handleCurrencyParams($params); + } - foreach ($defs['fields'] as $field => $d) { - if (isset($d['type']) && $d['type'] == 'currency') { - if (empty($params['customJoin'])) { - $params['customJoin'] = ''; - } - $alias = Util::toUnderScore($field) . "_currency_alias"; - $params['customJoin'] .= " - LEFT JOIN currency AS `{$alias}` ON {$alias}.id = ".Util::toUnderScore($entityName).".".Util::toUnderScore($field)."_currency - "; - } - } + protected function handleCurrencyParams(&$params) + { + $entityName = $this->entityName; - } + $metadata = $this->getMetadata(); - protected function handleEmailAddressParams(&$params) - { - $entityName = $this->entityName; + if (!$metadata) { + return; + } - $defs = $this->getEntityManager()->getMetadata()->get($entityName); - if (!empty($defs['relations']) && array_key_exists('emailAddresses', $defs['relations'])) { - if (empty($params['leftJoins'])) { - $params['leftJoins'] = array(); - } - if (empty($params['whereClause'])) { - $params['whereClause'] = array(); - } - if (empty($params['joinConditions'])) { - $params['joinConditions'] = array(); - } - $params['leftJoins'][] = 'emailAddresses'; - $params['joinConditions']['emailAddresses'] = array( - 'primary' => 1 - ); - } - } - - protected function handlePhoneNumberParams(&$params) - { - $entityName = $this->entityName; + $defs = $metadata->get('entityDefs.' . $entityName); - $defs = $this->getEntityManager()->getMetadata()->get($entityName); - if (!empty($defs['relations']) && array_key_exists('phoneNumbers', $defs['relations'])) { - if (empty($params['leftJoins'])) { - $params['leftJoins'] = array(); - } - if (empty($params['whereClause'])) { - $params['whereClause'] = array(); - } - if (empty($params['joinConditions'])) { - $params['joinConditions'] = array(); - } - $params['leftJoins'][] = 'phoneNumbers'; - $params['joinConditions']['phoneNumbers'] = array( - 'primary' => 1 - ); - } - } + foreach ($defs['fields'] as $field => $d) { + if (isset($d['type']) && $d['type'] == 'currency') { + if (empty($params['customJoin'])) { + $params['customJoin'] = ''; + } + $alias = Util::toUnderScore($field) . "_currency_alias"; + $params['customJoin'] .= " + LEFT JOIN currency AS `{$alias}` ON {$alias}.id = ".Util::toUnderScore($entityName).".".Util::toUnderScore($field)."_currency + "; + } + } - protected function beforeRemove(Entity $entity) - { - parent::beforeRemove($entity); - $this->getEntityManager()->getHookManager()->process($this->entityName, 'beforeRemove', $entity); - } + } - protected function afterRemove(Entity $entity) - { - parent::afterRemove($entity); - $this->getEntityManager()->getHookManager()->process($this->entityName, 'afterRemove', $entity); - } + protected function handleEmailAddressParams(&$params) + { + $entityName = $this->entityName; - public function remove(Entity $entity) - { - $this->getEntityManager()->getHookManager()->process($this->entityName, 'beforeRemove', $entity); + $defs = $this->getEntityManager()->getMetadata()->get($entityName); + if (!empty($defs['relations']) && array_key_exists('emailAddresses', $defs['relations'])) { + if (empty($params['leftJoins'])) { + $params['leftJoins'] = array(); + } + if (empty($params['whereClause'])) { + $params['whereClause'] = array(); + } + if (empty($params['joinConditions'])) { + $params['joinConditions'] = array(); + } + $params['leftJoins'][] = 'emailAddresses'; + $params['joinConditions']['emailAddresses'] = array( + 'primary' => 1 + ); + } + } - $result = parent::remove($entity); - if ($result) { - $this->getEntityManager()->getHookManager()->process($this->entityName, 'afterRemove', $entity); - } - return $result; - } + protected function handlePhoneNumberParams(&$params) + { + $entityName = $this->entityName; - protected function beforeSave(Entity $entity) - { - parent::beforeSave($entity); - $this->getEntityManager()->getHookManager()->process($this->entityName, 'beforeSave', $entity); - } + $defs = $this->getEntityManager()->getMetadata()->get($entityName); + if (!empty($defs['relations']) && array_key_exists('phoneNumbers', $defs['relations'])) { + if (empty($params['leftJoins'])) { + $params['leftJoins'] = array(); + } + if (empty($params['whereClause'])) { + $params['whereClause'] = array(); + } + if (empty($params['joinConditions'])) { + $params['joinConditions'] = array(); + } + $params['leftJoins'][] = 'phoneNumbers'; + $params['joinConditions']['phoneNumbers'] = array( + 'primary' => 1 + ); + } + } - protected function afterSave(Entity $entity) - { - parent::afterSave($entity); - $this->getEntityManager()->getHookManager()->process($this->entityName, 'afterSave', $entity); - } + protected function beforeRemove(Entity $entity) + { + parent::beforeRemove($entity); + $this->getEntityManager()->getHookManager()->process($this->entityName, 'beforeRemove', $entity); + } - public function save(Entity $entity) - { - $nowString = date('Y-m-d H:i:s', time()); - $restoreData = array(); + protected function afterRemove(Entity $entity) + { + parent::afterRemove($entity); + $this->getEntityManager()->getHookManager()->process($this->entityName, 'afterRemove', $entity); + } - if ($entity->isNew()) { - if (!$entity->has('id')) { - $entity->set('id', uniqid()); - } + public function remove(Entity $entity) + { + $this->getEntityManager()->getHookManager()->process($this->entityName, 'beforeRemove', $entity); - if ($entity->hasField('createdAt')) { - $entity->set('createdAt', $nowString); - } - if ($entity->hasField('createdById')) { - $entity->set('createdById', $this->entityManager->getUser()->id); - } + $result = parent::remove($entity); + if ($result) { + $this->getEntityManager()->getHookManager()->process($this->entityName, 'afterRemove', $entity); + } + return $result; + } - if ($entity->has('modifiedById')) { - $restoreData['modifiedById'] = $entity->get('modifiedById'); - } - if ($entity->has('modifiedAt')) { - $restoreData['modifiedAt'] = $entity->get('modifiedAt'); - } - $entity->clear('modifiedById'); - $entity->clear('modifiedAt'); - } else { - if ($entity->hasField('modifiedAt')) { - $entity->set('modifiedAt', $nowString); - } - if ($entity->hasField('modifiedById')) { - $entity->set('modifiedById', $this->entityManager->getUser()->id); - } + protected function beforeSave(Entity $entity) + { + parent::beforeSave($entity); + $this->getEntityManager()->getHookManager()->process($this->entityName, 'beforeSave', $entity); + } - if ($entity->has('createdById')) { - $restoreData['createdById'] = $entity->get('createdById'); - } - if ($entity->has('createdAt')) { - $restoreData['createdAt'] = $entity->get('createdAt'); - } - $entity->clear('createdById'); - $entity->clear('createdAt'); - } - $result = parent::save($entity); + protected function afterSave(Entity $entity) + { + parent::afterSave($entity); + $this->getEntityManager()->getHookManager()->process($this->entityName, 'afterSave', $entity); + } - $entity->set($restoreData); + public function save(Entity $entity) + { + $nowString = date('Y-m-d H:i:s', time()); + $restoreData = array(); - $this->handleEmailAddressSave($entity); - $this->handlePhoneNumberSave($entity); - $this->handleSpecifiedRelations($entity); + if ($entity->isNew()) { + if (!$entity->has('id')) { + $entity->set('id', uniqid()); + } - return $result; - } + if ($entity->hasField('createdAt')) { + $entity->set('createdAt', $nowString); + } + if ($entity->hasField('modifiedAt')) { + $entity->set('modifiedAt', $nowString); + } + if ($entity->hasField('createdById')) { + $entity->set('createdById', $this->entityManager->getUser()->id); + } - protected function handleEmailAddressSave(Entity $entity) - { - if ($entity->hasRelation('emailAddresses') && $entity->hasField('emailAddress')) { - $emailAddressRepository = $this->getEntityManager()->getRepository('EmailAddress')->storeEntityEmailAddress($entity); - } - } - - protected function handlePhoneNumberSave(Entity $entity) - { - if ($entity->hasRelation('phoneNumbers') && $entity->hasField('phoneNumber')) { - $emailAddressRepository = $this->getEntityManager()->getRepository('PhoneNumber')->storeEntityPhoneNumber($entity); - } - } + if ($entity->has('modifiedById')) { + $restoreData['modifiedById'] = $entity->get('modifiedById'); + } + if ($entity->has('modifiedAt')) { + $restoreData['modifiedAt'] = $entity->get('modifiedAt'); + } + $entity->clear('modifiedById'); + } else { + if ($entity->hasField('modifiedAt')) { + $entity->set('modifiedAt', $nowString); + } + if ($entity->hasField('modifiedById')) { + $entity->set('modifiedById', $this->entityManager->getUser()->id); + } - protected function handleSpecifiedRelations(Entity $entity) - { - $relationTypes = array($entity::HAS_MANY, $entity::MANY_MANY, $entity::HAS_CHILDREN); - foreach ($entity->getRelations() as $name => $defs) { - if (in_array($defs['type'], $relationTypes)) { - $fieldName = $name . 'Ids'; - if ($entity->has($fieldName)) { - $specifiedIds = $entity->get($fieldName); - if (is_array($specifiedIds)) { - $toRemoveIds = array(); - $existingIds = array(); - $toUpdateIds = array(); - $existingColumnsData = new \stdClass(); - - $defs = array(); - $columns = $this->getMetadata()->get("entityDefs." . $entity->getEntityName() . ".fields.{$name}.columns"); - if (!empty($columns)) { - $columnData = $entity->get($name . 'Columns'); - $defs['additionalColumns'] = $columns; + if ($entity->has('createdById')) { + $restoreData['createdById'] = $entity->get('createdById'); + } + if ($entity->has('createdAt')) { + $restoreData['createdAt'] = $entity->get('createdAt'); + } + $entity->clear('createdById'); + $entity->clear('createdAt'); + } + $result = parent::save($entity); - } - - foreach ($entity->get($name, $defs) as $foreignEntity) { - $existingIds[] = $foreignEntity->id; - if (!empty($columns)) { - $data = new \stdClass(); - foreach ($columns as $columnName => $columnField) { - $foreignId = $foreignEntity->id; - $data->$columnName = $foreignEntity->get($columnField); - } - $existingColumnsData->$foreignId = $data; - } - - } - foreach ($existingIds as $id) { - if (!in_array($id, $specifiedIds)) { - $toRemoveIds[] = $id; - } else { - if (!empty($columns)) { - foreach ($columns as $columnName => $columnField) { - if ($columnData->$id->$columnName != $existingColumnsData->$id->$columnName) { - $toUpdateIds[] = $id; - } - } - } - } - } - foreach ($specifiedIds as $id) { - if (!in_array($id, $existingIds)) { - $data = null; - if (!empty($columns)) { - $data = $columnData->$id; - } - $this->relate($entity, $name, $id, $data); - } - } - foreach ($toRemoveIds as $id) { - $this->unrelate($entity, $name, $id); - } - if (!empty($columns)) { - foreach ($toUpdateIds as $id) { - $data = $columnData->$id; - $this->updateRelation($entity, $name, $id, $data); - } - } - } - } - } - } - } + $entity->set($restoreData); + + $this->handleEmailAddressSave($entity); + $this->handlePhoneNumberSave($entity); + $this->handleSpecifiedRelations($entity); + + return $result; + } + + protected function handleEmailAddressSave(Entity $entity) + { + if ($entity->hasRelation('emailAddresses') && $entity->hasField('emailAddress')) { + $emailAddressRepository = $this->getEntityManager()->getRepository('EmailAddress')->storeEntityEmailAddress($entity); + } + } + + protected function handlePhoneNumberSave(Entity $entity) + { + if ($entity->hasRelation('phoneNumbers') && $entity->hasField('phoneNumber')) { + $emailAddressRepository = $this->getEntityManager()->getRepository('PhoneNumber')->storeEntityPhoneNumber($entity); + } + } + + protected function handleSpecifiedRelations(Entity $entity) + { + $relationTypes = array($entity::HAS_MANY, $entity::MANY_MANY, $entity::HAS_CHILDREN); + foreach ($entity->getRelations() as $name => $defs) { + if (in_array($defs['type'], $relationTypes)) { + $fieldName = $name . 'Ids'; + if ($entity->has($fieldName)) { + $specifiedIds = $entity->get($fieldName); + if (is_array($specifiedIds)) { + $toRemoveIds = array(); + $existingIds = array(); + $toUpdateIds = array(); + $existingColumnsData = new \stdClass(); + + $defs = array(); + $columns = $this->getMetadata()->get("entityDefs." . $entity->getEntityName() . ".fields.{$name}.columns"); + if (!empty($columns)) { + $columnData = $entity->get($name . 'Columns'); + $defs['additionalColumns'] = $columns; + + } + + foreach ($entity->get($name, $defs) as $foreignEntity) { + $existingIds[] = $foreignEntity->id; + if (!empty($columns)) { + $data = new \stdClass(); + foreach ($columns as $columnName => $columnField) { + $foreignId = $foreignEntity->id; + $data->$columnName = $foreignEntity->get($columnField); + } + $existingColumnsData->$foreignId = $data; + } + + } + foreach ($existingIds as $id) { + if (!in_array($id, $specifiedIds)) { + $toRemoveIds[] = $id; + } else { + if (!empty($columns)) { + foreach ($columns as $columnName => $columnField) { + if ($columnData->$id->$columnName != $existingColumnsData->$id->$columnName) { + $toUpdateIds[] = $id; + } + } + } + } + } + foreach ($specifiedIds as $id) { + if (!in_array($id, $existingIds)) { + $data = null; + if (!empty($columns)) { + $data = $columnData->$id; + } + $this->relate($entity, $name, $id, $data); + } + } + foreach ($toRemoveIds as $id) { + $this->unrelate($entity, $name, $id); + } + if (!empty($columns)) { + foreach ($toUpdateIds as $id) { + $data = $columnData->$id; + $this->updateRelation($entity, $name, $id, $data); + } + } + } + } + } + } + } } diff --git a/application/Espo/Core/ORM/Repository.php b/application/Espo/Core/ORM/Repository.php index a6386eae43..f3d4dd23d7 100644 --- a/application/Espo/Core/ORM/Repository.php +++ b/application/Espo/Core/ORM/Repository.php @@ -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\ORM; @@ -26,23 +26,23 @@ use \Espo\Core\Interfaces\Injectable; abstract class Repository extends \Espo\ORM\Repository implements Injectable { - protected $dependencies = array(); - - protected $injections = array(); - - public function inject($name, $object) - { - $this->injections[$name] = $object; - } - - protected function getInjection($name) - { - return $this->injections[$name]; - } - - public function getDependencyList() - { - return $this->dependencies; - } + protected $dependencies = array(); + + protected $injections = array(); + + public function inject($name, $object) + { + $this->injections[$name] = $object; + } + + protected function getInjection($name) + { + return $this->injections[$name]; + } + + public function getDependencyList() + { + return $this->dependencies; + } } diff --git a/application/Espo/Core/ORM/RepositoryFactory.php b/application/Espo/Core/ORM/RepositoryFactory.php index 6975192db8..dfd6a1b406 100644 --- a/application/Espo/Core/ORM/RepositoryFactory.php +++ b/application/Espo/Core/ORM/RepositoryFactory.php @@ -18,23 +18,23 @@ * * 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\ORM; class RepositoryFactory extends \Espo\ORM\RepositoryFactory -{ - protected $defaultRepositoryClassName = '\\Espo\\Core\\ORM\\Repositories\\RDB'; +{ + protected $defaultRepositoryClassName = '\\Espo\\Core\\ORM\\Repositories\\RDB'; - public function create($name) - { - $repository = parent::create($name); - - $dependencies = $repository->getDependencyList(); - foreach ($dependencies as $name) { - $repository->inject($name, $this->entityManager->getContainer()->get($name)); - } - return $repository; - } + public function create($name) + { + $repository = parent::create($name); + + $dependencies = $repository->getDependencyList(); + foreach ($dependencies as $name) { + $repository->inject($name, $this->entityManager->getContainer()->get($name)); + } + return $repository; + } } diff --git a/application/Espo/Core/SelectManagerFactory.php b/application/Espo/Core/SelectManagerFactory.php index dd035fe8b8..333023ee73 100644 --- a/application/Espo/Core/SelectManagerFactory.php +++ b/application/Espo/Core/SelectManagerFactory.php @@ -28,41 +28,41 @@ use \Espo\Core\Utils\Util; class SelectManagerFactory { - private $entityManager; - - private $user; - - private $acl; - - private $metadata; + private $entityManager; + + private $user; + + private $acl; + + private $metadata; public function __construct($entityManager, \Espo\Entities\User $user, Acl $acl, $metadata) { - $this->entityManager = $entityManager; - $this->user = $user; - $this->acl = $acl; - $this->metadata = $metadata; + $this->entityManager = $entityManager; + $this->user = $user; + $this->acl = $acl; + $this->metadata = $metadata; } - public function create($entityName) - { - $className = '\\Espo\\Custom\\SelectManagers\\' . Util::normilizeClassName($entityName); - if (!class_exists($className)) { - $moduleName = $this->metadata->getScopeModuleName($entityName); - if ($moduleName) { - $className = '\\Espo\\Modules\\' . $moduleName . '\\SelectManagers\\' . Util::normilizeClassName($entityName); - } else { - $className = '\\Espo\\SelectManagers\\' . Util::normilizeClassName($entityName); - } - if (!class_exists($className)) { - $className = '\\Espo\\Core\\SelectManagers\\Base'; - } - } - - $selectManager = new $className($this->entityManager, $this->user, $this->acl, $this->metadata); - $selectManager->setEntityName($entityName); - - return $selectManager; - } + public function create($entityName) + { + $className = '\\Espo\\Custom\\SelectManagers\\' . Util::normilizeClassName($entityName); + if (!class_exists($className)) { + $moduleName = $this->metadata->getScopeModuleName($entityName); + if ($moduleName) { + $className = '\\Espo\\Modules\\' . $moduleName . '\\SelectManagers\\' . Util::normilizeClassName($entityName); + } else { + $className = '\\Espo\\SelectManagers\\' . Util::normilizeClassName($entityName); + } + if (!class_exists($className)) { + $className = '\\Espo\\Core\\SelectManagers\\Base'; + } + } + + $selectManager = new $className($this->entityManager, $this->user, $this->acl, $this->metadata); + $selectManager->setEntityName($entityName); + + return $selectManager; + } } diff --git a/application/Espo/Core/SelectManagers/Base.php b/application/Espo/Core/SelectManagers/Base.php index b32890dfd0..c75d6f25a7 100644 --- a/application/Espo/Core/SelectManagers/Base.php +++ b/application/Espo/Core/SelectManagers/Base.php @@ -28,374 +28,374 @@ use \Espo\Core\Acl; class Base { - protected $container; + protected $container; - protected $user; + protected $user; - protected $acl; + protected $acl; - protected $entityManager; + protected $entityManager; - protected $entityName; + protected $entityName; - protected $metadata; + protected $metadata; - const MIN_LENGTH_FOR_CONTENT_SEARCH = 4; + const MIN_LENGTH_FOR_CONTENT_SEARCH = 4; public function __construct($entityManager, \Espo\Entities\User $user, Acl $acl, $metadata) { - $this->entityManager = $entityManager; - $this->user = $user; - $this->acl = $acl; - $this->metadata = $metadata; + $this->entityManager = $entityManager; + $this->user = $user; + $this->acl = $acl; + $this->metadata = $metadata; } public function setEntityName($entityName) { - $this->entityName = $entityName; + $this->entityName = $entityName; } protected function limit($params, &$result) { - if (isset($params['offset']) && !is_null($params['offset'])) { - $result['offset'] = $params['offset']; - } - if (isset($params['maxSize']) && !is_null($params['maxSize'])) { - $result['limit'] = $params['maxSize']; - } + if (isset($params['offset']) && !is_null($params['offset'])) { + $result['offset'] = $params['offset']; + } + if (isset($params['maxSize']) && !is_null($params['maxSize'])) { + $result['limit'] = $params['maxSize']; + } } protected function order($params, &$result) { - if (!empty($params['sortBy'])) { - $result['orderBy'] = $params['sortBy']; - $type = $this->metadata->get("entityDefs.{$this->entityName}.fields." . $result['orderBy'] . ".type"); - if ($type == 'link') { - $result['orderBy'] .= 'Name'; - } else if ($type == 'linkParent') { - $result['orderBy'] .= 'Type'; - } - } - if (isset($params['asc'])) { - if ($params['asc']) { - $result['order'] = 'ASC'; - } else { - $result['order'] = 'DESC'; - } - } + if (!empty($params['sortBy'])) { + $result['orderBy'] = $params['sortBy']; + $type = $this->metadata->get("entityDefs.{$this->entityName}.fields." . $result['orderBy'] . ".type"); + if ($type == 'link') { + $result['orderBy'] .= 'Name'; + } else if ($type == 'linkParent') { + $result['orderBy'] .= 'Type'; + } + } + if (isset($params['asc'])) { + if ($params['asc']) { + $result['order'] = 'ASC'; + } else { + $result['order'] = 'DESC'; + } + } } protected function getTextFilterFields() { - return $this->metadata->get("entityDefs.{$this->entityName}.collection.textFilterFields", array('name')); + return $this->metadata->get("entityDefs.{$this->entityName}.collection.textFilterFields", array('name')); } protected function where($params, &$result) { - if (!empty($params['where']) && is_array($params['where'])) { - $where = array(); + if (!empty($params['where']) && is_array($params['where'])) { + $where = array(); - foreach ($params['where'] as $item) { - if ($item['type'] == 'boolFilters' && !empty($item['value']) && is_array($item['value'])) { - foreach ($item['value'] as $filter) { - $p = $this->getBoolFilterWhere($filter); - if (!empty($p)) { - $params['where'][] = $p; - } - } - } else if ($item['type'] == 'textFilter' && !empty($item['value'])) { - if (!empty($item['value'])) { - if (empty($result['whereClause'])) { - $result['whereClause'] = array(); - } - $fieldDefs = $this->entityManager->getEntity($this->entityName)->getFields(); - $fieldList = $this->getTextFilterFields(); - $d = array(); - 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; - } - } - } + foreach ($params['where'] as $item) { + if ($item['type'] == 'boolFilters' && !empty($item['value']) && is_array($item['value'])) { + foreach ($item['value'] as $filter) { + $p = $this->getBoolFilterWhere($filter); + if (!empty($p)) { + $params['where'][] = $p; + } + } + } else if ($item['type'] == 'textFilter' && !empty($item['value'])) { + if (!empty($item['value'])) { + if (empty($result['whereClause'])) { + $result['whereClause'] = array(); + } + $fieldDefs = $this->entityManager->getEntity($this->entityName)->getFields(); + $fieldList = $this->getTextFilterFields(); + $d = array(); + 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; + } + } + } - $linkedWith = array(); - $ignoreList = array('linkedWith', 'boolFilters'); - foreach ($params['where'] as $item) { - if (!in_array($item['type'], $ignoreList)) { - $part = $this->getWherePart($item); - if (!empty($part)) { - $where[] = $part; - } - } else { - if ($item['type'] == 'linkedWith' && !empty($item['value'])) { - $linkedWith[$item['field']] = $item['value']; - } - } - } + $linkedWith = array(); + $ignoreList = array('linkedWith', 'boolFilters'); + foreach ($params['where'] as $item) { + if (!in_array($item['type'], $ignoreList)) { + $part = $this->getWherePart($item); + if (!empty($part)) { + $where[] = $part; + } + } else { + if ($item['type'] == 'linkedWith' && !empty($item['value'])) { + $linkedWith[$item['field']] = $item['value']; + } + } + } - if (!empty($linkedWith)) { - $joins = array(); + if (!empty($linkedWith)) { + $joins = array(); - $part = array(); - foreach ($linkedWith as $link => $ids) { - $joins[] = $link; - $defs = $this->entityManager->getMetadata()->get($this->entityName); + $part = array(); + foreach ($linkedWith as $link => $ids) { + $joins[] = $link; + $defs = $this->entityManager->getMetadata()->get($this->entityName); - $entityName = $defs['relations'][$link]['entity']; - if ($entityName) { - $part[$entityName . '.id'] = $ids; - } - } + $entityName = $defs['relations'][$link]['entity']; + if ($entityName) { + $part[$entityName . '.id'] = $ids; + } + } - if (!empty($part)) { - $where[] = $part; - } - $result['joins'] = $joins; - $result['distinct'] = true; + if (!empty($part)) { + $where[] = $part; + } + $result['joins'] = $joins; + $result['distinct'] = true; - } + } - $result['whereClause'] = $where; - } + $result['whereClause'] = $where; + } } protected function q($params, &$result) { - if (!empty($params['q'])) { - if (empty($result['whereClause'])) { - $result['whereClause'] = array(); - } - - $fieldDefs = $this->entityManager->getEntity($this->entityName)->getFields(); + if (!empty($params['q'])) { + if (empty($result['whereClause'])) { + $result['whereClause'] = array(); + } - $value = $params['q']; + $fieldDefs = $this->entityManager->getEntity($this->entityName)->getFields(); - $fieldList = $this->getTextFilterFields(); - $d = array(); - foreach ($fieldList as $field) { - if ( - strlen($item['value']) >= self::MIN_LENGTH_FOR_CONTENT_SEARCH - && - !empty($fieldDefs[$field]['type']) && $fieldDefs[$field]['type'] == 'text' - ) { - $d[$field . '*'] = '%' . $value . '%'; - } else { - $d[$field . '*'] = $value . '%'; - } - } + $value = $params['q']; - $result['whereClause']['OR'] = $d; - } - } + $fieldList = $this->getTextFilterFields(); + $d = array(); + foreach ($fieldList as $field) { + if ( + strlen($item['value']) >= self::MIN_LENGTH_FOR_CONTENT_SEARCH + && + !empty($fieldDefs[$field]['type']) && $fieldDefs[$field]['type'] == 'text' + ) { + $d[$field . '*'] = '%' . $value . '%'; + } else { + $d[$field . '*'] = $value . '%'; + } + } + + $result['whereClause']['OR'] = $d; + } + } protected function access(&$result) { - if ($this->acl->checkReadOnlyOwn($this->entityName)) { + if ($this->acl->checkReadOnlyOwn($this->entityName)) { - if (!array_key_exists('whereClause', $result)) { - $result['whereClause'] = array(); - } - $result['whereClause']['assignedUserId'] = $this->user->id; - } - if (!$this->user->isAdmin() && $this->acl->checkReadOnlyTeam($this->entityName)) { - if (!array_key_exists('whereClause', $result)) { - $result['whereClause'] = array(); - } - $result['distinct'] = true; - if (!array_key_exists('joins', $result)) { - $result['joins'] = array(); - } - if (!in_array('teams', $result['joins'])) { - $result['leftJoins'][] = 'teams'; - } + if (!array_key_exists('whereClause', $result)) { + $result['whereClause'] = array(); + } + $result['whereClause']['assignedUserId'] = $this->user->id; + } + if (!$this->user->isAdmin() && $this->acl->checkReadOnlyTeam($this->entityName)) { + if (!array_key_exists('whereClause', $result)) { + $result['whereClause'] = array(); + } + $result['distinct'] = true; + if (!array_key_exists('joins', $result)) { + $result['joins'] = array(); + } + if (!in_array('teams', $result['joins'])) { + $result['leftJoins'][] = 'teams'; + } - $result['whereClause']['OR'] = array( - 'Team.id' => $this->user->get('teamsIds'), - 'assignedUserId' => $this->user->id - ); - //$result['whereClause']['Team.id'] = $this->user->get('teamsIds'); - } + $result['whereClause']['OR'] = array( + 'Team.id' => $this->user->get('teamsIds'), + 'assignedUserId' => $this->user->id + ); + //$result['whereClause']['Team.id'] = $this->user->get('teamsIds'); + } } public function getAclParams() { - $result = array(); - $this->access($result); - return $result; + $result = array(); + $this->access($result); + return $result; } - public function getSelectParams(array $params, $withAcl = false) - { - $result = array(); + public function getSelectParams(array $params, $withAcl = false) + { + $result = array(); - $this->order($params, $result); - $this->limit($params, $result); - $this->where($params, $result); - $this->q($params, $result); + $this->order($params, $result); + $this->limit($params, $result); + $this->where($params, $result); + $this->q($params, $result); - if ($withAcl) { - $this->access($result); - } + if ($withAcl) { + $this->access($result); + } - return $result; - } + return $result; + } - protected function getWherePart($item) - { - $part = array(); + protected function getWherePart($item) + { + $part = array(); - if (!empty($item['type'])) { - switch ($item['type']) { - case 'or': - case 'and': - if (is_array($item['value'])) { - $arr = array(); - foreach ($item['value'] as $i) { - $a = $this->getWherePart($i); - foreach ($a as $left => $right) { - if (!empty($right)) { - $arr[$left] = $right; - } - } - } - $part[strtoupper($item['type'])] = $arr; - } - break; - case 'like': - $part[$item['field'] . '*'] = $item['value']; - break; - case 'equals': - case 'on': - $part[$item['field'] . '='] = $item['value']; - break; - case 'notEquals': - case 'notOn': - $part[$item['field'] . '!='] = $item['value']; - break; - case 'greaterThan': - case 'after': - $part[$item['field'] . '>'] = $item['value']; - break; - case 'lessThan': - case 'before': - $part[$item['field'] . '<'] = $item['value']; - break; - case 'greaterThanOrEquals': - $part[$item['field'] . '>='] = $item['value']; - break; - case 'lessThanOrEquals': - $part[$item['field'] . '<'] = $item['value']; - break; - case 'in': - $part[$item['field'] . '='] = $item['value']; - break; - case 'notIn': - $part[$item['field'] . '!='] = $item['value']; - break; - case 'isTrue': - $part[$item['field'] . '='] = true; - break; - case 'isFalse': - $part[$item['field'] . '='] = false; - break; - case 'today': - $part[$item['field'] . '='] = date('Y-m-d'); - break; - case 'past': - $part[$item['field'] . '<'] = date('Y-m-d'); - break; - case 'future': - $part[$item['field'] . '>'] = date('Y-m-d'); - break; - case 'currentMonth': - $dt = new \DateTime(); - $part['AND'] = array( - $item['field'] . '>=' => $dt->modify('first day of this month')->format('Y-m-d'), - $item['field'] . '<' => $dt->add(new \DateInterval('P1M'))->format('Y-m-d'), - ); - break; - case 'lastMonth': - $dt = new \DateTime(); - $part['AND'] = array( - $item['field'] . '>=' => $dt->modify('first day of last month')->format('Y-m-d'), - $item['field'] . '<' => $dt->add(new \DateInterval('P1M'))->format('Y-m-d'), - ); - break; - case 'currentQuarter': - $dt = new \DateTime(); - $quarter = ceil($dt->format('m') / 3); - $dt->modify('first day of January this year'); - $part['AND'] = array( - $item['field'] . '>=' => $dt->add(new \DateInterval('P'.(($quarter - 1) * 3).'M'))->format('Y-m-d'), - $item['field'] . '<' => $dt->add(new \DateInterval('P3M'))->format('Y-m-d'), - ); - break; - case 'lastQuarter': - $dt = new \DateTime(); - $quarter = ceil($dt->format('m') / 3); - $dt->modify('first day of January this year'); - $quarter--; - if ($quarter == 0) { - $quarter = 4; - $dt->sub('P1Y'); - } - $part['AND'] = array( - $item['field'] . '>=' => $dt->add(new \DateInterval('P'.(($quarter - 1) * 3).'M'))->format('Y-m-d'), - $item['field'] . '<' => $dt->add(new \DateInterval('P3M'))->format('Y-m-d'), - ); - break; - case 'currentYear': - $dt = new \DateTime(); - $part['AND'] = array( - $item['field'] . '>=' => $dt->modify('first day of January this year')->format('Y-m-d'), - $item['field'] . '<' => $dt->add(new \DateInterval('P1Y'))->format('Y-m-d'), - ); - break; - case 'lastYear': - $dt = new \DateTime(); - $part['AND'] = array( - $item['field'] . '>=' => $dt->modify('first day of January last year')->format('Y-m-d'), - $item['field'] . '<' => $dt->add(new \DateInterval('P1Y'))->format('Y-m-d'), - ); - break; - case 'between': - if (is_array($item['value'])) { - $part['AND'] = array( - $item['field'] . '>=' => $item['value'][0], - $item['field'] . '<=' => $item['value'][1], - ); - } - break; - } - } + if (!empty($item['type'])) { + switch ($item['type']) { + case 'or': + case 'and': + if (is_array($item['value'])) { + $arr = array(); + foreach ($item['value'] as $i) { + $a = $this->getWherePart($i); + foreach ($a as $left => $right) { + if (!empty($right)) { + $arr[$left] = $right; + } + } + } + $part[strtoupper($item['type'])] = $arr; + } + break; + case 'like': + $part[$item['field'] . '*'] = $item['value']; + break; + case 'equals': + case 'on': + $part[$item['field'] . '='] = $item['value']; + break; + case 'notEquals': + case 'notOn': + $part[$item['field'] . '!='] = $item['value']; + break; + case 'greaterThan': + case 'after': + $part[$item['field'] . '>'] = $item['value']; + break; + case 'lessThan': + case 'before': + $part[$item['field'] . '<'] = $item['value']; + break; + case 'greaterThanOrEquals': + $part[$item['field'] . '>='] = $item['value']; + break; + case 'lessThanOrEquals': + $part[$item['field'] . '<'] = $item['value']; + break; + case 'in': + $part[$item['field'] . '='] = $item['value']; + break; + case 'notIn': + $part[$item['field'] . '!='] = $item['value']; + break; + case 'isTrue': + $part[$item['field'] . '='] = true; + break; + case 'isFalse': + $part[$item['field'] . '='] = false; + break; + case 'today': + $part[$item['field'] . '='] = date('Y-m-d'); + break; + case 'past': + $part[$item['field'] . '<'] = date('Y-m-d'); + break; + case 'future': + $part[$item['field'] . '>'] = date('Y-m-d'); + break; + case 'currentMonth': + $dt = new \DateTime(); + $part['AND'] = array( + $item['field'] . '>=' => $dt->modify('first day of this month')->format('Y-m-d'), + $item['field'] . '<' => $dt->add(new \DateInterval('P1M'))->format('Y-m-d'), + ); + break; + case 'lastMonth': + $dt = new \DateTime(); + $part['AND'] = array( + $item['field'] . '>=' => $dt->modify('first day of last month')->format('Y-m-d'), + $item['field'] . '<' => $dt->add(new \DateInterval('P1M'))->format('Y-m-d'), + ); + break; + case 'currentQuarter': + $dt = new \DateTime(); + $quarter = ceil($dt->format('m') / 3); + $dt->modify('first day of January this year'); + $part['AND'] = array( + $item['field'] . '>=' => $dt->add(new \DateInterval('P'.(($quarter - 1) * 3).'M'))->format('Y-m-d'), + $item['field'] . '<' => $dt->add(new \DateInterval('P3M'))->format('Y-m-d'), + ); + break; + case 'lastQuarter': + $dt = new \DateTime(); + $quarter = ceil($dt->format('m') / 3); + $dt->modify('first day of January this year'); + $quarter--; + if ($quarter == 0) { + $quarter = 4; + $dt->sub('P1Y'); + } + $part['AND'] = array( + $item['field'] . '>=' => $dt->add(new \DateInterval('P'.(($quarter - 1) * 3).'M'))->format('Y-m-d'), + $item['field'] . '<' => $dt->add(new \DateInterval('P3M'))->format('Y-m-d'), + ); + break; + case 'currentYear': + $dt = new \DateTime(); + $part['AND'] = array( + $item['field'] . '>=' => $dt->modify('first day of January this year')->format('Y-m-d'), + $item['field'] . '<' => $dt->add(new \DateInterval('P1Y'))->format('Y-m-d'), + ); + break; + case 'lastYear': + $dt = new \DateTime(); + $part['AND'] = array( + $item['field'] . '>=' => $dt->modify('first day of January last year')->format('Y-m-d'), + $item['field'] . '<' => $dt->add(new \DateInterval('P1Y'))->format('Y-m-d'), + ); + break; + case 'between': + if (is_array($item['value'])) { + $part['AND'] = array( + $item['field'] . '>=' => $item['value'][0], + $item['field'] . '<=' => $item['value'][1], + ); + } + break; + } + } - return $part; - } + return $part; + } - protected function getBoolFilterWhere($filterName) - { - $method = 'getBoolFilterWhere' . ucfirst($filterName); - if (method_exists($this, $method)) { - return $this->$method(); - } - } + protected function getBoolFilterWhere($filterName) + { + $method = 'getBoolFilterWhere' . ucfirst($filterName); + if (method_exists($this, $method)) { + return $this->$method(); + } + } - protected function getBoolFilterWhereOnlyMy() - { - return array( - 'type' => 'equals', - 'field' => 'assignedUserId', - 'value' => $this->user->id, - ); - } + protected function getBoolFilterWhereOnlyMy() + { + return array( + 'type' => 'equals', + 'field' => 'assignedUserId', + 'value' => $this->user->id, + ); + } } diff --git a/application/Espo/Core/ServiceFactory.php b/application/Espo/Core/ServiceFactory.php index b55d69b22b..3bc21e5dfd 100644 --- a/application/Espo/Core/ServiceFactory.php +++ b/application/Espo/Core/ServiceFactory.php @@ -28,127 +28,127 @@ use \Espo\Core\Utils\Util; class ServiceFactory { - private $container; + private $container; - protected $cacheFile = 'data/cache/application/services.php'; + protected $cacheFile = 'data/cache/application/services.php'; - /** + /** * @var array - path to Service files */ - protected $paths = array( - 'corePath' => 'application/Espo/Services', - 'modulePath' => 'application/Espo/Modules/{*}/Services', - 'customPath' => 'custom/Espo/Custom/Services', - ); + protected $paths = array( + 'corePath' => 'application/Espo/Services', + 'modulePath' => 'application/Espo/Modules/{*}/Services', + 'customPath' => 'custom/Espo/Custom/Services', + ); - protected $data; + protected $data; public function __construct(Container $container) { - $this->container = $container; + $this->container = $container; } - protected function init() - { - $config = $this->getContainer()->get('config'); + protected function init() + { + $config = $this->getContainer()->get('config'); - if (file_exists($this->cacheFile) && $config->get('useCache')) { - $this->data = $this->getFileManager()->getContents($this->cacheFile); - } else { - $this->data = $this->getClassNameHash($this->paths['corePath']); + if (file_exists($this->cacheFile) && $config->get('useCache')) { + $this->data = $this->getFileManager()->getContents($this->cacheFile); + } else { + $this->data = $this->getClassNameHash($this->paths['corePath']); - foreach ($this->getContainer()->get('metadata')->getModuleList() as $moduleName) { - $path = str_replace('{*}', $moduleName, $this->paths['modulePath']); - $this->data = array_merge($this->data, $this->getClassNameHash($path)); - } + foreach ($this->getContainer()->get('metadata')->getModuleList() as $moduleName) { + $path = str_replace('{*}', $moduleName, $this->paths['modulePath']); + $this->data = array_merge($this->data, $this->getClassNameHash($path)); + } - $this->data = array_merge($this->data, $this->getClassNameHash($this->paths['customPath'])); + $this->data = array_merge($this->data, $this->getClassNameHash($this->paths['customPath'])); - if ($config->get('useCache')) { - $result = $this->getFileManager()->putContentsPHP($this->cacheFile, $this->data); - if ($result == false) { - throw new \Espo\Core\Exceptions\Error(); - } - } - } - } + if ($config->get('useCache')) { + $result = $this->getFileManager()->putContentsPHP($this->cacheFile, $this->data); + if ($result == false) { + throw new \Espo\Core\Exceptions\Error(); + } + } + } + } - protected function getFileManager() - { - return $this->container->get('fileManager'); - } + protected function getFileManager() + { + return $this->container->get('fileManager'); + } - protected function getContainer() - { - return $this->container; - } + protected function getContainer() + { + return $this->container; + } - protected function getClassName($name) - { - $name = Util::normilizeClassName($name); + protected function getClassName($name) + { + $name = Util::normilizeClassName($name); - if (!isset($this->data)) { - $this->init(); - } + if (!isset($this->data)) { + $this->init(); + } - $name = ucfirst($name); - if (isset($this->data[$name])) { - return $this->data[$name]; - } + $name = ucfirst($name); + if (isset($this->data[$name])) { + return $this->data[$name]; + } return false; - } + } - public function checkExists($name) { - $className = $this->getClassName($name); - if (!empty($className)) { - return true; - } - } + public function checkExists($name) { + $className = $this->getClassName($name); + if (!empty($className)) { + return true; + } + } public function create($name) { - $className = $this->getClassName($name); - if (empty($className)) { - throw new Error(); - } - return $this->createByClassName($className); + $className = $this->getClassName($name); + if (empty($className)) { + throw new Error(); + } + return $this->createByClassName($className); } - protected function createByClassName($className) - { - if (class_exists($className)) { - $service = new $className(); - $dependencies = $service->getDependencyList(); - foreach ($dependencies as $name) { - $service->inject($name, $this->container->get($name)); - } - return $service; - } - throw new Error("Class '$className' does not exist"); - } + protected function createByClassName($className) + { + if (class_exists($className)) { + $service = new $className(); + $dependencies = $service->getDependencyList(); + foreach ($dependencies as $name) { + $service->inject($name, $this->container->get($name)); + } + return $service; + } + throw new Error("Class '$className' does not exist"); + } - // TODO delegate to another class - protected function getClassNameHash($dirs) - { - if (is_string($dirs)) { - $dirs = (array) $dirs; - } + // TODO delegate to another class + protected function getClassNameHash($dirs) + { + if (is_string($dirs)) { + $dirs = (array) $dirs; + } - $data = array(); + $data = array(); - foreach ($dirs as $dir) { - if (file_exists($dir)) { - $fileList = $this->getFileManager()->getFileList($dir, false, '\.php$', 'file'); - foreach ($fileList as $file) { - $filePath = Util::concatPath($dir, $file); - $className = Util::getClassName($filePath); - $fileName = $this->getFileManager()->getFileName($filePath); - $data[$fileName] = $className; - } - } - } - return $data; - } + foreach ($dirs as $dir) { + if (file_exists($dir)) { + $fileList = $this->getFileManager()->getFileList($dir, false, '\.php$', true); + foreach ($fileList as $file) { + $filePath = Util::concatPath($dir, $file); + $className = Util::getClassName($filePath); + $fileName = $this->getFileManager()->getFileName($filePath); + $data[$fileName] = $className; + } + } + } + return $data; + } } diff --git a/application/Espo/Core/Services/Base.php b/application/Espo/Core/Services/Base.php index d28a8afb23..016cd037aa 100644 --- a/application/Espo/Core/Services/Base.php +++ b/application/Espo/Core/Services/Base.php @@ -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\Services; @@ -26,51 +26,51 @@ use \Espo\Core\Interfaces\Injectable; abstract class Base implements Injectable { - protected $dependencies = array( - 'config', - 'entityManager', - 'user', - ); - - protected $injections = array(); - - public function inject($name, $object) - { - $this->injections[$name] = $object; - } - - public function __construct() - { - $this->init(); - } - - protected function init() - { - } - - protected function getInjection($name) - { - return $this->injections[$name]; - } - - public function getDependencyList() - { - return $this->dependencies; - } - - protected function getEntityManager() - { - return $this->getInjection('entityManager'); - } - - protected function getConfig() - { - return $this->getInjection('config'); - } + protected $dependencies = array( + 'config', + 'entityManager', + 'user', + ); - protected function getUser() - { - return $this->getInjection('user'); - } + protected $injections = array(); + + public function inject($name, $object) + { + $this->injections[$name] = $object; + } + + public function __construct() + { + $this->init(); + } + + protected function init() + { + } + + protected function getInjection($name) + { + return $this->injections[$name]; + } + + public function getDependencyList() + { + return $this->dependencies; + } + + protected function getEntityManager() + { + return $this->getInjection('entityManager'); + } + + protected function getConfig() + { + return $this->getInjection('config'); + } + + protected function getUser() + { + return $this->getInjection('user'); + } } diff --git a/application/Espo/Core/UpgradeManager.php b/application/Espo/Core/UpgradeManager.php index 5d42afe3d7..e6e62bdd18 100644 --- a/application/Espo/Core/UpgradeManager.php +++ b/application/Espo/Core/UpgradeManager.php @@ -26,14 +26,14 @@ use Espo\Core\Exceptions\Error; class UpgradeManager extends Upgrades\Base { - protected $name = 'Upgrade'; + protected $name = 'Upgrade'; - protected $params = array( - 'packagePath' => 'data/upload/upgrades', + protected $params = array( + 'packagePath' => 'data/upload/upgrades', - 'scriptNames' => array( - 'before' => 'BeforeUpgrade', - 'after' => 'AfterUpgrade', - ) - ); + 'scriptNames' => array( + 'before' => 'BeforeUpgrade', + 'after' => 'AfterUpgrade', + ) + ); } \ No newline at end of file diff --git a/application/Espo/Core/Upgrades/ActionManager.php b/application/Espo/Core/Upgrades/ActionManager.php index 44a0fc7b8a..7b176230b4 100644 --- a/application/Espo/Core/Upgrades/ActionManager.php +++ b/application/Espo/Core/Upgrades/ActionManager.php @@ -26,77 +26,77 @@ use Espo\Core\Exceptions\Error; class ActionManager { - private $managerName; + private $managerName; - private $container; + private $container; - private $objects; + private $objects; - protected $currentAction; + protected $currentAction; - protected $params; + protected $params; - public function __construct($managerName, $container, $params) - { - $this->managerName = $managerName; - $this->container = $container; + public function __construct($managerName, $container, $params) + { + $this->managerName = $managerName; + $this->container = $container; - $params['name'] = $managerName; - $this->params = $params; - } + $params['name'] = $managerName; + $this->params = $params; + } - protected function getManagerName() - { - return $this->managerName; - } + protected function getManagerName() + { + return $this->managerName; + } - protected function getContainer() - { - return $this->container; - } + protected function getContainer() + { + return $this->container; + } - public function setAction($action) - { - $this->currentAction = $action; - } + public function setAction($action) + { + $this->currentAction = $action; + } - public function getAction() - { - return $this->currentAction; - } + public function getAction() + { + return $this->currentAction; + } - public function getParams() - { - return $this->params; - } + public function getParams() + { + return $this->params; + } - public function run($data) - { - $object = $this->getObject(); + public function run($data) + { + $object = $this->getObject(); - return $object->run($data); - } + return $object->run($data); + } - public function getManifest() - { - return $this->getObject()->getManifest(); - } + public function getManifest() + { + return $this->getObject()->getManifest(); + } - protected function getObject() - { - $managerName = $this->getManagerName(); - $actionName = $this->getAction(); + protected function getObject() + { + $managerName = $this->getManagerName(); + $actionName = $this->getAction(); - if (!isset($this->objects[$managerName][$actionName])) { - $class = '\Espo\Core\Upgrades\Actions\\' . ucfirst($managerName) . '\\' . ucfirst($actionName); + if (!isset($this->objects[$managerName][$actionName])) { + $class = '\Espo\Core\Upgrades\Actions\\' . ucfirst($managerName) . '\\' . ucfirst($actionName); - if (!class_exists($class)) { - throw new Error('Could not find an action ['.ucfirst($actionName).'], class ['.$class.'].'); - } + if (!class_exists($class)) { + throw new Error('Could not find an action ['.ucfirst($actionName).'], class ['.$class.'].'); + } - $this->objects[$managerName][$actionName] = new $class($this->container, $this); - } + $this->objects[$managerName][$actionName] = new $class($this->container, $this); + } - return $this->objects[$managerName][$actionName]; - } + return $this->objects[$managerName][$actionName]; + } } \ No newline at end of file diff --git a/application/Espo/Core/Upgrades/Actions/Base.php b/application/Espo/Core/Upgrades/Actions/Base.php index fb270cf0b9..4f39970fa3 100644 --- a/application/Espo/Core/Upgrades/Actions/Base.php +++ b/application/Espo/Core/Upgrades/Actions/Base.php @@ -23,466 +23,473 @@ namespace Espo\Core\Upgrades\Actions; use Espo\Core\Utils\Util, - Espo\Core\Utils\Json, - Espo\Core\Exceptions\Error; + Espo\Core\Utils\Json, + Espo\Core\Exceptions\Error; abstract class Base { - private $container; + private $config; - private $actionManager; + private $entityManager; - private $zipUtil; + protected $data; - private $fileManager; - - private $config; + protected $params = null; + + private $container; - private $entityManager; - - protected $data; - - protected $params = null; - - protected $processId = null; + private $actionManager; + + private $zipUtil; + + private $fileManager; + + protected $processId = null; - protected $manifestName = 'manifest.json'; - - protected $packagePostfix = 'z'; - - /** - * Directory name of files in a package - */ - const FILES = 'files'; + protected $manifestName = 'manifest.json'; + + protected $packagePostfix = 'z'; + + /** + * Directory name of files in a package + */ + const FILES = 'files'; - /** - * Directory name of scripts in a package - */ - const SCRIPTS = 'scripts'; - - /** - * Package types - */ - protected $packageTypes = array( - 'upgrade' => 'upgrade', - 'extension' => 'extension', - ); - - /** - * Default package type - */ - protected $defaultPackageType = 'extension'; - - - public function __construct(\Espo\Core\Container $container, \Espo\Core\Upgrades\ActionManager $actionManager) - { - $this->container = $container; - $this->actionManager = $actionManager; - $this->params = $actionManager->getParams(); - - $this->zipUtil = new \Espo\Core\Utils\File\ZipArchive($container->get('fileManager')); - } - - public function __destruct() - { - $this->processId = null; - $this->data = null; - } - - protected function getContainer() - { - return $this->container; - } - - protected function getActionManager() - { - return $this->actionManager; - } - - protected function getParams($name = null) - { - if (isset($this->params[$name])) { - return $this->params[$name]; - } - - return $this->params; - } - - protected function getZipUtil() - { - return $this->zipUtil; - } - - protected function getFileManager() - { - if (!isset($this->fileManager)) { - $this->fileManager = $this->getContainer()->get('fileManager'); - } - return $this->fileManager; - } - - protected function getConfig() - { - if (!isset($this->config)) { - $this->config = $this->getContainer()->get('config'); - } - return $this->config; - } - - protected function getEntityManager() - { - if (!isset($this->entityManager)) { - $this->entityManager = $this->getContainer()->get('entityManager'); - } - return $this->entityManager; - } - - protected function throwErrorAndRemovePackage($errorMessage = '') - { - $this->deletePackageFiles(); - $this->deletePackageArchive(); - throw new Error($errorMessage); - } - - abstract public function run($data); - - protected function createProcessId() - { - if (isset($this->processId)) { - throw new Error('Another installation process is currently running.'); - } - - $this->processId = uniqid(); - - return $this->processId; - } - - protected function getProcessId() - { - if (!isset($this->processId)) { - throw new Error('Installation ID was not specified.'); - } - - return $this->processId; - } - - protected function setProcessId($processId) - { - $this->processId = $processId; - } - - /** - * Check if version of upgrade/extension is acceptable to current version of EspoCRM - * - * @param string $version - * @return boolean - */ - protected function isAcceptable() - { - $res = $this->checkPackageType(); - $res &= $this->checkVersions(); - - return (bool) $res; - } - - protected function checkVersions() - { - $manifest = $this->getManifest(); - - /** check acceptable versions */ - $version = $manifest['acceptableVersions']; - if (empty($version)) { - return true; - } - - $currentVersion = $this->getConfig()->get('version'); - - if (is_string($version)) { - $version = (array) $version; - } - - foreach ($version as $strVersion) { - - $strVersion = trim($strVersion); - - if ($strVersion == $currentVersion) { - return true; - } - - $strVersion = str_replace('\\', '', $strVersion); - $strVersion = preg_quote($strVersion); - $strVersion = str_replace('\\*', '+', $strVersion); - - if (preg_match('/^'.$strVersion.'/', $currentVersion)) { - return true; - } - } - - $this->throwErrorAndRemovePackage('Your EspoCRM version doesn\'t match for this installation package.'); - } - - protected function checkPackageType() - { - $manifest = $this->getManifest(); - - /** check package type */ - $type = strtolower( $this->getParams('name') ); - $manifestType = isset($manifest['type']) ? strtolower($manifest['type']) : $this->defaultPackageType; - - if (!in_array($manifestType, $this->packageTypes)) { - $this->throwErrorAndRemovePackage('Unknown package type.'); - } - - if ($type != $manifestType) { - $this->throwErrorAndRemovePackage('Wrong package type. You cannot install '.$manifestType.' package via '.ucfirst($type).' Manager.'); - } - - return true; - } - - /** - * Run scripts by type - * @param string $type Ex. "before", "after" - * @return void - */ - protected function runScript($type) - { - $packagePath = $this->getPackagePath(); - $scriptNames = $this->getParams('scriptNames'); - - $scriptName = $scriptNames[$type]; - if (!isset($scriptName)) { - return; - } - - $beforeInstallScript = Util::concatPath( array($packagePath, self::SCRIPTS, $scriptName) ) . '.php'; - - if (file_exists($beforeInstallScript)) { - require_once($beforeInstallScript); - $script = new $scriptName(); - - try { - $script->run($this->getContainer()); - } catch (\Exception $e) { - $this->throwErrorAndRemovePackage($e->getMessage()); - } - } - } - - /** - * Get package path - * - * @param string $processId - * @return string - */ - protected function getPath($name = 'packagePath', $isPackage = false) - { - $postfix = $isPackage ? $this->packagePostfix : ''; - - $processId = $this->getProcessId(); - $path = Util::concatPath($this->getParams($name), $processId); - - return $path . $postfix; - } - - protected function getPackagePath($isPackage = false) - { - return $this->getPath('packagePath', $isPackage); - } - - /** - * Get a list of files defined in manifest.json - * - * @return [type] [description] - */ - protected function getDeleteFileList() - { - $manifest = $this->getManifest(); - - if (!empty($manifest['delete'])) { - return $manifest['delete']; - } - - return array(); - } - - /** - * Delete files defined in a manifest - * - * @return boolen - */ - protected function deleteFiles() - { - $deleteFileList = $this->getDeleteFileList(); - - if (!empty($deleteFileList)) { - return $this->getFileManager()->remove($deleteFileList); - } - - return true; - } - - protected function getCopyFileList() - { - if (!isset($this->data['fileList'])) { - $packagePath = $this->getPackagePath(); - $filesPath = Util::concatPath($packagePath, self::FILES); - - $this->data['fileList'] = $this->getFileManager()->getFileList($filesPath, true, '', 'all', true); - } - - return $this->data['fileList']; - } - - protected function copy($sourcePath, $destPath, $recursively = false, array $fileList = null, $copyOnlyFiles = false) - { - try { - $res = $this->getFileManager()->copy($sourcePath, $destPath, $recursively, $fileList, $copyOnlyFiles); - } catch (\Exception $e) { - $this->throwErrorAndRemovePackage($e->getMessage()); - } - - return $res; - } - - /** - * Copy files from upgrade/extension package - * - * @param string $processId - * @return boolean - */ - protected function copyFiles() - { - $packagePath = $this->getPackagePath(); - $filesPath = Util::concatPath($packagePath, self::FILES); - - return $this->copy($filesPath, '', true); - } - - public function getManifest() - { - if (!isset($this->data['manifest'])) { - $packagePath = $this->getPackagePath(); - - $manifestPath = Util::concatPath($packagePath, $this->manifestName); - if (!file_exists($manifestPath)) { - $this->throwErrorAndRemovePackage('It\'s not an Installation package.'); - } - - $manifestJson = $this->getFileManager()->getContents($manifestPath); - $this->data['manifest'] = Json::decode($manifestJson, true); - - if (!$this->data['manifest']) { - $this->throwErrorAndRemovePackage('Syntax error in manifest.json.'); - } - - if (!$this->checkManifest($this->data['manifest'])) { - $this->throwErrorAndRemovePackage('Unsupported package.'); - } - } - - return $this->data['manifest']; - } - - /** - * Check if the manifest is correct - * - * @param array $manifest - * @return boolean - */ - protected function checkManifest(array $manifest) - { - $requiredFields = array( - 'name', - 'version', - ); - - foreach ($requiredFields as $fieldName) { - if (empty($manifest[$fieldName])) { - return false; - } - } - - return true; - } - - /** - * Unzip a package archieve - * - * @return void - */ - protected function unzipArchive($packagePath = null) - { - $packagePath = isset($packagePath) ? $packagePath : $this->getPackagePath(); - $packageArchivePath = $this->getPackagePath(true); - - if (!file_exists($packageArchivePath)) { - throw new Error('Package Archive doesn\'t exist.'); - } - - $res = $this->getZipUtil()->unzip($packageArchivePath, $packagePath); - if ($res === false) { - throw new Error('Unnable to unzip the file - '.$packagePath.'.'); - } - } - - /** - * Delete temporary package files - * - * @return boolean - */ - protected function deletePackageFiles() - { - $packagePath = $this->getPackagePath(); - $res = $this->getFileManager()->removeInDir($packagePath, true); - - return $res; - } - - /** - * Delete temporary package archive - * - * @return boolean - */ - protected function deletePackageArchive() - { - $packageArchive = $this->getPackagePath(true); - $res = $this->getFileManager()->removeFile($packageArchive); - - return $res; - } - - protected function systemRebuild() - { - return $this->getContainer()->get('dataManager')->rebuild(); - } - - /** - * Execute an action. For ex., execute uninstall action in install - * - * @param [type] $actionName [description] - * @param [type] $data [description] - * @return [type] [description] - */ - protected function executeAction($actionName, $data) - { - $currentAction = $this->getActionManager()->getAction(); - - $this->getActionManager()->setAction($actionName); - $this->getActionManager()->run($data); - - $this->getActionManager()->setAction($currentAction); - } - - protected function beforeRunAction() - { - - } - - protected function afterRunAction() - { - - } + /** + * Directory name of scripts in a package + */ + const SCRIPTS = 'scripts'; + + /** + * Package types + */ + protected $packageTypes = array( + 'upgrade' => 'upgrade', + 'extension' => 'extension', + ); + + /** + * Default package type + */ + protected $defaultPackageType = 'extension'; + + + public function __construct(\Espo\Core\Container $container, \Espo\Core\Upgrades\ActionManager $actionManager) + { + $this->container = $container; + $this->actionManager = $actionManager; + $this->params = $actionManager->getParams(); + + $this->zipUtil = new \Espo\Core\Utils\File\ZipArchive($container->get('fileManager')); + } + + public function __destruct() + { + $this->processId = null; + $this->data = null; + } + + protected function getContainer() + { + return $this->container; + } + + protected function getActionManager() + { + return $this->actionManager; + } + + protected function getParams($name = null) + { + if (isset($this->params[$name])) { + return $this->params[$name]; + } + + return $this->params; + } + + protected function getZipUtil() + { + return $this->zipUtil; + } + + protected function getFileManager() + { + if (!isset($this->fileManager)) { + $this->fileManager = $this->getContainer()->get('fileManager'); + } + return $this->fileManager; + } + + protected function getConfig() + { + if (!isset($this->config)) { + $this->config = $this->getContainer()->get('config'); + } + return $this->config; + } + + protected function getEntityManager() + { + if (!isset($this->entityManager)) { + $this->entityManager = $this->getContainer()->get('entityManager'); + } + return $this->entityManager; + } + + protected function throwErrorAndRemovePackage($errorMessage = '') + { + $this->deletePackageFiles(); + $this->deletePackageArchive(); + throw new Error($errorMessage); + } + + abstract public function run($data); + + protected function createProcessId() + { + if (isset($this->processId)) { + throw new Error('Another installation process is currently running.'); + } + + $this->processId = uniqid(); + + return $this->processId; + } + + protected function getProcessId() + { + if (!isset($this->processId)) { + throw new Error('Installation ID was not specified.'); + } + + return $this->processId; + } + + protected function setProcessId($processId) + { + $this->processId = $processId; + } + + /** + * Check if version of upgrade/extension is acceptable to current version of EspoCRM + * + * @param string $version + * @return boolean + */ + protected function isAcceptable() + { + $res = $this->checkPackageType(); + $res &= $this->checkVersions(); + + return (bool) $res; + } + + protected function checkVersions() + { + $manifest = $this->getManifest(); + + /** check acceptable versions */ + $version = $manifest['acceptableVersions']; + if (empty($version)) { + return true; + } + + $currentVersion = $this->getConfig()->get('version'); + + if (is_string($version)) { + $version = (array) $version; + } + + foreach ($version as $strVersion) { + + $strVersion = trim($strVersion); + + if ($strVersion == $currentVersion) { + return true; + } + + $strVersion = str_replace('\\', '', $strVersion); + $strVersion = preg_quote($strVersion); + $strVersion = str_replace('\\*', '+', $strVersion); + + if (preg_match('/^'.$strVersion.'/', $currentVersion)) { + return true; + } + } + + $this->throwErrorAndRemovePackage('Your EspoCRM version doesn\'t match for this installation package.'); + } + + protected function checkPackageType() + { + $manifest = $this->getManifest(); + + /** check package type */ + $type = strtolower( $this->getParams('name') ); + $manifestType = isset($manifest['type']) ? strtolower($manifest['type']) : $this->defaultPackageType; + + if (!in_array($manifestType, $this->packageTypes)) { + $this->throwErrorAndRemovePackage('Unknown package type.'); + } + + if ($type != $manifestType) { + $this->throwErrorAndRemovePackage('Wrong package type. You cannot install '.$manifestType.' package via '.ucfirst($type).' Manager.'); + } + + return true; + } + + /** + * Run scripts by type + * @param string $type Ex. "before", "after" + * @return void + */ + protected function runScript($type) + { + $packagePath = $this->getPackagePath(); + $scriptNames = $this->getParams('scriptNames'); + + $scriptName = $scriptNames[$type]; + if (!isset($scriptName)) { + return; + } + + $beforeInstallScript = Util::concatPath( array($packagePath, self::SCRIPTS, $scriptName) ) . '.php'; + + if (file_exists($beforeInstallScript)) { + require_once($beforeInstallScript); + $script = new $scriptName(); + + try { + $script->run($this->getContainer()); + } catch (\Exception $e) { + $this->throwErrorAndRemovePackage($e->getMessage()); + } + } + } + + /** + * Get package path + * + * @param string $processId + * @return string + */ + protected function getPath($name = 'packagePath', $isPackage = false) + { + $postfix = $isPackage ? $this->packagePostfix : ''; + + $processId = $this->getProcessId(); + $path = Util::concatPath($this->getParams($name), $processId); + + return $path . $postfix; + } + + protected function getPackagePath($isPackage = false) + { + return $this->getPath('packagePath', $isPackage); + } + + /** + * Get a list of files defined in manifest.json + * + * @return [type] [description] + */ + protected function getDeleteFileList() + { + $manifest = $this->getManifest(); + + if (!empty($manifest['delete'])) { + return $manifest['delete']; + } + + return array(); + } + + /** + * Delete files defined in a manifest + * + * @return boolen + */ + protected function deleteFiles($withEmptyDirs = false) + { + $deleteFileList = $this->getDeleteFileList(); + + //remove directories, leave only files + foreach ($deleteFileList as $key => $filePath) { + if (!is_file($filePath)) { + unset($deleteFileList[$key]); + } + } + + if (!empty($deleteFileList)) { + return $this->getFileManager()->remove($deleteFileList, null, $withEmptyDirs); + } + + return true; + } + + protected function getCopyFileList() + { + if (!isset($this->data['fileList'])) { + $packagePath = $this->getPackagePath(); + $filesPath = Util::concatPath($packagePath, self::FILES); + + $this->data['fileList'] = $this->getFileManager()->getFileList($filesPath, true, '', true, true); + } + + return $this->data['fileList']; + } + + protected function copy($sourcePath, $destPath, $recursively = false, array $fileList = null, $copyOnlyFiles = false) + { + try { + $res = $this->getFileManager()->copy($sourcePath, $destPath, $recursively, $fileList, $copyOnlyFiles); + } catch (\Exception $e) { + $this->throwErrorAndRemovePackage($e->getMessage()); + } + + return $res; + } + + /** + * Copy files from upgrade/extension package + * + * @param string $processId + * @return boolean + */ + protected function copyFiles() + { + $packagePath = $this->getPackagePath(); + $filesPath = Util::concatPath($packagePath, self::FILES); + + return $this->copy($filesPath, '', true); + } + + public function getManifest() + { + if (!isset($this->data['manifest'])) { + $packagePath = $this->getPackagePath(); + + $manifestPath = Util::concatPath($packagePath, $this->manifestName); + if (!file_exists($manifestPath)) { + $this->throwErrorAndRemovePackage('It\'s not an Installation package.'); + } + + $manifestJson = $this->getFileManager()->getContents($manifestPath); + $this->data['manifest'] = Json::decode($manifestJson, true); + + if (!$this->data['manifest']) { + $this->throwErrorAndRemovePackage('Syntax error in manifest.json.'); + } + + if (!$this->checkManifest($this->data['manifest'])) { + $this->throwErrorAndRemovePackage('Unsupported package.'); + } + } + + return $this->data['manifest']; + } + + /** + * Check if the manifest is correct + * + * @param array $manifest + * @return boolean + */ + protected function checkManifest(array $manifest) + { + $requiredFields = array( + 'name', + 'version', + ); + + foreach ($requiredFields as $fieldName) { + if (empty($manifest[$fieldName])) { + return false; + } + } + + return true; + } + + /** + * Unzip a package archieve + * + * @return void + */ + protected function unzipArchive($packagePath = null) + { + $packagePath = isset($packagePath) ? $packagePath : $this->getPackagePath(); + $packageArchivePath = $this->getPackagePath(true); + + if (!file_exists($packageArchivePath)) { + throw new Error('Package Archive doesn\'t exist.'); + } + + $res = $this->getZipUtil()->unzip($packageArchivePath, $packagePath); + if ($res === false) { + throw new Error('Unnable to unzip the file - '.$packagePath.'.'); + } + } + + /** + * Delete temporary package files + * + * @return boolean + */ + protected function deletePackageFiles() + { + $packagePath = $this->getPackagePath(); + $res = $this->getFileManager()->removeInDir($packagePath, true); + + return $res; + } + + /** + * Delete temporary package archive + * + * @return boolean + */ + protected function deletePackageArchive() + { + $packageArchive = $this->getPackagePath(true); + $res = $this->getFileManager()->removeFile($packageArchive); + + return $res; + } + + protected function systemRebuild() + { + return $this->getContainer()->get('dataManager')->rebuild(); + } + + /** + * Execute an action. For ex., execute uninstall action in install + * + * @param [type] $actionName [description] + * @param [type] $data [description] + * @return [type] [description] + */ + protected function executeAction($actionName, $data) + { + $currentAction = $this->getActionManager()->getAction(); + + $this->getActionManager()->setAction($actionName); + $this->getActionManager()->run($data); + + $this->getActionManager()->setAction($currentAction); + } + + protected function beforeRunAction() + { + + } + + protected function afterRunAction() + { + + } } diff --git a/application/Espo/Core/Upgrades/Actions/Base/Delete.php b/application/Espo/Core/Upgrades/Actions/Base/Delete.php index 210dceb73d..445f6b7209 100644 --- a/application/Espo/Core/Upgrades/Actions/Base/Delete.php +++ b/application/Espo/Core/Upgrades/Actions/Base/Delete.php @@ -24,32 +24,32 @@ namespace Espo\Core\Upgrades\Actions\Base; class Delete extends \Espo\Core\Upgrades\Actions\Base { - public function run($processId) - { - $GLOBALS['log']->debug('Delete package process ['.$processId.']: start run.'); + public function run($processId) + { + $GLOBALS['log']->debug('Delete package process ['.$processId.']: start run.'); - if (empty($processId)) { - throw new Error('Delete package package ID was not specified.'); - } + if (empty($processId)) { + throw new Error('Delete package package ID was not specified.'); + } - $this->setProcessId($processId); + $this->setProcessId($processId); - $this->beforeRunAction(); + $this->beforeRunAction(); - /* delete a package */ - $this->deletePackage(); + /* delete a package */ + $this->deletePackage(); - $this->afterRunAction(); + $this->afterRunAction(); - $GLOBALS['log']->debug('Delete package process ['.$processId.']: end run.'); - } + $GLOBALS['log']->debug('Delete package process ['.$processId.']: end run.'); + } - protected function deletePackage() - { - $packageArchivePath = $this->getPackagePath(true); - $res = $this->getFileManager()->removeFile($packageArchivePath); + protected function deletePackage() + { + $packageArchivePath = $this->getPackagePath(true); + $res = $this->getFileManager()->removeFile($packageArchivePath); - return $res; - } + return $res; + } } \ No newline at end of file diff --git a/application/Espo/Core/Upgrades/Actions/Base/Install.php b/application/Espo/Core/Upgrades/Actions/Base/Install.php index 4eb235165d..c1e0c83080 100644 --- a/application/Espo/Core/Upgrades/Actions/Base/Install.php +++ b/application/Espo/Core/Upgrades/Actions/Base/Install.php @@ -26,87 +26,87 @@ use Espo\Core\Exceptions\Error; class Install extends \Espo\Core\Upgrades\Actions\Base { - /** - * Is copied extension files to Espo - * - * @var [type] - */ - protected $isCopied = null; + /** + * Is copied extension files to Espo + * + * @var [type] + */ + protected $isCopied = null; - /** - * Main installation process - * - * @param string $processId Upgrade/Extension ID, gotten in upload stage - * @return bool - */ - public function run($processId) - { - $GLOBALS['log']->debug('Installation process ['.$processId.']: start run.'); + /** + * Main installation process + * + * @param string $processId Upgrade/Extension ID, gotten in upload stage + * @return bool + */ + public function run($processId) + { + $GLOBALS['log']->debug('Installation process ['.$processId.']: start run.'); - if (empty($processId)) { - throw new Error('Installation package ID was not specified.'); - } + if (empty($processId)) { + throw new Error('Installation package ID was not specified.'); + } - $this->setProcessId($processId); + $this->setProcessId($processId); - $this->isCopied = false; + $this->isCopied = false; - /** check if an archive is unzipped, if no then unzip */ - $packagePath = $this->getPackagePath(); - if (!file_exists($packagePath)) { - $this->unzipArchive(); - $this->isAcceptable(); - } + /** check if an archive is unzipped, if no then unzip */ + $packagePath = $this->getPackagePath(); + if (!file_exists($packagePath)) { + $this->unzipArchive(); + $this->isAcceptable(); + } - $this->beforeRunAction(); + $this->beforeRunAction(); - /* run before install script */ - $this->runScript('before'); + /* run before install script */ + $this->runScript('before'); - /* remove files defined in a manifest */ - if (!$this->deleteFiles()) { - $this->throwErrorAndRemovePackage('Permission denied to delete files.'); - } + /* remove files defined in a manifest */ + if (!$this->deleteFiles()) { + $this->throwErrorAndRemovePackage('Permission denied to delete files.'); + } - /* copy files from directory "Files" to EspoCRM files */ - if (!$this->copyFiles()) { - $this->throwErrorAndRemovePackage('Cannot copy files.'); - } - $this->isCopied = true; + /* copy files from directory "Files" to EspoCRM files */ + if (!$this->copyFiles()) { + $this->throwErrorAndRemovePackage('Cannot copy files.'); + } + $this->isCopied = true; - if (!$this->systemRebuild()) { - $this->throwErrorAndRemovePackage('Error occurred while EspoCRM rebuild.'); - } + if (!$this->systemRebuild()) { + $this->throwErrorAndRemovePackage('Error occurred while EspoCRM rebuild.'); + } - /* run before install script */ - $this->runScript('after'); + /* run before install script */ + $this->runScript('after'); - $this->afterRunAction(); + $this->afterRunAction(); - /* delete unziped files */ - $this->deletePackageFiles(); + /* delete unziped files */ + $this->deletePackageFiles(); - $GLOBALS['log']->debug('Installation process ['.$processId.']: end run.'); - } + $GLOBALS['log']->debug('Installation process ['.$processId.']: end run.'); + } - protected function restoreFiles() - { - $backupPath = $this->getPath('backupPath'); + protected function restoreFiles() + { + $backupPath = $this->getPath('backupPath'); - $res = true; - if ($this->isCopied) { - $res &= $this->copy(array($backupPath, self::FILES), '', true); - $GLOBALS['log']->info('Restore: copy back'); - } + $res = true; + if ($this->isCopied) { + $res &= $this->copy(array($backupPath, self::FILES), '', true); + $GLOBALS['log']->info('Restore: copy back'); + } - $res &= $this->getFileManager()->removeInDir($backupPath, true); + $res &= $this->getFileManager()->removeInDir($backupPath, true); - return $res; - } + return $res; + } - protected function throwErrorAndRemovePackage($errorMessage = '') - { - $this->restoreFiles(); - parent::throwErrorAndRemovePackage($errorMessage); - } + protected function throwErrorAndRemovePackage($errorMessage = '') + { + $this->restoreFiles(); + parent::throwErrorAndRemovePackage($errorMessage); + } } diff --git a/application/Espo/Core/Upgrades/Actions/Base/Uninstall.php b/application/Espo/Core/Upgrades/Actions/Base/Uninstall.php index 68528b50bd..d3e4960d20 100644 --- a/application/Espo/Core/Upgrades/Actions/Base/Uninstall.php +++ b/application/Espo/Core/Upgrades/Actions/Base/Uninstall.php @@ -23,110 +23,110 @@ namespace Espo\Core\Upgrades\Actions\Base; use Espo\Core\Exceptions\Error, - Espo\Core\Utils\Util; + Espo\Core\Utils\Util; class Uninstall extends \Espo\Core\Upgrades\Actions\Base { - public function run($processId) - { - $GLOBALS['log']->debug('Uninstallation process ['.$processId.']: start run.'); + public function run($processId) + { + $GLOBALS['log']->debug('Uninstallation process ['.$processId.']: start run.'); - if (empty($processId)) { - throw new Error('Uninstallation package ID was not specified.'); - } + if (empty($processId)) { + throw new Error('Uninstallation package ID was not specified.'); + } - $this->setProcessId($processId); + $this->setProcessId($processId); - $this->beforeRunAction(); + $this->beforeRunAction(); - /* run before install script */ - $this->runScript('beforeUninstall'); + /* run before install script */ + $this->runScript('beforeUninstall'); - $backupPath = $this->getPath('backupPath'); - if (file_exists($backupPath)) { + $backupPath = $this->getPath('backupPath'); + if (file_exists($backupPath)) { - /* remove extension files, saved in fileList */ - if (!$this->deleteFiles()) { - throw new Error('Permission denied to delete files.'); - } + /* remove extension files, saved in fileList */ + if (!$this->deleteFiles(true)) { + throw new Error('Permission denied to delete files.'); + } - /* copy core files */ - if (!$this->copyFiles()) { - throw new Error('Cannot copy files.'); - } - } + /* copy core files */ + if (!$this->copyFiles()) { + throw new Error('Cannot copy files.'); + } + } - if (!$this->systemRebuild()) { - throw new Error('Error occurred while EspoCRM rebuild.'); - } + if (!$this->systemRebuild()) { + throw new Error('Error occurred while EspoCRM rebuild.'); + } - /* run before install script */ - $this->runScript('afterUninstall'); + /* run before install script */ + $this->runScript('afterUninstall'); - $this->afterRunAction(); + $this->afterRunAction(); - /* delete backup files */ - $this->deletePackageFiles(); + /* delete backup files */ + $this->deletePackageFiles(); - $GLOBALS['log']->debug('Uninstallation process ['.$processId.']: end run.'); - } + $GLOBALS['log']->debug('Uninstallation process ['.$processId.']: end run.'); + } - protected function getDeleteFileList() - { - $extensionEntity = $this->getExtensionEntity(); - return $extensionEntity->get('fileList'); - } + protected function getDeleteFileList() + { + $extensionEntity = $this->getExtensionEntity(); + return $extensionEntity->get('fileList'); + } - protected function restoreFiles() - { - $packagePath = $this->getPath('packagePath'); - $filesPath = Util::concatPath($packagePath, self::FILES); + protected function restoreFiles() + { + $packagePath = $this->getPath('packagePath'); + $filesPath = Util::concatPath($packagePath, self::FILES); - if (!file_exists($filesPath)) { - $this->unzipArchive($packagePath); - } + if (!file_exists($filesPath)) { + $this->unzipArchive($packagePath); + } - $res = $this->copy($filesPath, '', true); - $res &= $this->getFileManager()->removeInDir($packagePath, true); + $res = $this->copy($filesPath, '', true); + $res &= $this->getFileManager()->removeInDir($packagePath, true); - return $res; - } + return $res; + } - protected function copyFiles() - { - $backupPath = $this->getPath('backupPath'); - $res = $this->copy(array($backupPath, self::FILES), '', true); + protected function copyFiles() + { + $backupPath = $this->getPath('backupPath'); + $res = $this->copy(array($backupPath, self::FILES), '', true); - return $res; - } + return $res; + } - /** - * Get backup path - * - * @param string $processId - * @return string - */ - protected function getPackagePath($isPackage = false) - { - if ($isPackage) { - return $this->getPath('packagePath', $isPackage); - } + /** + * Get backup path + * + * @param string $processId + * @return string + */ + protected function getPackagePath($isPackage = false) + { + if ($isPackage) { + return $this->getPath('packagePath', $isPackage); + } - return $this->getPath('backupPath'); - } + return $this->getPath('backupPath'); + } - protected function deletePackageFiles() - { - $backupPath = $this->getPath('backupPath'); - $res = $this->getFileManager()->removeInDir($backupPath, true); + protected function deletePackageFiles() + { + $backupPath = $this->getPath('backupPath'); + $res = $this->getFileManager()->removeInDir($backupPath, true); - return $res; - } + return $res; + } - protected function throwErrorAndRemovePackage($errorMessage = '') - { - $this->restoreFiles(); - throw new Error($errorMessage); - } + protected function throwErrorAndRemovePackage($errorMessage = '') + { + $this->restoreFiles(); + throw new Error($errorMessage); + } } diff --git a/application/Espo/Core/Upgrades/Actions/Base/Upload.php b/application/Espo/Core/Upgrades/Actions/Base/Upload.php index aff8d61a84..9a4d7bfd3a 100644 --- a/application/Espo/Core/Upgrades/Actions/Base/Upload.php +++ b/application/Espo/Core/Upgrades/Actions/Base/Upload.php @@ -26,37 +26,37 @@ use Espo\Core\Exceptions\Error; class Upload extends \Espo\Core\Upgrades\Actions\Base { - /** - * Upload an upgrade/extension package - * - * @param [type] $contents - * @return string ID of upgrade/extension process - */ - public function run($data) - { - $processId = $this->createProcessId(); + /** + * Upload an upgrade/extension package + * + * @param [type] $contents + * @return string ID of upgrade/extension process + */ + public function run($data) + { + $processId = $this->createProcessId(); - $GLOBALS['log']->debug('Installation process ['.$processId.']: start upload the package.'); + $GLOBALS['log']->debug('Installation process ['.$processId.']: start upload the package.'); - $packagePath = $this->getPackagePath(); - $packageArchivePath = $this->getPackagePath(true); + $packagePath = $this->getPackagePath(); + $packageArchivePath = $this->getPackagePath(true); - if (!empty($data)) { - list($prefix, $contents) = explode(',', $data); - $contents = base64_decode($contents); - } + if (!empty($data)) { + list($prefix, $contents) = explode(',', $data); + $contents = base64_decode($contents); + } - $res = $this->getFileManager()->putContents($packageArchivePath, $contents); - if ($res === false) { - throw new Error('Could not upload the package.'); - } + $res = $this->getFileManager()->putContents($packageArchivePath, $contents); + if ($res === false) { + throw new Error('Could not upload the package.'); + } - $this->unzipArchive(); + $this->unzipArchive(); - $this->isAcceptable(); + $this->isAcceptable(); - $GLOBALS['log']->debug('Installation process ['.$processId.']: end upload the package.'); + $GLOBALS['log']->debug('Installation process ['.$processId.']: end upload the package.'); - return $processId; - } + return $processId; + } } \ No newline at end of file diff --git a/application/Espo/Core/Upgrades/Actions/Extension/Delete.php b/application/Espo/Core/Upgrades/Actions/Extension/Delete.php index 4edc165261..cc8ad25a32 100644 --- a/application/Espo/Core/Upgrades/Actions/Extension/Delete.php +++ b/application/Espo/Core/Upgrades/Actions/Extension/Delete.php @@ -26,44 +26,44 @@ use Espo\Core\Exceptions\Error; class Delete extends \Espo\Core\Upgrades\Actions\Base\Delete { - protected $extensionEntity; + protected $extensionEntity; - /** - * Get entity of this extension - * - * @return \Espo\Entities\Extension - */ - protected function getExtensionEntity() - { - return $this->extensionEntity; - } + /** + * Get entity of this extension + * + * @return \Espo\Entities\Extension + */ + protected function getExtensionEntity() + { + return $this->extensionEntity; + } - /** - * Set Extension Entity - * - * @param \Espo\Entities\Extension $extensionEntity - */ - protected function setExtensionEntity(\Espo\Entities\Extension $extensionEntity) - { - $this->extensionEntity = $extensionEntity; - } + /** + * Set Extension Entity + * + * @param \Espo\Entities\Extension $extensionEntity + */ + protected function setExtensionEntity(\Espo\Entities\Extension $extensionEntity) + { + $this->extensionEntity = $extensionEntity; + } - protected function beforeRunAction() - { - $processId = $this->getProcessId(); + protected function beforeRunAction() + { + $processId = $this->getProcessId(); - /** get extension entity */ - $extensionEntity = $this->getEntityManager()->getEntity('Extension', $processId); - if (!isset($extensionEntity)) { - throw new Error('Extension Entity not found.'); - } - $this->setExtensionEntity($extensionEntity); - } + /** get extension entity */ + $extensionEntity = $this->getEntityManager()->getEntity('Extension', $processId); + if (!isset($extensionEntity)) { + throw new Error('Extension Entity not found.'); + } + $this->setExtensionEntity($extensionEntity); + } - protected function afterRunAction() - { - /** Delete extension entity */ - $extensionEntity = $this->getExtensionEntity(); - $this->getEntityManager()->removeEntity($extensionEntity); - } + protected function afterRunAction() + { + /** Delete extension entity */ + $extensionEntity = $this->getExtensionEntity(); + $this->getEntityManager()->removeEntity($extensionEntity); + } } \ No newline at end of file diff --git a/application/Espo/Core/Upgrades/Actions/Extension/Install.php b/application/Espo/Core/Upgrades/Actions/Extension/Install.php index b5425c41b3..0221a7b7f0 100644 --- a/application/Espo/Core/Upgrades/Actions/Extension/Install.php +++ b/application/Espo/Core/Upgrades/Actions/Extension/Install.php @@ -23,205 +23,205 @@ namespace Espo\Core\Upgrades\Actions\Extension; use Espo\Core\Exceptions\Error, - Espo\Core\ExtensionManager; + Espo\Core\ExtensionManager; class Install extends \Espo\Core\Upgrades\Actions\Base\Install { - protected $extensionEntity = null; + protected $extensionEntity = null; - protected function beforeRunAction() - { - $this->findExtension(); - if (!$this->isNew()) { - $this->compareVersion(); - $this->uninstallExtension(); - $this->deleteExtension(); - } + protected function beforeRunAction() + { + $this->findExtension(); + if (!$this->isNew()) { + $this->compareVersion(); + $this->uninstallExtension(); + $this->deleteExtension(); + } - $this->copyExistingFiles(); - } + $this->copyExistingFiles(); + } - protected function afterRunAction() - { - $this->storeExtension(); - } + protected function afterRunAction() + { + $this->storeExtension(); + } - /** - * Copy Existing files to backup directory - * - * @return bool - */ - protected function copyExistingFiles() - { - $fileList = $this->getCopyFileList(); - $backupPath = $this->getPath('backupPath'); + /** + * Copy Existing files to backup directory + * + * @return bool + */ + protected function copyExistingFiles() + { + $fileList = $this->getCopyFileList(); + $backupPath = $this->getPath('backupPath'); - $res = $this->copy('', array($backupPath, self::FILES), false, $fileList); + $res = $this->copy('', array($backupPath, self::FILES), false, $fileList); - /** copy scripts files */ - $packagePath = $this->getPackagePath(); - $res &= $this->copy(array($packagePath, self::SCRIPTS), array($backupPath, self::SCRIPTS), true); + /** copy scripts files */ + $packagePath = $this->getPackagePath(); + $res &= $this->copy(array($packagePath, self::SCRIPTS), array($backupPath, self::SCRIPTS), true); - return $res; - } + return $res; + } - protected function restoreFiles() - { - $res = true; - if ($this->isCopied) { - $extensionFileList = $this->getCopyFileList(); - $res &= $this->getFileManager()->remove($extensionFileList); - } + protected function restoreFiles() + { + $res = true; + if ($this->isCopied) { + $extensionFileList = $this->getCopyFileList(); + $res &= $this->getFileManager()->remove($extensionFileList); + } - $res &= parent::restoreFiles(); + $res &= parent::restoreFiles(); - return $res; - } + return $res; + } - protected function isNew() - { - $extensionEntity = $this->getExtensionEntity(); + protected function isNew() + { + $extensionEntity = $this->getExtensionEntity(); - if (isset($extensionEntity)) { - $id = $this->getExtensionEntity()->get('id'); - } + if (isset($extensionEntity)) { + $id = $this->getExtensionEntity()->get('id'); + } - return isset($id) ? false : true; - } + return isset($id) ? false : true; + } - /** - * Get extension ID. It's an ID of existing entity (if available) or Installation ID - * - * @return string - */ - protected function getExtensionId() - { - $extensionEntity = $this->getExtensionEntity(); - if (isset($extensionEntity)) { - $extensionEntityId = $extensionEntity->get('id'); - } + /** + * Get extension ID. It's an ID of existing entity (if available) or Installation ID + * + * @return string + */ + protected function getExtensionId() + { + $extensionEntity = $this->getExtensionEntity(); + if (isset($extensionEntity)) { + $extensionEntityId = $extensionEntity->get('id'); + } - if (!isset($extensionEntityId)) { - return $this->getProcessId(); - } + if (!isset($extensionEntityId)) { + return $this->getProcessId(); + } - return $extensionEntityId; - } + return $extensionEntityId; + } - /** - * Get entity of this extension - * - * @return \Espo\Entities\Extension - */ - protected function getExtensionEntity() - { - return $this->extensionEntity; - } + /** + * Get entity of this extension + * + * @return \Espo\Entities\Extension + */ + protected function getExtensionEntity() + { + return $this->extensionEntity; + } - /** - * Find Extension entity - * - * @return \Espo\Entities\Extension - */ - protected function findExtension() - { - $manifest = $this->getManifest(); + /** + * Find Extension entity + * + * @return \Espo\Entities\Extension + */ + protected function findExtension() + { + $manifest = $this->getManifest(); - $this->extensionEntity = $this->getEntityManager()->getRepository('Extension')->where(array( - 'name' => $manifest['name'], - 'isInstalled' => true, - ))->findOne(); + $this->extensionEntity = $this->getEntityManager()->getRepository('Extension')->where(array( + 'name' => $manifest['name'], + 'isInstalled' => true, + ))->findOne(); - return $this->extensionEntity; - } + return $this->extensionEntity; + } - /** - * Create a record of Extension Entity - * - * @return bool - */ - protected function storeExtension() - { - $entityManager = $this->getEntityManager(); + /** + * Create a record of Extension Entity + * + * @return bool + */ + protected function storeExtension() + { + $entityManager = $this->getEntityManager(); - $extensionEntity = $entityManager->getEntity('Extension', $this->getProcessId()); - if (!isset($extensionEntity)) { - $extensionEntity = $entityManager->getEntity('Extension'); - } + $extensionEntity = $entityManager->getEntity('Extension', $this->getProcessId()); + if (!isset($extensionEntity)) { + $extensionEntity = $entityManager->getEntity('Extension'); + } - $manifest = $this->getManifest(); - $fileList = $this->getCopyFileList(); + $manifest = $this->getManifest(); + $fileList = $this->getCopyFileList(); - $data = array( - 'id' => $this->getProcessId(), - 'name' => $manifest['name'], - 'isInstalled' => true, - 'version' => $manifest['version'], - 'fileList' => $fileList, - 'description' => $manifest['description'], - ); - $extensionEntity->set($data); + $data = array( + 'id' => $this->getProcessId(), + 'name' => $manifest['name'], + 'isInstalled' => true, + 'version' => $manifest['version'], + 'fileList' => $fileList, + 'description' => $manifest['description'], + ); + $extensionEntity->set($data); - return $entityManager->saveEntity($extensionEntity); - } + return $entityManager->saveEntity($extensionEntity); + } - /** - * Compare version between installed and a new extensions - * - * @return void - */ - protected function compareVersion() - { - $manifest = $this->getManifest(); - $extensionEntity = $this->getExtensionEntity(); + /** + * Compare version between installed and a new extensions + * + * @return void + */ + protected function compareVersion() + { + $manifest = $this->getManifest(); + $extensionEntity = $this->getExtensionEntity(); - if (isset($extensionEntity)) { - $comparedVersion = version_compare($manifest['version'], $extensionEntity->get('version')); - if ($comparedVersion <= 0) { - $this->throwErrorAndRemovePackage('You cannot install an older version of this extension.'); - } - } - } + if (isset($extensionEntity)) { + $comparedVersion = version_compare($manifest['version'], $extensionEntity->get('version')); + if ($comparedVersion <= 0) { + $this->throwErrorAndRemovePackage('You cannot install an older version of this extension.'); + } + } + } - /** - * Throw an exception and remove package files. - * Redeclared to prevent of deleting a package of installed extension. - * - * @param string $errorMessage [description] - * @return [type] [description] - */ - protected function throwErrorAndRemovePackage($errorMessage = '') - { - if (!$this->isNew()) { - throw new Error($errorMessage); - } + /** + * Throw an exception and remove package files. + * Redeclared to prevent of deleting a package of installed extension. + * + * @param string $errorMessage [description] + * @return [type] [description] + */ + protected function throwErrorAndRemovePackage($errorMessage = '') + { + if (!$this->isNew()) { + throw new Error($errorMessage); + } - return parent::throwErrorAndRemovePackage($errorMessage); - } + return parent::throwErrorAndRemovePackage($errorMessage); + } - /** - * If extension already installed, uninstall an old version - * - * @return void - */ - protected function uninstallExtension() - { - $extensionEntity = $this->getExtensionEntity(); + /** + * If extension already installed, uninstall an old version + * + * @return void + */ + protected function uninstallExtension() + { + $extensionEntity = $this->getExtensionEntity(); - $this->executeAction(ExtensionManager::UNINSTALL, $extensionEntity->get('id')); - } + $this->executeAction(ExtensionManager::UNINSTALL, $extensionEntity->get('id')); + } - /** - * Delete extension package - * - * @return void - */ - protected function deleteExtension() - { - $extensionEntity = $this->getExtensionEntity(); + /** + * Delete extension package + * + * @return void + */ + protected function deleteExtension() + { + $extensionEntity = $this->getExtensionEntity(); - $this->executeAction(ExtensionManager::DELETE, $extensionEntity->get('id')); - } + $this->executeAction(ExtensionManager::DELETE, $extensionEntity->get('id')); + } diff --git a/application/Espo/Core/Upgrades/Actions/Extension/Uninstall.php b/application/Espo/Core/Upgrades/Actions/Extension/Uninstall.php index a405e6beea..bc8a4ded94 100644 --- a/application/Espo/Core/Upgrades/Actions/Extension/Uninstall.php +++ b/application/Espo/Core/Upgrades/Actions/Extension/Uninstall.php @@ -26,46 +26,46 @@ use Espo\Core\Exceptions\Error; class Uninstall extends \Espo\Core\Upgrades\Actions\Base\Uninstall { - protected $extensionEntity; + protected $extensionEntity; - /** - * Get entity of this extension - * - * @return \Espo\Entities\Extension - */ - protected function getExtensionEntity() - { - return $this->extensionEntity; - } + /** + * Get entity of this extension + * + * @return \Espo\Entities\Extension + */ + protected function getExtensionEntity() + { + return $this->extensionEntity; + } - /** - * Set Extension Entity - * - * @param \Espo\Entities\Extension $extensionEntity [description] - */ - protected function setExtensionEntity(\Espo\Entities\Extension $extensionEntity) - { - $this->extensionEntity = $extensionEntity; - } + /** + * Set Extension Entity + * + * @param \Espo\Entities\Extension $extensionEntity [description] + */ + protected function setExtensionEntity(\Espo\Entities\Extension $extensionEntity) + { + $this->extensionEntity = $extensionEntity; + } - protected function beforeRunAction() - { - $processId = $this->getProcessId(); + protected function beforeRunAction() + { + $processId = $this->getProcessId(); - /** get extension entity */ - $extensionEntity = $this->getEntityManager()->getEntity('Extension', $processId); - if (!isset($extensionEntity)) { - throw new Error('Extension Entity not found.'); - } - $this->setExtensionEntity($extensionEntity); - } + /** get extension entity */ + $extensionEntity = $this->getEntityManager()->getEntity('Extension', $processId); + if (!isset($extensionEntity)) { + throw new Error('Extension Entity not found.'); + } + $this->setExtensionEntity($extensionEntity); + } - protected function afterRunAction() - { - /** Set extension entity, isInstalled = false */ - $extensionEntity = $this->getExtensionEntity(); + protected function afterRunAction() + { + /** Set extension entity, isInstalled = false */ + $extensionEntity = $this->getExtensionEntity(); - $extensionEntity->set('isInstalled', false); - $this->getEntityManager()->saveEntity($extensionEntity); - } + $extensionEntity->set('isInstalled', false); + $this->getEntityManager()->saveEntity($extensionEntity); + } } \ No newline at end of file diff --git a/application/Espo/Core/Upgrades/Actions/Upgrade/Install.php b/application/Espo/Core/Upgrades/Actions/Upgrade/Install.php index bff4a69052..ec3b787293 100644 --- a/application/Espo/Core/Upgrades/Actions/Upgrade/Install.php +++ b/application/Espo/Core/Upgrades/Actions/Upgrade/Install.php @@ -24,29 +24,29 @@ namespace Espo\Core\Upgrades\Actions\Upgrade; class Install extends \Espo\Core\Upgrades\Actions\Base\Install { - protected function systemRebuild() - { - $manifest = $this->getManifest(); + protected function systemRebuild() + { + $manifest = $this->getManifest(); - $res = $this->getConfig()->set('version', $manifest['version']); - if (method_exists($this->getConfig(), 'save')) { - $res = $this->getConfig()->save(); - } - $res &= parent::systemRebuild(); + $res = $this->getConfig()->set('version', $manifest['version']); + if (method_exists($this->getConfig(), 'save')) { + $res = $this->getConfig()->save(); + } + $res &= parent::systemRebuild(); - return $res; - } + return $res; + } - /** - * Delete temporary package files - * - * @return boolean - */ - protected function deletePackageFiles() - { - $res = parent::deletePackageFiles(); - $res &= $this->deletePackageArchive(); + /** + * Delete temporary package files + * + * @return boolean + */ + protected function deletePackageFiles() + { + $res = parent::deletePackageFiles(); + $res &= $this->deletePackageArchive(); - return $res; - } + return $res; + } } diff --git a/application/Espo/Core/Upgrades/Base.php b/application/Espo/Core/Upgrades/Base.php index 66129556a3..ff351f4485 100644 --- a/application/Espo/Core/Upgrades/Base.php +++ b/application/Espo/Core/Upgrades/Base.php @@ -23,72 +23,72 @@ namespace Espo\Core\Upgrades; use Espo\Core\Utils\Util, - Espo\Core\Utils\Json, - Espo\Core\Exceptions\Error; + Espo\Core\Utils\Json, + Espo\Core\Exceptions\Error; abstract class Base { - private $container; + private $container; - protected $name = null; + protected $name = null; - protected $params = array(); + protected $params = array(); - const UPLOAD = 'upload'; + const UPLOAD = 'upload'; - const INSTALL = 'install'; + const INSTALL = 'install'; - const UNINSTALL = 'uninstall'; + const UNINSTALL = 'uninstall'; - const DELETE = 'delete'; + const DELETE = 'delete'; - public function __construct($container) - { - $this->container = $container; + public function __construct($container) + { + $this->container = $container; - $this->actionManager = new ActionManager($this->name, $container, $this->params); - } + $this->actionManager = new ActionManager($this->name, $container, $this->params); + } - protected function getContainer() - { - return $this->container; - } + protected function getContainer() + { + return $this->container; + } - protected function getActionManager() - { - return $this->actionManager; - } + protected function getActionManager() + { + return $this->actionManager; + } - public function getManifest() - { - return $this->getActionManager()->getManifest(); - } + public function getManifest() + { + return $this->getActionManager()->getManifest(); + } - public function upload($data) - { - $this->getActionManager()->setAction(self::UPLOAD); + public function upload($data) + { + $this->getActionManager()->setAction(self::UPLOAD); - return $this->getActionManager()->run($data); - } + return $this->getActionManager()->run($data); + } - public function install($processId) - { - $this->getActionManager()->setAction(self::INSTALL); + public function install($processId) + { + $this->getActionManager()->setAction(self::INSTALL); - return $this->getActionManager()->run($processId); - } + return $this->getActionManager()->run($processId); + } - public function uninstall($processId) - { - $this->getActionManager()->setAction(self::UNINSTALL); + public function uninstall($processId) + { + $this->getActionManager()->setAction(self::UNINSTALL); - return $this->getActionManager()->run($processId); - } + return $this->getActionManager()->run($processId); + } - public function delete($processId) - { - $this->getActionManager()->setAction(self::DELETE); + public function delete($processId) + { + $this->getActionManager()->setAction(self::DELETE); - return $this->getActionManager()->run($processId); - } + return $this->getActionManager()->run($processId); + } } diff --git a/application/Espo/Core/Utils/Api/Auth.php b/application/Espo/Core/Utils/Api/Auth.php index 5394fa16f1..d9ec0b96e7 100644 --- a/application/Espo/Core/Utils/Api/Auth.php +++ b/application/Espo/Core/Utils/Api/Auth.php @@ -26,108 +26,108 @@ use \Espo\Core\Utils\Api\Slim; class Auth extends \Slim\Middleware { - protected $auth; + protected $auth; - protected $authRequired = null; + protected $authRequired = null; - protected $showDialog = false; + protected $showDialog = false; - public function __construct(\Espo\Core\Utils\Auth $auth, $authRequired = null, $showDialog = false) - { - $this->auth = $auth; - $this->authRequired = $authRequired; - $this->showDialog = $showDialog; - } + public function __construct(\Espo\Core\Utils\Auth $auth, $authRequired = null, $showDialog = false) + { + $this->auth = $auth; + $this->authRequired = $authRequired; + $this->showDialog = $showDialog; + } - function call() - { - $req = $this->app->request(); + function call() + { + $req = $this->app->request(); - $uri = $req->getResourceUri(); - $httpMethod = $req->getMethod(); + $uri = $req->getResourceUri(); + $httpMethod = $req->getMethod(); - $authUsername = $req->headers('PHP_AUTH_USER'); - $authPassword = $req->headers('PHP_AUTH_PW'); + $authUsername = $req->headers('PHP_AUTH_USER'); + $authPassword = $req->headers('PHP_AUTH_PW'); - $espoAuth = $req->headers('HTTP_ESPO_AUTHORIZATION'); - if (isset($espoAuth)) { - list($authUsername, $authPassword) = explode(':', base64_decode($espoAuth)); - } + $espoAuth = $req->headers('HTTP_ESPO_AUTHORIZATION'); + if (isset($espoAuth)) { + list($authUsername, $authPassword) = explode(':', base64_decode($espoAuth)); + } - $espoCgiAuth = $req->headers('HTTP_ESPO_CGI_AUTH'); - if ( !isset($authUsername) && !isset($authPassword) && isset($espoCgiAuth) ) { - list($authUsername, $authPassword) = explode(':' , base64_decode(substr($espoCgiAuth, 6))); - } + $espoCgiAuth = $req->headers('HTTP_ESPO_CGI_AUTH'); + if ( !isset($authUsername) && !isset($authPassword) && isset($espoCgiAuth) ) { + list($authUsername, $authPassword) = explode(':' , base64_decode(substr($espoCgiAuth, 6))); + } - if (is_null($this->authRequired)) { - $routes = $this->app->router()->getMatchedRoutes($httpMethod, $uri); + if (is_null($this->authRequired)) { + $routes = $this->app->router()->getMatchedRoutes($httpMethod, $uri); - if (!empty($routes[0])) { - $routeConditions = $routes[0]->getConditions(); - if (isset($routeConditions['auth']) && $routeConditions['auth'] === false) { + if (!empty($routes[0])) { + $routeConditions = $routes[0]->getConditions(); + if (isset($routeConditions['auth']) && $routeConditions['auth'] === false) { - if ($authUsername && $authPassword) { - $isAuthenticated = $this->auth->login($authUsername, $authPassword); - if ($isAuthenticated) { - $this->next->call(); - return; - } - } + if ($authUsername && $authPassword) { + $isAuthenticated = $this->auth->login($authUsername, $authPassword); + if ($isAuthenticated) { + $this->next->call(); + return; + } + } - $this->auth->useNoAuth(); - $this->next->call(); - return; - } - } - } else { - if (!$this->authRequired) { - $this->auth->useNoAuth(); - $this->next->call(); - return; - } - } + $this->auth->useNoAuth(); + $this->next->call(); + return; + } + } + } else { + if (!$this->authRequired) { + $this->auth->useNoAuth(); + $this->next->call(); + return; + } + } - if ($authUsername && $authPassword) { + if ($authUsername && $authPassword) { - $isAuthenticated = $this->auth->login($authUsername, $authPassword); + $isAuthenticated = $this->auth->login($authUsername, $authPassword); - if ($isAuthenticated) { - $this->next->call(); - } else { - $this->processUnauthorized(); - } - } else { - if (!$this->isXMLHttpRequest()) { - $this->showDialog = true; - } - $this->processUnauthorized(); - } - } + if ($isAuthenticated) { + $this->next->call(); + } else { + $this->processUnauthorized(); + } + } else { + if (!$this->isXMLHttpRequest()) { + $this->showDialog = true; + } + $this->processUnauthorized(); + } + } - protected function processUnauthorized() - { - $res = $this->app->response(); + protected function processUnauthorized() + { + $res = $this->app->response(); - if ($this->showDialog) { - $res->header('WWW-Authenticate', 'Basic realm=""'); - } else { - $res->header('WWW-Authenticate'); - } - $res->status(401); - } + if ($this->showDialog) { + $res->header('WWW-Authenticate', 'Basic realm=""'); + } else { + $res->header('WWW-Authenticate'); + } + $res->status(401); + } - protected function isXMLHttpRequest() - { - $req = $this->app->request(); + protected function isXMLHttpRequest() + { + $req = $this->app->request(); - $httpXRequestedWith = $req->headers('HTTP_X_REQUESTED_WITH'); + $httpXRequestedWith = $req->headers('HTTP_X_REQUESTED_WITH'); - if (isset($httpXRequestedWith) && strtolower($httpXRequestedWith) == 'xmlhttprequest') { - return true; - } + if (isset($httpXRequestedWith) && strtolower($httpXRequestedWith) == 'xmlhttprequest') { + return true; + } - return false; - } + return false; + } } diff --git a/application/Espo/Core/Utils/Api/Output.php b/application/Espo/Core/Utils/Api/Output.php index 8955f25f62..e1791ec1c2 100644 --- a/application/Espo/Core/Utils/Api/Output.php +++ b/application/Espo/Core/Utils/Api/Output.php @@ -24,94 +24,94 @@ namespace Espo\Core\Utils\Api; class Output { - private $slim; + private $slim; - protected $errorDesc = array( - 400 => 'Bad Request', - 401 => 'Unauthorized', - 403 => 'Forbidden', - 404 => 'Page Not Found', - 409 => 'Conflict', - 500 => 'Internal Server Error', - ); + protected $errorDesc = array( + 400 => 'Bad Request', + 401 => 'Unauthorized', + 403 => 'Forbidden', + 404 => 'Page Not Found', + 409 => 'Conflict', + 500 => 'Internal Server Error', + ); - public function __construct(\Espo\Core\Utils\Api\Slim $slim) - { - $this->slim = $slim; - } + public function __construct(\Espo\Core\Utils\Api\Slim $slim) + { + $this->slim = $slim; + } - protected function getSlim() - { - return $this->slim; - } + protected function getSlim() + { + return $this->slim; + } - /** - * Output the result - * - * @param mixed $data - JSON - */ - public function render($data = null) - { - if (is_array($data)) { - $dataArr = array_values($data); - $data = empty($dataArr[0]) ? false : $dataArr[0]; - } + /** + * Output the result + * + * @param mixed $data - JSON + */ + public function render($data = null) + { + if (is_array($data)) { + $dataArr = array_values($data); + $data = empty($dataArr[0]) ? false : $dataArr[0]; + } - ob_clean(); - echo $data; - } + ob_clean(); + echo $data; + } - public function processError($message = 'Error', $code = 500, $isPrint = false) - { - $GLOBALS['log']->error('API ['.$this->getSlim()->request()->getMethod().']:'.$this->getSlim()->router()->getCurrentRoute()->getPattern().', Params:'.print_r($this->getSlim()->router()->getCurrentRoute()->getParams(), true).', InputData: '.$this->getSlim()->request()->getBody().' - '.$message); - $this->displayError($message, $code, $isPrint); - } + public function processError($message = 'Error', $code = 500, $isPrint = false) + { + $GLOBALS['log']->error('API ['.$this->getSlim()->request()->getMethod().']:'.$this->getSlim()->router()->getCurrentRoute()->getPattern().', Params:'.print_r($this->getSlim()->router()->getCurrentRoute()->getParams(), true).', InputData: '.$this->getSlim()->request()->getBody().' - '.$message); + $this->displayError($message, $code, $isPrint); + } - /** - * Output the error and stop app execution - * - * @param string $text - * @param int $statusCode - * - * @return void - */ - public function displayError($text, $statusCode = 500, $isPrint = false) - { - $GLOBALS['log']->error('Display Error: '.$text.', Code: '.$statusCode.' URL: '.$_SERVER['REQUEST_URI']); + /** + * Output the error and stop app execution + * + * @param string $text + * @param int $statusCode + * + * @return void + */ + public function displayError($text, $statusCode = 500, $isPrint = false) + { + $GLOBALS['log']->error('Display Error: '.$text.', Code: '.$statusCode.' URL: '.$_SERVER['REQUEST_URI']); - if (!empty( $this->slim)) { - $this->getSlim()->response()->status($statusCode); - $this->getSlim()->response()->header('X-Status-Reason', $text); + if (!empty( $this->slim)) { + $this->getSlim()->response()->status($statusCode); + $this->getSlim()->response()->header('X-Status-Reason', $text); - if ($isPrint) { - $status = $this->getCodeDesc($statusCode); - $status = isset($status) ? $statusCode.' '.$status : 'HTTP '.$statusCode; - $this->getSlim()->printError($text, $status); - } + if ($isPrint) { + $status = $this->getCodeDesc($statusCode); + $status = isset($status) ? $statusCode.' '.$status : 'HTTP '.$statusCode; + $this->getSlim()->printError($text, $status); + } - $this->getSlim()->stop(); - } - else { - $GLOBALS['log']->info('Could not get Slim instance. It looks like a direct call (bypass API). URL: '.$_SERVER['REQUEST_URI']); - die($text); - } - } + $this->getSlim()->stop(); + } + else { + $GLOBALS['log']->info('Could not get Slim instance. It looks like a direct call (bypass API). URL: '.$_SERVER['REQUEST_URI']); + die($text); + } + } - /** - * Get status code desription - * - * @param int $statusCode - * @return string | null - */ - protected function getCodeDesc($statusCode) - { - if (isset($this->errorDesc[$statusCode])) { - return $this->errorDesc[$statusCode]; - } + /** + * Get status code desription + * + * @param int $statusCode + * @return string | null + */ + protected function getCodeDesc($statusCode) + { + if (isset($this->errorDesc[$statusCode])) { + return $this->errorDesc[$statusCode]; + } - return null; - } + return null; + } diff --git a/application/Espo/Core/Utils/Api/Slim.php b/application/Espo/Core/Utils/Api/Slim.php index b91d4acda8..e03e55fb6f 100644 --- a/application/Espo/Core/Utils/Api/Slim.php +++ b/application/Espo/Core/Utils/Api/Slim.php @@ -26,60 +26,60 @@ namespace Espo\Core\Utils\Api; class Slim extends \Slim\Slim { - /** - * Redefine the run method - * - * We no need to use a Slim handler - */ - public function run() - { - //set_error_handler(array('\Slim\Slim', 'handleErrors')); //Espo: no needs to use this handler + /** + * Redefine the run method + * + * We no need to use a Slim handler + */ + public function run() + { + //set_error_handler(array('\Slim\Slim', 'handleErrors')); //Espo: no needs to use this handler - //Apply final outer middleware layers - if ($this->config('debug')) { - //Apply pretty exceptions only in debug to avoid accidental information leakage in production - //$this->add(new \Slim\Middleware\PrettyExceptions()); //Espo: no needs to use this handler - } + //Apply final outer middleware layers + if ($this->config('debug')) { + //Apply pretty exceptions only in debug to avoid accidental information leakage in production + //$this->add(new \Slim\Middleware\PrettyExceptions()); //Espo: no needs to use this handler + } - //Invoke middleware and application stack - $this->middleware[0]->call(); + //Invoke middleware and application stack + $this->middleware[0]->call(); - //Fetch status, header, and body - list($status, $headers, $body) = $this->response->finalize(); + //Fetch status, header, and body + list($status, $headers, $body) = $this->response->finalize(); - // Serialize cookies (with optional encryption) - \Slim\Http\Util::serializeCookies($headers, $this->response->cookies, $this->settings); + // Serialize cookies (with optional encryption) + \Slim\Http\Util::serializeCookies($headers, $this->response->cookies, $this->settings); - //Send headers - if (headers_sent() === false) { - //Send status - if (strpos(PHP_SAPI, 'cgi') === 0) { - header(sprintf('Status: %s', \Slim\Http\Response::getMessageForCode($status))); - } else { - header(sprintf('HTTP/%s %s', $this->config('http.version'), \Slim\Http\Response::getMessageForCode($status))); - } + //Send headers + if (headers_sent() === false) { + //Send status + if (strpos(PHP_SAPI, 'cgi') === 0) { + header(sprintf('Status: %s', \Slim\Http\Response::getMessageForCode($status))); + } else { + header(sprintf('HTTP/%s %s', $this->config('http.version'), \Slim\Http\Response::getMessageForCode($status))); + } - //Send headers - foreach ($headers as $name => $value) { - $hValues = explode("\n", $value); - foreach ($hValues as $hVal) { - header("$name: $hVal", false); - } - } - } + //Send headers + foreach ($headers as $name => $value) { + $hValues = explode("\n", $value); + foreach ($hValues as $hVal) { + header("$name: $hVal", false); + } + } + } - //Send body, but only if it isn't a HEAD request - if (!$this->request->isHead()) { - echo $body; - } + //Send body, but only if it isn't a HEAD request + if (!$this->request->isHead()) { + echo $body; + } - //restore_error_handler(); //Espo: no needs to use this handler - } + //restore_error_handler(); //Espo: no needs to use this handler + } - public function printError($error, $status) - { - echo static::generateTemplateMarkup($status, '

'.$error.'

Visit the Home Page'); - } + public function printError($error, $status) + { + echo static::generateTemplateMarkup($status, '

'.$error.'

Visit the Home Page'); + } } \ No newline at end of file diff --git a/application/Espo/Core/Utils/Auth.php b/application/Espo/Core/Utils/Auth.php index f8d56b0530..b35bafb358 100644 --- a/application/Espo/Core/Utils/Auth.php +++ b/application/Espo/Core/Utils/Auth.php @@ -26,88 +26,88 @@ use \Espo\Core\Exceptions\Error; class Auth { - protected $container; + protected $container; - protected $authentication; + protected $authentication; - protected $config; + protected $config; - protected $entityManager; + protected $entityManager; - public function __construct(\Espo\Core\Container $container) - { - $this->container = $container; + public function __construct(\Espo\Core\Container $container) + { + $this->container = $container; - $this->entityManager = $this->container->get('entityManager'); - $this->config = $this->container->get('config'); + $this->entityManager = $this->container->get('entityManager'); + $this->config = $this->container->get('config'); - $authenticationMethod = $this->config->get('authenticationMethod', 'Espo'); - $authenticationClassName = "\\Espo\\Core\\Utils\\Authentication\\" . $authenticationMethod; - $this->authentication = new $authenticationClassName($this->config, $this->entityManager, $this); - } + $authenticationMethod = $this->config->get('authenticationMethod', 'Espo'); + $authenticationClassName = "\\Espo\\Core\\Utils\\Authentication\\" . $authenticationMethod; + $this->authentication = new $authenticationClassName($this->config, $this->entityManager, $this); + } - public function useNoAuth($isAdmin = false) - { - $entityManager = $this->container->get('entityManager'); + public function useNoAuth($isAdmin = false) + { + $entityManager = $this->container->get('entityManager'); - $user = $entityManager->getRepository('User')->get('system'); - if (!$user) { - throw new Error('System user is not found'); - } + $user = $entityManager->getRepository('User')->get('system'); + if (!$user) { + throw new Error('System user is not found'); + } - $user->set('isAdmin', $isAdmin); + $user->set('isAdmin', $isAdmin); - $entityManager->setUser($user); - $this->container->setUser($user); - } + $entityManager->setUser($user); + $this->container->setUser($user); + } - public function login($username, $password) - { - $GLOBALS['log']->debug('AUTH: Try to authenticate'); + public function login($username, $password) + { + $GLOBALS['log']->debug('AUTH: Try to authenticate'); - $entityManager = $this->entityManager; + $entityManager = $this->entityManager; - $authToken = $entityManager->getRepository('AuthToken')->where(array('token' => $password))->findOne(); + $authToken = $entityManager->getRepository('AuthToken')->where(array('token' => $password))->findOne(); - $user = $this->authentication->login($username, $password, $authToken); + $user = $this->authentication->login($username, $password, $authToken); - if ($user) { - $entityManager->setUser($user); - $this->container->setUser($user); - $GLOBALS['log']->debug('AUTH: Result of authenticate is [true]'); + if ($user) { + $entityManager->setUser($user); + $this->container->setUser($user); + $GLOBALS['log']->debug('AUTH: Result of authenticate is [true]'); - if (!$authToken) { - $authToken = $entityManager->getEntity('AuthToken'); - $token = $this->createToken($user); - $authToken->set('token', $token); - $authToken->set('hash', $user->get('password')); - $authToken->set('ipAddress', $_SERVER['REMOTE_ADDR']); - $authToken->set('userId', $user->id); - } + if (!$authToken) { + $authToken = $entityManager->getEntity('AuthToken'); + $token = $this->createToken($user); + $authToken->set('token', $token); + $authToken->set('hash', $user->get('password')); + $authToken->set('ipAddress', $_SERVER['REMOTE_ADDR']); + $authToken->set('userId', $user->id); + } - $authToken->set('lastAccess', date('Y-m-d H:i:s')); + $authToken->set('lastAccess', date('Y-m-d H:i:s')); - $entityManager->saveEntity($authToken); - $user->set('token', $authToken->get('token')); + $entityManager->saveEntity($authToken); + $user->set('token', $authToken->get('token')); - return true; - } - } + return true; + } + } - protected function createToken($user) - { - return md5(uniqid($user->get('id'))); - } + protected function createToken($user) + { + return md5(uniqid($user->get('id'))); + } - public function destroyAuthToken($token) - { - $entityManager = $this->container->get('entityManager'); + public function destroyAuthToken($token) + { + $entityManager = $this->container->get('entityManager'); - $authToken = $entityManager->getRepository('AuthToken')->where(array('token' => $token))->findOne(); - if ($authToken) { - $entityManager->removeEntity($authToken); - return true; - } - } + $authToken = $entityManager->getRepository('AuthToken')->where(array('token' => $token))->findOne(); + if ($authToken) { + $entityManager->removeEntity($authToken); + return true; + } + } } diff --git a/application/Espo/Core/Utils/Authentication/Base.php b/application/Espo/Core/Utils/Authentication/Base.php index 17905e09f7..e196cd2156 100644 --- a/application/Espo/Core/Utils/Authentication/Base.php +++ b/application/Espo/Core/Utils/Authentication/Base.php @@ -28,33 +28,44 @@ use \Espo\Core\Utils\Auth; abstract class Base { - private $config; + private $config; - private $entityManager; + private $entityManager; - private $auth; + private $auth; - public function __construct(Config $config, EntityManager $entityManager, Auth $auth) - { - $this->config = $config; - $this->entityManager = $entityManager; - $this->auth = $auth; - } + private $passwordHash; - protected function getConfig() - { - return $this->config; - } + public function __construct(Config $config, EntityManager $entityManager, Auth $auth) + { + $this->config = $config; + $this->entityManager = $entityManager; + $this->auth = $auth; + } - protected function getEntityManager() - { - return $this->entityManager; - } + protected function getConfig() + { + return $this->config; + } - protected function getAuth() - { - return $this->auth; - } + protected function getEntityManager() + { + return $this->entityManager; + } + + protected function getAuth() + { + return $this->auth; + } + + protected function getPasswordHash() + { + if (!isset($this->passwordHash)) { + $this->passwordHash = new \Espo\Core\Utils\PasswordHash($this->config); + } + + return $this->passwordHash; + } } diff --git a/application/Espo/Core/Utils/Authentication/Espo.php b/application/Espo/Core/Utils/Authentication/Espo.php index 1adebac4dc..ba220e1d35 100644 --- a/application/Espo/Core/Utils/Authentication/Espo.php +++ b/application/Espo/Core/Utils/Authentication/Espo.php @@ -18,31 +18,30 @@ * * 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\Authentication; use \Espo\Core\Exceptions\Error; class Espo extends Base -{ - - public function login($username, $password, \Espo\Entities\AuthToken $authToken = null) - { - if ($authToken) { - $hash = $authToken->get('hash'); - } else { - $hash = md5($password); - } - - $user = $this->getEntityManager()->getRepository('User')->findOne(array( - 'whereClause' => array( - 'userName' => $username, - 'password' => $hash - ), - )); - - return $user; - } +{ + public function login($username, $password, \Espo\Entities\AuthToken $authToken = null) + { + if ($authToken) { + $hash = $authToken->get('hash'); + } else { + $hash = $this->getPasswordHash()->hash($password); + } + + $user = $this->getEntityManager()->getRepository('User')->findOne(array( + 'whereClause' => array( + 'userName' => $username, + 'password' => $hash + ), + )); + + return $user; + } } diff --git a/application/Espo/Core/Utils/Authentication/LDAP.php b/application/Espo/Core/Utils/Authentication/LDAP.php index abb4cf5d96..8bbb90ad7b 100644 --- a/application/Espo/Core/Utils/Authentication/LDAP.php +++ b/application/Espo/Core/Utils/Authentication/LDAP.php @@ -23,177 +23,177 @@ namespace Espo\Core\Utils\Authentication; use Espo\Core\Exceptions\Error, - Espo\Core\Utils\Config, - Espo\Core\ORM\EntityManager, - Espo\Core\Utils\Auth; + Espo\Core\Utils\Config, + Espo\Core\ORM\EntityManager, + Espo\Core\Utils\Auth; class LDAP extends Base { - private $utils; + private $utils; - private $zendLdap; + private $zendLdap; - /** - * Espo => LDAP name - * - * @var array - */ - private $fields = array( - 'userName' => 'cn', - 'firstName' => 'givenname', - 'lastName' => 'sn', - 'title' => 'title', - 'emailAddress' => 'mail', - 'phoneNumber' => 'telephonenumber', - ); + /** + * Espo => LDAP name + * + * @var array + */ + private $fields = array( + 'userName' => 'cn', + 'firstName' => 'givenname', + 'lastName' => 'sn', + 'title' => 'title', + 'emailAddress' => 'mail', + 'phoneNumber' => 'telephonenumber', + ); - public function __construct(Config $config, EntityManager $entityManager, Auth $auth) - { - parent::__construct($config, $entityManager, $auth); + public function __construct(Config $config, EntityManager $entityManager, Auth $auth) + { + parent::__construct($config, $entityManager, $auth); - $this->zendLdap = new LDAP\LDAP(); - $this->utils = new LDAP\Utils($config); - } + $this->zendLdap = new LDAP\LDAP(); + $this->utils = new LDAP\Utils($config); + } - protected function getZendLdap() - { - return $this->zendLdap; - } + protected function getZendLdap() + { + return $this->zendLdap; + } - protected function getUtils() - { - return $this->utils; - } + protected function getUtils() + { + return $this->utils; + } - /** - * LDAP login - * - * @param string $username - * @param string $password - * @param \Espo\Entities\AuthToken $authToken - * @return \Espo\Entities\User | null - */ - public function login($username, $password, \Espo\Entities\AuthToken $authToken = null) - { - if ($authToken) { - return $this->loginByToken($username, $authToken); - } + /** + * LDAP login + * + * @param string $username + * @param string $password + * @param \Espo\Entities\AuthToken $authToken + * @return \Espo\Entities\User | null + */ + public function login($username, $password, \Espo\Entities\AuthToken $authToken = null) + { + if ($authToken) { + return $this->loginByToken($username, $authToken); + } - $options = $this->getUtils()->getZendOptions(); + $options = $this->getUtils()->getZendOptions(); - $ldap = $this->getZendLdap(); - $ldap = $ldap->setOptions($options); + $ldap = $this->getZendLdap(); + $ldap = $ldap->setOptions($options); - try { - $ldap->bind($username, $password); + try { + $ldap->bind($username, $password); - $dn = $ldap->getDn($username); + $dn = $ldap->getDn($username); - $loginFilter = $this->getUtils()->getOption('userLoginFilter'); - $userData = $ldap->searchByLoginFilter($loginFilter, $dn, 3); + $loginFilter = $this->getUtils()->getOption('userLoginFilter'); + $userData = $ldap->searchByLoginFilter($loginFilter, $dn, 3); - } catch (\Zend\Ldap\Exception\LdapException $zle) { + } catch (\Zend\Ldap\Exception\LdapException $zle) { - $admin = $this->adminLogin($username, $password); - if (!isset($admin)) { - $GLOBALS['log']->info('LDAP Authentication: ' . $zle->getMessage()); - return null; - } + $admin = $this->adminLogin($username, $password); + if (!isset($admin)) { + $GLOBALS['log']->info('LDAP Authentication: ' . $zle->getMessage()); + return null; + } - $GLOBALS['log']->info('LDAP Authentication: Administrator login by username ['.$username.']'); - } + $GLOBALS['log']->info('LDAP Authentication: Administrator login by username ['.$username.']'); + } - $user = $this->getEntityManager()->getRepository('User')->findOne(array( - 'whereClause' => array( - 'userName' => $username, - ), - )); + $user = $this->getEntityManager()->getRepository('User')->findOne(array( + 'whereClause' => array( + 'userName' => $username, + ), + )); - $isCreateUser = $this->getUtils()->getOption('createEspoUser'); - if (!isset($user) && $isCreateUser) { - $this->getAuth()->useNoAuth(); /** Required to fix Acl "isFetched()" error */ - $user = $this->createUser($userData); - } + $isCreateUser = $this->getUtils()->getOption('createEspoUser'); + if (!isset($user) && $isCreateUser) { + $this->getAuth()->useNoAuth(); /** Required to fix Acl "isFetched()" error */ + $user = $this->createUser($userData); + } - return $user; - } + return $user; + } - /** - * Login by authorization token - * - * @param string $username - * @param \Espo\Entities\AuthToken $authToken - * @return \Espo\Entities\User | null - */ - protected function loginByToken($username, \Espo\Entities\AuthToken $authToken = null) - { - if (!isset($authToken)) { - return null; - } + /** + * Login by authorization token + * + * @param string $username + * @param \Espo\Entities\AuthToken $authToken + * @return \Espo\Entities\User | null + */ + protected function loginByToken($username, \Espo\Entities\AuthToken $authToken = null) + { + if (!isset($authToken)) { + return null; + } - $userId = $authToken->get('userId'); - $user = $this->getEntityManager()->getEntity('User', $userId); + $userId = $authToken->get('userId'); + $user = $this->getEntityManager()->getEntity('User', $userId); - $tokenUsername = $user->get('userName'); - if ($username != $tokenUsername) { - $GLOBALS['log']->alert('Unauthorized access attempt for user ['.$username.'] from IP ['.$_SERVER['REMOTE_ADDR'].']'); - return null; - } + $tokenUsername = $user->get('userName'); + if ($username != $tokenUsername) { + $GLOBALS['log']->alert('Unauthorized access attempt for user ['.$username.'] from IP ['.$_SERVER['REMOTE_ADDR'].']'); + return null; + } - $user = $this->getEntityManager()->getRepository('User')->findOne(array( - 'whereClause' => array( - 'userName' => $username, - ), - )); + $user = $this->getEntityManager()->getRepository('User')->findOne(array( + 'whereClause' => array( + 'userName' => $username, + ), + )); - return $user; - } + return $user; + } - /** - * Login user with administrator rights - * - * @param string $username - * @param string $password - * @return \Espo\Entities\User | null - */ - protected function adminLogin($username, $password) - { - $hash = md5($password); + /** + * Login user with administrator rights + * + * @param string $username + * @param string $password + * @return \Espo\Entities\User | null + */ + protected function adminLogin($username, $password) + { + $hash = $this->getPasswordHash()->hash($password); - $user = $this->getEntityManager()->getRepository('User')->findOne(array( - 'whereClause' => array( - 'userName' => $username, - 'password' => $hash, - 'isAdmin' => 1 - ), - )); + $user = $this->getEntityManager()->getRepository('User')->findOne(array( + 'whereClause' => array( + 'userName' => $username, + 'password' => $hash, + 'isAdmin' => 1 + ), + )); - return $user; - } + return $user; + } - /** - * Create Espo user with data gets from LDAP server - * - * @param array $userData LDAP entity data - * @return \Espo\Entities\User - */ - protected function createUser(array $userData) - { - $data = array(); - foreach ($this->fields as $espo => $ldap) { - if (isset($userData[$ldap][0])) { - $data[$espo] = $userData[$ldap][0]; - } - } + /** + * Create Espo user with data gets from LDAP server + * + * @param array $userData LDAP entity data + * @return \Espo\Entities\User + */ + protected function createUser(array $userData) + { + $data = array(); + foreach ($this->fields as $espo => $ldap) { + if (isset($userData[$ldap][0])) { + $data[$espo] = $userData[$ldap][0]; + } + } - $user = $this->getEntityManager()->getEntity('User'); - $user->set($data); + $user = $this->getEntityManager()->getEntity('User'); + $user->set($data); - $this->getEntityManager()->saveEntity($user); + $this->getEntityManager()->saveEntity($user); - return $user; - } + return $user; + } diff --git a/application/Espo/Core/Utils/Authentication/LDAP/LDAP.php b/application/Espo/Core/Utils/Authentication/LDAP/LDAP.php index 0361d617e0..eda42a9b16 100644 --- a/application/Espo/Core/Utils/Authentication/LDAP/LDAP.php +++ b/application/Espo/Core/Utils/Authentication/LDAP/LDAP.php @@ -24,100 +24,100 @@ namespace Espo\Core\Utils\Authentication\LDAP; class LDAP extends \Zend\Ldap\Ldap { - protected $usernameAttribute = 'cn'; + protected $usernameAttribute = 'cn'; - /** - * Get DN depends on options, ex. "cn=test,ou=People,dc=maxcrc,dc=com" - * - * @return string DN format - */ - public function getDn($acctname) - { - return $this->getAccountDn($acctname, \Zend\Ldap\Ldap::ACCTNAME_FORM_DN); - } + /** + * Get DN depends on options, ex. "cn=test,ou=People,dc=maxcrc,dc=com" + * + * @return string DN format + */ + public function getDn($acctname) + { + return $this->getAccountDn($acctname, \Zend\Ldap\Ldap::ACCTNAME_FORM_DN); + } - /** - * Fix a bug, ex. CN=Alice Baker,CN=Users,DC=example,DC=com - * - * @param string $acctname - * @return string - Account DN - */ - protected function getAccountDn($acctname) - { - $baseDn = $this->getBaseDn(); + /** + * Fix a bug, ex. CN=Alice Baker,CN=Users,DC=example,DC=com + * + * @param string $acctname + * @return string - Account DN + */ + protected function getAccountDn($acctname) + { + $baseDn = $this->getBaseDn(); - if ($this->getBindRequiresDn() && isset($baseDn)) { - try { - return parent::getAccountDn($acctname); - } catch (\Zend\Ldap\Exception\LdapException $zle) { - if ($zle->getCode() != \Zend\Ldap\Exception\LdapException::LDAP_NO_SUCH_OBJECT) { - throw $zle; - } - } + if ($this->getBindRequiresDn() && isset($baseDn)) { + try { + return parent::getAccountDn($acctname); + } catch (\Zend\Ldap\Exception\LdapException $zle) { + if ($zle->getCode() != \Zend\Ldap\Exception\LdapException::LDAP_NO_SUCH_OBJECT) { + throw $zle; + } + } - $acctname = $this->usernameAttribute . '=' . \Zend\Ldap\Filter\AbstractFilter::escapeValue($acctname) . ',' . $baseDn; - } + $acctname = $this->usernameAttribute . '=' . \Zend\Ldap\Filter\AbstractFilter::escapeValue($acctname) . ',' . $baseDn; + } - return parent::getAccountDn($acctname); - } + return parent::getAccountDn($acctname); + } - /** - * Search a user using userLoginFilter - * - * @param string $filter - * @param string $basedn - * @param int $scope - * @param array $attributes - * @return array - */ - public function searchByLoginFilter($filter, $basedn = null, $scope = self::SEARCH_SCOPE_SUB, array $attributes = array()) - { - $filter = $this->getLoginFilter($filter); + /** + * Search a user using userLoginFilter + * + * @param string $filter + * @param string $basedn + * @param int $scope + * @param array $attributes + * @return array + */ + public function searchByLoginFilter($filter, $basedn = null, $scope = self::SEARCH_SCOPE_SUB, array $attributes = array()) + { + $filter = $this->getLoginFilter($filter); - $result = $this->search($filter, $basedn, $scope, $attributes); + $result = $this->search($filter, $basedn, $scope, $attributes); - if ($result->count() > 0) { - return $result->getFirst(); - } + if ($result->count() > 0) { + return $result->getFirst(); + } - throw new \Zend\Ldap\Exception\LdapException($this, 'searching: ' . $filter); - } + throw new \Zend\Ldap\Exception\LdapException($this, 'searching: ' . $filter); + } - /** - * Get login filter in LDAP format - * - * @param string $filter - * @return string - */ - protected function getLoginFilter($filter) - { - $baseFilter = '(objectClass=*)'; + /** + * Get login filter in LDAP format + * + * @param string $filter + * @return string + */ + protected function getLoginFilter($filter) + { + $baseFilter = '(objectClass=*)'; - if (!empty($filter)) { - $baseFilter = '(&' . $baseFilter . $this->convertToFilterFormat($filter). ')'; - } + if (!empty($filter)) { + $baseFilter = '(&' . $baseFilter . $this->convertToFilterFormat($filter). ')'; + } - return $baseFilter; - } + return $baseFilter; + } - /** - * Check and convert filter item in LDAP format - * - * @param string $filter [description] - * @return string - */ - protected function convertToFilterFormat($filter) - { - $filter = trim($filter); - if (substr($filter, 0, 1) != '(') { - $filter = '(' . $filter; - } + /** + * Check and convert filter item in LDAP format + * + * @param string $filter [description] + * @return string + */ + protected function convertToFilterFormat($filter) + { + $filter = trim($filter); + if (substr($filter, 0, 1) != '(') { + $filter = '(' . $filter; + } - if (substr($filter, -1) != ')') { - $filter = $filter . ')'; - } + if (substr($filter, -1) != ')') { + $filter = $filter . ')'; + } - return $filter; - } + return $filter; + } } \ No newline at end of file diff --git a/application/Espo/Core/Utils/Authentication/LDAP/Utils.php b/application/Espo/Core/Utils/Authentication/LDAP/Utils.php index 35da2e3917..25ee732b06 100644 --- a/application/Espo/Core/Utils/Authentication/LDAP/Utils.php +++ b/application/Espo/Core/Utils/Authentication/LDAP/Utils.php @@ -26,130 +26,130 @@ use \Espo\Core\Utils\Config; class Utils { - private $config; + private $config; - protected $options = null; + protected $options = null; - /** - * Association between LDAP and Espo fields - * @var array - */ - protected $fieldMap = array( - 'host' => 'ldapHost', - 'port' => 'ldapPort', - 'useSsl' => 'ldapSecurity', - 'useStartTls' => 'ldapSecurity', - 'username' => 'ldapUsername', - 'password' => 'ldapPassword', - 'bindRequiresDn' => 'ldapBindRequiresDn', - 'baseDn' => 'ldapBaseDn', - 'accountCanonicalForm' => 'ldapAccountCanonicalForm', - 'accountDomainName' => 'ldapAccountDomainName', - 'accountDomainNameShort' => 'ldapAccountDomainNameShort', - 'accountFilterFormat' => 'ldapAccountFilterFormat', - 'optReferrals' => 'ldapOptReferrals', - 'tryUsernameSplit' => 'ldapTryUsernameSplit', - 'networkTimeout' => 'ldapNetworkTimeout', - 'createEspoUser' => 'ldapCreateEspoUser', - 'userLoginFilter' => 'ldapUserLoginFilter', - ); + /** + * Association between LDAP and Espo fields + * @var array + */ + protected $fieldMap = array( + 'host' => 'ldapHost', + 'port' => 'ldapPort', + 'useSsl' => 'ldapSecurity', + 'useStartTls' => 'ldapSecurity', + 'username' => 'ldapUsername', + 'password' => 'ldapPassword', + 'bindRequiresDn' => 'ldapBindRequiresDn', + 'baseDn' => 'ldapBaseDn', + 'accountCanonicalForm' => 'ldapAccountCanonicalForm', + 'accountDomainName' => 'ldapAccountDomainName', + 'accountDomainNameShort' => 'ldapAccountDomainNameShort', + 'accountFilterFormat' => 'ldapAccountFilterFormat', + 'optReferrals' => 'ldapOptReferrals', + 'tryUsernameSplit' => 'ldapTryUsernameSplit', + 'networkTimeout' => 'ldapNetworkTimeout', + 'createEspoUser' => 'ldapCreateEspoUser', + 'userLoginFilter' => 'ldapUserLoginFilter', + ); - /** - * Permitted Espo Options - * - * @var array - */ - protected $permittedEspoOptions = array( - 'createEspoUser' => false, - 'userLoginFilter' => null, - ); + /** + * Permitted Espo Options + * + * @var array + */ + protected $permittedEspoOptions = array( + 'createEspoUser' => false, + 'userLoginFilter' => null, + ); - /** - * accountCanonicalForm Map between Espo and Zend value - * - * @var array - */ - protected $accountCanonicalFormMap = array( - 'Dn' => 1, - 'Username' => 2, - 'Backslash' => 3, - 'Principal' => 4, - ); + /** + * accountCanonicalForm Map between Espo and Zend value + * + * @var array + */ + protected $accountCanonicalFormMap = array( + 'Dn' => 1, + 'Username' => 2, + 'Backslash' => 3, + 'Principal' => 4, + ); - public function __construct(Config $config) - { - $this->config = $config; - } + public function __construct(Config $config) + { + $this->config = $config; + } - protected function getConfig() - { - return $this->config; - } + protected function getConfig() + { + return $this->config; + } - /** - * Get Options from espo config according to $this->fieldMap - * - * @return array - */ - public function getOptions() - { - if (isset($this->options)) { - return $this->options; - } + /** + * Get Options from espo config according to $this->fieldMap + * + * @return array + */ + public function getOptions() + { + if (isset($this->options)) { + return $this->options; + } - $options = array(); - foreach ($this->fieldMap as $ldapName => $espoName) { + $options = array(); + foreach ($this->fieldMap as $ldapName => $espoName) { - $option = $this->getConfig()->get($espoName); - if (isset($option)) { - $options[$ldapName] = $option; - } - } + $option = $this->getConfig()->get($espoName); + if (isset($option)) { + $options[$ldapName] = $option; + } + } - /** peculiar fields */ - $options['useSsl'] = (bool) ($options['useSsl'] == 'SSL'); - $options['useStartTls'] = (bool) ($options['useStartTls'] == 'TLS'); - $options['accountCanonicalForm'] = $this->accountCanonicalFormMap[ $options['accountCanonicalForm'] ]; + /** peculiar fields */ + $options['useSsl'] = (bool) ($options['useSsl'] == 'SSL'); + $options['useStartTls'] = (bool) ($options['useStartTls'] == 'TLS'); + $options['accountCanonicalForm'] = $this->accountCanonicalFormMap[ $options['accountCanonicalForm'] ]; - $this->options = $options; + $this->options = $options; - return $this->options; - } + return $this->options; + } - /** - * Get an ldap option - * - * @param string $name - * @param mixed $returns Return value - * @return mixed - */ - public function getOption($name, $returns = null) - { - if (isset($this->options)) { - $this->getOptions(); - } + /** + * Get an ldap option + * + * @param string $name + * @param mixed $returns Return value + * @return mixed + */ + public function getOption($name, $returns = null) + { + if (isset($this->options)) { + $this->getOptions(); + } - if (isset($this->options[$name])) { - return $this->options[$name]; - } + if (isset($this->options[$name])) { + return $this->options[$name]; + } - return $returns; - } + return $returns; + } - /** - * Get Zend options for using Zend\Ldap - * - * @return array - */ - public function getZendOptions() - { - $options = $this->getOptions(); - $espoOptions = array_keys($this->permittedEspoOptions); + /** + * Get Zend options for using Zend\Ldap + * + * @return array + */ + public function getZendOptions() + { + $options = $this->getOptions(); + $espoOptions = array_keys($this->permittedEspoOptions); - $zendOptions = array_diff_key($options, array_flip($espoOptions)); + $zendOptions = array_diff_key($options, array_flip($espoOptions)); - return $zendOptions; - } + return $zendOptions; + } } \ No newline at end of file diff --git a/application/Espo/Core/Utils/Config.php b/application/Espo/Core/Utils/Config.php index 09cde9ef46..9d1a18b727 100644 --- a/application/Espo/Core/Utils/Config.php +++ b/application/Espo/Core/Utils/Config.php @@ -24,265 +24,265 @@ namespace Espo\Core\Utils; class Config { - /** - * Path of default config file - * - * @access private - * @var string - */ - private $defaultConfigPath = 'application/Espo/Core/defaults/config.php'; + /** + * Path of default config file + * + * @access private + * @var string + */ + private $defaultConfigPath = 'application/Espo/Core/defaults/config.php'; - private $systemConfigPath = 'application/Espo/Core/defaults/systemConfig.php'; + private $systemConfigPath = 'application/Espo/Core/defaults/systemConfig.php'; - protected $configPath = 'data/config.php'; + protected $configPath = 'data/config.php'; - private $cacheTimestamp = 'cacheTimestamp'; + private $cacheTimestamp = 'cacheTimestamp'; - /** - * Array of admin items - * - * @access protected - * @var array - */ - protected $adminItems = array(); + /** + * Array of admin items + * + * @access protected + * @var array + */ + protected $adminItems = array(); - /** - * Contains content of config - * - * @access private - * @var array - */ - private $data; + /** + * Contains content of config + * + * @access private + * @var array + */ + private $data; - private $changedData = array(); - private $removeData = array(); + private $changedData = array(); + private $removeData = array(); - private $fileManager; + private $fileManager; - public function __construct(\Espo\Core\Utils\File\Manager $fileManager) //TODO - { - $this->fileManager = $fileManager; - } + public function __construct(\Espo\Core\Utils\File\Manager $fileManager) //TODO + { + $this->fileManager = $fileManager; + } - protected function getFileManager() - { - return $this->fileManager; - } + protected function getFileManager() + { + return $this->fileManager; + } - public function getConfigPath() - { - return $this->configPath; - } + public function getConfigPath() + { + return $this->configPath; + } - /** - * Get an option from config - * - * @param string $name - * @param string $default - * @return string | array - */ - public function get($name, $default = null) - { - $keys = explode('.', $name); + /** + * Get an option from config + * + * @param string $name + * @param string $default + * @return string | array + */ + public function get($name, $default = null) + { + $keys = explode('.', $name); - $lastBranch = $this->loadConfig(); - foreach ($keys as $keyName) { - if (isset($lastBranch[$keyName]) && is_array($lastBranch)) { - $lastBranch = $lastBranch[$keyName]; - } else { - return $default; - } - } + $lastBranch = $this->loadConfig(); + foreach ($keys as $keyName) { + if (isset($lastBranch[$keyName]) && is_array($lastBranch)) { + $lastBranch = $lastBranch[$keyName]; + } else { + return $default; + } + } - return $lastBranch; - } + return $lastBranch; + } - /** - * Set an option to the config - * - * @param string $name - * @param string $value - * @return bool - */ - public function set($name, $value = '') - { - if (!is_array($name)) { - $name = array($name => $value); - } + /** + * Set an option to the config + * + * @param string $name + * @param string $value + * @return bool + */ + public function set($name, $value = '') + { + if (!is_array($name)) { + $name = array($name => $value); + } - foreach ($name as $key => $value) { + foreach ($name as $key => $value) { - if (is_object($value)) { - $value = (array) $value; - } + if (is_object($value)) { + $value = (array) $value; + } - $this->data[$key] = $value; - $this->changedData[$key] = $value; - } - } + $this->data[$key] = $value; + $this->changedData[$key] = $value; + } + } - /** - * Remove an option in config - * - * @param string $name - * @return bool | null - null if an option doesn't exist - */ - public function remove($name) - { - if (array_key_exists($name, $this->data)) { - unset($this->data[$name]); - $this->removeData[] = $name; - return true; - } + /** + * Remove an option in config + * + * @param string $name + * @return bool | null - null if an option doesn't exist + */ + public function remove($name) + { + if (array_key_exists($name, $this->data)) { + unset($this->data[$name]); + $this->removeData[] = $name; + return true; + } - return null; - } + return null; + } - public function save() - { - $values = $this->changedData; + public function save() + { + $values = $this->changedData; - if (!isset($values[$this->cacheTimestamp])) { - $values = array_merge($this->updateCacheTimestamp(true), $values); - } + if (!isset($values[$this->cacheTimestamp])) { + $values = array_merge($this->updateCacheTimestamp(true), $values); + } - $removeData = empty($this->removeData) ? null : $this->removeData; + $removeData = empty($this->removeData) ? null : $this->removeData; - $result = $this->getFileManager()->mergeContentsPHP($this->configPath, $values, $removeData); - if ($result) { - $this->changedData = array(); - $this->removeData = array(); - $this->loadConfig(true); - } + $result = $this->getFileManager()->mergeContentsPHP($this->configPath, $values, $removeData); + if ($result) { + $this->changedData = array(); + $this->removeData = array(); + $this->loadConfig(true); + } - return $result; - } + return $result; + } - public function getDefaults() - { - return $this->getFileManager()->getContents($this->defaultConfigPath); - } + public function getDefaults() + { + return $this->getFileManager()->getContents($this->defaultConfigPath); + } - /** - * Return an Object of all configs - * @param boolean $reload - * @return array() - */ - protected function loadConfig($reload = false) - { - if (!$reload && isset($this->data) && !empty($this->data)) { - return $this->data; - } + /** + * Return an Object of all configs + * @param boolean $reload + * @return array() + */ + protected function loadConfig($reload = false) + { + if (!$reload && isset($this->data) && !empty($this->data)) { + return $this->data; + } - $configPath = file_exists($this->configPath) ? $this->configPath : $this->defaultConfigPath; + $configPath = file_exists($this->configPath) ? $this->configPath : $this->defaultConfigPath; - $this->data = $this->getFileManager()->getContents($configPath); + $this->data = $this->getFileManager()->getContents($configPath); - $systemConfig = $this->getFileManager()->getContents($this->systemConfigPath); - $this->data = Util::merge($systemConfig, $this->data); + $systemConfig = $this->getFileManager()->getContents($this->systemConfigPath); + $this->data = Util::merge($systemConfig, $this->data); - return $this->data; - } + return $this->data; + } - /** - * Get config acording to restrictions for a user - * - * @param $isAdmin - * @return array - */ - public function getData($isAdmin = false) - { - $data = $this->loadConfig(); + /** + * Get config acording to restrictions for a user + * + * @param $isAdmin + * @return array + */ + public function getData($isAdmin = false) + { + $data = $this->loadConfig(); - $restrictedConfig = $data; - foreach($this->getRestrictItems($isAdmin) as $name) { - if (isset($restrictedConfig[$name])) { - unset($restrictedConfig[$name]); - } - } + $restrictedConfig = $data; + foreach($this->getRestrictItems($isAdmin) as $name) { + if (isset($restrictedConfig[$name])) { + unset($restrictedConfig[$name]); + } + } - return $restrictedConfig; - } + return $restrictedConfig; + } - /** - * Set JSON data acording to restrictions for a user - * - * @param $isAdmin - * @return bool - */ - public function setData($data, $isAdmin = false) - { - $restrictItems = $this->getRestrictItems($isAdmin); + /** + * Set JSON data acording to restrictions for a user + * + * @param $isAdmin + * @return bool + */ + public function setData($data, $isAdmin = false) + { + $restrictItems = $this->getRestrictItems($isAdmin); - $values = array(); - foreach($data as $key => $item) { - if (!in_array($key, $restrictItems)) { - $values[$key]= $item; - } - } + $values = array(); + foreach($data as $key => $item) { + if (!in_array($key, $restrictItems)) { + $values[$key]= $item; + } + } - return $this->set($values); - } + return $this->set($values); + } - /** - * Update cache timestamp - * - * @param $onlyValue - If need to return just timestamp array - * @return bool | array - */ - public function updateCacheTimestamp($onlyValue = false) - { - $timestamp = array( - $this->cacheTimestamp => time(), - ); + /** + * Update cache timestamp + * + * @param $onlyValue - If need to return just timestamp array + * @return bool | array + */ + public function updateCacheTimestamp($onlyValue = false) + { + $timestamp = array( + $this->cacheTimestamp => time(), + ); - if ($onlyValue) { - return $timestamp; - } + if ($onlyValue) { + return $timestamp; + } - return $this->set($timestamp); - } + return $this->set($timestamp); + } - /** - * Get admin items - * - * @return object - */ - protected function getRestrictItems($onlySystemItems = false) - { - $data = $this->loadConfig(); + /** + * Get admin items + * + * @return object + */ + protected function getRestrictItems($onlySystemItems = false) + { + $data = $this->loadConfig(); - if ($onlySystemItems) { - return $data['systemItems']; - } + if ($onlySystemItems) { + return $data['systemItems']; + } - if (empty($this->adminItems)) { - $this->adminItems= Util::merge($data['systemItems'], $data['adminItems']); - } + if (empty($this->adminItems)) { + $this->adminItems= Util::merge($data['systemItems'], $data['adminItems']); + } - return $this->adminItems; - } + return $this->adminItems; + } - /** - * Check if an item is allowed to get and save - * - * @param $name - * @param $isAdmin - * @return bool - */ - protected function isAllowed($name, $isAdmin = false) - { - if (in_array($name, $this->getRestrictItems($isAdmin))) { - return false; - } + /** + * Check if an item is allowed to get and save + * + * @param $name + * @param $isAdmin + * @return bool + */ + protected function isAllowed($name, $isAdmin = false) + { + if (in_array($name, $this->getRestrictItems($isAdmin))) { + return false; + } - return true; - } + return true; + } } ?> diff --git a/application/Espo/Core/Utils/Crypt.php b/application/Espo/Core/Utils/Crypt.php new file mode 100644 index 0000000000..8d4e591232 --- /dev/null +++ b/application/Espo/Core/Utils/Crypt.php @@ -0,0 +1,62 @@ +config = $config; + $this->cryptKey = $config->get('cryptKey', ''); + } + + protected function getKey() + { + if (empty($this->key)) { + $this->key = hash('sha256', $this->cryptKey, true); + } + return $this->key; + } + + public function encrypt($string) + { + return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $this->getKey(), $string, MCRYPT_MODE_CBC)); + } + + public function decrypt($encryptedString) + { + return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $this->getKey(), base64_decode($encryptedString), MCRYPT_MODE_CBC)); + } + + public function generateKey() + { + return md5(uniqid()); + } +} + diff --git a/application/Espo/Core/Utils/Database/Converter.php b/application/Espo/Core/Utils/Database/Converter.php index 570ca66d43..a0704d9372 100644 --- a/application/Espo/Core/Utils/Database/Converter.php +++ b/application/Espo/Core/Utils/Database/Converter.php @@ -23,81 +23,81 @@ namespace Espo\Core\Utils\Database; use Espo\Core\Utils\Util, - Espo\ORM\Entity; + Espo\ORM\Entity; class Converter { - private $metadata; + private $metadata; - private $fileManager; + private $fileManager; - private $schemaConverter; + private $schemaConverter; - private $schemaFromMetadata = null; + private $schemaFromMetadata = null; - /** - * @var array $meta - metadata array - */ - //private $meta; + /** + * @var array $meta - metadata array + */ + //private $meta; - public function __construct(\Espo\Core\Utils\Metadata $metadata, \Espo\Core\Utils\File\Manager $fileManager) - { - $this->metadata = $metadata; - $this->fileManager = $fileManager; + public function __construct(\Espo\Core\Utils\Metadata $metadata, \Espo\Core\Utils\File\Manager $fileManager) + { + $this->metadata = $metadata; + $this->fileManager = $fileManager; - $this->ormConverter = new Orm\Converter($this->metadata, $this->fileManager); + $this->ormConverter = new Orm\Converter($this->metadata, $this->fileManager); - $this->schemaConverter = new Schema\Converter($this->fileManager); - } + $this->schemaConverter = new Schema\Converter($this->fileManager); + } - protected function getMetadata() - { - return $this->metadata; - } + protected function getMetadata() + { + return $this->metadata; + } - protected function getOrmConverter() - { - return $this->ormConverter; - } + protected function getOrmConverter() + { + return $this->ormConverter; + } - protected function getSchemaConverter() - { - return $this->schemaConverter; - } + protected function getSchemaConverter() + { + return $this->schemaConverter; + } - public function getSchemaFromMetadata($entityList = null) - { - $ormMeta = $this->getMetadata()->getOrmMetadata(); - $entityDefs = $this->getMetadata()->get('entityDefs'); + public function getSchemaFromMetadata($entityList = null) + { + $ormMeta = $this->getMetadata()->getOrmMetadata(); + $entityDefs = $this->getMetadata()->get('entityDefs'); - $this->schemaFromMetadata = $this->getSchemaConverter()->process($ormMeta, $entityDefs, $entityList); + $this->schemaFromMetadata = $this->getSchemaConverter()->process($ormMeta, $entityDefs, $entityList); - return $this->schemaFromMetadata; - } + return $this->schemaFromMetadata; + } - /** - * Main method of convertation from metadata to orm metadata and database schema - * - * @return bool - */ - public function process() - { - $GLOBALS['log']->debug('Orm\Converter - Start: orm convertation'); + /** + * Main method of convertation from metadata to orm metadata and database schema + * + * @return bool + */ + public function process() + { + $GLOBALS['log']->debug('Orm\Converter - Start: orm convertation'); - $ormMeta = $this->getOrmConverter()->process(); + $ormMeta = $this->getOrmConverter()->process(); - //save database meta to a file espoMetadata.php - $result = $this->getMetadata()->setOrmMetadata($ormMeta); + //save database meta to a file espoMetadata.php + $result = $this->getMetadata()->setOrmMetadata($ormMeta); - $GLOBALS['log']->debug('Orm\Converter - End: orm convertation, result=['.$result.']'); + $GLOBALS['log']->debug('Orm\Converter - End: orm convertation, result=['.$result.']'); - return $result; - } + return $result; + } diff --git a/application/Espo/Core/Utils/Database/DBAL/Driver/Mysqli/Driver.php b/application/Espo/Core/Utils/Database/DBAL/Driver/Mysqli/Driver.php index f7be7e83c8..15a66152b5 100644 --- a/application/Espo/Core/Utils/Database/DBAL/Driver/Mysqli/Driver.php +++ b/application/Espo/Core/Utils/Database/DBAL/Driver/Mysqli/Driver.php @@ -25,7 +25,7 @@ namespace Espo\Core\Utils\Database\DBAL\Driver\Mysqli; class Driver extends \Doctrine\DBAL\Driver\Mysqli\Driver { - public function getDatabasePlatform() + public function getDatabasePlatform() { return new \Espo\Core\Utils\Database\DBAL\Platforms\MySqlPlatform(); } diff --git a/application/Espo/Core/Utils/Database/DBAL/Driver/PDOMySql/Driver.php b/application/Espo/Core/Utils/Database/DBAL/Driver/PDOMySql/Driver.php index db6f43b00b..11e5887e7b 100644 --- a/application/Espo/Core/Utils/Database/DBAL/Driver/PDOMySql/Driver.php +++ b/application/Espo/Core/Utils/Database/DBAL/Driver/PDOMySql/Driver.php @@ -25,7 +25,7 @@ namespace Espo\Core\Utils\Database\DBAL\Driver\PDOMySql; class Driver extends \Doctrine\DBAL\Driver\PDOMySql\Driver { - public function getDatabasePlatform() + public function getDatabasePlatform() { return new \Espo\Core\Utils\Database\DBAL\Platforms\MySqlPlatform(); } diff --git a/application/Espo/Core/Utils/Database/DBAL/FieldTypes/Bool.php b/application/Espo/Core/Utils/Database/DBAL/FieldTypes/Bool.php index c6dce4d685..d43063b9c2 100644 --- a/application/Espo/Core/Utils/Database/DBAL/FieldTypes/Bool.php +++ b/application/Espo/Core/Utils/Database/DBAL/FieldTypes/Bool.php @@ -26,15 +26,15 @@ use Doctrine\DBAL\Types\BooleanType; class Bool extends BooleanType { - const BOOL = 'bool'; + const BOOL = 'bool'; - public function getName() + public function getName() { return self::BOOL; } - public static function getDbTypeName() - { - return 'TINYINT'; - } + public static function getDbTypeName() + { + return 'TINYINT'; + } } \ No newline at end of file diff --git a/application/Espo/Core/Utils/Database/DBAL/FieldTypes/Int.php b/application/Espo/Core/Utils/Database/DBAL/FieldTypes/Int.php index 0c0c688af0..5f3c06a03e 100644 --- a/application/Espo/Core/Utils/Database/DBAL/FieldTypes/Int.php +++ b/application/Espo/Core/Utils/Database/DBAL/FieldTypes/Int.php @@ -26,7 +26,7 @@ use Doctrine\DBAL\Types\IntegerType; class Int extends IntegerType { - const INTtype = 'int'; + const INTtype = 'int'; public function getName() { diff --git a/application/Espo/Core/Utils/Database/DBAL/FieldTypes/JsonArray.php b/application/Espo/Core/Utils/Database/DBAL/FieldTypes/JsonArray.php index cd822e27a0..2651398edc 100644 --- a/application/Espo/Core/Utils/Database/DBAL/FieldTypes/JsonArray.php +++ b/application/Espo/Core/Utils/Database/DBAL/FieldTypes/JsonArray.php @@ -24,16 +24,16 @@ namespace Espo\Core\Utils\Database\DBAL\FieldTypes; class JsonArray extends \Doctrine\DBAL\Types\JsonArrayType { - const JSON_ARRAY = 'jsonArray'; + const JSON_ARRAY = 'jsonArray'; - public function getName() - { - return self::JSON_ARRAY; - } + public function getName() + { + return self::JSON_ARRAY; + } - public static function getDbTypeName() - { - return 'TEXT'; - } + public static function getDbTypeName() + { + return 'TEXT'; + } } diff --git a/application/Espo/Core/Utils/Database/DBAL/FieldTypes/JsonObject.php b/application/Espo/Core/Utils/Database/DBAL/FieldTypes/JsonObject.php index f2f4f756ff..5d6382aef1 100644 --- a/application/Espo/Core/Utils/Database/DBAL/FieldTypes/JsonObject.php +++ b/application/Espo/Core/Utils/Database/DBAL/FieldTypes/JsonObject.php @@ -24,16 +24,16 @@ namespace Espo\Core\Utils\Database\DBAL\FieldTypes; class JsonObject extends \Doctrine\DBAL\Types\ObjectType { - const JSON_OBJECT = 'jsonObject'; + const JSON_OBJECT = 'jsonObject'; - public function getName() - { - return self::JSON_OBJECT; - } + public function getName() + { + return self::JSON_OBJECT; + } - public static function getDbTypeName() - { - return 'TEXT'; - } + public static function getDbTypeName() + { + return 'TEXT'; + } } diff --git a/application/Espo/Core/Utils/Database/DBAL/FieldTypes/Password.php b/application/Espo/Core/Utils/Database/DBAL/FieldTypes/Password.php index 5d408dfec6..aaf6fcbfeb 100644 --- a/application/Espo/Core/Utils/Database/DBAL/FieldTypes/Password.php +++ b/application/Espo/Core/Utils/Database/DBAL/FieldTypes/Password.php @@ -28,14 +28,14 @@ class Password extends StringType { const PASSWORD = 'password'; - public function getName() + public function getName() { return self::PASSWORD; } - public static function getDbTypeName() - { - return 'VARCHAR'; - } + public static function getDbTypeName() + { + return 'VARCHAR'; + } } diff --git a/application/Espo/Core/Utils/Database/DBAL/FieldTypes/Varchar.php b/application/Espo/Core/Utils/Database/DBAL/FieldTypes/Varchar.php index 77910cc1e3..e3ed0f7ff2 100644 --- a/application/Espo/Core/Utils/Database/DBAL/FieldTypes/Varchar.php +++ b/application/Espo/Core/Utils/Database/DBAL/FieldTypes/Varchar.php @@ -26,9 +26,9 @@ use Doctrine\DBAL\Types\StringType; class Varchar extends StringType { - const VARCHAR = 'varchar'; + const VARCHAR = 'varchar'; - public function getName() + public function getName() { return self::VARCHAR; } diff --git a/application/Espo/Core/Utils/Database/DBAL/Platforms/MySqlPlatform.php b/application/Espo/Core/Utils/Database/DBAL/Platforms/MySqlPlatform.php index 8b2947825f..0c92c2beb2 100644 --- a/application/Espo/Core/Utils/Database/DBAL/Platforms/MySqlPlatform.php +++ b/application/Espo/Core/Utils/Database/DBAL/Platforms/MySqlPlatform.php @@ -23,252 +23,252 @@ namespace Espo\Core\Utils\Database\DBAL\Platforms; use Doctrine\DBAL\Schema\TableDiff, - Doctrine\DBAL\Schema\Index, - Doctrine\DBAL\Schema\Table, - Doctrine\DBAL\Schema\Constraint, - Doctrine\DBAL\Schema\ForeignKeyConstraint; + Doctrine\DBAL\Schema\Index, + Doctrine\DBAL\Schema\Table, + Doctrine\DBAL\Schema\Constraint, + Doctrine\DBAL\Schema\ForeignKeyConstraint; class MySqlPlatform extends \Doctrine\DBAL\Platforms\MySqlPlatform { - public function getAlterTableSQL(TableDiff $diff) - { - $columnSql = array(); - $queryParts = array(); - if ($diff->newName !== false) { - $queryParts[] = 'RENAME TO ' . $diff->newName; - } + public function getAlterTableSQL(TableDiff $diff) + { + $columnSql = array(); + $queryParts = array(); + if ($diff->newName !== false) { + $queryParts[] = 'RENAME TO ' . $diff->newName; + } - foreach ($diff->addedColumns as $column) { - if ($this->onSchemaAlterTableAddColumn($column, $diff, $columnSql)) { - continue; - } + foreach ($diff->addedColumns as $column) { + if ($this->onSchemaAlterTableAddColumn($column, $diff, $columnSql)) { + continue; + } - $columnArray = $column->toArray(); - $columnArray['comment'] = $this->getColumnComment($column); - $queryParts[] = 'ADD ' . $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnArray); - } + $columnArray = $column->toArray(); + $columnArray['comment'] = $this->getColumnComment($column); + $queryParts[] = 'ADD ' . $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnArray); + } - foreach ($diff->removedColumns as $column) { - if ($this->onSchemaAlterTableRemoveColumn($column, $diff, $columnSql)) { - continue; - } + foreach ($diff->removedColumns as $column) { + if ($this->onSchemaAlterTableRemoveColumn($column, $diff, $columnSql)) { + continue; + } - //$queryParts[] = 'DROP ' . $column->getQuotedName($this); //espo: no needs to remove columns - } + //$queryParts[] = 'DROP ' . $column->getQuotedName($this); //espo: no needs to remove columns + } - foreach ($diff->changedColumns as $columnDiff) { - if ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) { - continue; - } + foreach ($diff->changedColumns as $columnDiff) { + if ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) { + continue; + } - /* @var $columnDiff \Doctrine\DBAL\Schema\ColumnDiff */ - $column = $columnDiff->column; - $columnArray = $column->toArray(); - $columnArray['comment'] = $this->getColumnComment($column); + /* @var $columnDiff \Doctrine\DBAL\Schema\ColumnDiff */ + $column = $columnDiff->column; + $columnArray = $column->toArray(); + $columnArray['comment'] = $this->getColumnComment($column); - $queryParts[] = 'CHANGE ' . $this->espoQuote($columnDiff->oldColumnName) . ' ' - . $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnArray); - } + $queryParts[] = 'CHANGE ' . $this->espoQuote($columnDiff->oldColumnName) . ' ' + . $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnArray); + } - //espo: It works not correctly. It can rename some existing fields - foreach ($diff->renamedColumns as $oldColumnName => $column) { - if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $column, $diff, $columnSql)) { - continue; - } + //espo: It works not correctly. It can rename some existing fields + foreach ($diff->renamedColumns as $oldColumnName => $column) { + if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $column, $diff, $columnSql)) { + continue; + } - $columnArray = $column->toArray(); - $columnArray['comment'] = $this->getColumnComment($column); - /*$queryParts[] = 'CHANGE ' . $oldColumnName . ' ' - . $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnArray); */ - $queryParts[] = 'ADD ' . $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnArray); //espo: fixed the problem - } //espo: END + $columnArray = $column->toArray(); + $columnArray['comment'] = $this->getColumnComment($column); + /*$queryParts[] = 'CHANGE ' . $oldColumnName . ' ' + . $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnArray); */ + $queryParts[] = 'ADD ' . $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnArray); //espo: fixed the problem + } //espo: END - $sql = array(); - $tableSql = array(); + $sql = array(); + $tableSql = array(); - if ( ! $this->onSchemaAlterTable($diff, $tableSql)) { - if (count($queryParts) > 0) { - $sql[] = 'ALTER TABLE ' . $this->espoQuote($diff->name) . ' ' . implode(", ", $queryParts); - } - $sql = array_merge( - $this->getPreAlterTableIndexForeignKeySQL($diff), - $sql, - $this->getPostAlterTableIndexForeignKeySQL($diff) - ); - } + if ( ! $this->onSchemaAlterTable($diff, $tableSql)) { + if (count($queryParts) > 0) { + $sql[] = 'ALTER TABLE ' . $this->espoQuote($diff->name) . ' ' . implode(", ", $queryParts); + } + $sql = array_merge( + $this->getPreAlterTableIndexForeignKeySQL($diff), + $sql, + $this->getPostAlterTableIndexForeignKeySQL($diff) + ); + } - return array_merge($sql, $tableSql, $columnSql); - } + return array_merge($sql, $tableSql, $columnSql); + } - protected function getPreAlterTableIndexForeignKeySQL(TableDiff $diff) - { - $sql = array(); - $table = $diff->name; + protected function getPreAlterTableIndexForeignKeySQL(TableDiff $diff) + { + $sql = array(); + $table = $diff->name; - foreach ($diff->removedIndexes as $remKey => $remIndex) { + foreach ($diff->removedIndexes as $remKey => $remIndex) { - foreach ($diff->addedIndexes as $addKey => $addIndex) { - if ($remIndex->getColumns() == $addIndex->getColumns()) { + foreach ($diff->addedIndexes as $addKey => $addIndex) { + if ($remIndex->getColumns() == $addIndex->getColumns()) { - $type = ''; - if ($addIndex->isUnique()) { - $type = 'UNIQUE '; - } + $type = ''; + if ($addIndex->isUnique()) { + $type = 'UNIQUE '; + } - $query = 'ALTER TABLE ' . $this->espoQuote($table) . ' DROP INDEX ' . $remIndex->getName() . ', '; - $query .= 'ADD ' . $type . 'INDEX ' . $addIndex->getName(); - $query .= ' (' . $this->getIndexFieldDeclarationListSQL($addIndex->getQuotedColumns($this)) . ')'; + $query = 'ALTER TABLE ' . $this->espoQuote($table) . ' DROP INDEX ' . $remIndex->getName() . ', '; + $query .= 'ADD ' . $type . 'INDEX ' . $addIndex->getName(); + $query .= ' (' . $this->getIndexFieldDeclarationListSQL($addIndex->getQuotedColumns($this)) . ')'; - $sql[] = $query; + $sql[] = $query; - unset($diff->removedIndexes[$remKey]); - unset($diff->addedIndexes[$addKey]); + unset($diff->removedIndexes[$remKey]); + unset($diff->addedIndexes[$addKey]); - break; - } - } - } + break; + } + } + } - $sql = array_merge($sql, parent::getPreAlterTableIndexForeignKeySQL($diff)); + $sql = array_merge($sql, parent::getPreAlterTableIndexForeignKeySQL($diff)); - return $sql; - } + return $sql; + } - public function getDropIndexSQL($index, $table=null) - { - if ($index instanceof Index) { - $indexName = $index->getQuotedName($this); - } else if(is_string($index)) { - $indexName = $index; - } else { - throw new \InvalidArgumentException('MysqlPlatform::getDropIndexSQL() expects $index parameter to be string or \Doctrine\DBAL\Schema\Index.'); - } + public function getDropIndexSQL($index, $table=null) + { + if ($index instanceof Index) { + $indexName = $index->getQuotedName($this); + } else if(is_string($index)) { + $indexName = $index; + } else { + throw new \InvalidArgumentException('MysqlPlatform::getDropIndexSQL() expects $index parameter to be string or \Doctrine\DBAL\Schema\Index.'); + } - if ($table instanceof Table) { - $table = $table->getQuotedName($this); - } else if(!is_string($table)) { - throw new \InvalidArgumentException('MysqlPlatform::getDropIndexSQL() expects $table parameter to be string or \Doctrine\DBAL\Schema\Table.'); - } + if ($table instanceof Table) { + $table = $table->getQuotedName($this); + } else if(!is_string($table)) { + throw new \InvalidArgumentException('MysqlPlatform::getDropIndexSQL() expects $table parameter to be string or \Doctrine\DBAL\Schema\Table.'); + } - if ($index instanceof Index && $index->isPrimary()) { - // mysql primary keys are always named "PRIMARY", - // so we cannot use them in statements because of them being keyword. - return $this->getDropPrimaryKeySQL($table); - } + if ($index instanceof Index && $index->isPrimary()) { + // mysql primary keys are always named "PRIMARY", + // so we cannot use them in statements because of them being keyword. + return $this->getDropPrimaryKeySQL($table); + } - return 'DROP INDEX ' . $indexName . ' ON ' . $this->espoQuote($table); - } + return 'DROP INDEX ' . $indexName . ' ON ' . $this->espoQuote($table); + } - protected function getDropPrimaryKeySQL($table) - { - return 'ALTER TABLE ' . $this->espoQuote($table) . ' DROP PRIMARY KEY'; - } + protected function getDropPrimaryKeySQL($table) + { + return 'ALTER TABLE ' . $this->espoQuote($table) . ' DROP PRIMARY KEY'; + } - public function getDropTemporaryTableSQL($table) - { - if ($table instanceof Table) { - $table = $table->getQuotedName($this); - } else if(!is_string($table)) { - throw new \InvalidArgumentException('getDropTableSQL() expects $table parameter to be string or \Doctrine\DBAL\Schema\Table.'); - } + public function getDropTemporaryTableSQL($table) + { + if ($table instanceof Table) { + $table = $table->getQuotedName($this); + } else if(!is_string($table)) { + throw new \InvalidArgumentException('getDropTableSQL() expects $table parameter to be string or \Doctrine\DBAL\Schema\Table.'); + } - return 'DROP TEMPORARY TABLE ' . $this->espoQuote($table); - } + return 'DROP TEMPORARY TABLE ' . $this->espoQuote($table); + } - //ESPO: fix problem with quoting table name - public function espoQuote($name) - { - if ($name instanceof Table) { - $name = $name->getQuotedName($this); - } + //ESPO: fix problem with quoting table name + public function espoQuote($name) + { + if ($name instanceof Table) { + $name = $name->getQuotedName($this); + } - if (isset($name[0]) && $name[0] != '`') { - $name = $this->quoteIdentifier($name); - } - return $name; - } + if (isset($name[0]) && $name[0] != '`') { + $name = $this->quoteIdentifier($name); + } + return $name; + } - public function getCreateForeignKeySQL(\Doctrine\DBAL\Schema\ForeignKeyConstraint $foreignKey, $table) - { - $query = 'ALTER TABLE ' . $this->espoQuote($table) . ' ADD ' . $this->getForeignKeyDeclarationSQL($foreignKey); + public function getCreateForeignKeySQL(\Doctrine\DBAL\Schema\ForeignKeyConstraint $foreignKey, $table) + { + $query = 'ALTER TABLE ' . $this->espoQuote($table) . ' ADD ' . $this->getForeignKeyDeclarationSQL($foreignKey); - return $query; - } + return $query; + } - public function getIndexDeclarationSQL($name, Index $index) - { - $columns = $index->getQuotedColumns($this); + public function getIndexDeclarationSQL($name, Index $index) + { + $columns = $index->getQuotedColumns($this); - if (count($columns) === 0) { - throw new \InvalidArgumentException("Incomplete definition. 'columns' required."); - } + if (count($columns) === 0) { + throw new \InvalidArgumentException("Incomplete definition. 'columns' required."); + } - return $this->getCreateIndexSQLFlags($index) . 'INDEX ' . $this->espoQuote($name) . ' (' - . $this->getIndexFieldDeclarationListSQL($columns) - . ')'; - } + return $this->getCreateIndexSQLFlags($index) . 'INDEX ' . $this->espoQuote($name) . ' (' + . $this->getIndexFieldDeclarationListSQL($columns) + . ')'; + } - public function getCreateIndexSQL(Index $index, $table) - { - if ($table instanceof Table) { - $table = $table->getQuotedName($this); - } - $name = $index->getQuotedName($this); - $columns = $index->getQuotedColumns($this); + public function getCreateIndexSQL(Index $index, $table) + { + if ($table instanceof Table) { + $table = $table->getQuotedName($this); + } + $name = $index->getQuotedName($this); + $columns = $index->getQuotedColumns($this); - if (count($columns) == 0) { - throw new \InvalidArgumentException("Incomplete definition. 'columns' required."); - } + if (count($columns) == 0) { + throw new \InvalidArgumentException("Incomplete definition. 'columns' required."); + } - if ($index->isPrimary()) { - return $this->getCreatePrimaryKeySQL($index, $table); - } + if ($index->isPrimary()) { + return $this->getCreatePrimaryKeySQL($index, $table); + } - $query = 'CREATE ' . $this->getCreateIndexSQLFlags($index) . 'INDEX ' . $name . ' ON ' . $this->espoQuote($table); - $query .= ' (' . $this->getIndexFieldDeclarationListSQL($columns) . ')'; + $query = 'CREATE ' . $this->getCreateIndexSQLFlags($index) . 'INDEX ' . $name . ' ON ' . $this->espoQuote($table); + $query .= ' (' . $this->getIndexFieldDeclarationListSQL($columns) . ')'; - return $query; - } + return $query; + } - public function getDropConstraintSQL($constraint, $table) - { - if ($constraint instanceof Constraint) { - $constraint = $constraint->getQuotedName($this); - } + public function getDropConstraintSQL($constraint, $table) + { + if ($constraint instanceof Constraint) { + $constraint = $constraint->getQuotedName($this); + } - if ($table instanceof Table) { - $table = $table->getQuotedName($this); - } + if ($table instanceof Table) { + $table = $table->getQuotedName($this); + } - return 'ALTER TABLE ' . $this->espoQuote($table) . ' DROP CONSTRAINT ' . $constraint; - } + return 'ALTER TABLE ' . $this->espoQuote($table) . ' DROP CONSTRAINT ' . $constraint; + } - public function getDropForeignKeySQL($foreignKey, $table) - { - if ($foreignKey instanceof ForeignKeyConstraint) { - $foreignKey = $foreignKey->getQuotedName($this); - } + public function getDropForeignKeySQL($foreignKey, $table) + { + if ($foreignKey instanceof ForeignKeyConstraint) { + $foreignKey = $foreignKey->getQuotedName($this); + } - if ($table instanceof Table) { - $table = $table->getQuotedName($this); - } + if ($table instanceof Table) { + $table = $table->getQuotedName($this); + } - return 'ALTER TABLE ' . $this->espoQuote($table) . ' DROP FOREIGN KEY ' . $foreignKey; - } + return 'ALTER TABLE ' . $this->espoQuote($table) . ' DROP FOREIGN KEY ' . $foreignKey; + } - public function getCreatePrimaryKeySQL(Index $index, $table) - { - if ($table instanceof Table) { - $table = $table->getQuotedName($this); - } + public function getCreatePrimaryKeySQL(Index $index, $table) + { + if ($table instanceof Table) { + $table = $table->getQuotedName($this); + } - return 'ALTER TABLE ' . $this->espoQuote($table) . ' ADD PRIMARY KEY (' . $this->getIndexFieldDeclarationListSQL($index->getQuotedColumns($this)) . ')'; - } - //end: ESPO + return 'ALTER TABLE ' . $this->espoQuote($table) . ' ADD PRIMARY KEY (' . $this->getIndexFieldDeclarationListSQL($index->getQuotedColumns($this)) . ')'; + } + //end: ESPO } \ No newline at end of file diff --git a/application/Espo/Core/Utils/Database/DBAL/Schema/Column.php b/application/Espo/Core/Utils/Database/DBAL/Schema/Column.php index ceb0e9aa97..afabc89dbd 100644 --- a/application/Espo/Core/Utils/Database/DBAL/Schema/Column.php +++ b/application/Espo/Core/Utils/Database/DBAL/Schema/Column.php @@ -26,57 +26,57 @@ namespace Espo\Core\Utils\Database\DBAL\Schema; class Column extends \Doctrine\DBAL\Schema\Column { - /** - * @var boolean - */ - protected $_notnull = false; + /** + * @var boolean + */ + protected $_notnull = false; - /** - * @var boolean - */ - protected $_unique = false; + /** + * @var boolean + */ + protected $_unique = false; - /** - * @param boolean $unique - * - * @return \Doctrine\DBAL\Schema\Column - */ - public function setUnique($unique) - { - $this->_unique = (bool)$unique; + /** + * @param boolean $unique + * + * @return \Doctrine\DBAL\Schema\Column + */ + public function setUnique($unique) + { + $this->_unique = (bool)$unique; - return $this; - } + return $this; + } - /** - * @return boolean - */ - public function getUnique() - { - return $this->_unique; - } + /** + * @return boolean + */ + public function getUnique() + { + return $this->_unique; + } - /** - * @return array - */ - public function toArray() - { - return array_merge(array( - 'name' => $this->_name, - 'type' => $this->_type, - 'default' => $this->_default, - 'notnull' => $this->_notnull, - 'length' => $this->_length, - 'precision' => $this->_precision, - 'scale' => $this->_scale, - 'fixed' => $this->_fixed, - 'unsigned' => $this->_unsigned, - 'autoincrement' => $this->_autoincrement, - 'unique' => $this->_unique, - 'columnDefinition' => $this->_columnDefinition, - 'comment' => $this->_comment, - ), $this->_platformOptions, $this->_customSchemaOptions); - } + /** + * @return array + */ + public function toArray() + { + return array_merge(array( + 'name' => $this->_name, + 'type' => $this->_type, + 'default' => $this->_default, + 'notnull' => $this->_notnull, + 'length' => $this->_length, + 'precision' => $this->_precision, + 'scale' => $this->_scale, + 'fixed' => $this->_fixed, + 'unsigned' => $this->_unsigned, + 'autoincrement' => $this->_autoincrement, + 'unique' => $this->_unique, + 'columnDefinition' => $this->_columnDefinition, + 'comment' => $this->_comment, + ), $this->_platformOptions, $this->_customSchemaOptions); + } } \ No newline at end of file diff --git a/application/Espo/Core/Utils/Database/DBAL/Schema/Comparator.php b/application/Espo/Core/Utils/Database/DBAL/Schema/Comparator.php index 4e9ee27a37..407901aac6 100644 --- a/application/Espo/Core/Utils/Database/DBAL/Schema/Comparator.php +++ b/application/Espo/Core/Utils/Database/DBAL/Schema/Comparator.php @@ -28,86 +28,86 @@ use Doctrine\DBAL\Schema\Column; class Comparator extends \Doctrine\DBAL\Schema\Comparator { - public function diffColumn(Column $column1, Column $column2) - { - $changedProperties = array(); - if ( $column1->getType() != $column2->getType() ) { + public function diffColumn(Column $column1, Column $column2) + { + $changedProperties = array(); + if ( $column1->getType() != $column2->getType() ) { - //espo: fix problem with executing query for custom types - $column1DbTypeName = method_exists($column1->getType(), 'getDbTypeName') ? $column1->getType()->getDbTypeName() : $column1->getType()->getName(); - $column2DbTypeName = method_exists($column2->getType(), 'getDbTypeName') ? $column2->getType()->getDbTypeName() : $column2->getType()->getName(); + //espo: fix problem with executing query for custom types + $column1DbTypeName = method_exists($column1->getType(), 'getDbTypeName') ? $column1->getType()->getDbTypeName() : $column1->getType()->getName(); + $column2DbTypeName = method_exists($column2->getType(), 'getDbTypeName') ? $column2->getType()->getDbTypeName() : $column2->getType()->getName(); - if (strtolower($column1DbTypeName) != strtolower($column2DbTypeName)) { - $changedProperties[] = 'type'; - } - //END: espo - } + if (strtolower($column1DbTypeName) != strtolower($column2DbTypeName)) { + $changedProperties[] = 'type'; + } + //END: espo + } - if ($column1->getNotnull() != $column2->getNotnull()) { - $changedProperties[] = 'notnull'; - } + if ($column1->getNotnull() != $column2->getNotnull()) { + $changedProperties[] = 'notnull'; + } - if ($column1->getDefault() != $column2->getDefault()) { - $changedProperties[] = 'default'; - } + if ($column1->getDefault() != $column2->getDefault()) { + $changedProperties[] = 'default'; + } - if ($column1->getUnsigned() != $column2->getUnsigned()) { - $changedProperties[] = 'unsigned'; - } + if ($column1->getUnsigned() != $column2->getUnsigned()) { + $changedProperties[] = 'unsigned'; + } - if ($column1->getType() instanceof \Doctrine\DBAL\Types\StringType) { - // check if value of length is set at all, default value assumed otherwise. - $length1 = $column1->getLength() ?: 255; - $length2 = $column2->getLength() ?: 255; + if ($column1->getType() instanceof \Doctrine\DBAL\Types\StringType) { + // check if value of length is set at all, default value assumed otherwise. + $length1 = $column1->getLength() ?: 255; + $length2 = $column2->getLength() ?: 255; - /** Espo: column length can be increased only */ - /*if ($length1 != $length2) { - $changedProperties[] = 'length'; - }*/ - if ($length2 > $length1) { - $changedProperties[] = 'length'; - } - /** Espo: end */ + /** Espo: column length can be increased only */ + /*if ($length1 != $length2) { + $changedProperties[] = 'length'; + }*/ + if ($length2 > $length1) { + $changedProperties[] = 'length'; + } + /** Espo: end */ - if ($column1->getFixed() != $column2->getFixed()) { - $changedProperties[] = 'fixed'; - } - } + if ($column1->getFixed() != $column2->getFixed()) { + $changedProperties[] = 'fixed'; + } + } - if ($column1->getType() instanceof \Doctrine\DBAL\Types\DecimalType) { - if (($column1->getPrecision()?:10) != ($column2->getPrecision()?:10)) { - $changedProperties[] = 'precision'; - } - if ($column1->getScale() != $column2->getScale()) { - $changedProperties[] = 'scale'; - } - } + if ($column1->getType() instanceof \Doctrine\DBAL\Types\DecimalType) { + if (($column1->getPrecision()?:10) != ($column2->getPrecision()?:10)) { + $changedProperties[] = 'precision'; + } + if ($column1->getScale() != $column2->getScale()) { + $changedProperties[] = 'scale'; + } + } - if ($column1->getAutoincrement() != $column2->getAutoincrement()) { - $changedProperties[] = 'autoincrement'; - } + if ($column1->getAutoincrement() != $column2->getAutoincrement()) { + $changedProperties[] = 'autoincrement'; + } - // only allow to delete comment if its set to '' not to null. - if ($column1->getComment() !== null && $column1->getComment() != $column2->getComment()) { - $changedProperties[] = 'comment'; - } + // only allow to delete comment if its set to '' not to null. + if ($column1->getComment() !== null && $column1->getComment() != $column2->getComment()) { + $changedProperties[] = 'comment'; + } - $options1 = $column1->getCustomSchemaOptions(); - $options2 = $column2->getCustomSchemaOptions(); + $options1 = $column1->getCustomSchemaOptions(); + $options2 = $column2->getCustomSchemaOptions(); - $commonKeys = array_keys(array_intersect_key($options1, $options2)); + $commonKeys = array_keys(array_intersect_key($options1, $options2)); - foreach ($commonKeys as $key) { - if ($options1[$key] !== $options2[$key]) { - $changedProperties[] = $key; - } - } + foreach ($commonKeys as $key) { + if ($options1[$key] !== $options2[$key]) { + $changedProperties[] = $key; + } + } - $diffKeys = array_keys(array_diff_key($options1, $options2) + array_diff_key($options2, $options1)); + $diffKeys = array_keys(array_diff_key($options1, $options2) + array_diff_key($options2, $options1)); - $changedProperties = array_merge($changedProperties, $diffKeys); + $changedProperties = array_merge($changedProperties, $diffKeys); - return $changedProperties; - } + return $changedProperties; + } } \ No newline at end of file diff --git a/application/Espo/Core/Utils/Database/DBAL/Schema/Schema.php b/application/Espo/Core/Utils/Database/DBAL/Schema/Schema.php index 6cde05516d..d370412579 100644 --- a/application/Espo/Core/Utils/Database/DBAL/Schema/Schema.php +++ b/application/Espo/Core/Utils/Database/DBAL/Schema/Schema.php @@ -25,23 +25,23 @@ namespace Espo\Core\Utils\Database\DBAL\Schema; class Schema extends \Doctrine\DBAL\Schema\Schema { - /** - * Creates a new table. - * - * @param string $tableName - * - * @return \Doctrine\DBAL\Schema\Table - */ - public function createTable($tableName) - { - $table = new Table($tableName); - $this->_addTable($table); + /** + * Creates a new table. + * + * @param string $tableName + * + * @return \Doctrine\DBAL\Schema\Table + */ + public function createTable($tableName) + { + $table = new Table($tableName); + $this->_addTable($table); - foreach ($this->_schemaConfig->getDefaultTableOptions() as $name => $value) { - $table->addOption($name, $value); - } + foreach ($this->_schemaConfig->getDefaultTableOptions() as $name => $value) { + $table->addOption($name, $value); + } - return $table; - } + return $table; + } } \ No newline at end of file diff --git a/application/Espo/Core/Utils/Database/DBAL/Schema/Table.php b/application/Espo/Core/Utils/Database/DBAL/Schema/Table.php index c6c82b1a93..d9b28b5a0b 100644 --- a/application/Espo/Core/Utils/Database/DBAL/Schema/Table.php +++ b/application/Espo/Core/Utils/Database/DBAL/Schema/Table.php @@ -27,20 +27,20 @@ use Doctrine\DBAL\Types\Type; class Table extends \Doctrine\DBAL\Schema\Table { - /** - * @param string $columnName - * @param string $typeName - * @param array $options - * - * @return \Doctrine\DBAL\Schema\Column - */ - public function addColumn($columnName, $typeName, array $options=array()) - { - $column = new Column($columnName, Type::getType($typeName), $options); + /** + * @param string $columnName + * @param string $typeName + * @param array $options + * + * @return \Doctrine\DBAL\Schema\Column + */ + public function addColumn($columnName, $typeName, array $options=array()) + { + $column = new Column($columnName, Type::getType($typeName), $options); - $this->_addColumn($column); + $this->_addColumn($column); - return $column; - } + return $column; + } } \ No newline at end of file diff --git a/application/Espo/Core/Utils/Database/Orm/Base.php b/application/Espo/Core/Utils/Database/Orm/Base.php index fae05139fe..5733e75360 100644 --- a/application/Espo/Core/Utils/Database/Orm/Base.php +++ b/application/Espo/Core/Utils/Database/Orm/Base.php @@ -26,245 +26,245 @@ use Espo\Core\Utils\Util; class Base { - private $itemName = null; + private $itemName = null; - private $entityName = null; + private $entityName = null; - private $metadata; + private $metadata; - private $ormEntityDefs; + private $ormEntityDefs; - private $entityDefs; + private $entityDefs; - public function __construct(\Espo\Core\Utils\Metadata $metadata, array $ormEntityDefs, array $entityDefs) - { - $this->metadata = $metadata; - $this->ormEntityDefs = $ormEntityDefs; - $this->entityDefs = $entityDefs; - } + public function __construct(\Espo\Core\Utils\Metadata $metadata, array $ormEntityDefs, array $entityDefs) + { + $this->metadata = $metadata; + $this->ormEntityDefs = $ormEntityDefs; + $this->entityDefs = $entityDefs; + } - protected function getMetadata() - { - return $this->metadata; - } + protected function getMetadata() + { + return $this->metadata; + } - protected function getOrmEntityDefs() - { - return $this->ormEntityDefs; - } + protected function getOrmEntityDefs() + { + return $this->ormEntityDefs; + } - protected function getEntityDefs() - { - return $this->entityDefs; - } + protected function getEntityDefs() + { + return $this->entityDefs; + } - /** - * Set current Field name OR Link name - * - * @param void - */ - protected function setItemName($itemName) - { - $this->itemName = $itemName; - } + /** + * Set current Field name OR Link name + * + * @param void + */ + protected function setItemName($itemName) + { + $this->itemName = $itemName; + } - /** - * Get current Field name - * - * @return string - */ - protected function getFieldName() - { - return $this->itemName; - } + /** + * Get current Field name + * + * @return string + */ + protected function getFieldName() + { + return $this->itemName; + } - /** - * Get current Link name - * - * @return string - */ - protected function getLinkName() - { - return $this->itemName; - } + /** + * Get current Link name + * + * @return string + */ + protected function getLinkName() + { + return $this->itemName; + } - /** - * Set current Entity Name - * - * @param void - */ - protected function setEntityName($entityName) - { - $this->entityName = $entityName; - } + /** + * Set current Entity Name + * + * @param void + */ + protected function setEntityName($entityName) + { + $this->entityName = $entityName; + } - /** - * Get current Entity Name - * - * @return string - */ - protected function getEntityName() - { - return $this->entityName; - } + /** + * Get current Entity Name + * + * @return string + */ + protected function getEntityName() + { + return $this->entityName; + } - protected function setMethods(array $keyValueList) - { - foreach ($keyValueList as $key => $value) { - $methodName = 'set' . ucfirst($key); - if (method_exists($this, $methodName)) { - $this->$methodName($value); - } - } - } + protected function setMethods(array $keyValueList) + { + foreach ($keyValueList as $key => $value) { + $methodName = 'set' . ucfirst($key); + if (method_exists($this, $methodName)) { + $this->$methodName($value); + } + } + } - /** - * Start process Orm converting for fields/relations - * - * @param string $itemName Field name OR Link name - * @param string $entityName - * @return array - */ - public function process($itemName, $entityName) - { - $inputs = array( - 'itemName' => $itemName, - 'entityName' => $entityName, - ); - $this->setMethods($inputs); + /** + * Start process Orm converting for fields/relations + * + * @param string $itemName Field name OR Link name + * @param string $entityName + * @return array + */ + public function process($itemName, $entityName) + { + $inputs = array( + 'itemName' => $itemName, + 'entityName' => $entityName, + ); + $this->setMethods($inputs); - $convertedDefs = $this->load($itemName, $entityName); + $convertedDefs = $this->load($itemName, $entityName); - $inputs = $this->setArrayValue(null, $inputs); - $this->setMethods($inputs); + $inputs = $this->setArrayValue(null, $inputs); + $this->setMethods($inputs); - return $convertedDefs; - } + return $convertedDefs; + } - /** - * Get Entity Defs by type (entity/orm) - * - * @param boolean $isOrmEntityDefs - * @return array - */ - protected function getDefs($isOrmEntityDefs = false) - { - $entityDefs = $isOrmEntityDefs ? $this->getOrmEntityDefs() : $this->getEntityDefs(); + /** + * Get Entity Defs by type (entity/orm) + * + * @param boolean $isOrmEntityDefs + * @return array + */ + protected function getDefs($isOrmEntityDefs = false) + { + $entityDefs = $isOrmEntityDefs ? $this->getOrmEntityDefs() : $this->getEntityDefs(); - return $entityDefs; - } + return $entityDefs; + } - /** - * Get entity params by name - * - * @param string $entityName - * @param bool $isOrmEntityDefs - * @param mixed $returns - * @return mixed - */ - protected function getEntityParams($entityName = null, $isOrmEntityDefs = false, $returns = null) - { - if (!isset($entityName)) { - $entityName = $this->getEntityName(); - } + /** + * Get entity params by name + * + * @param string $entityName + * @param bool $isOrmEntityDefs + * @param mixed $returns + * @return mixed + */ + protected function getEntityParams($entityName = null, $isOrmEntityDefs = false, $returns = null) + { + if (!isset($entityName)) { + $entityName = $this->getEntityName(); + } - $entityDefs = $this->getDefs($isOrmEntityDefs); + $entityDefs = $this->getDefs($isOrmEntityDefs); - if (isset($entityDefs[$entityName])) { - return $entityDefs[$entityName]; - } + if (isset($entityDefs[$entityName])) { + return $entityDefs[$entityName]; + } - return $returns; - } + return $returns; + } - /** - * Get field params by name for a specified entity - * - * @param string $fieldName - * @param string $entityName - * @param bool $isOrmEntityDefs - * @param mixed $returns - * @return mixed - */ - protected function getFieldParams($fieldName = null, $entityName = null, $isOrmEntityDefs = false, $returns = null) - { - if (!isset($fieldName)) { - $fieldName = $this->getFieldName(); - } - if (!isset($entityName)) { - $entityName = $this->getEntityName(); - } + /** + * Get field params by name for a specified entity + * + * @param string $fieldName + * @param string $entityName + * @param bool $isOrmEntityDefs + * @param mixed $returns + * @return mixed + */ + protected function getFieldParams($fieldName = null, $entityName = null, $isOrmEntityDefs = false, $returns = null) + { + if (!isset($fieldName)) { + $fieldName = $this->getFieldName(); + } + if (!isset($entityName)) { + $entityName = $this->getEntityName(); + } - $entityDefs = $this->getDefs($isOrmEntityDefs); + $entityDefs = $this->getDefs($isOrmEntityDefs); - if (isset($entityDefs[$entityName]) && isset($entityDefs[$entityName]['fields'][$fieldName])) { - return $entityDefs[$entityName]['fields'][$fieldName]; - } + if (isset($entityDefs[$entityName]) && isset($entityDefs[$entityName]['fields'][$fieldName])) { + return $entityDefs[$entityName]['fields'][$fieldName]; + } - return $returns; - } + return $returns; + } - /** - * Get relation params by name for a specified entity - * - * @param string $linkName - * @param string $entityName - * @param bool $isOrmEntityDefs - * @param mixed $returns - * @return mixed - */ - protected function getLinkParams($linkName = null, $entityName = null, $isOrmEntityDefs = false, $returns = null) - { - if (!isset($linkName)) { - $linkName = $this->getLinkName(); - } - if (!isset($entityName)) { - $entityName = $this->getEntityName(); - } + /** + * Get relation params by name for a specified entity + * + * @param string $linkName + * @param string $entityName + * @param bool $isOrmEntityDefs + * @param mixed $returns + * @return mixed + */ + protected function getLinkParams($linkName = null, $entityName = null, $isOrmEntityDefs = false, $returns = null) + { + if (!isset($linkName)) { + $linkName = $this->getLinkName(); + } + if (!isset($entityName)) { + $entityName = $this->getEntityName(); + } - $entityDefs = $this->getDefs($isOrmEntityDefs); - $relationKeyName = $isOrmEntityDefs ? 'relations' : 'links'; + $entityDefs = $this->getDefs($isOrmEntityDefs); + $relationKeyName = $isOrmEntityDefs ? 'relations' : 'links'; - if (isset($entityDefs[$entityName]) && isset($entityDefs[$entityName][$relationKeyName][$linkName])) { - return $entityDefs[$entityName][$relationKeyName][$linkName]; - } + if (isset($entityDefs[$entityName]) && isset($entityDefs[$entityName][$relationKeyName][$linkName])) { + return $entityDefs[$entityName][$relationKeyName][$linkName]; + } - return $returns; - } + return $returns; + } - /** - * Get Foreign field - * - * @param string $name - * @param string $entityName - * @return string - */ - protected function getForeignField($name, $entityName) - { - $foreignField = $this->getMetadata()->get('entityDefs.'.$entityName.'.fields.'.$name); + /** + * Get Foreign field + * + * @param string $name + * @param string $entityName + * @return string + */ + protected function getForeignField($name, $entityName) + { + $foreignField = $this->getMetadata()->get('entityDefs.'.$entityName.'.fields.'.$name); - if ($foreignField['type'] != 'varchar') { - if ($foreignField['type'] == 'personName') { - return array('first' . ucfirst($name), ' ', 'last' . ucfirst($name)); - } - } + if ($foreignField['type'] != 'varchar') { + if ($foreignField['type'] == 'personName') { + return array('first' . ucfirst($name), ' ', 'last' . ucfirst($name)); + } + } - return $name; - } + return $name; + } - /** - * Set a value for all elements of array. So, in result all elements will have the same values - * - * @param string $value - * @param array $array - */ - protected function setArrayValue($inputValue, array $array) - { - foreach ($array as &$value) { - $value = $inputValue; - } + /** + * Set a value for all elements of array. So, in result all elements will have the same values + * + * @param string $value + * @param array $array + */ + protected function setArrayValue($inputValue, array $array) + { + foreach ($array as &$value) { + $value = $inputValue; + } - return $array; - } + return $array; + } } diff --git a/application/Espo/Core/Utils/Database/Orm/Converter.php b/application/Espo/Core/Utils/Database/Orm/Converter.php index 5527ad3e09..d7b38bdf00 100644 --- a/application/Espo/Core/Utils/Database/Orm/Converter.php +++ b/application/Espo/Core/Utils/Database/Orm/Converter.php @@ -23,402 +23,405 @@ namespace Espo\Core\Utils\Database\Orm; use Espo\Core\Utils\Util, - Espo\ORM\Entity; + Espo\ORM\Entity; class Converter { - private $metadata; - private $fileManager; - private $metadataUtils; - - private $relationManager; - - private $entityDefs; - - protected $defaultFieldType = 'varchar'; - protected $defaultNaming = 'postfix'; - - protected $defaultLength = array( - 'varchar' => 255, - 'int' => 11, - ); - - protected $defaultValue = array( - 'bool' => false, - ); - - /* - * //pair Espo => ORM - */ - protected $fieldAccordances = array( - 'type' => 'type', - 'dbType' => 'dbType', - 'maxLength' => 'len', - 'len' => 'len', - 'notNull' => 'notNull', - 'autoincrement' => 'autoincrement', - 'entity' => 'entity', - 'notStorable' => 'notStorable', - 'link' => 'relation', - 'field' => 'foreign', //todo change "foreign" to "field" - 'unique' => 'unique', - 'index' => 'index', - /*'conditions' => 'conditions', - 'additionalColumns' => 'additionalColumns', */ - 'default' => array( - 'condition' => '^javascript:', - 'conditionEquals' => false, - 'value' => array( - 'default' => '{0}', - ), - ), - 'select' => 'select', - 'orderBy' => 'orderBy', - 'where' => 'where', - ); - - protected $idParams = array( - 'dbType' => 'varchar', - 'len' => '24', - ); - - - public function __construct(\Espo\Core\Utils\Metadata $metadata, \Espo\Core\Utils\File\Manager $fileManager) - { - $this->metadata = $metadata; - $this->fileManager = $fileManager; //need to featue with ormHooks. Ex. isFollowed field - - $this->relationManager = new RelationManager($this->metadata); - - $this->metadataUtils = new \Espo\Core\Utils\Metadata\Utils($this->metadata); - - $this->entityDefs = $this->getMetadata()->get('entityDefs'); - } - - - protected function getMetadata() - { - return $this->metadata; - } - - protected function getEntityDefs() - { - return $this->entityDefs; - } - - protected function getFileManager() - { - return $this->fileManager; - } - - protected function getRelationManager() - { - return $this->relationManager; - } - - protected function getMetadataUtils() - { - return $this->metadataUtils; - } - - public function process() - { - $entityDefs = $this->getEntityDefs(); - - $ormMeta = array(); - foreach($entityDefs as $entityName => $entityMeta) { - - if (empty($entityMeta)) { - $GLOBALS['log']->critical('Orm\Converter:process(), Entity:'.$entityName.' - metadata cannot be converted into ORM format'); - continue; - } - - $ormMeta = Util::merge($ormMeta, $this->convertEntity($entityName, $entityMeta)); - } - - $ormMeta = $this->afterProcess($ormMeta); - - return $ormMeta; - } - - protected function convertEntity($entityName, $entityMeta) - { - $ormMeta = array(); - $ormMeta[$entityName] = array( - 'fields' => array( - ), - 'relations' => array( - ), - ); - - $ormMeta[$entityName]['fields'] = $this->convertFields($entityName, $entityMeta); - - $convertedLinks = $this->convertLinks($entityName, $entityMeta, $ormMeta); - - $ormMeta = Util::merge($ormMeta, $convertedLinks); - - return $ormMeta; - } - - public function afterProcess(array $ormMeta) - { - $entityDefs = $this->getEntityDefs(); - - $currentOrmMeta = $ormMeta; - //load custom field definitions and customCodes - foreach($currentOrmMeta as $entityName => $entityParams) { - foreach($entityParams['fields'] as $fieldName => $fieldParams) { - - //load custom field definitions - $fieldType = ucfirst($fieldParams['type']); - $className = '\Espo\Custom\Core\Utils\Database\Orm\Fields\\'.$fieldType; - if (!class_exists($className)) { - $className = '\Espo\Core\Utils\Database\Orm\Fields\\'.$fieldType; - } - - if (class_exists($className) && method_exists($className, 'load')) { - $helperClass = new $className($this->metadata, $ormMeta, $entityDefs); - $fieldResult = $helperClass->process( $fieldName, $entityName ); - if (isset($fieldResult['unset'])) { - $ormMeta = Util::unsetInArray($ormMeta, $fieldResult['unset']); - unset($fieldResult['unset']); - } - - $ormMeta = Util::merge($ormMeta, $fieldResult); - - } //END: load custom field definitions - - //todo move to separate file - //add a field 'isFollowed' for scopes with 'stream => true' - $scopeDefs = $this->getMetadata()->get('scopes.'.$entityName); - if (isset($scopeDefs['stream']) && $scopeDefs['stream']) { - if (!isset($entityParams['fields']['isFollowed'])) { - $ormMeta[$entityName]['fields']['isFollowed'] = array( - 'type' => 'varchar', - 'notStorable' => true, - ); - } - } //END: add a field 'isFollowed' for stream => true - - } - } - - foreach($ormMeta as $entityName => &$entityParams) { - foreach($entityParams['fields'] as $fieldName => &$fieldParams) { - - switch ($fieldParams['type']) { - case 'id': - if ($fieldParams['dbType'] != 'int') { - $fieldParams = array_merge($fieldParams, $this->idParams); - } - break; - - case 'foreignId': - $fieldParams = array_merge($fieldParams, $this->idParams); - $fieldParams['notNull'] = false; - break; - - case 'foreignType': - $fieldParams['dbType'] = Entity::VARCHAR; - $fieldParams['len'] = $this->defaultLength['varchar']; - break; - - case 'bool': - $fieldParams['default'] = isset($fieldParams['default']) ? (bool) $fieldParams['default'] : $this->defaultValue['bool']; - break; - } - } - - } - - return $ormMeta; - } - - /** - * Metadata conversion from Espo format into Doctrine - * - * @param string $entityName - * @param array $entityMeta - * - * @return array - */ - protected function convertFields($entityName, &$entityMeta) - { - $outputMeta = array( - 'id' => array( - 'type' => Entity::ID, - 'dbType' => 'varchar', - ), - 'name' => array( - 'type' => isset($entityMeta['fields']['name']['type']) ? $entityMeta['fields']['name']['type'] : Entity::VARCHAR, - 'notStorable' => true, - ), - ); - - foreach($entityMeta['fields'] as $fieldName => $fieldParams) { - - /** check if "fields" option exists in $fieldMeta */ - $fieldTypeMeta = $this->getMetadataUtils()->getFieldDefsByType($fieldParams); - - if (isset($fieldTypeMeta['fields']) && is_array($fieldTypeMeta['fields'])) { - - foreach($fieldTypeMeta['actualFields'] as $subFieldName) { - - $subField = $this->convertActualFields($entityName, $fieldName, $fieldParams, $subFieldName, $fieldTypeMeta); - - if (!isset($outputMeta[ $subField['naming'] ])) { - $subFieldDefs = $this->convertField($entityName, $subField['name'], $subField['params']); - if ($subFieldDefs !== false) { - $outputMeta[ $subField['naming'] ] = $subFieldDefs; //push fieldDefs to the main array - } - } - } - } else { - $fieldDefs = $this->convertField($entityName, $fieldName, $fieldParams, $fieldTypeMeta); - if ($fieldDefs !== false) { - $outputMeta[$fieldName] = $fieldDefs; //push fieldDefs to the main array - } - } - - /** check and set the linkDefs from 'fields' metadata */ - if (isset($fieldTypeMeta['linkDefs'])) { - $linkDefs = $this->getMetadataUtils()->getLinkDefsInFieldMeta($entityName, $fieldParams, $fieldTypeMeta['linkDefs']); - if (isset($linkDefs)) { - $entityMeta['links'] = Util::merge( array($fieldName => $linkDefs), $entityMeta['links'] ); - } - } - } - - if (!isset($outputMeta['deleted'])) { - $outputMeta['deleted'] = array( - 'type' => Entity::BOOL, - 'default' => false, - ); - } - - return $outputMeta; - } - - protected function convertField($entityName, $fieldName, array $fieldParams, $fieldTypeMeta = null) - { - /** set default type if exists */ - if (!isset($fieldParams['type']) || empty($fieldParams['type'])) { - $GLOBALS['log']->debug('Field type does not exist for '.$entityName.':'.$fieldName.'. Use default type ['.$this->defaultFieldType.']'); - $fieldParams['type'] = $this->defaultFieldType; - } /** END: set default type if exists */ - - /** merge fieldDefs option from field definition */ - if (!isset($fieldTypeMeta)) { - $fieldTypeMeta = $this->getMetadataUtils()->getFieldDefsByType($fieldParams); - } - - if (isset($fieldTypeMeta['fieldDefs'])) { - $fieldParams = Util::merge($fieldParams, $fieldTypeMeta['fieldDefs']); - } - - /** check if need to skip this field in ORM metadata */ - if (isset($fieldParams['skip']) && $fieldParams['skip'] === true) { - return false; - } - - /** if defined 'notNull => false' and 'required => true', then remove 'notNull' */ - if (isset($fieldParams['notNull']) && !$fieldParams['notNull'] && isset($fieldParams['required']) && $fieldParams['required']) { - unset($fieldParams['notNull']); - } - - $fieldDefs = $this->getInitValues($fieldParams); - - /** check if the field need to be saved in database */ - if ( (isset($fieldParams['db']) && $fieldParams['db'] === false) ) { - $fieldDefs['notStorable'] = true; - } - - /** check and set the field length */ - if (!isset($fieldDefs['len']) && in_array($fieldDefs['type'], array_keys($this->defaultLength))) { - $fieldDefs['len'] = $this->defaultLength[$fieldDefs['type']]; - } - - return $fieldDefs; - } - - protected function convertActualFields($entityName, $fieldName, $fieldParams, $subFieldName, $fieldTypeMeta) - { - $subField = array(); - - $subField['params'] = $this->getInitValues($fieldParams); - - if (isset($fieldTypeMeta['fieldDefs'])) { - $subField['params'] = Util::merge($subField['params'], $fieldTypeMeta['fieldDefs']); - } - - //if empty field name, then use the main field - if (trim($subFieldName) == '') { + private $metadata; + private $fileManager; + private $metadataUtils; + + private $relationManager; + + private $entityDefs; + + protected $defaultFieldType = 'varchar'; + protected $defaultNaming = 'postfix'; + + protected $defaultLength = array( + 'varchar' => 255, + 'int' => 11, + ); + + protected $defaultValue = array( + 'bool' => false, + ); + + /* + * //pair Espo => ORM + */ + protected $fieldAccordances = array( + 'type' => 'type', + 'dbType' => 'dbType', + 'maxLength' => 'len', + 'len' => 'len', + 'notNull' => 'notNull', + 'autoincrement' => 'autoincrement', + 'entity' => 'entity', + 'notStorable' => 'notStorable', + 'link' => 'relation', + 'field' => 'foreign', //todo change "foreign" to "field" + 'unique' => 'unique', + 'index' => 'index', + /*'conditions' => 'conditions', + 'additionalColumns' => 'additionalColumns', */ + 'default' => array( + 'condition' => '^javascript:', + 'conditionEquals' => false, + 'value' => array( + 'default' => '{0}', + ), + ), + 'select' => 'select', + 'orderBy' => 'orderBy', + 'where' => 'where', + ); + + protected $idParams = array( + 'dbType' => 'varchar', + 'len' => '24', + ); + + + public function __construct(\Espo\Core\Utils\Metadata $metadata, \Espo\Core\Utils\File\Manager $fileManager) + { + $this->metadata = $metadata; + $this->fileManager = $fileManager; //need to featue with ormHooks. Ex. isFollowed field + + $this->relationManager = new RelationManager($this->metadata); + + $this->metadataUtils = new \Espo\Core\Utils\Metadata\Utils($this->metadata); + + $this->entityDefs = $this->getMetadata()->get('entityDefs'); + } + + + protected function getMetadata() + { + return $this->metadata; + } + + protected function getEntityDefs() + { + return $this->entityDefs; + } + + protected function getFileManager() + { + return $this->fileManager; + } + + protected function getRelationManager() + { + return $this->relationManager; + } + + protected function getMetadataUtils() + { + return $this->metadataUtils; + } + + public function process() + { + $entityDefs = $this->getEntityDefs(); + + $ormMeta = array(); + foreach($entityDefs as $entityName => $entityMeta) { + + if (empty($entityMeta)) { + $GLOBALS['log']->critical('Orm\Converter:process(), Entity:'.$entityName.' - metadata cannot be converted into ORM format'); + continue; + } + + $ormMeta = Util::merge($ormMeta, $this->convertEntity($entityName, $entityMeta)); + } + + $ormMeta = $this->afterProcess($ormMeta); + + return $ormMeta; + } + + protected function convertEntity($entityName, $entityMeta) + { + $ormMeta = array(); + $ormMeta[$entityName] = array( + 'fields' => array( + ), + 'relations' => array( + ), + ); + + $ormMeta[$entityName]['fields'] = $this->convertFields($entityName, $entityMeta); + + $convertedLinks = $this->convertLinks($entityName, $entityMeta, $ormMeta); + + $ormMeta = Util::merge($ormMeta, $convertedLinks); + + return $ormMeta; + } + + public function afterProcess(array $ormMeta) + { + $entityDefs = $this->getEntityDefs(); + + $currentOrmMeta = $ormMeta; + //load custom field definitions and customCodes + foreach($currentOrmMeta as $entityName => $entityParams) { + foreach($entityParams['fields'] as $fieldName => $fieldParams) { + + //load custom field definitions + $fieldType = ucfirst($fieldParams['type']); + $className = '\Espo\Custom\Core\Utils\Database\Orm\Fields\\'.$fieldType; + if (!class_exists($className)) { + $className = '\Espo\Core\Utils\Database\Orm\Fields\\'.$fieldType; + } + + if (class_exists($className) && method_exists($className, 'load')) { + $helperClass = new $className($this->metadata, $ormMeta, $entityDefs); + $fieldResult = $helperClass->process( $fieldName, $entityName ); + if (isset($fieldResult['unset'])) { + $ormMeta = Util::unsetInArray($ormMeta, $fieldResult['unset']); + unset($fieldResult['unset']); + } + + $ormMeta = Util::merge($ormMeta, $fieldResult); + + } //END: load custom field definitions + + //todo move to separate file + //add a field 'isFollowed' for scopes with 'stream => true' + $scopeDefs = $this->getMetadata()->get('scopes.'.$entityName); + if (isset($scopeDefs['stream']) && $scopeDefs['stream']) { + if (!isset($entityParams['fields']['isFollowed'])) { + $ormMeta[$entityName]['fields']['isFollowed'] = array( + 'type' => 'varchar', + 'notStorable' => true, + ); + } + } //END: add a field 'isFollowed' for stream => true + + } + } + + foreach($ormMeta as $entityName => &$entityParams) { + foreach($entityParams['fields'] as $fieldName => &$fieldParams) { + + switch ($fieldParams['type']) { + case 'id': + if ($fieldParams['dbType'] != 'int') { + $fieldParams = array_merge($fieldParams, $this->idParams); + } + break; + + case 'foreignId': + $fieldParams = array_merge($fieldParams, $this->idParams); + $fieldParams['notNull'] = false; + break; + + case 'foreignType': + $fieldParams['dbType'] = Entity::VARCHAR; + $fieldParams['len'] = $this->defaultLength['varchar']; + break; + + case 'bool': + $fieldParams['default'] = isset($fieldParams['default']) ? (bool) $fieldParams['default'] : $this->defaultValue['bool']; + break; + } + } + + } + + return $ormMeta; + } + + /** + * Metadata conversion from Espo format into Doctrine + * + * @param string $entityName + * @param array $entityMeta + * + * @return array + */ + protected function convertFields($entityName, &$entityMeta) + { + $outputMeta = array( + 'id' => array( + 'type' => Entity::ID, + 'dbType' => 'varchar', + ), + 'name' => array( + 'type' => isset($entityMeta['fields']['name']['type']) ? $entityMeta['fields']['name']['type'] : Entity::VARCHAR, + 'notStorable' => true, + ), + ); + + foreach($entityMeta['fields'] as $fieldName => $fieldParams) { + + /** check if "fields" option exists in $fieldMeta */ + $fieldTypeMeta = $this->getMetadataUtils()->getFieldDefsByType($fieldParams); + + if (isset($fieldTypeMeta['fields']) && is_array($fieldTypeMeta['fields'])) { + + foreach($fieldTypeMeta['actualFields'] as $subFieldName) { + + $subField = $this->convertActualFields($entityName, $fieldName, $fieldParams, $subFieldName, $fieldTypeMeta); + + if (!isset($outputMeta[ $subField['naming'] ])) { + $subFieldDefs = $this->convertField($entityName, $subField['name'], $subField['params']); + if ($subFieldDefs !== false) { + $outputMeta[ $subField['naming'] ] = $subFieldDefs; //push fieldDefs to the main array + } + } + } + } else { + $fieldDefs = $this->convertField($entityName, $fieldName, $fieldParams, $fieldTypeMeta); + if ($fieldDefs !== false) { + $outputMeta[$fieldName] = $fieldDefs; //push fieldDefs to the main array + } + } + + /** check and set the linkDefs from 'fields' metadata */ + if (isset($fieldTypeMeta['linkDefs'])) { + $linkDefs = $this->getMetadataUtils()->getLinkDefsInFieldMeta($entityName, $fieldParams, $fieldTypeMeta['linkDefs']); + if (isset($linkDefs)) { + if (!isset($entityMeta['links'])) { + $entityMeta['links'] = array(); + } + $entityMeta['links'] = Util::merge( array($fieldName => $linkDefs), $entityMeta['links'] ); + } + } + } + + if (!isset($outputMeta['deleted'])) { + $outputMeta['deleted'] = array( + 'type' => Entity::BOOL, + 'default' => false, + ); + } + + return $outputMeta; + } + + protected function convertField($entityName, $fieldName, array $fieldParams, $fieldTypeMeta = null) + { + /** set default type if exists */ + if (!isset($fieldParams['type']) || empty($fieldParams['type'])) { + $GLOBALS['log']->debug('Field type does not exist for '.$entityName.':'.$fieldName.'. Use default type ['.$this->defaultFieldType.']'); + $fieldParams['type'] = $this->defaultFieldType; + } /** END: set default type if exists */ + + /** merge fieldDefs option from field definition */ + if (!isset($fieldTypeMeta)) { + $fieldTypeMeta = $this->getMetadataUtils()->getFieldDefsByType($fieldParams); + } + + if (isset($fieldTypeMeta['fieldDefs'])) { + $fieldParams = Util::merge($fieldParams, $fieldTypeMeta['fieldDefs']); + } + + /** check if need to skip this field in ORM metadata */ + if (isset($fieldParams['skip']) && $fieldParams['skip'] === true) { + return false; + } + + /** if defined 'notNull => false' and 'required => true', then remove 'notNull' */ + if (isset($fieldParams['notNull']) && !$fieldParams['notNull'] && isset($fieldParams['required']) && $fieldParams['required']) { + unset($fieldParams['notNull']); + } + + $fieldDefs = $this->getInitValues($fieldParams); + + /** check if the field need to be saved in database */ + if ( (isset($fieldParams['db']) && $fieldParams['db'] === false) ) { + $fieldDefs['notStorable'] = true; + } + + /** check and set the field length */ + if (!isset($fieldDefs['len']) && in_array($fieldDefs['type'], array_keys($this->defaultLength))) { + $fieldDefs['len'] = $this->defaultLength[$fieldDefs['type']]; + } + + return $fieldDefs; + } + + protected function convertActualFields($entityName, $fieldName, $fieldParams, $subFieldName, $fieldTypeMeta) + { + $subField = array(); + + $subField['params'] = $this->getInitValues($fieldParams); + + if (isset($fieldTypeMeta['fieldDefs'])) { + $subField['params'] = Util::merge($subField['params'], $fieldTypeMeta['fieldDefs']); + } + + //if empty field name, then use the main field + if (trim($subFieldName) == '') { + + $subField['name'] = $fieldName; + $subField['naming'] = $fieldName; + + } else { + + $namingType = isset($fieldTypeMeta['naming']) ? $fieldTypeMeta['naming'] : $this->defaultNaming; + + $subField['name'] = $subFieldName; + $subField['naming'] = Util::getNaming($fieldName, $subFieldName, $namingType); + if (isset($fieldTypeMeta['fields'][$subFieldName])) { + $subField['params'] = Util::merge($subField['params'], $fieldTypeMeta['fields'][$subFieldName]); + } + + } + + return $subField; + } + + protected function convertLinks($entityName, $entityMeta, $ormMeta) + { + if (!isset($entityMeta['links'])) { + return array(); + } + + $entityDefs = $this->getEntityDefs(); + + $relationships = array(); + foreach($entityMeta['links'] as $linkName => $linkParams) { - $subField['name'] = $fieldName; - $subField['naming'] = $fieldName; - - } else { - - $namingType = isset($fieldTypeMeta['naming']) ? $fieldTypeMeta['naming'] : $this->defaultNaming; - - $subField['name'] = $subFieldName; - $subField['naming'] = Util::getNaming($fieldName, $subFieldName, $namingType); - if (isset($fieldTypeMeta['fields'][$subFieldName])) { - $subField['params'] = Util::merge($subField['params'], $fieldTypeMeta['fields'][$subFieldName]); - } - - } - - return $subField; - } - - protected function convertLinks($entityName, $entityMeta, $ormMeta) - { - if (!isset($entityMeta['links'])) { - return array(); - } + $convertedLink = $this->getRelationManager()->convert($linkName, $linkParams, $entityName, $ormMeta); - $entityDefs = $this->getEntityDefs(); + if (isset($convertedLink)) { + $relationships = Util::merge($convertedLink, $relationships); + } + } - $relationships = array(); - foreach($entityMeta['links'] as $linkName => $linkParams) { + return $relationships; + } - $convertedLink = $this->getRelationManager()->convert($linkName, $linkParams, $entityName, $ormMeta); + protected function getInitValues(array $fieldParams) + { + $values = array(); + foreach($this->fieldAccordances as $espoType => $ormType) { - if (isset($convertedLink)) { - $relationships = Util::merge($convertedLink, $relationships); - } - } + if (isset($fieldParams[$espoType])) { - return $relationships; - } + if (is_array($ormType)) { - protected function getInitValues(array $fieldParams) - { - $values = array(); - foreach($this->fieldAccordances as $espoType => $ormType) { + $conditionRes = false; + if (!is_array($fieldParams[$espoType])) { + $conditionRes = preg_match('/'.$ormType['condition'].'/i', $fieldParams[$espoType]); + } - if (isset($fieldParams[$espoType])) { + if (!$conditionRes || ($conditionRes && $conditionRes === $ormType['conditionEquals']) ) { + $value = is_array($fieldParams[$espoType]) ? json_encode($fieldParams[$espoType]) : $fieldParams[$espoType]; + $values = Util::merge( $values, Util::replaceInArray('{0}', $value, $ormType['value']) ); + } + } else { + $values[$ormType] = $fieldParams[$espoType]; + } - if (is_array($ormType)) { + } + } - $conditionRes = false; - if (!is_array($fieldParams[$espoType])) { - $conditionRes = preg_match('/'.$ormType['condition'].'/i', $fieldParams[$espoType]); - } - - if (!$conditionRes || ($conditionRes && $conditionRes === $ormType['conditionEquals']) ) { - $value = is_array($fieldParams[$espoType]) ? json_encode($fieldParams[$espoType]) : $fieldParams[$espoType]; - $values = Util::merge( $values, Util::replaceInArray('{0}', $value, $ormType['value']) ); - } - } else { - $values[$ormType] = $fieldParams[$espoType]; - } - - } - } - - return $values; - } + return $values; + } } diff --git a/application/Espo/Core/Utils/Database/Orm/Fields/Currency.php b/application/Espo/Core/Utils/Database/Orm/Fields/Currency.php index f3d56094a2..12013e34b1 100644 --- a/application/Espo/Core/Utils/Database/Orm/Fields/Currency.php +++ b/application/Espo/Core/Utils/Database/Orm/Fields/Currency.php @@ -26,39 +26,39 @@ use Espo\Core\Utils\Util; class Currency extends \Espo\Core\Utils\Database\Orm\Base { - protected function load($fieldName, $entityName) - { - $converedFieldName = $fieldName . 'Converted'; - - $currencyColumnName = Util::toUnderScore($fieldName); - - $alias = Util::toUnderScore($fieldName) . "_currency_alias"; - - return array( - $entityName => array( - 'fields' => array( - $fieldName => array( - "type" => "float", - "orderBy" => $converedFieldName . " {direction}" - ), - $fieldName . 'Converted' => array( - 'type' => 'float', - 'select' => Util::toUnderScore($entityName) . "." . $currencyColumnName . " * {$alias}.rate" , - 'where' => - array ( - "=" => Util::toUnderScore($entityName) . "." . $currencyColumnName . " * {$alias}.rate = {value}", - ">" => Util::toUnderScore($entityName) . "." . $currencyColumnName . " * {$alias}.rate > {value}", - "<" => Util::toUnderScore($entityName) . "." . $currencyColumnName . " * {$alias}.rate < {value}", - ">=" => Util::toUnderScore($entityName) . "." . $currencyColumnName . " * {$alias}.rate >= {value}", - "<=" => Util::toUnderScore($entityName) . "." . $currencyColumnName . " * {$alias}.rate <= {value}", - "<>" => Util::toUnderScore($entityName) . "." . $currencyColumnName . " * {$alias}.rate <> {value}" - ), - 'notStorable' => true, - 'orderBy' => $converedFieldName . " {direction}" - ), - ), - ), - ); - } + protected function load($fieldName, $entityName) + { + $converedFieldName = $fieldName . 'Converted'; + + $currencyColumnName = Util::toUnderScore($fieldName); + + $alias = Util::toUnderScore($fieldName) . "_currency_alias"; + + return array( + $entityName => array( + 'fields' => array( + $fieldName => array( + "type" => "float", + "orderBy" => $converedFieldName . " {direction}" + ), + $fieldName . 'Converted' => array( + 'type' => 'float', + 'select' => Util::toUnderScore($entityName) . "." . $currencyColumnName . " * {$alias}.rate" , + 'where' => + array ( + "=" => Util::toUnderScore($entityName) . "." . $currencyColumnName . " * {$alias}.rate = {value}", + ">" => Util::toUnderScore($entityName) . "." . $currencyColumnName . " * {$alias}.rate > {value}", + "<" => Util::toUnderScore($entityName) . "." . $currencyColumnName . " * {$alias}.rate < {value}", + ">=" => Util::toUnderScore($entityName) . "." . $currencyColumnName . " * {$alias}.rate >= {value}", + "<=" => Util::toUnderScore($entityName) . "." . $currencyColumnName . " * {$alias}.rate <= {value}", + "<>" => Util::toUnderScore($entityName) . "." . $currencyColumnName . " * {$alias}.rate <> {value}" + ), + 'notStorable' => true, + 'orderBy' => $converedFieldName . " {direction}" + ), + ), + ), + ); + } } diff --git a/application/Espo/Core/Utils/Database/Orm/Fields/Email.php b/application/Espo/Core/Utils/Database/Orm/Fields/Email.php index 0ecfc60968..422e34557b 100644 --- a/application/Espo/Core/Utils/Database/Orm/Fields/Email.php +++ b/application/Espo/Core/Utils/Database/Orm/Fields/Email.php @@ -24,74 +24,74 @@ namespace Espo\Core\Utils\Database\Orm\Fields; class Email extends \Espo\Core\Utils\Database\Orm\Base { - protected function load($fieldName, $entityName) - { - return array( - $entityName => array( - 'fields' => array( - $fieldName => array( - 'select' => 'email_address.name', - 'where' => - array ( - 'LIKE' => \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 LIKE {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} - )", - '<>' => \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}', - ), - $fieldName .'Data' => array( - 'type' => 'text', - 'notStorable' => true - ), - ), - 'relations' => array( - $fieldName.'es' => array( - 'type' => 'manyMany', - 'entity' => 'EmailAddress', - 'relationName' => 'entityEmailAddress', - 'midKeys' => array( - 'entity_id', - 'email_address_id', - ), - 'conditions' => array( - 'entityType' => $entityName, - ), - 'additionalColumns' => array( - 'entityType' => array( - 'type' => 'varchar', - 'len' => 100, - ), - 'primary' => array( - 'type' => 'bool', - 'default' => false, - ), - ), - ), - ), - ), - ); - } + protected function load($fieldName, $entityName) + { + return array( + $entityName => array( + 'fields' => array( + $fieldName => array( + 'select' => 'email_address.name', + 'where' => + array ( + 'LIKE' => \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 LIKE {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} + )", + '<>' => \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}', + ), + $fieldName .'Data' => array( + 'type' => 'text', + 'notStorable' => true + ), + ), + 'relations' => array( + $fieldName.'es' => array( + 'type' => 'manyMany', + 'entity' => 'EmailAddress', + 'relationName' => 'entityEmailAddress', + 'midKeys' => array( + 'entity_id', + 'email_address_id', + ), + 'conditions' => array( + 'entityType' => $entityName, + ), + 'additionalColumns' => array( + 'entityType' => array( + 'type' => 'varchar', + 'len' => 100, + ), + 'primary' => array( + 'type' => 'bool', + 'default' => false, + ), + ), + ), + ), + ), + ); + } } diff --git a/application/Espo/Core/Utils/Database/Orm/Fields/LinkMultiple.php b/application/Espo/Core/Utils/Database/Orm/Fields/LinkMultiple.php index fba8cfce4b..62e42b261e 100644 --- a/application/Espo/Core/Utils/Database/Orm/Fields/LinkMultiple.php +++ b/application/Espo/Core/Utils/Database/Orm/Fields/LinkMultiple.php @@ -24,38 +24,38 @@ namespace Espo\Core\Utils\Database\Orm\Fields; class LinkMultiple extends \Espo\Core\Utils\Database\Orm\Base { - protected function load($fieldName, $entityName) - { - $data = array( - $entityName => array ( - 'fields' => array( - $fieldName.'Ids' => array( - 'type' => 'varchar', - 'notStorable' => true, - ), - $fieldName.'Names' => array( - 'type' => 'varchar', - 'notStorable' => true, - ), - ), - ), - 'unset' => array( - $entityName => array( - 'fields.'.$fieldName, - ), - ), - ); + protected function load($fieldName, $entityName) + { + $data = array( + $entityName => array ( + 'fields' => array( + $fieldName.'Ids' => array( + 'type' => 'varchar', + 'notStorable' => true, + ), + $fieldName.'Names' => array( + 'type' => 'varchar', + 'notStorable' => true, + ), + ), + ), + 'unset' => array( + $entityName => array( + 'fields.'.$fieldName, + ), + ), + ); - $columns = $this->getMetadata()->get("entityDefs.{$entityName}.fields.{$fieldName}.columns"); - if (!empty($columns)) { - $data[$entityName]['fields'][$fieldName . 'Columns'] = array( - 'type' => 'varchar', - 'notStorable' => true, - ); - } + $columns = $this->getMetadata()->get("entityDefs.{$entityName}.fields.{$fieldName}.columns"); + if (!empty($columns)) { + $data[$entityName]['fields'][$fieldName . 'Columns'] = array( + 'type' => 'varchar', + 'notStorable' => true, + ); + } - return $data; - } + return $data; + } } diff --git a/application/Espo/Core/Utils/Database/Orm/Fields/LinkParent.php b/application/Espo/Core/Utils/Database/Orm/Fields/LinkParent.php index 34998bbd61..4006275eb0 100644 --- a/application/Espo/Core/Utils/Database/Orm/Fields/LinkParent.php +++ b/application/Espo/Core/Utils/Database/Orm/Fields/LinkParent.php @@ -24,28 +24,28 @@ namespace Espo\Core\Utils\Database\Orm\Fields; class LinkParent extends \Espo\Core\Utils\Database\Orm\Base { - protected function load($fieldName, $entityName) - { - return array( - $entityName => array ( - 'fields' => array( - $fieldName.'Id' => array( - 'type' => 'foreignId', - 'index' => $fieldName, - ), - $fieldName.'Type' => array( - 'type' => 'foreignType', - 'notNull' => false, - 'index' => $fieldName, - ), - $fieldName.'Name' => array( - 'type' => 'varchar', - 'notStorable' => true, - ), - ), - ), - ); - } + protected function load($fieldName, $entityName) + { + return array( + $entityName => array ( + 'fields' => array( + $fieldName.'Id' => array( + 'type' => 'foreignId', + 'index' => $fieldName, + ), + $fieldName.'Type' => array( + 'type' => 'foreignType', + 'notNull' => false, + 'index' => $fieldName, + ), + $fieldName.'Name' => array( + 'type' => 'varchar', + 'notStorable' => true, + ), + ), + ), + ); + } } \ No newline at end of file diff --git a/application/Espo/Core/Utils/Database/Orm/Fields/PersonName.php b/application/Espo/Core/Utils/Database/Orm/Fields/PersonName.php index b1bb17c231..b924a73aad 100644 --- a/application/Espo/Core/Utils/Database/Orm/Fields/PersonName.php +++ b/application/Espo/Core/Utils/Database/Orm/Fields/PersonName.php @@ -26,65 +26,65 @@ use Espo\Core\Utils\Util; class PersonName extends \Espo\Core\Utils\Database\Orm\Base { - protected function load($fieldName, $entityName) - { - $foreignField = array('first' . ucfirst($fieldName), ' ', 'last' . ucfirst($fieldName)); - - $tableName = Util::toUnderScore($entityName); + protected function load($fieldName, $entityName) + { + $foreignField = array('first' . ucfirst($fieldName), ' ', 'last' . ucfirst($fieldName)); + + $tableName = Util::toUnderScore($entityName); - $fullList = array(); //contains empty string (" ") like delimiter - $fullListReverse = array(); //reverse of $fullList - $fieldList = array(); //doesn't contain empty string (" ") like delimiter - $like = array(); - $equal = array(); + $fullList = array(); //contains empty string (" ") like delimiter + $fullListReverse = array(); //reverse of $fullList + $fieldList = array(); //doesn't contain empty string (" ") like delimiter + $like = array(); + $equal = array(); - foreach($foreignField as $foreignFieldName) { + foreach($foreignField as $foreignFieldName) { - $fieldNameTrimmed = trim($foreignFieldName); - if (!empty($fieldNameTrimmed)) { - $columnName = $tableName.'.'.Util::toUnderScore($fieldNameTrimmed); + $fieldNameTrimmed = trim($foreignFieldName); + if (!empty($fieldNameTrimmed)) { + $columnName = $tableName.'.'.Util::toUnderScore($fieldNameTrimmed); - $fullList[] = $fieldList[] = $columnName; - $like[] = $columnName." LIKE {value}"; - $equal[] = $columnName." = {value}"; - } else { - $fullList[] = "'".$foreignFieldName."'"; - } - } + $fullList[] = $fieldList[] = $columnName; + $like[] = $columnName." LIKE {value}"; + $equal[] = $columnName." = {value}"; + } else { + $fullList[] = "'".$foreignFieldName."'"; + } + } - $fullListReverse = array_reverse($fullList); + $fullListReverse = array_reverse($fullList); - return array( - $entityName => array ( - 'fields' => array( - $fieldName => array( - 'type' => 'varchar', - 'select' => $this->getSelect($fullList), - 'where' => array( - 'LIKE' => "(".implode(" OR ", $like)." OR CONCAT(".implode(", ", $fullList).") LIKE {value} OR CONCAT(".implode(", ", $fullListReverse).") LIKE {value})", - '=' => "(".implode(" OR ", $equal)." OR CONCAT(".implode(", ", $fullList).") = {value} OR CONCAT(".implode(", ", $fullListReverse).") = {value})", - ), - 'orderBy' => implode(", ", array_map(function ($item) {return $item . ' {direction}';}, $fieldList)), - ), - ), - ), - ); - } + return array( + $entityName => array ( + 'fields' => array( + $fieldName => array( + 'type' => 'varchar', + 'select' => $this->getSelect($fullList), + 'where' => array( + 'LIKE' => "(".implode(" OR ", $like)." OR CONCAT(".implode(", ", $fullList).") LIKE {value} OR CONCAT(".implode(", ", $fullListReverse).") LIKE {value})", + '=' => "(".implode(" OR ", $equal)." OR CONCAT(".implode(", ", $fullList).") = {value} OR CONCAT(".implode(", ", $fullListReverse).") = {value})", + ), + 'orderBy' => implode(", ", array_map(function ($item) {return $item . ' {direction}';}, $fieldList)), + ), + ), + ), + ); + } - protected function getSelect(array $fullList) - { - foreach ($fullList as &$item) { + protected function getSelect(array $fullList) + { + foreach ($fullList as &$item) { - $rowItem = trim($item, " '"); + $rowItem = trim($item, " '"); - if (!empty($rowItem)) { - $item = "IFNULL(".$item.", '')"; - } - } + if (!empty($rowItem)) { + $item = "IFNULL(".$item.", '')"; + } + } - $select = "TRIM(CONCAT(".implode(", ", $fullList)."))"; + $select = "TRIM(CONCAT(".implode(", ", $fullList)."))"; - return $select; - } + return $select; + } } diff --git a/application/Espo/Core/Utils/Database/Orm/Fields/Phone.php b/application/Espo/Core/Utils/Database/Orm/Fields/Phone.php index fb0a863b26..8e5baa60fa 100644 --- a/application/Espo/Core/Utils/Database/Orm/Fields/Phone.php +++ b/application/Espo/Core/Utils/Database/Orm/Fields/Phone.php @@ -24,74 +24,74 @@ namespace Espo\Core\Utils\Database\Orm\Fields; class Phone extends \Espo\Core\Utils\Database\Orm\Base { - protected function load($fieldName, $entityName) - { - return array( - $entityName => array( - 'fields' => array( - $fieldName => array( - 'select' => 'phone_number.name', - 'where' => - array ( - 'LIKE' => \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 LIKE {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} - )", - '<>' => \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}', - ), - $fieldName .'Data' => array( - 'type' => 'text', - 'notStorable' => true - ), - ), - 'relations' => array( - $fieldName.'s' => array( - 'type' => 'manyMany', - 'entity' => 'PhoneNumber', - 'relationName' => 'entityPhoneNumber', - 'midKeys' => array( - 'entity_id', - 'phone_number_id', - ), - 'conditions' => array( - 'entityType' => $entityName, - ), - 'additionalColumns' => array( - 'entityType' => array( - 'type' => 'varchar', - 'len' => 100, - ), - 'primary' => array( - 'type' => 'bool', - 'default' => false, - ), - ), - ), - ), - ), - ); - } + protected function load($fieldName, $entityName) + { + return array( + $entityName => array( + 'fields' => array( + $fieldName => array( + 'select' => 'phone_number.name', + 'where' => + array ( + 'LIKE' => \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 LIKE {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} + )", + '<>' => \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}', + ), + $fieldName .'Data' => array( + 'type' => 'text', + 'notStorable' => true + ), + ), + 'relations' => array( + $fieldName.'s' => array( + 'type' => 'manyMany', + 'entity' => 'PhoneNumber', + 'relationName' => 'entityPhoneNumber', + 'midKeys' => array( + 'entity_id', + 'phone_number_id', + ), + 'conditions' => array( + 'entityType' => $entityName, + ), + 'additionalColumns' => array( + 'entityType' => array( + 'type' => 'varchar', + 'len' => 100, + ), + 'primary' => array( + 'type' => 'bool', + 'default' => false, + ), + ), + ), + ), + ), + ); + } } diff --git a/application/Espo/Core/Utils/Database/Orm/RelationManager.php b/application/Espo/Core/Utils/Database/Orm/RelationManager.php index 14b0cc15f5..7c952e194e 100644 --- a/application/Espo/Core/Utils/Database/Orm/RelationManager.php +++ b/application/Espo/Core/Utils/Database/Orm/RelationManager.php @@ -26,118 +26,118 @@ use Espo\Core\Utils\Util; class RelationManager { - private $metadata; + private $metadata; - private $entityDefs; + private $entityDefs; - public function __construct(\Espo\Core\Utils\Metadata $metadata) - { - $this->metadata = $metadata; + public function __construct(\Espo\Core\Utils\Metadata $metadata) + { + $this->metadata = $metadata; - $this->entityDefs = $this->getMetadata()->get('entityDefs'); - } + $this->entityDefs = $this->getMetadata()->get('entityDefs'); + } - protected function getMetadata() - { - return $this->metadata; - } + protected function getMetadata() + { + return $this->metadata; + } - protected function getEntityDefs() - { - return $this->entityDefs; - } + protected function getEntityDefs() + { + return $this->entityDefs; + } - public function getLinkEntityName($entityName, $linkParams) - { - return isset($linkParams['entity']) ? $linkParams['entity'] : $entityName; - } + public function getLinkEntityName($entityName, $linkParams) + { + return isset($linkParams['entity']) ? $linkParams['entity'] : $entityName; + } - public function isRelationExists($relationName) - { - if ($this->getRelationClass($relationName) !== false) { - return true; - } + public function isRelationExists($relationName) + { + if ($this->getRelationClass($relationName) !== false) { + return true; + } - return false; - } + return false; + } - protected function getRelationClass($relationName) - { - $relationName = ucfirst($relationName); + protected function getRelationClass($relationName) + { + $relationName = ucfirst($relationName); - $className = '\Espo\Custom\Core\Utils\Database\Orm\Relations\\'.$relationName; - if (!class_exists($className)) { - $className = '\Espo\Core\Utils\Database\Orm\Relations\\'.$relationName; - } + $className = '\Espo\Custom\Core\Utils\Database\Orm\Relations\\'.$relationName; + if (!class_exists($className)) { + $className = '\Espo\Core\Utils\Database\Orm\Relations\\'.$relationName; + } - if (class_exists($className)) { - return $className; - } + if (class_exists($className)) { + return $className; + } - return false; - } + return false; + } - protected function isMethodExists($relationName) - { - $className = $this->getRelationClass($relationName); + protected function isMethodExists($relationName) + { + $className = $this->getRelationClass($relationName); - return method_exists($className, 'load'); - } + return method_exists($className, 'load'); + } - /** - * Get foreign Link - * - * @param string $parentLinkName - * @param array $parentLinkParams - * @param array $currentEntityDefs - * - * @return array - in format array('name', 'params') - */ - private function getForeignLink($parentLinkName, $parentLinkParams, $currentEntityDefs) - { - if (isset($parentLinkParams['foreign']) && isset($currentEntityDefs['links'][$parentLinkParams['foreign']])) { - return array( - 'name' => $parentLinkParams['foreign'], - 'params' => $currentEntityDefs['links'][$parentLinkParams['foreign']], - ); - } + /** + * Get foreign Link + * + * @param string $parentLinkName + * @param array $parentLinkParams + * @param array $currentEntityDefs + * + * @return array - in format array('name', 'params') + */ + private function getForeignLink($parentLinkName, $parentLinkParams, $currentEntityDefs) + { + if (isset($parentLinkParams['foreign']) && isset($currentEntityDefs['links'][$parentLinkParams['foreign']])) { + return array( + 'name' => $parentLinkParams['foreign'], + 'params' => $currentEntityDefs['links'][$parentLinkParams['foreign']], + ); + } - return false; - } + return false; + } - public function convert($linkName, $linkParams, $entityName, $ormMeta) - { - $entityDefs = $this->getEntityDefs(); + public function convert($linkName, $linkParams, $entityName, $ormMeta) + { + $entityDefs = $this->getEntityDefs(); - $foreignEntityName = $this->getLinkEntityName($entityName, $linkParams); - $foreignLink = $this->getForeignLink($linkName, $linkParams, $entityDefs[$foreignEntityName]); + $foreignEntityName = $this->getLinkEntityName($entityName, $linkParams); + $foreignLink = $this->getForeignLink($linkName, $linkParams, $entityDefs[$foreignEntityName]); - $currentType = $linkParams['type']; + $currentType = $linkParams['type']; - $method = $currentType; - if ($foreignLink !== false) { - $method .= '-'.$foreignLink['params']['type']; - } - $method = Util::toCamelCase($method); + $method = $currentType; + if ($foreignLink !== false) { + $method .= '_' . $foreignLink['params']['type']; + } + $method = Util::toCamelCase($method); - $relationName = $this->isRelationExists($method) ? $method /*hasManyHasMany*/ : $currentType /*hasMany*/; + $relationName = $this->isRelationExists($method) ? $method /*hasManyHasMany*/ : $currentType /*hasMany*/; - //relationDefs defined in separate file - if (isset($linkParams['relationName']) && $this->isMethodExists($linkParams['relationName'])) { - $className = $this->getRelationClass($linkParams['relationName']); - } else if ($this->isMethodExists($relationName)) { - $className = $this->getRelationClass($relationName); - } + //relationDefs defined in separate file + if (isset($linkParams['relationName']) && $this->isMethodExists($linkParams['relationName'])) { + $className = $this->getRelationClass($linkParams['relationName']); + } else if ($this->isMethodExists($relationName)) { + $className = $this->getRelationClass($relationName); + } - if (isset($className) && $className !== false) { - $helperClass = new $className($this->metadata, $ormMeta, $entityDefs); - return $helperClass->process($linkName, $entityName, $foreignLink['name'], $foreignEntityName); - } - //END: relationDefs defined in separate file + if (isset($className) && $className !== false) { + $helperClass = new $className($this->metadata, $ormMeta, $entityDefs); + return $helperClass->process($linkName, $entityName, $foreignLink['name'], $foreignEntityName); + } + //END: relationDefs defined in separate file - return null; - } + return null; + } } \ No newline at end of file diff --git a/application/Espo/Core/Utils/Database/Orm/Relations/Base.php b/application/Espo/Core/Utils/Database/Orm/Relations/Base.php index 5348e946f3..66c8ee5e9e 100644 --- a/application/Espo/Core/Utils/Database/Orm/Relations/Base.php +++ b/application/Espo/Core/Utils/Database/Orm/Relations/Base.php @@ -24,128 +24,128 @@ namespace Espo\Core\Utils\Database\Orm\Relations; class Base extends \Espo\Core\Utils\Database\Orm\Base { - private $params; + private $params; - private $foreignParams; + private $foreignParams; - protected $foreignLinkName = null; - protected $foreignEntityName = null; + protected $foreignLinkName = null; + protected $foreignEntityName = null; - protected $allowedParams = array( - 'relationName', - 'conditions', - 'additionalColumns', - 'midKeys', - ); + protected $allowedParams = array( + 'relationName', + 'conditions', + 'additionalColumns', + 'midKeys', + ); - protected function getParams() - { - return $this->params; - } + protected function getParams() + { + return $this->params; + } - protected function getForeignParams() - { - return $this->foreignParams; - } + protected function getForeignParams() + { + return $this->foreignParams; + } - protected function setParams(array $params) - { - $this->params = $params; - } + protected function setParams(array $params) + { + $this->params = $params; + } - protected function setForeignParams(array $foreignParams) - { - $this->foreignParams = $foreignParams; - } + protected function setForeignParams(array $foreignParams) + { + $this->foreignParams = $foreignParams; + } - protected function setForeignLinkName($foreignLinkName) - { - $this->foreignLinkName = $foreignLinkName; - } + protected function setForeignLinkName($foreignLinkName) + { + $this->foreignLinkName = $foreignLinkName; + } - protected function getForeignLinkName() - { - return $this->foreignLinkName; - } + protected function getForeignLinkName() + { + return $this->foreignLinkName; + } - protected function setForeignEntityName($foreignEntityName) - { - $this->foreignEntityName = $foreignEntityName; - } + protected function setForeignEntityName($foreignEntityName) + { + $this->foreignEntityName = $foreignEntityName; + } - protected function getForeignEntityName() - { - return $this->foreignEntityName; - } + protected function getForeignEntityName() + { + return $this->foreignEntityName; + } - protected function getForeignLinkParams() - { - $foreignLinkName = $this->getForeignLinkName(); - $foreignEntityName = $this->getForeignEntityName(); - $foreignLinkParams = $this->getLinkParams($foreignLinkName, $foreignEntityName); + protected function getForeignLinkParams() + { + $foreignLinkName = $this->getForeignLinkName(); + $foreignEntityName = $this->getForeignEntityName(); + $foreignLinkParams = $this->getLinkParams($foreignLinkName, $foreignEntityName); - return $foreignLinkParams; - } + return $foreignLinkParams; + } - public function process($linkName, $entityName, $foreignLinkName, $foreignEntityName) - { - $inputs = array( - 'itemName' => $linkName, - 'entityName' => $entityName, - 'foreignLinkName' => $foreignLinkName, - 'foreignEntityName' => $foreignEntityName, - ); - $this->setMethods($inputs); + public function process($linkName, $entityName, $foreignLinkName, $foreignEntityName) + { + $inputs = array( + 'itemName' => $linkName, + 'entityName' => $entityName, + 'foreignLinkName' => $foreignLinkName, + 'foreignEntityName' => $foreignEntityName, + ); + $this->setMethods($inputs); - $convertedDefs = $this->load($linkName, $entityName); - $convertedDefs = $this->mergeAllowedParams($convertedDefs); + $convertedDefs = $this->load($linkName, $entityName); + $convertedDefs = $this->mergeAllowedParams($convertedDefs); - $inputs = $this->setArrayValue(null, $inputs); - $this->setMethods($inputs); + $inputs = $this->setArrayValue(null, $inputs); + $this->setMethods($inputs); - return $convertedDefs; - } + return $convertedDefs; + } - private function mergeAllowedParams($loads) - { - $linkName = $this->getLinkName(); - $entityName = $this->getEntityName(); + private function mergeAllowedParams($loads) + { + $linkName = $this->getLinkName(); + $entityName = $this->getEntityName(); - if (!empty($this->allowedParams)) { - $linkParams = &$loads[$entityName]['relations'][$linkName]; + if (!empty($this->allowedParams)) { + $linkParams = &$loads[$entityName]['relations'][$linkName]; - foreach ($this->allowedParams as $name) { + foreach ($this->allowedParams as $name) { - $additionalParrams = $this->getAllowedAdditionalParams($name); + $additionalParrams = $this->getAllowedAdditionalParams($name); - if (isset($additionalParrams) && !isset($linkParams[$name])) { - $linkParams[$name] = $additionalParrams; - } - } - } + if (isset($additionalParrams) && !isset($linkParams[$name])) { + $linkParams[$name] = $additionalParrams; + } + } + } - return $loads; - } + return $loads; + } - private function getAllowedAdditionalParams($allowedItemName) - { - $linkParams = $this->getLinkParams(); - $foreignLinkParams = $this->getForeignLinkParams(); + private function getAllowedAdditionalParams($allowedItemName) + { + $linkParams = $this->getLinkParams(); + $foreignLinkParams = $this->getForeignLinkParams(); - $itemLinkParams = isset($linkParams[$allowedItemName]) ? $linkParams[$allowedItemName] : null; - $itemForeignLinkParams = isset($foreignLinkParams[$allowedItemName]) ? $foreignLinkParams[$allowedItemName] : null; + $itemLinkParams = isset($linkParams[$allowedItemName]) ? $linkParams[$allowedItemName] : null; + $itemForeignLinkParams = isset($foreignLinkParams[$allowedItemName]) ? $foreignLinkParams[$allowedItemName] : null; - $additionalParrams = null; + $additionalParrams = null; - if (isset($itemLinkParams) && isset($itemForeignLinkParams)) { - $additionalParrams = Util::merge($itemLinkParams, $itemForeignLinkParams); - } else if (isset($itemLinkParams)) { - $additionalParrams = $itemLinkParams; - } else if (isset($itemForeignLinkParams)) { - $additionalParrams = $itemForeignLinkParams; - } + if (isset($itemLinkParams) && isset($itemForeignLinkParams)) { + $additionalParrams = Util::merge($itemLinkParams, $itemForeignLinkParams); + } else if (isset($itemLinkParams)) { + $additionalParrams = $itemLinkParams; + } else if (isset($itemForeignLinkParams)) { + $additionalParrams = $itemForeignLinkParams; + } - return $additionalParrams; - } + return $additionalParrams; + } } \ No newline at end of file diff --git a/application/Espo/Core/Utils/Database/Orm/Relations/BelongsTo.php b/application/Espo/Core/Utils/Database/Orm/Relations/BelongsTo.php index 1991ba3b14..6e2dd88dc4 100644 --- a/application/Espo/Core/Utils/Database/Orm/Relations/BelongsTo.php +++ b/application/Espo/Core/Utils/Database/Orm/Relations/BelongsTo.php @@ -24,33 +24,33 @@ namespace Espo\Core\Utils\Database\Orm\Relations; class BelongsTo extends Base { - protected function load($linkName, $entityName) - { - $foreignEntityName = $this->getForeignEntityName(); + protected function load($linkName, $entityName) + { + $foreignEntityName = $this->getForeignEntityName(); - return array ( - $entityName => array ( - 'fields' => array( - $linkName.'Name' => array( - 'type' => 'foreign', - 'relation' => $linkName, - 'foreign' => $this->getForeignField('name', $foreignEntityName), - ), - $linkName.'Id' => array( - 'type' => 'foreignId', - 'index' => true, - ), - ), - 'relations' => array( - $linkName => array( - 'type' => 'belongsTo', - 'entity' => $foreignEntityName, - 'key' => $linkName.'Id', - 'foreignKey' => 'id', //???? - ), - ), - ), - ); - } + return array ( + $entityName => array ( + 'fields' => array( + $linkName.'Name' => array( + 'type' => 'foreign', + 'relation' => $linkName, + 'foreign' => $this->getForeignField('name', $foreignEntityName), + ), + $linkName.'Id' => array( + 'type' => 'foreignId', + 'index' => true, + ), + ), + 'relations' => array( + $linkName => array( + 'type' => 'belongsTo', + 'entity' => $foreignEntityName, + 'key' => $linkName.'Id', + 'foreignKey' => 'id', //???? + ), + ), + ), + ); + } } \ No newline at end of file diff --git a/application/Espo/Core/Utils/Database/Orm/Relations/EmailEmailAddress.php b/application/Espo/Core/Utils/Database/Orm/Relations/EmailEmailAddress.php index 0349fab96b..c5de43f7e8 100644 --- a/application/Espo/Core/Utils/Database/Orm/Relations/EmailEmailAddress.php +++ b/application/Espo/Core/Utils/Database/Orm/Relations/EmailEmailAddress.php @@ -24,28 +24,28 @@ namespace Espo\Core\Utils\Database\Orm\Relations; class EmailEmailAddress extends HasMany { - protected function load($linkName, $entityName) - { - $parentRelation = parent::load($linkName, $entityName); + protected function load($linkName, $entityName) + { + $parentRelation = parent::load($linkName, $entityName); - $foreignEntityName = $this->getForeignEntityName(); + $foreignEntityName = $this->getForeignEntityName(); - $relation = array( - $entityName => array ( - 'relations' => array( - $linkName => array( - 'midKeys' => array( - lcfirst($entityName).'Id', - lcfirst($foreignEntityName).'Id', - ), - ), - ), - ), - ); + $relation = array( + $entityName => array ( + 'relations' => array( + $linkName => array( + 'midKeys' => array( + lcfirst($entityName).'Id', + lcfirst($foreignEntityName).'Id', + ), + ), + ), + ), + ); - $relation = \Espo\Core\Utils\Util::merge($parentRelation, $relation); + $relation = \Espo\Core\Utils\Util::merge($parentRelation, $relation); - return $relation; - } + return $relation; + } } diff --git a/application/Espo/Core/Utils/Database/Orm/Relations/EntityTeam.php b/application/Espo/Core/Utils/Database/Orm/Relations/EntityTeam.php index b387058e47..7f5f689995 100644 --- a/application/Espo/Core/Utils/Database/Orm/Relations/EntityTeam.php +++ b/application/Espo/Core/Utils/Database/Orm/Relations/EntityTeam.php @@ -24,35 +24,35 @@ namespace Espo\Core\Utils\Database\Orm\Relations; class EntityTeam extends Base { - protected function load($linkName, $entityName) - { - $linkParams = $this->getLinkParams(); - $foreignEntityName = $this->getForeignEntityName(); + protected function load($linkName, $entityName) + { + $linkParams = $this->getLinkParams(); + $foreignEntityName = $this->getForeignEntityName(); - return array( - $entityName => array( - 'relations' => array( - $linkName => array( - 'type' => 'manyMany', - 'entity' => $foreignEntityName, - 'relationName' => lcfirst($linkParams['relationName']), - 'midKeys' => array( - 'entity_id', - 'team_id', - ), - 'conditions' => array( - 'entityType' => $entityName, - ), - 'additionalColumns' => array( - 'entityType' => array( - 'type' => 'varchar', - 'len' => 100, - ), - ), - ), - ), - ), - ); - } + return array( + $entityName => array( + 'relations' => array( + $linkName => array( + 'type' => 'manyMany', + 'entity' => $foreignEntityName, + 'relationName' => lcfirst($linkParams['relationName']), + 'midKeys' => array( + 'entity_id', + 'team_id', + ), + 'conditions' => array( + 'entityType' => $entityName, + ), + 'additionalColumns' => array( + 'entityType' => array( + 'type' => 'varchar', + 'len' => 100, + ), + ), + ), + ), + ), + ); + } } \ No newline at end of file diff --git a/application/Espo/Core/Utils/Database/Orm/Relations/HasChildren.php b/application/Espo/Core/Utils/Database/Orm/Relations/HasChildren.php index cdc67ce6ce..486e0f448d 100644 --- a/application/Espo/Core/Utils/Database/Orm/Relations/HasChildren.php +++ b/application/Espo/Core/Utils/Database/Orm/Relations/HasChildren.php @@ -24,34 +24,34 @@ namespace Espo\Core\Utils\Database\Orm\Relations; class HasChildren extends Base { - protected function load($linkName, $entityName) - { - $foreignLinkName = $this->getForeignLinkName(); - $foreignEntityName = $this->getForeignEntityName(); + protected function load($linkName, $entityName) + { + $foreignLinkName = $this->getForeignLinkName(); + $foreignEntityName = $this->getForeignEntityName(); - return array( - $entityName => array ( - 'fields' => array( - $linkName.'Ids' => array( - 'type' => 'varchar', - 'notStorable' => true, - ), - $linkName.'Names' => array( - 'type' => 'varchar', - 'notStorable' => true, - ), - ), - 'relations' => array( - $linkName => array( - 'type' => 'hasChildren', - 'entity' => $foreignEntityName, - 'foreignKey' => $foreignLinkName.'Id', - 'foreignType' => $foreignLinkName.'Type', - ), - ), - ), - ); - } + return array( + $entityName => array ( + 'fields' => array( + $linkName.'Ids' => array( + 'type' => 'varchar', + 'notStorable' => true, + ), + $linkName.'Names' => array( + 'type' => 'varchar', + 'notStorable' => true, + ), + ), + 'relations' => array( + $linkName => array( + 'type' => 'hasChildren', + 'entity' => $foreignEntityName, + 'foreignKey' => $foreignLinkName.'Id', + 'foreignType' => $foreignLinkName.'Type', + ), + ), + ), + ); + } } \ No newline at end of file diff --git a/application/Espo/Core/Utils/Database/Orm/Relations/HasMany.php b/application/Espo/Core/Utils/Database/Orm/Relations/HasMany.php index be20d6d0ae..8e5b29e52a 100644 --- a/application/Espo/Core/Utils/Database/Orm/Relations/HasMany.php +++ b/application/Espo/Core/Utils/Database/Orm/Relations/HasMany.php @@ -24,38 +24,38 @@ namespace Espo\Core\Utils\Database\Orm\Relations; class HasMany extends Base { - protected function load($linkName, $entityName) - { - $linkParams = $this->getLinkParams(); - $foreignLinkName = $this->getForeignLinkName(); - $foreignEntityName = $this->getForeignEntityName(); + protected function load($linkName, $entityName) + { + $linkParams = $this->getLinkParams(); + $foreignLinkName = $this->getForeignLinkName(); + $foreignEntityName = $this->getForeignEntityName(); - $relationType = isset($linkParams['relationName']) ? 'manyMany' : 'hasMany'; + $relationType = isset($linkParams['relationName']) ? 'manyMany' : 'hasMany'; - $relation = array( - $entityName => array ( - 'fields' => array( - $linkName.'Ids' => array( - 'type' => 'varchar', - 'notStorable' => true, - ), - $linkName.'Names' => array( - 'type' => 'varchar', - 'notStorable' => true, - ), - ), - 'relations' => array( - $linkName => array( - 'type' => $relationType, - 'entity' => $foreignEntityName, - 'foreignKey' => lcfirst($foreignLinkName.'Id'), - ), - ), - ), - ); + $relation = array( + $entityName => array ( + 'fields' => array( + $linkName.'Ids' => array( + 'type' => 'varchar', + 'notStorable' => true, + ), + $linkName.'Names' => array( + 'type' => 'varchar', + 'notStorable' => true, + ), + ), + 'relations' => array( + $linkName => array( + 'type' => $relationType, + 'entity' => $foreignEntityName, + 'foreignKey' => lcfirst($foreignLinkName.'Id'), + ), + ), + ), + ); return $relation; - } + } } \ No newline at end of file diff --git a/application/Espo/Core/Utils/Database/Orm/Relations/ManyMany.php b/application/Espo/Core/Utils/Database/Orm/Relations/ManyMany.php index 0606901ffa..58cd78bb64 100644 --- a/application/Espo/Core/Utils/Database/Orm/Relations/ManyMany.php +++ b/application/Espo/Core/Utils/Database/Orm/Relations/ManyMany.php @@ -26,56 +26,56 @@ use Espo\Core\Utils\Util; class ManyMany extends Base { - protected function load($linkName, $entityName) - { - $foreignEntityName = $this->getForeignEntityName(); + protected function load($linkName, $entityName) + { + $foreignEntityName = $this->getForeignEntityName(); - return array( - $entityName => array( - 'fields' => array( - $linkName.'Ids' => array( - 'type' => 'varchar', - 'notStorable' => true, - ), - $linkName.'Names' => array( - 'type' => 'varchar', - 'notStorable' => true, - ), - ), - 'relations' => array( - $linkName => array( - 'type' => 'manyMany', - 'entity' => $foreignEntityName, - 'relationName' => $this->getJoinTable($entityName, $foreignEntityName), - 'key' => 'id', //todo specify 'key' - 'foreignKey' => 'id', //todo specify 'foreignKey' - 'midKeys' => array( - lcfirst($entityName).'Id', - lcfirst($foreignEntityName).'Id', - ), - ), - ), - ), - ); - } + return array( + $entityName => array( + 'fields' => array( + $linkName.'Ids' => array( + 'type' => 'varchar', + 'notStorable' => true, + ), + $linkName.'Names' => array( + 'type' => 'varchar', + 'notStorable' => true, + ), + ), + 'relations' => array( + $linkName => array( + 'type' => 'manyMany', + 'entity' => $foreignEntityName, + 'relationName' => $this->getJoinTable($entityName, $foreignEntityName), + 'key' => 'id', //todo specify 'key' + 'foreignKey' => 'id', //todo specify 'foreignKey' + 'midKeys' => array( + lcfirst($entityName).'Id', + lcfirst($foreignEntityName).'Id', + ), + ), + ), + ), + ); + } - protected function getJoinTable($tableName1, $tableName2) - { - $tables = $this->getSortEntities($tableName1, $tableName2); + protected function getJoinTable($tableName1, $tableName2) + { + $tables = $this->getSortEntities($tableName1, $tableName2); - return Util::toCamelCase( implode('-', $tables) ); - } + return Util::toCamelCase( implode('_', $tables) ); + } protected function getSortEntities($entity1, $entity2) - { - $entities = array( - Util::toCamelCase(lcfirst($entity1)), - Util::toCamelCase(lcfirst($entity2)), - ); + { + $entities = array( + Util::toCamelCase(lcfirst($entity1)), + Util::toCamelCase(lcfirst($entity2)), + ); - sort($entities); + sort($entities); - return $entities; - } + return $entities; + } } \ No newline at end of file diff --git a/application/Espo/Core/Utils/Database/Orm/Relations/NoteAttachments.php b/application/Espo/Core/Utils/Database/Orm/Relations/NoteAttachments.php index fb937000a5..713a617ae1 100644 --- a/application/Espo/Core/Utils/Database/Orm/Relations/NoteAttachments.php +++ b/application/Espo/Core/Utils/Database/Orm/Relations/NoteAttachments.php @@ -24,24 +24,24 @@ namespace Espo\Core\Utils\Database\Orm\Relations; class NoteAttachments extends HasChildren { - protected function load($linkName, $entityName) - { - $parentRelation = parent::load($linkName, $entityName); + protected function load($linkName, $entityName) + { + $parentRelation = parent::load($linkName, $entityName); - $relation = array( - $entityName => array ( - 'fields' => array( - $linkName.'Types' => array( - 'type' => 'varchar', - 'notStorable' => true, - ), - ), - ), - ); + $relation = array( + $entityName => array ( + 'fields' => array( + $linkName.'Types' => array( + 'type' => 'varchar', + 'notStorable' => true, + ), + ), + ), + ); - $relation = \Espo\Core\Utils\Util::merge($parentRelation, $relation); + $relation = \Espo\Core\Utils\Util::merge($parentRelation, $relation); - return $relation; - } + return $relation; + } } diff --git a/application/Espo/Core/Utils/Database/Schema/BaseRebuildActions.php b/application/Espo/Core/Utils/Database/Schema/BaseRebuildActions.php index 786aabec4e..b7afcf6b45 100644 --- a/application/Espo/Core/Utils/Database/Schema/BaseRebuildActions.php +++ b/application/Espo/Core/Utils/Database/Schema/BaseRebuildActions.php @@ -24,69 +24,69 @@ namespace Espo\Core\Utils\Database\Schema; abstract class BaseRebuildActions { - private $metadata; + private $metadata; - private $config; + private $config; - private $entityManager; - - protected $currentSchema = null; + private $entityManager; + + protected $currentSchema = null; - protected $metadataSchema = null; + protected $metadataSchema = null; - public function __construct(\Espo\Core\Utils\Metadata $metadata, \Espo\Core\Utils\Config $config, \Espo\Core\ORM\EntityManager $entityManager) - { - $this->metadata = $metadata; - $this->config = $config; - $this->entityManager = $entityManager; - } - - protected function getEntityManager() - { - return $this->entityManager; - } - - protected function getConfig() - { - return $this->config; - } - - protected function getMetadata() - { - return $this->metadata; - } + public function __construct(\Espo\Core\Utils\Metadata $metadata, \Espo\Core\Utils\Config $config, \Espo\Core\ORM\EntityManager $entityManager) + { + $this->metadata = $metadata; + $this->config = $config; + $this->entityManager = $entityManager; + } + + protected function getEntityManager() + { + return $this->entityManager; + } + + protected function getConfig() + { + return $this->config; + } + + protected function getMetadata() + { + return $this->metadata; + } - public function setCurrentSchema(\Doctrine\DBAL\Schema\Schema $currentSchema) - { - $this->currentSchema = $currentSchema; - } + public function setCurrentSchema(\Doctrine\DBAL\Schema\Schema $currentSchema) + { + $this->currentSchema = $currentSchema; + } - public function setMetadataSchema(\Doctrine\DBAL\Schema\Schema $metadataSchema) - { - $this->metadataSchema = $metadataSchema; - } + public function setMetadataSchema(\Doctrine\DBAL\Schema\Schema $metadataSchema) + { + $this->metadataSchema = $metadataSchema; + } - protected function getCurrentSchema() - { - return $this->currentSchema; - } + protected function getCurrentSchema() + { + return $this->currentSchema; + } - protected function getMetadataSchema() - { - return $this->metadataSchema; - } + protected function getMetadataSchema() + { + return $this->metadataSchema; + } - /* - public function beforeRebuild() - { - } + /* + public function beforeRebuild() + { + } - public function afterRebuild() - { - } - */ - - + public function afterRebuild() + { + } + */ + + } diff --git a/application/Espo/Core/Utils/Database/Schema/Converter.php b/application/Espo/Core/Utils/Database/Schema/Converter.php index b337f50340..f6d44f1dea 100644 --- a/application/Espo/Core/Utils/Database/Schema/Converter.php +++ b/application/Espo/Core/Utils/Database/Schema/Converter.php @@ -23,343 +23,343 @@ namespace Espo\Core\Utils\Database\Schema; use Espo\Core\Utils\Util, - Espo\ORM\Entity, - Espo\Core\Exceptions\Error; + Espo\ORM\Entity, + Espo\Core\Exceptions\Error; class Converter { - private $dbalSchema; - private $fileManager; + private $dbalSchema; + private $fileManager; - private $ormMeta = null; + private $ormMeta = null; - private $customTablePath = 'application/Espo/Core/Utils/Database/Schema/tables'; + private $customTablePath = 'application/Espo/Core/Utils/Database/Schema/tables'; - protected $typeList; + protected $typeList; - //pair ORM => doctrine - protected $allowedDbFieldParams = array( - 'len' => 'length', - 'default' => 'default', - 'notNull' => 'notnull', - 'autoincrement' => 'autoincrement', - 'unique' => 'unique', - ); + //pair ORM => doctrine + protected $allowedDbFieldParams = array( + 'len' => 'length', + 'default' => 'default', + 'notNull' => 'notnull', + 'autoincrement' => 'autoincrement', + 'unique' => 'unique', + ); - //todo: same array in Converters\Orm - protected $idParams = array( - 'dbType' => 'varchar', - 'len' => '24', - ); + //todo: same array in Converters\Orm + protected $idParams = array( + 'dbType' => 'varchar', + 'len' => '24', + ); - //todo: same array in Converters\Orm - protected $defaultLength = array( - 'varchar' => 255, - 'int' => 11, - ); + //todo: same array in Converters\Orm + protected $defaultLength = array( + 'varchar' => 255, + 'int' => 11, + ); - protected $notStorableTypes = array( - 'foreign' - ); + protected $notStorableTypes = array( + 'foreign' + ); - public function __construct(\Espo\Core\Utils\File\Manager $fileManager) - { - $this->fileManager = $fileManager; - - $this->dbalSchema = new \Espo\Core\Utils\Database\DBAL\Schema\Schema(); - - $this->typeList = array_keys(\Doctrine\DBAL\Types\Type::getTypesMap()); - } - - protected function getFileManager() - { - return $this->fileManager; - } - - protected function getSchema() - { - return $this->dbalSchema; - } + public function __construct(\Espo\Core\Utils\File\Manager $fileManager) + { + $this->fileManager = $fileManager; + + $this->dbalSchema = new \Espo\Core\Utils\Database\DBAL\Schema\Schema(); + + $this->typeList = array_keys(\Doctrine\DBAL\Types\Type::getTypesMap()); + } + + protected function getFileManager() + { + return $this->fileManager; + } + + protected function getSchema() + { + return $this->dbalSchema; + } - public function process(array $ormMeta, $entityDefs, $entityList = null) - { - $GLOBALS['log']->debug('Schema\Converter - Start: building schema'); + public function process(array $ormMeta, $entityDefs, $entityList = null) + { + $GLOBALS['log']->debug('Schema\Converter - Start: building schema'); - //check if exist files in "Tables" directory and merge with ormMetadata - $ormMeta = Util::merge($ormMeta, $this->getCustomTables()); - - //unset some keys in orm - if (isset($ormMeta['unset'])) { - $ormMeta = Util::unsetInArray($ormMeta, $ormMeta['unset']); - unset($ormMeta['unset']); - } //END: unset some keys in orm - - if (isset($entityList)) { - $entityList = is_string($entityList) ? (array) $entityList : $entityList; - - $dependentEntities = $this->getDependentEntities($entityList, $ormMeta); - $GLOBALS['log']->debug('Rebuild Database for entities: ['.implode(', ', $entityList).'] with dependent entities: ['.implode(', ', $dependentEntities).']'); - - $ormMeta = array_intersect_key($ormMeta, array_flip($dependentEntities)); - } - - $schema = $this->getSchema(); - - $tables = array(); - foreach ($ormMeta as $entityName => $entityParams) { - - $tableName = Util::toUnderScore($entityName); - - if ($schema->hasTable($tableName)) { - if (!isset($tables[$entityName])) { - $tables[$entityName] = $schema->getTable($tableName); - } - $GLOBALS['log']->debug('DBAL: Table ['.$tableName.'] exists.'); - continue; - } - - $tables[$entityName] = $schema->createTable($tableName); - - $primaryColumns = array(); - $uniqueColumns = array(); - $indexList = array(); //list of indexes like array( array(comlumn1, column2), array(column3)) - foreach ($entityParams['fields'] as $fieldName => $fieldParams) { - - if ((isset($fieldParams['notStorable']) && $fieldParams['notStorable']) || in_array($fieldParams['type'], $this->notStorableTypes)) { - continue; - } - - switch ($fieldParams['type']) { - case 'id': - $primaryColumns[] = Util::toUnderScore($fieldName); - break; - } - - $fieldType = isset($fieldParams['dbType']) ? $fieldParams['dbType'] : $fieldParams['type']; - $fieldType = strtolower($fieldType); /** doctrine uses strtolower for all field types */ - if (!in_array($fieldType, $this->typeList)) { - $GLOBALS['log']->debug('Converters\Schema::process(): Field type ['.$fieldType.'] does not exist '.$entityName.':'.$fieldName); - continue; - } - - $columnName = Util::toUnderScore($fieldName); - if (!$tables[$entityName]->hasColumn($columnName)) { - $tables[$entityName]->addColumn($columnName, $fieldType, $this->getDbFieldParams($fieldParams)); - } - - //add unique - if ($fieldParams['type']!= 'id' && isset($fieldParams['unique'])) { - $uniqueColumns = $this->getKeyList($columnName, $fieldParams['unique'], $uniqueColumns); - } //END: add unique - - //add index. It can be defined in entityDefs as "index" - if (isset($fieldParams['index'])) { - $indexList = $this->getKeyList($columnName, $fieldParams['index'], $indexList); - } //END: add index - } - - $tables[$entityName]->setPrimaryKey($primaryColumns); - if (!empty($indexList)) { - foreach($indexList as $indexItem) { - $tables[$entityName]->addIndex($indexItem); - } - } - - if (!empty($uniqueColumns)) { - foreach($uniqueColumns as $uniqueItem) { - $tables[$entityName]->addUniqueIndex($uniqueItem); - } - } - } - - //check and create columns/tables for relations - foreach ($ormMeta as $entityName => $entityParams) { - - if (!isset($entityParams['relations'])) { - continue; - } - - foreach ($entityParams['relations'] as $relationName => $relationParams) { - - switch ($relationParams['type']) { - case 'manyMany': - $tableName = $relationParams['relationName']; - - //check for duplication tables - if (!isset($tables[$tableName])) { //no needs to create the table if it already exists - $tables[$tableName] = $this->prepareManyMany($entityName, $relationParams, $tables); - } - break; - - case 'belongsTo': - $columnName = Util::toUnderScore($relationParams['key']); - $tables[$entityName]->addIndex(array($columnName)); - break; - } - } - } - //END: check and create columns/tables for relations - - $GLOBALS['log']->debug('Schema\Converter - End: building schema'); - - return $schema; - } - - /** - * Prepare a relation table for the manyMany relation - * - * @param string $entityName - * @param array $relationParams - * @param array $tables - * - * @return \Doctrine\DBAL\Schema\Table - */ - protected function prepareManyMany($entityName, $relationParams, $tables) - { - $tableName = Util::toUnderScore($relationParams['relationName']); - - if ($this->getSchema()->hasTable($tableName)) { - $GLOBALS['log']->debug('DBAL: Table ['.$tableName.'] exists.'); - return $this->getSchema()->getTable($tableName); - } - - $table = $this->getSchema()->createTable($tableName); - $table->addColumn('id', 'int', array('length'=>$this->defaultLength['int'], 'autoincrement' => true, 'notnull' => true,)); //'unique' => true, - - //add midKeys to a schema - foreach($relationParams['midKeys'] as $index => $midKey) { - - $usMidKey = Util::toUnderScore($midKey); - $table->addColumn($usMidKey, $this->idParams['dbType'], array('length'=>$this->idParams['len'])); - $table->addIndex(array($usMidKey)); - - } //END: add midKeys to a schema - - //add additionalColumns - if (isset($relationParams['additionalColumns'])) { - foreach($relationParams['additionalColumns'] as $fieldName => $fieldParams) { - - if (!isset($fieldParams['type'])) { - $fieldParams = array_merge($fieldParams, array( - 'type' => 'varchar', - 'length' => $this->defaultLength['varchar'], - )); - } - - $table->addColumn(Util::toUnderScore($fieldName), $fieldParams['type'], $this->getDbFieldParams($fieldParams)); - } - } //END: add additionalColumns - - - $table->addColumn('deleted', 'bool', array('default' => 0)); - $table->setPrimaryKey(array("id")); - - return $table; - } - - - protected function getDbFieldParams($fieldParams) - { - $dbFieldParams = array(); - - foreach($this->allowedDbFieldParams as $espoName => $dbalName) { - - if (isset($fieldParams[$espoName])) { - $dbFieldParams[$dbalName] = $fieldParams[$espoName]; - } - } - - switch ($fieldParams['type']) { - case 'array': - case 'jsonArray': - case 'text': - case 'longtext': - unset($dbFieldParams['default']); //for db type TEXT can't be defined a default value - break; - - case 'bool': - $dbFieldParams['default'] = intval($dbFieldParams['default']); - break; - } - - - if ( isset($fieldParams['autoincrement']) && $fieldParams['autoincrement'] ) { - $dbFieldParams['unique'] = true; - $dbFieldParams['notnull'] = true; - } - - return $dbFieldParams; - } - - /** - * Get key list (index, unique). Ex. index => true OR index => 'somename' - * @param string $columnName Column name (underscore field name) - * @param bool | string $keyValue - * @return array - */ - protected function getKeyList($columnName, $keyValue, array $keyList) - { - if ($keyValue === true) { - $keyList[] = array($columnName); - } else if (is_string($keyValue)) { - $keyList[$keyValue][] = $columnName; - } - - return $keyList; - } - - - /* - * @return array - ormMeta - */ - protected function getCustomTables() - { - $customTables = array(); + //check if exist files in "Tables" directory and merge with ormMetadata + $ormMeta = Util::merge($ormMeta, $this->getCustomTables()); + + //unset some keys in orm + if (isset($ormMeta['unset'])) { + $ormMeta = Util::unsetInArray($ormMeta, $ormMeta['unset']); + unset($ormMeta['unset']); + } //END: unset some keys in orm + + if (isset($entityList)) { + $entityList = is_string($entityList) ? (array) $entityList : $entityList; + + $dependentEntities = $this->getDependentEntities($entityList, $ormMeta); + $GLOBALS['log']->debug('Rebuild Database for entities: ['.implode(', ', $entityList).'] with dependent entities: ['.implode(', ', $dependentEntities).']'); + + $ormMeta = array_intersect_key($ormMeta, array_flip($dependentEntities)); + } + + $schema = $this->getSchema(); + + $tables = array(); + foreach ($ormMeta as $entityName => $entityParams) { + + $tableName = Util::toUnderScore($entityName); + + if ($schema->hasTable($tableName)) { + if (!isset($tables[$entityName])) { + $tables[$entityName] = $schema->getTable($tableName); + } + $GLOBALS['log']->debug('DBAL: Table ['.$tableName.'] exists.'); + continue; + } + + $tables[$entityName] = $schema->createTable($tableName); + + $primaryColumns = array(); + $uniqueColumns = array(); + $indexList = array(); //list of indexes like array( array(comlumn1, column2), array(column3)) + foreach ($entityParams['fields'] as $fieldName => $fieldParams) { + + if ((isset($fieldParams['notStorable']) && $fieldParams['notStorable']) || in_array($fieldParams['type'], $this->notStorableTypes)) { + continue; + } + + switch ($fieldParams['type']) { + case 'id': + $primaryColumns[] = Util::toUnderScore($fieldName); + break; + } + + $fieldType = isset($fieldParams['dbType']) ? $fieldParams['dbType'] : $fieldParams['type']; + $fieldType = strtolower($fieldType); /** doctrine uses strtolower for all field types */ + if (!in_array($fieldType, $this->typeList)) { + $GLOBALS['log']->debug('Converters\Schema::process(): Field type ['.$fieldType.'] does not exist '.$entityName.':'.$fieldName); + continue; + } + + $columnName = Util::toUnderScore($fieldName); + if (!$tables[$entityName]->hasColumn($columnName)) { + $tables[$entityName]->addColumn($columnName, $fieldType, $this->getDbFieldParams($fieldParams)); + } + + //add unique + if ($fieldParams['type']!= 'id' && isset($fieldParams['unique'])) { + $uniqueColumns = $this->getKeyList($columnName, $fieldParams['unique'], $uniqueColumns); + } //END: add unique + + //add index. It can be defined in entityDefs as "index" + if (isset($fieldParams['index'])) { + $indexList = $this->getKeyList($columnName, $fieldParams['index'], $indexList); + } //END: add index + } + + $tables[$entityName]->setPrimaryKey($primaryColumns); + if (!empty($indexList)) { + foreach($indexList as $indexItem) { + $tables[$entityName]->addIndex($indexItem); + } + } + + if (!empty($uniqueColumns)) { + foreach($uniqueColumns as $uniqueItem) { + $tables[$entityName]->addUniqueIndex($uniqueItem); + } + } + } + + //check and create columns/tables for relations + foreach ($ormMeta as $entityName => $entityParams) { + + if (!isset($entityParams['relations'])) { + continue; + } + + foreach ($entityParams['relations'] as $relationName => $relationParams) { + + switch ($relationParams['type']) { + case 'manyMany': + $tableName = $relationParams['relationName']; + + //check for duplication tables + if (!isset($tables[$tableName])) { //no needs to create the table if it already exists + $tables[$tableName] = $this->prepareManyMany($entityName, $relationParams, $tables); + } + break; + + case 'belongsTo': + $columnName = Util::toUnderScore($relationParams['key']); + $tables[$entityName]->addIndex(array($columnName)); + break; + } + } + } + //END: check and create columns/tables for relations + + $GLOBALS['log']->debug('Schema\Converter - End: building schema'); + + return $schema; + } + + /** + * Prepare a relation table for the manyMany relation + * + * @param string $entityName + * @param array $relationParams + * @param array $tables + * + * @return \Doctrine\DBAL\Schema\Table + */ + protected function prepareManyMany($entityName, $relationParams, $tables) + { + $tableName = Util::toUnderScore($relationParams['relationName']); + + if ($this->getSchema()->hasTable($tableName)) { + $GLOBALS['log']->debug('DBAL: Table ['.$tableName.'] exists.'); + return $this->getSchema()->getTable($tableName); + } + + $table = $this->getSchema()->createTable($tableName); + $table->addColumn('id', 'int', array('length'=>$this->defaultLength['int'], 'autoincrement' => true, 'notnull' => true,)); //'unique' => true, + + //add midKeys to a schema + foreach($relationParams['midKeys'] as $index => $midKey) { + + $usMidKey = Util::toUnderScore($midKey); + $table->addColumn($usMidKey, $this->idParams['dbType'], array('length'=>$this->idParams['len'])); + $table->addIndex(array($usMidKey)); + + } //END: add midKeys to a schema + + //add additionalColumns + if (isset($relationParams['additionalColumns'])) { + foreach($relationParams['additionalColumns'] as $fieldName => $fieldParams) { + + if (!isset($fieldParams['type'])) { + $fieldParams = array_merge($fieldParams, array( + 'type' => 'varchar', + 'length' => $this->defaultLength['varchar'], + )); + } + + $table->addColumn(Util::toUnderScore($fieldName), $fieldParams['type'], $this->getDbFieldParams($fieldParams)); + } + } //END: add additionalColumns + + + $table->addColumn('deleted', 'bool', array('default' => 0)); + $table->setPrimaryKey(array("id")); + + return $table; + } + + + protected function getDbFieldParams($fieldParams) + { + $dbFieldParams = array(); + + foreach($this->allowedDbFieldParams as $espoName => $dbalName) { + + if (isset($fieldParams[$espoName])) { + $dbFieldParams[$dbalName] = $fieldParams[$espoName]; + } + } + + switch ($fieldParams['type']) { + case 'array': + case 'jsonArray': + case 'text': + case 'longtext': + unset($dbFieldParams['default']); //for db type TEXT can't be defined a default value + break; + + case 'bool': + $dbFieldParams['default'] = intval($dbFieldParams['default']); + break; + } + + + if ( isset($fieldParams['autoincrement']) && $fieldParams['autoincrement'] ) { + $dbFieldParams['unique'] = true; + $dbFieldParams['notnull'] = true; + } + + return $dbFieldParams; + } + + /** + * Get key list (index, unique). Ex. index => true OR index => 'somename' + * @param string $columnName Column name (underscore field name) + * @param bool | string $keyValue + * @return array + */ + protected function getKeyList($columnName, $keyValue, array $keyList) + { + if ($keyValue === true) { + $keyList[] = array($columnName); + } else if (is_string($keyValue)) { + $keyList[$keyValue][] = $columnName; + } + + return $keyList; + } + + + /* + * @return array - ormMeta + */ + protected function getCustomTables() + { + $customTables = array(); - $fileList = $this->getFileManager()->getFileList($this->customTablePath, false, '\.php$', 'file'); + $fileList = $this->getFileManager()->getFileList($this->customTablePath, false, '\.php$', true); - foreach($fileList as $fileName) { - $fileData = $this->getFileManager()->getContents( array($this->customTablePath, $fileName) ); - if (is_array($fileData)) { - $customTables = Util::merge($customTables, $fileData); - } - } + foreach($fileList as $fileName) { + $fileData = $this->getFileManager()->getContents( array($this->customTablePath, $fileName) ); + if (is_array($fileData)) { + $customTables = Util::merge($customTables, $fileData); + } + } - return $customTables; - } + return $customTables; + } - protected function getDependentEntities($entityList, $ormMeta, $dependentEntities = array()) - { - if (is_string($entityList)) { - $entityList = (array) $entityList; - } + protected function getDependentEntities($entityList, $ormMeta, $dependentEntities = array()) + { + if (is_string($entityList)) { + $entityList = (array) $entityList; + } - foreach ($entityList as $entityName) { + foreach ($entityList as $entityName) { - if (in_array($entityName, $dependentEntities)) { - continue; - } + if (in_array($entityName, $dependentEntities)) { + continue; + } - $dependentEntities[] = $entityName; + $dependentEntities[] = $entityName; - foreach ($ormMeta[$entityName]['relations'] as $relationName => $relationParams) { + foreach ($ormMeta[$entityName]['relations'] as $relationName => $relationParams) { - if (isset($relationParams['entity'])) { - $relationEntity = $relationParams['entity']; + if (isset($relationParams['entity'])) { + $relationEntity = $relationParams['entity']; - if (!in_array($relationEntity, $dependentEntities)) { - $dependentEntities = $this->getDependentEntities($relationEntity, $ormMeta, $dependentEntities); - } - } - } + if (!in_array($relationEntity, $dependentEntities)) { + $dependentEntities = $this->getDependentEntities($relationEntity, $ormMeta, $dependentEntities); + } + } + } - } + } - return $dependentEntities; - } + return $dependentEntities; + } } diff --git a/application/Espo/Core/Utils/Database/Schema/Schema.php b/application/Espo/Core/Utils/Database/Schema/Schema.php index e0e51249ec..3a4eddebce 100644 --- a/application/Espo/Core/Utils/Database/Schema/Schema.php +++ b/application/Espo/Core/Utils/Database/Schema/Schema.php @@ -23,282 +23,282 @@ namespace Espo\Core\Utils\Database\Schema; use Doctrine\DBAL\Types\Type, - Espo\Core\Utils\Util; + Espo\Core\Utils\Util; class Schema { - private $config; + private $config; - private $metadata; + private $metadata; - private $fileManager; + private $fileManager; - private $entityManager; + private $entityManager; - private $classParser; + private $classParser; - private $comparator; + private $comparator; - private $converter; + private $converter; - private $connection; + private $connection; - protected $drivers = array( - 'mysqli' => '\Espo\Core\Utils\Database\DBAL\Driver\Mysqli\Driver', - 'pdo_mysql' => '\Espo\Core\Utils\Database\DBAL\Driver\PDOMySql\Driver', - ); + protected $drivers = array( + 'mysqli' => '\Espo\Core\Utils\Database\DBAL\Driver\Mysqli\Driver', + 'pdo_mysql' => '\Espo\Core\Utils\Database\DBAL\Driver\PDOMySql\Driver', + ); - protected $fieldTypePaths = array( - 'application/Espo/Core/Utils/Database/DBAL/FieldTypes', - 'custom/Espo/Custom/Core/Utils/Database/DBAL/FieldTypes', - ); + protected $fieldTypePaths = array( + 'application/Espo/Core/Utils/Database/DBAL/FieldTypes', + 'custom/Espo/Custom/Core/Utils/Database/DBAL/FieldTypes', + ); - /** - * Paths of rebuild action folders - * @var array - */ - protected $rebuildActionsPath = array( - 'corePath' => 'application/Espo/Core/Utils/Database/Schema/rebuildActions', - 'customPath' => 'custom/Espo/Custom/Core/Utils/Database/Schema/rebuildActions', - ); + /** + * Paths of rebuild action folders + * @var array + */ + protected $rebuildActionsPath = array( + 'corePath' => 'application/Espo/Core/Utils/Database/Schema/rebuildActions', + 'customPath' => 'custom/Espo/Custom/Core/Utils/Database/Schema/rebuildActions', + ); - /** - * Array of rebuildActions classes in format: - * array( - * 'beforeRebuild' => array(...), - * 'afterRebuild' => array(...), - * ) - * @var array - */ - protected $rebuildActionClasses = null; + /** + * Array of rebuildActions classes in format: + * array( + * 'beforeRebuild' => array(...), + * 'afterRebuild' => array(...), + * ) + * @var array + */ + protected $rebuildActionClasses = null; - public function __construct(\Espo\Core\Utils\Config $config, \Espo\Core\Utils\Metadata $metadata, \Espo\Core\Utils\File\Manager $fileManager, \Espo\Core\ORM\EntityManager $entityManager, \Espo\Core\Utils\File\ClassParser $classParser) - { - $this->config = $config; - $this->metadata = $metadata; - $this->fileManager = $fileManager; - $this->entityManager = $entityManager; - $this->classParser = $classParser; + public function __construct(\Espo\Core\Utils\Config $config, \Espo\Core\Utils\Metadata $metadata, \Espo\Core\Utils\File\Manager $fileManager, \Espo\Core\ORM\EntityManager $entityManager, \Espo\Core\Utils\File\ClassParser $classParser) + { + $this->config = $config; + $this->metadata = $metadata; + $this->fileManager = $fileManager; + $this->entityManager = $entityManager; + $this->classParser = $classParser; - $this->comparator = new \Espo\Core\Utils\Database\DBAL\Schema\Comparator(); - $this->initFieldTypes(); + $this->comparator = new \Espo\Core\Utils\Database\DBAL\Schema\Comparator(); + $this->initFieldTypes(); - $this->converter = new \Espo\Core\Utils\Database\Converter($this->metadata, $this->fileManager); - } + $this->converter = new \Espo\Core\Utils\Database\Converter($this->metadata, $this->fileManager); + } - protected function getConfig() - { - return $this->config; - } + protected function getConfig() + { + return $this->config; + } - protected function getMetadata() - { - return $this->metadata; - } + protected function getMetadata() + { + return $this->metadata; + } - protected function getFileManager() - { - return $this->fileManager; - } + protected function getFileManager() + { + return $this->fileManager; + } - protected function getEntityManager() - { - return $this->entityManager; - } + protected function getEntityManager() + { + return $this->entityManager; + } - protected function getComparator() - { - return $this->comparator; - } + protected function getComparator() + { + return $this->comparator; + } - protected function getConverter() - { - return $this->converter; - } + protected function getConverter() + { + return $this->converter; + } - protected function getClassParser() - { - return $this->classParser; - } + protected function getClassParser() + { + return $this->classParser; + } - public function getPlatform() - { - return $this->getConnection()->getDatabasePlatform(); - } + public function getPlatform() + { + return $this->getConnection()->getDatabasePlatform(); + } - public function getConnection() - { - if (isset($this->connection)) { - return $this->connection; - } + public function getConnection() + { + if (isset($this->connection)) { + return $this->connection; + } - $dbalConfig = new \Doctrine\DBAL\Configuration(); + $dbalConfig = new \Doctrine\DBAL\Configuration(); - $connectionParams = $this->getConfig()->get('database'); + $connectionParams = $this->getConfig()->get('database'); - $connectionParams['driverClass'] = $this->drivers[ $connectionParams['driver'] ]; - unset($connectionParams['driver']); + $connectionParams['driverClass'] = $this->drivers[ $connectionParams['driver'] ]; + unset($connectionParams['driver']); - $this->connection = \Doctrine\DBAL\DriverManager::getConnection($connectionParams, $dbalConfig); + $this->connection = \Doctrine\DBAL\DriverManager::getConnection($connectionParams, $dbalConfig); - return $this->connection; - } + return $this->connection; + } - protected function initFieldTypes() - { - foreach($this->fieldTypePaths as $path) { + protected function initFieldTypes() + { + foreach($this->fieldTypePaths as $path) { - $typeList = $this->getFileManager()->getFileList($path, false, '\.php$'); - if ($typeList !== false) { - foreach($typeList as $name) { - $typeName = preg_replace('/\.php$/i', '', $name); - $dbalTypeName = strtolower($typeName); + $typeList = $this->getFileManager()->getFileList($path, false, '\.php$'); + if ($typeList !== false) { + foreach($typeList as $name) { + $typeName = preg_replace('/\.php$/i', '', $name); + $dbalTypeName = strtolower($typeName); - $filePath = Util::concatPath($path, $typeName); - $class = Util::getClassName($filePath); + $filePath = Util::concatPath($path, $typeName); + $class = Util::getClassName($filePath); - if( ! Type::hasType($dbalTypeName) ) { - Type::addType($dbalTypeName, $class); - } else { - Type::overrideType($dbalTypeName, $class); - } + if( ! Type::hasType($dbalTypeName) ) { + Type::addType($dbalTypeName, $class); + } else { + Type::overrideType($dbalTypeName, $class); + } - $dbTypeName = method_exists($class, 'getDbTypeName') ? $class::getDbTypeName() : $dbalTypeName; + $dbTypeName = method_exists($class, 'getDbTypeName') ? $class::getDbTypeName() : $dbalTypeName; - $this->getConnection()->getDatabasePlatform()->registerDoctrineTypeMapping($dbTypeName, $dbalTypeName); - } - } - } - } + $this->getConnection()->getDatabasePlatform()->registerDoctrineTypeMapping($dbTypeName, $dbalTypeName); + } + } + } + } - /* - * Rebuild database schema - */ - public function rebuild($entityList = null) - { - if ($this->getConverter()->process() === false) { - return false; - } + /* + * Rebuild database schema + */ + public function rebuild($entityList = null) + { + if ($this->getConverter()->process() === false) { + return false; + } - $currentSchema = $this->getCurrentSchema(); - $metadataSchema = $this->getConverter()->getSchemaFromMetadata($entityList); + $currentSchema = $this->getCurrentSchema(); + $metadataSchema = $this->getConverter()->getSchemaFromMetadata($entityList); - $this->initRebuildActions($currentSchema, $metadataSchema); - $this->executeRebuildActions('beforeRebuild'); + $this->initRebuildActions($currentSchema, $metadataSchema); + $this->executeRebuildActions('beforeRebuild'); - $queries = $this->getDiffSql($currentSchema, $metadataSchema); + $queries = $this->getDiffSql($currentSchema, $metadataSchema); - $result = true; - $connection = $this->getConnection(); - foreach ($queries as $sql) { - $GLOBALS['log']->debug('SCHEMA, Execute Query: '.$sql); - try { - $result &= (bool) $connection->executeQuery($sql); - } catch (\Exception $e) { - $GLOBALS['log']->alert('Rebuild database fault: '.$e); - $result = false; - } - } + $result = true; + $connection = $this->getConnection(); + foreach ($queries as $sql) { + $GLOBALS['log']->debug('SCHEMA, Execute Query: '.$sql); + try { + $result &= (bool) $connection->executeQuery($sql); + } catch (\Exception $e) { + $GLOBALS['log']->alert('Rebuild database fault: '.$e); + $result = false; + } + } - $this->executeRebuildActions('afterRebuild'); + $this->executeRebuildActions('afterRebuild'); - return (bool) $result; - } + return (bool) $result; + } - /* - * Get current database schema - * - * @return \Doctrine\DBAL\Schema\Schema - */ - protected function getCurrentSchema() - { - return $this->getConnection()->getSchemaManager()->createSchema(); - } + /* + * Get current database schema + * + * @return \Doctrine\DBAL\Schema\Schema + */ + protected function getCurrentSchema() + { + return $this->getConnection()->getSchemaManager()->createSchema(); + } - /* - * Get SQL queries of database schema - * - * @params \Doctrine\DBAL\Schema\Schema $schema - * - * @return array - array of SQL queries - */ - public function toSql(\Doctrine\DBAL\Schema\SchemaDiff $schema) //Doctrine\DBAL\Schema\SchemaDiff | \Doctrine\DBAL\Schema\Schema - { - return $schema->toSaveSql($this->getPlatform()); - //return $schema->toSql($this->getPlatform()); //it can return with DROP TABLE - } + /* + * Get SQL queries of database schema + * + * @params \Doctrine\DBAL\Schema\Schema $schema + * + * @return array - array of SQL queries + */ + public function toSql(\Doctrine\DBAL\Schema\SchemaDiff $schema) //Doctrine\DBAL\Schema\SchemaDiff | \Doctrine\DBAL\Schema\Schema + { + return $schema->toSaveSql($this->getPlatform()); + //return $schema->toSql($this->getPlatform()); //it can return with DROP TABLE + } - /* - * Get SQL queries to get from one to another schema - * - * @return array - array of SQL queries - */ - public function getDiffSql(\Doctrine\DBAL\Schema\Schema $fromSchema, \Doctrine\DBAL\Schema\Schema $toSchema) - { - $schemaDiff = $this->getComparator()->compare($fromSchema, $toSchema); + /* + * Get SQL queries to get from one to another schema + * + * @return array - array of SQL queries + */ + public function getDiffSql(\Doctrine\DBAL\Schema\Schema $fromSchema, \Doctrine\DBAL\Schema\Schema $toSchema) + { + $schemaDiff = $this->getComparator()->compare($fromSchema, $toSchema); - return $this->toSql($schemaDiff); //$schemaDiff->toSql($this->getPlatform()); - } + return $this->toSql($schemaDiff); //$schemaDiff->toSql($this->getPlatform()); + } - /** - * Init Rebuild Actions, get all classes and create them - * @return void - */ - protected function initRebuildActions($currentSchema = null, $metadataSchema = null) - { - $methods = array('beforeRebuild', 'afterRebuild'); + /** + * Init Rebuild Actions, get all classes and create them + * @return void + */ + protected function initRebuildActions($currentSchema = null, $metadataSchema = null) + { + $methods = array('beforeRebuild', 'afterRebuild'); - $this->getClassParser()->setAllowedMethods($methods); - $rebuildActions = $this->getClassParser()->getData($this->rebuildActionsPath); + $this->getClassParser()->setAllowedMethods($methods); + $rebuildActions = $this->getClassParser()->getData($this->rebuildActionsPath); - $classes = array(); - foreach ($rebuildActions as $actionName => $actionClass) { - $rebuildActionClass = new $actionClass($this->metadata, $this->config, $this->entityManager); - if (isset($currentSchema)) { - $rebuildActionClass->setCurrentSchema($currentSchema); - } - if (isset($metadataSchema)) { - $rebuildActionClass->setMetadataSchema($metadataSchema); - } + $classes = array(); + foreach ($rebuildActions as $actionName => $actionClass) { + $rebuildActionClass = new $actionClass($this->metadata, $this->config, $this->entityManager); + if (isset($currentSchema)) { + $rebuildActionClass->setCurrentSchema($currentSchema); + } + if (isset($metadataSchema)) { + $rebuildActionClass->setMetadataSchema($metadataSchema); + } - foreach ($methods as $methodName) { - if (method_exists($rebuildActionClass, $methodName)) { - $classes[$methodName][] = $rebuildActionClass; - } - } - } + foreach ($methods as $methodName) { + if (method_exists($rebuildActionClass, $methodName)) { + $classes[$methodName][] = $rebuildActionClass; + } + } + } - $this->rebuildActionClasses = $classes; - } + $this->rebuildActionClasses = $classes; + } - /** - * Execute actions for RebuildAction classes - * @param string $action action name, possible values 'beforeRebuild' | 'afterRebuild' - * @return void - */ - protected function executeRebuildActions($action = 'beforeRebuild') - { - if (!isset($this->rebuildActionClasses)) { - $this->initRebuildActions(); - } + /** + * Execute actions for RebuildAction classes + * @param string $action action name, possible values 'beforeRebuild' | 'afterRebuild' + * @return void + */ + protected function executeRebuildActions($action = 'beforeRebuild') + { + if (!isset($this->rebuildActionClasses)) { + $this->initRebuildActions(); + } - if (isset($this->rebuildActionClasses[$action])) { - foreach ($this->rebuildActionClasses[$action] as $rebuildActionClass) { - $rebuildActionClass->$action(); - } - } - } + if (isset($this->rebuildActionClasses[$action])) { + foreach ($this->rebuildActionClasses[$action] as $rebuildActionClass) { + $rebuildActionClass->$action(); + } + } + } } diff --git a/application/Espo/Core/Utils/Database/Schema/rebuildActions/AddSystemUser.php b/application/Espo/Core/Utils/Database/Schema/rebuildActions/AddSystemUser.php index 5bfc2cba15..0c618fd520 100644 --- a/application/Espo/Core/Utils/Database/Schema/rebuildActions/AddSystemUser.php +++ b/application/Espo/Core/Utils/Database/Schema/rebuildActions/AddSystemUser.php @@ -24,23 +24,23 @@ namespace Espo\Core\Utils\Database\Schema\rebuildActions; class AddSystemUser extends \Espo\Core\Utils\Database\Schema\BaseRebuildActions { - - public function afterRebuild() - { - $userId = $this->getConfig()->get('systemUser.id'); + + public function afterRebuild() + { + $userId = $this->getConfig()->get('systemUser.id'); - $entity = $this->getEntityManager()->getEntity('User', $userId); + $entity = $this->getEntityManager()->getEntity('User', $userId); - if (!isset($entity)) { + if (!isset($entity)) { - $systemUser = $this->getConfig()->get('systemUser'); + $systemUser = $this->getConfig()->get('systemUser'); - $entity = $this->getEntityManager()->getEntity('User'); - $entity->set($systemUser); + $entity = $this->getEntityManager()->getEntity('User'); + $entity->set($systemUser); - return $this->getEntityManager()->saveEntity($entity); - } - } - + return $this->getEntityManager()->saveEntity($entity); + } + } + } diff --git a/application/Espo/Core/Utils/Database/Schema/rebuildActions/Currency.php b/application/Espo/Core/Utils/Database/Schema/rebuildActions/Currency.php index d6aed5179d..b5e030d360 100644 --- a/application/Espo/Core/Utils/Database/Schema/rebuildActions/Currency.php +++ b/application/Espo/Core/Utils/Database/Schema/rebuildActions/Currency.php @@ -25,60 +25,60 @@ namespace Espo\Core\Utils\Database\Schema\rebuildActions; class Currency extends \Espo\Core\Utils\Database\Schema\BaseRebuildActions { - public function afterRebuild() - { - $defaultCurrency = $this->getConfig()->get('defaultCurrency'); + public function afterRebuild() + { + $defaultCurrency = $this->getConfig()->get('defaultCurrency'); - $baseCurrency = $this->getConfig()->get('baseCurrency'); - $currencyRates = $this->getConfig()->get('currencyRates'); + $baseCurrency = $this->getConfig()->get('baseCurrency'); + $currencyRates = $this->getConfig()->get('currencyRates'); - if ($defaultCurrency != $baseCurrency) { - $currencyRates = $this->exchangeRates($baseCurrency, $defaultCurrency, $currencyRates); - } + if ($defaultCurrency != $baseCurrency) { + $currencyRates = $this->exchangeRates($baseCurrency, $defaultCurrency, $currencyRates); + } - $currencyRates[$defaultCurrency] = '1.00'; + $currencyRates[$defaultCurrency] = '1.00'; - $pdo = $this->getEntityManager()->getPDO(); + $pdo = $this->getEntityManager()->getPDO(); - $sql = "TRUNCATE `currency`"; - $pdo->prepare($sql)->execute(); + $sql = "TRUNCATE `currency`"; + $pdo->prepare($sql)->execute(); - foreach ($currencyRates as $currencyName => $rate) { + foreach ($currencyRates as $currencyName => $rate) { - $sql = " - INSERT INTO `currency` - (id, rate) - VALUES - (".$pdo->quote($currencyName) . ", " . $pdo->quote($rate) . ") - "; - $pdo->prepare($sql)->execute(); - } - } + $sql = " + INSERT INTO `currency` + (id, rate) + VALUES + (".$pdo->quote($currencyName) . ", " . $pdo->quote($rate) . ") + "; + $pdo->prepare($sql)->execute(); + } + } - /** - * Calculate exchange rates if defaultCurrency doesn't equals baseCurrency - * - * @param string $baseCurrency - * @param string $defaultCurrency - * @param array $currencyRates [description] - * @return array - List of new currency rates - */ - protected function exchangeRates($baseCurrency, $defaultCurrency, array $currencyRates) - { - $precision = 5; - $defaultCurrencyRate = round(1 / $currencyRates[$defaultCurrency], $precision); + /** + * Calculate exchange rates if defaultCurrency doesn't equals baseCurrency + * + * @param string $baseCurrency + * @param string $defaultCurrency + * @param array $currencyRates [description] + * @return array - List of new currency rates + */ + protected function exchangeRates($baseCurrency, $defaultCurrency, array $currencyRates) + { + $precision = 5; + $defaultCurrencyRate = round(1 / $currencyRates[$defaultCurrency], $precision); - $exchangedRates = array(); - $exchangedRates[$baseCurrency] = $defaultCurrencyRate; + $exchangedRates = array(); + $exchangedRates[$baseCurrency] = $defaultCurrencyRate; - unset($currencyRates[$baseCurrency], $currencyRates[$defaultCurrency]); + unset($currencyRates[$baseCurrency], $currencyRates[$defaultCurrency]); - foreach ($currencyRates as $currencyName => $rate) { - $exchangedRates[$currencyName] = round($rate * $defaultCurrencyRate, $precision); - } + foreach ($currencyRates as $currencyName => $rate) { + $exchangedRates[$currencyName] = round($rate * $defaultCurrencyRate, $precision); + } - return $exchangedRates; - } + return $exchangedRates; + } } diff --git a/application/Espo/Core/Utils/Database/Schema/tables/preferences.php b/application/Espo/Core/Utils/Database/Schema/tables/preferences.php index 50e4c0560d..ef661452e3 100644 --- a/application/Espo/Core/Utils/Database/Schema/tables/preferences.php +++ b/application/Espo/Core/Utils/Database/Schema/tables/preferences.php @@ -20,11 +20,11 @@ * along with EspoCRM. If not, see http://www.gnu.org/licenses/. ************************************************************************/ -return array( +return array( - 'unset' => array( - 'Preferences', - ), + 'unset' => array( + 'Preferences', + ), ); diff --git a/application/Espo/Core/Utils/Database/Schema/tables/settings.php b/application/Espo/Core/Utils/Database/Schema/tables/settings.php index d5a0c366fd..be2b892cb9 100644 --- a/application/Espo/Core/Utils/Database/Schema/tables/settings.php +++ b/application/Espo/Core/Utils/Database/Schema/tables/settings.php @@ -20,11 +20,11 @@ * along with EspoCRM. If not, see http://www.gnu.org/licenses/. ************************************************************************/ -return array( +return array( - 'unset' => array( - 'Settings', - ), + 'unset' => array( + 'Settings', + ), ); diff --git a/application/Espo/Core/Utils/Database/Schema/tables/subscription.php b/application/Espo/Core/Utils/Database/Schema/tables/subscription.php index 43cef1ae42..157530d161 100644 --- a/application/Espo/Core/Utils/Database/Schema/tables/subscription.php +++ b/application/Espo/Core/Utils/Database/Schema/tables/subscription.php @@ -22,32 +22,32 @@ return array( - 'Subscription' => array( - 'fields' => array( - 'id' => array( - 'type' => 'id', - 'dbType' => 'int', - 'len' => '11', - 'autoincrement' => true, - 'unique' => true, - ), - 'entityId' => array( - 'type' => 'varchar', - 'len' => '24', - 'index' => 'entity', - ), - 'entityType' => array( - 'type' => 'varchar', - 'len' => '100', - 'index' => 'entity', - ), - 'userId' => array( - 'type' => 'varchar', - 'len' => '24', - 'index' => true, - ), - ), - ), + 'Subscription' => array( + 'fields' => array( + 'id' => array( + 'type' => 'id', + 'dbType' => 'int', + 'len' => '11', + 'autoincrement' => true, + 'unique' => true, + ), + 'entityId' => array( + 'type' => 'varchar', + 'len' => '24', + 'index' => 'entity', + ), + 'entityType' => array( + 'type' => 'varchar', + 'len' => '100', + 'index' => 'entity', + ), + 'userId' => array( + 'type' => 'varchar', + 'len' => '24', + 'index' => true, + ), + ), + ), ); diff --git a/application/Espo/Core/Utils/DateTime.php b/application/Espo/Core/Utils/DateTime.php index b406c678e6..ee15ef8f99 100644 --- a/application/Espo/Core/Utils/DateTime.php +++ b/application/Espo/Core/Utils/DateTime.php @@ -24,60 +24,60 @@ namespace Espo\Core\Utils; class DateTime { - protected $dataFormat; - - protected $timeFormat; - - protected $timezone; - - protected $dateFormats = array( - 'MM/DD/YYYY' => 'm/d/Y', - 'YYYY-MM-DD' => 'Y-m-d', - 'DD.MM.YYYY' => 'd.m.Y', - ); - - protected $timeFormats = array( - 'HH:mm' => 'H:i', - 'hh:mm A' => 'h:i A', - 'hh:mm a' => 'h:ia', - 'hh:mmA' => 'h:iA', - ); - - public function __construct($dateFormat = 'YYYY-MM-DD', $timeFormat = 'HH:mm', $timeZone = 'UTC') - { - $this->dateFormat = $dateFormat; - $this->timeFormat = $timeFormat; - - $this->timezone = new \DateTimeZone($timeZone); - } - - protected function getPhpDateFormat() - { - return $this->dateFormats[$this->dateFormat]; - } - - protected function getPhpDateTimeFormat() - { - return $this->dateFormats[$this->dateFormat] . ' ' . $this->timeFormats[$this->timeFormat]; - } - - public function convertSystemDateToGlobal($string) - { - $dateTime = \DateTime::createFromFormat('Y-m-d', $string); - if ($dateTime) { - return $dateTime->format($this->getPhpDateFormat()); - } - return null; - } - - public function convertSystemDateTimeToGlobal($string) - { - $dateTime = \DateTime::createFromFormat('Y-m-d H:i:s', $string); - if ($dateTime) { - return $dateTime->setTimezone($this->timezone)->format($this->getPhpDateTimeFormat()); - } - return null; - } + protected $dataFormat; + + protected $timeFormat; + + protected $timezone; + + protected $dateFormats = array( + 'MM/DD/YYYY' => 'm/d/Y', + 'YYYY-MM-DD' => 'Y-m-d', + 'DD.MM.YYYY' => 'd.m.Y', + ); + + protected $timeFormats = array( + 'HH:mm' => 'H:i', + 'hh:mm A' => 'h:i A', + 'hh:mm a' => 'h:ia', + 'hh:mmA' => 'h:iA', + ); + + public function __construct($dateFormat = 'YYYY-MM-DD', $timeFormat = 'HH:mm', $timeZone = 'UTC') + { + $this->dateFormat = $dateFormat; + $this->timeFormat = $timeFormat; + + $this->timezone = new \DateTimeZone($timeZone); + } + + protected function getPhpDateFormat() + { + return $this->dateFormats[$this->dateFormat]; + } + + protected function getPhpDateTimeFormat() + { + return $this->dateFormats[$this->dateFormat] . ' ' . $this->timeFormats[$this->timeFormat]; + } + + public function convertSystemDateToGlobal($string) + { + $dateTime = \DateTime::createFromFormat('Y-m-d', $string); + if ($dateTime) { + return $dateTime->format($this->getPhpDateFormat()); + } + return null; + } + + public function convertSystemDateTimeToGlobal($string) + { + $dateTime = \DateTime::createFromFormat('Y-m-d H:i:s', $string); + if ($dateTime) { + return $dateTime->setTimezone($this->timezone)->format($this->getPhpDateTimeFormat()); + } + return null; + } } diff --git a/application/Espo/Core/Utils/FieldManager.php b/application/Espo/Core/Utils/FieldManager.php index 8ccae1fcdb..707e7bfef5 100644 --- a/application/Espo/Core/Utils/FieldManager.php +++ b/application/Espo/Core/Utils/FieldManager.php @@ -23,243 +23,254 @@ namespace Espo\Core\Utils; use \Espo\Core\Exceptions\Error, - \Espo\Core\Exceptions\Conflict; + \Espo\Core\Exceptions\Conflict; class FieldManager { - private $metadata; + private $metadata; - private $language; + private $language; - private $metadataUtils; + private $metadataUtils; - protected $isChanged = null; + protected $isChanged = null; - protected $metadataType = 'entityDefs'; + protected $metadataType = 'entityDefs'; - protected $customOptionName = 'isCustom'; + protected $customOptionName = 'isCustom'; - public function __construct(Metadata $metadata, Language $language) - { - $this->metadata = $metadata; - $this->language = $language; + public function __construct(Metadata $metadata, Language $language) + { + $this->metadata = $metadata; + $this->language = $language; - $this->metadataUtils = new \Espo\Core\Utils\Metadata\Utils($this->metadata); - } + $this->metadataUtils = new \Espo\Core\Utils\Metadata\Utils($this->metadata); + } - protected function getMetadata() - { - return $this->metadata; - } + protected function getMetadata() + { + return $this->metadata; + } - protected function getLanguage() - { - return $this->language; - } + protected function getLanguage() + { + return $this->language; + } - protected function getMetadataUtils() - { - return $this->metadataUtils; - } + protected function getMetadataUtils() + { + return $this->metadataUtils; + } - public function read($name, $scope) - { - $fieldDef = $this->getFieldDef($name, $scope); + public function read($name, $scope) + { + $fieldDef = $this->getFieldDef($name, $scope); - $fieldDef['label'] = $this->getLanguage()->translate($name, 'fields', $scope); + $fieldDef['label'] = $this->getLanguage()->translate($name, 'fields', $scope); - return $fieldDef; - } + return $fieldDef; + } - public function create($name, $fieldDef, $scope) - { - $existingField = $this->getFieldDef($name, $scope); - if (isset($existingField)) { - throw new Conflict('Field ['.$name.'] exists in '.$scope); - } + public function create($name, $fieldDef, $scope) + { + $existingField = $this->getFieldDef($name, $scope); + if (isset($existingField)) { + throw new Conflict('Field ['.$name.'] exists in '.$scope); + } - return $this->update($name, $fieldDef, $scope); - } + return $this->update($name, $fieldDef, $scope); + } - public function update($name, $fieldDef, $scope) - { - /*Add option to metadata to identify the custom field*/ - if (!$this->isCore($name, $scope)) { - $fieldDef[$this->customOptionName] = true; - } + public function update($name, $fieldDef, $scope) + { + /*Add option to metadata to identify the custom field*/ + if (!$this->isCore($name, $scope)) { + $fieldDef[$this->customOptionName] = true; + } - $res = true; - if (isset($fieldDef['label'])) { - $res &= $this->setLabel($name, $fieldDef['label'], $scope); - } + $res = true; + if (isset($fieldDef['label'])) { + $res &= $this->setLabel($name, $fieldDef['label'], $scope); + } - if ($this->isDefsChanged($name, $fieldDef, $scope)) { - $res &= $this->setEntityDefs($name, $fieldDef, $scope); - } + if (isset($fieldDef['type']) && $fieldDef['type'] == 'enum') { + if (isset($fieldDef['translatedOptions'])) { + $res &= $this->setTranslatedOptions($name, $fieldDef['translatedOptions'], $scope); + } + } - return (bool) $res; - } + if ($this->isDefsChanged($name, $fieldDef, $scope)) { + $res &= $this->setEntityDefs($name, $fieldDef, $scope); + } - public function delete($name, $scope) - { - if ($this->isCore($name, $scope)) { - throw new Error('Cannot delete core field ['.$name.'] in '.$scope); - } + return (bool) $res; + } - $unsets = array( - 'fields.'.$name, - 'links.'.$name, - ); + public function delete($name, $scope) + { + if ($this->isCore($name, $scope)) { + throw new Error('Cannot delete core field ['.$name.'] in '.$scope); + } - $res = $this->getMetadata()->delete($unsets, $this->metadataType, $scope); + $unsets = array( + 'fields.'.$name, + 'links.'.$name, + ); - $this->deleteLabel($name, $scope); + $res = $this->getMetadata()->delete($unsets, $this->metadataType, $scope); - return $res; - } + $this->deleteLabel($name, $scope); - protected function setEntityDefs($name, $fieldDef, $scope) - { - $fieldDef = $this->normalizeDefs($name, $fieldDef, $scope); + return $res; + } - $data = Json::encode($fieldDef); - $res = $this->getMetadata()->set($data, $this->metadataType, $scope); + protected function setEntityDefs($name, $fieldDef, $scope) + { + $fieldDef = $this->normalizeDefs($name, $fieldDef, $scope); - return $res; - } + $data = Json::encode($fieldDef); + $res = $this->getMetadata()->set($data, $this->metadataType, $scope); - protected function setLabel($name, $value, $scope) - { - return $this->getLanguage()->set($name, $value, 'fields', $scope); - } + return $res; + } - protected function deleteLabel($name, $scope) - { - return $this->getLanguage()->delete($name, 'fields', $scope); - } + protected function setTranslatedOptions($name, $value, $scope) + { + return $this->getLanguage()->set($name, $value, 'options', $scope); + } - protected function getFieldDef($name, $scope) - { - return $this->getMetadata()->get($this->metadataType.'.'.$scope.'.fields.'.$name); - } + protected function setLabel($name, $value, $scope) + { + return $this->getLanguage()->set($name, $value, 'fields', $scope); + } - protected function getLinkDef($name, $scope) - { - return $this->getMetadata()->get($this->metadataType.'.'.$scope.'.links.'.$name); - } + protected function deleteLabel($name, $scope) + { + return $this->getLanguage()->delete($name, 'fields', $scope); + } - /** - * Prepare input fieldDefs, remove unnecessary fields - * - * @param string $fieldName - * @param array $fieldDef - * @param string $scope - * @return array - */ - protected function prepareFieldDef($name, $fieldDef, $scope) - { - $unnecessaryFields = array( - 'name', - 'label', - ); + protected function getFieldDef($name, $scope) + { + return $this->getMetadata()->get($this->metadataType.'.'.$scope.'.fields.'.$name); + } - foreach ($unnecessaryFields as $fieldName) { - if (isset($fieldDef[$fieldName])) { - unset($fieldDef[$fieldName]); - } - } + protected function getLinkDef($name, $scope) + { + return $this->getMetadata()->get($this->metadataType.'.'.$scope.'.links.'.$name); + } - if (isset($fieldDef['linkDefs'])) { - $linkDefs = $fieldDef['linkDefs']; - unset($fieldDef['linkDefs']); - } + /** + * Prepare input fieldDefs, remove unnecessary fields + * + * @param string $fieldName + * @param array $fieldDef + * @param string $scope + * @return array + */ + protected function prepareFieldDef($name, $fieldDef, $scope) + { + $unnecessaryFields = array( + 'name', + 'label', + ); - $currentOptionList = array_keys((array) $this->getFieldDef($name, $scope)); - foreach ($fieldDef as $defName => $defValue) { - if ( (!isset($defValue) || $defValue === '') && !in_array($defName, $currentOptionList) ) { - unset($fieldDef[$defName]); - } - } + foreach ($unnecessaryFields as $fieldName) { + if (isset($fieldDef[$fieldName])) { + unset($fieldDef[$fieldName]); + } + } - return $fieldDef; - } + if (isset($fieldDef['linkDefs'])) { + $linkDefs = $fieldDef['linkDefs']; + unset($fieldDef['linkDefs']); + } - /** - * Add all needed block for a field defenition - * - * @param string $fieldName - * @param array $fieldDef - * @param string $scope - * @return array - */ - protected function normalizeDefs($fieldName, array $fieldDef, $scope) - { - $fieldDef = $this->prepareFieldDef($fieldName, $fieldDef, $scope); + $currentOptionList = array_keys((array) $this->getFieldDef($name, $scope)); + foreach ($fieldDef as $defName => $defValue) { + if ( (!isset($defValue) || $defValue === '') && !in_array($defName, $currentOptionList) ) { + unset($fieldDef[$defName]); + } + } - $metaFieldDef = $this->getMetadataUtils()->getFieldDefsInFieldMeta($fieldDef); - if (isset($metaFieldDef)) { - $fieldDef = Util::merge($metaFieldDef, $fieldDef); - } + return $fieldDef; + } - $defs = array( - 'fields' => array( - $fieldName => $fieldDef, - ), - ); + /** + * Add all needed block for a field defenition + * + * @param string $fieldName + * @param array $fieldDef + * @param string $scope + * @return array + */ + protected function normalizeDefs($fieldName, array $fieldDef, $scope) + { + $fieldDef = $this->prepareFieldDef($fieldName, $fieldDef, $scope); - /** Save links for a field. */ - $metaLinkDef = $this->getMetadataUtils()->getLinkDefsInFieldMeta($scope, $fieldDef); - if (isset($linkDefs) || isset($metaLinkDef)) { - $linkDefs = Util::merge((array) $metaLinkDef, (array) $linkDefs); - $defs['links'] = array( - $fieldName => $linkDefs, - ); - } + $metaFieldDef = $this->getMetadataUtils()->getFieldDefsInFieldMeta($fieldDef); + if (isset($metaFieldDef)) { + $fieldDef = Util::merge($metaFieldDef, $fieldDef); + } - return $defs; - } + $defs = array( + 'fields' => array( + $fieldName => $fieldDef, + ), + ); - /** - * Check if changed metadata defenition for a field except 'label' - * - * @return boolean - */ - protected function isDefsChanged($name, $fieldDef, $scope) - { - $fieldDef = $this->prepareFieldDef($name, $fieldDef, $scope); - $currentFieldDef = $this->getFieldDef($name, $scope); + /** Save links for a field. */ + $metaLinkDef = $this->getMetadataUtils()->getLinkDefsInFieldMeta($scope, $fieldDef); + if (isset($linkDefs) || isset($metaLinkDef)) { + $linkDefs = Util::merge((array) $metaLinkDef, (array) $linkDefs); + $defs['links'] = array( + $fieldName => $linkDefs, + ); + } - $this->isChanged = Util::isEquals($fieldDef, $currentFieldDef) ? false : true; + return $defs; + } - return $this->isChanged; - } + /** + * Check if changed metadata defenition for a field except 'label' + * + * @return boolean + */ + protected function isDefsChanged($name, $fieldDef, $scope) + { + $fieldDef = $this->prepareFieldDef($name, $fieldDef, $scope); + $currentFieldDef = $this->getFieldDef($name, $scope); - /** - * Only for update method - * - * @return boolean - */ - public function isChanged() - { - return $this->isChanged; - } + $this->isChanged = Util::isEquals($fieldDef, $currentFieldDef) ? false : true; - /** - * Check if a field is core field - * - * @param string $name - * @param string $scope - * @return boolean - */ - protected function isCore($name, $scope) - { - $existingField = $this->getFieldDef($name, $scope); - if (isset($existingField) && (!isset($existingField[$this->customOptionName]) || !$existingField[$this->customOptionName])) { - return true; - } + return $this->isChanged; + } - return false; - } + /** + * Only for update method + * + * @return boolean + */ + public function isChanged() + { + return $this->isChanged; + } + + /** + * Check if a field is core field + * + * @param string $name + * @param string $scope + * @return boolean + */ + protected function isCore($name, $scope) + { + $existingField = $this->getFieldDef($name, $scope); + if (isset($existingField) && (!isset($existingField[$this->customOptionName]) || !$existingField[$this->customOptionName])) { + return true; + } + + return false; + } } \ No newline at end of file diff --git a/application/Espo/Core/Utils/File/ClassParser.php b/application/Espo/Core/Utils/File/ClassParser.php index a404c54736..cc8512da1a 100644 --- a/application/Espo/Core/Utils/File/ClassParser.php +++ b/application/Espo/Core/Utils/File/ClassParser.php @@ -18,132 +18,130 @@ * * 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\File; use \Espo\Core\Utils\Util; -class ClassParser +class ClassParser { - private $fileManager; + private $fileManager; - private $config; + private $config; - private $metadata; + private $metadata; - protected $cacheFile = null; + protected $cacheFile = null; - protected $allowedMethods = array( - 'run', - ); + protected $allowedMethods = array( + 'run', + ); - public function __construct(\Espo\Core\Utils\File\Manager $fileManager, \Espo\Core\Utils\Config $config, \Espo\Core\Utils\Metadata $metadata) - { - $this->fileManager = $fileManager; - $this->config = $config; - $this->metadata = $metadata; - } + public function __construct(\Espo\Core\Utils\File\Manager $fileManager, \Espo\Core\Utils\Config $config, \Espo\Core\Utils\Metadata $metadata) + { + $this->fileManager = $fileManager; + $this->config = $config; + $this->metadata = $metadata; + } - protected function getFileManager() - { - return $this->fileManager; - } + protected function getFileManager() + { + return $this->fileManager; + } - protected function getConfig() - { - return $this->config; - } + protected function getConfig() + { + return $this->config; + } - protected function getMetadata() - { - return $this->metadata; - } + protected function getMetadata() + { + return $this->metadata; + } - public function setAllowedMethods(array $methods) - { - $this->allowedMethods = $methods; - } + public function setAllowedMethods(array $methods) + { + $this->allowedMethods = $methods; + } + /** + * Return path data of classes + * + * @param string $cacheFile full path for a cache file, ex. data/cache/application/entryPoints.php + * @param string | array $paths in format array( + * 'corePath' => '', + * 'modulePath' => '', + * 'customPath' => '', + * ); + * @return array + */ + public function getData($paths, $cacheFile = false) + { + $data = null; + if (is_string($paths)) { + $paths = array( + 'corePath' => $paths, + ); + } - /** - * Return path data of classes - * @param string $cacheFile full path for a cache file, ex. data/cache/application/entryPoints.php - * @param string | array $paths in format array( - * 'corePath' => '', - * 'modulePath' => '', - * 'customPath' => '', - * ); - * @return array - */ - public function getData($paths, $cacheFile = false) - { - $data = null; + if ($cacheFile && file_exists($cacheFile) && $this->getConfig()->get('useCache')) { + $data = $this->getFileManager()->getContents($cacheFile); + } else { + $data = $this->getClassNameHash($paths['corePath']); - if (is_string($paths)) { - $paths = array( - 'corePath' => $paths, - ); - } + if (isset($paths['modulePath'])) { + foreach ($this->getMetadata()->getModuleList() as $moduleName) { + $path = str_replace('{*}', $moduleName, $paths['modulePath']); - if ($cacheFile && file_exists($cacheFile) && $this->getConfig()->get('useCache')) { - $data = $this->getFileManager()->getContents($cacheFile); - } else { - $data = $this->getClassNameHash($paths['corePath']); + $data = array_merge($data, $this->getClassNameHash($path)); + } + } - if (isset($paths['modulePath'])) { - foreach ($this->getMetadata()->getModuleList() as $moduleName) { - $path = str_replace('{*}', $moduleName, $paths['modulePath']); + if (isset($paths['customPath'])) { + $data = array_merge($data, $this->getClassNameHash($paths['customPath'])); + } - $data = array_merge($data, $this->getClassNameHash($path)); - } - } + if ($cacheFile && $this->getConfig()->get('useCache')) { + $result = $this->getFileManager()->putContentsPHP($cacheFile, $data); + if ($result == false) { + throw new \Espo\Core\Exceptions\Error(); + } + } + } - if (isset($paths['customPath'])) { - $data = array_merge($data, $this->getClassNameHash($paths['customPath'])); - } - - if ($cacheFile && $this->getConfig()->get('useCache')) { - $result = $this->getFileManager()->putContentsPHP($cacheFile, $data); - if ($result == false) { - throw new \Espo\Core\Exceptions\Error(); - } - } - } + return $data; + } - return $data; - } - + protected function getClassNameHash($dirs) + { + if (is_string($dirs)) { + $dirs = (array) $dirs; + } - protected function getClassNameHash($dirs) - { - if (is_string($dirs)) { - $dirs = (array) $dirs; - } + $data = array(); + foreach ($dirs as $dir) { + if (file_exists($dir)) { + $fileList = $this->getFileManager()->getFileList($dir, false, '\.php$', true); - $data = array(); - foreach ($dirs as $dir) { - if (file_exists($dir)) { - $fileList = $this->getFileManager()->getFileList($dir, false, '\.php$', 'file'); + foreach ($fileList as $file) { + $filePath = Util::concatPath($dir, $file); + $className = Util::getClassName($filePath); + $fileName = $this->getFileManager()->getFileName($filePath); + $fileName = ucfirst($fileName); - foreach ($fileList as $file) { - $filePath = Util::concatPath($dir, $file); - $className = Util::getClassName($filePath); - $fileName = $this->getFileManager()->getFileName($filePath); - $fileName = ucfirst($fileName); + foreach ($this->allowedMethods as $methodName) { + if (method_exists($className, $methodName)) { + $data[$fileName] = $className; + } + } - foreach ($this->allowedMethods as $methodName) { - if (method_exists($className, $methodName)) { - $data[$fileName] = $className; - } - } - - } - } - } + } + } + } + + return $data; + } - return $data; - } - } \ No newline at end of file diff --git a/application/Espo/Core/Utils/File/Manager.php b/application/Espo/Core/Utils/File/Manager.php index 2dbe3cf034..3fec93e3cf 100644 --- a/application/Espo/Core/Utils/File/Manager.php +++ b/application/Espo/Core/Utils/File/Manager.php @@ -23,602 +23,711 @@ namespace Espo\Core\Utils\File; use Espo\Core\Utils, - Espo\Core\Exceptions\Error; + Espo\Core\Exceptions\Error; class Manager { - private $permission; - - public function __construct(\Espo\Core\Utils\Config $config = null) - { - $params = null; - if (isset($config)) { - $params = array( - 'defaultPermissions' => $config->get('defaultPermissions'), - 'permissionMap' => $config->get('permissionMap'), - ); - } - - $this->permission = new Permission($this, $params); - } - - public function getPermissionUtils() - { - return $this->permission; - } - - /** - * Get a list of files in specified directory - * - * @param string $path string - Folder path, Ex. myfolder - * @param bool | int $recursively - Find files in subfolders - * @param string $filter - Filter for files. Use regular expression, Ex. \.json$ - * @param string $fileType [all, file, dir] - Filter for type of files/directories. - * @param bool $isReturnSingleArray - if need to return a single array of file list - * - * @return array - */ - public function getFileList($path, $recursively=false, $filter='', $fileType='all', $isReturnSingleArray = false) - { - if (!file_exists($path)) { - return false; - } - - $result = array(); - - $cdir = scandir($path); - foreach ($cdir as $key => $value) - { - if (!in_array($value,array(".",".."))) - { - $add= false; - if (is_dir($path . Utils\Util::getSeparator() . $value)) { - if ($recursively || (is_int($recursively) && $recursively!=0) ) { - $nextRecursively = is_int($recursively) ? ($recursively-1) : $recursively; - $result[$value] = $this->getFileList($path.Utils\Util::getSeparator().$value, $nextRecursively, $filter, $fileType); - } - else if (in_array($fileType, array('all', 'dir'))){ - $add= true; - } - } - else if (in_array($fileType, array('all', 'file'))) { - $add= true; - } - - if ($add) { - if (!empty($filter)) { - if (preg_match('/'.$filter.'/i', $value)) { - $result[] = $value; - } - } - else { - $result[] = $value; - } - } - - } - } - - if ($isReturnSingleArray) { - return $this->getSingeFileList($result); - } - - return $result; - } - - /** - * Convert file list to a single array - * - * @param aray $fileList - * @param string $parentDirName - * - * @return aray - */ - protected function getSingeFileList(array $fileList, $parentDirName = '') - { - $singleFileList = array(); - foreach($fileList as $dirName => $fileName) { - - if (is_array($fileName)) { - $currentDir = Utils\Util::concatPath($parentDirName, $dirName); - $singleFileList = array_merge($singleFileList, $this->getSingeFileList($fileName, $currentDir)); - } else { - $singleFileList[] = Utils\Util::concatPath($parentDirName, $fileName); - } - } - - return $singleFileList; - } - - /** - * Reads entire file into a string - * - * @param string | array $path Ex. 'path.php' OR array('dir', 'path.php') - * @param boolean $useIncludePath - * @param resource $context - * @param integer $offset - * @param integer $maxlen - * @return mixed - */ - public function getContents($path, $useIncludePath = false, $context = null, $offset = -1, $maxlen = null) - { - $fullPath = $this->concatPaths($path); - - if (file_exists($fullPath)) { - - if (strtolower(substr($fullPath, -4))=='.php') { - return include($fullPath); - } else { - if (isset($maxlen)) { - return file_get_contents($fullPath, $useIncludePath, $context, $offset, $maxlen); - } else { - return file_get_contents($fullPath, $useIncludePath, $context, $offset); - } - } - - } - - return false; - } - - /** - * Write data to a file - * - * @param string | array $path - * @param mixed $data - * @param integer $flags - * @param resource $context - * - * @return bool - */ - public function putContents($path, $data, $flags = 0, $context = null) - { - $fullPath = $this->concatPaths($path); //todo remove after changing the params - - if ($this->checkCreateFile($fullPath) === false) { - throw new Error('Permission denied in '. $fullPath); - } - - $res = (file_put_contents($fullPath, $data, $flags, $context) !== FALSE); - if ($res && function_exists('opcache_invalidate')) { - opcache_invalidate($fullPath); - } - - return $res; - } - - /** - * Save PHP content to file - * - * @param string | array $path - * @param string $data - * - * @return bool - */ - public function putContentsPHP($path, $data) - { - return $this->putContents($path, $this->getPHPFormat($data)); - } - - /** - * Save JSON content to file - * - * @param string | array $path - * @param string $data - * @param integer $flags - * @param resource $context - * - * @return bool - */ - public function putContentsJson($path, $data) - { - if (!Utils\Json::isJSON($data)) { - $data = Utils\Json::encode($data, JSON_PRETTY_PRINT); - } - - return $this->putContents($path, $data); - } - - /** - * Merge file content and save it to a file - * - * @param string | array $path - * @param string $content JSON string - * @param bool $isJSON - * @param string | array $removeOptions - List of unset keys from content - * @param bool $isReturn - Is result to be returned or stored - * - * @return bool | array - */ - public function mergeContents($path, $content, $isJSON = false, $removeOptions = null, $isReturn = false) - { - $fileContent = $this->getContents($path); - - $savedDataArray = Utils\Json::getArrayData($fileContent); - $newDataArray = Utils\Json::getArrayData($content); - - if (isset($removeOptions)) { - $savedDataArray = Utils\Util::unsetInArray($savedDataArray, $removeOptions); - $newDataArray = Utils\Util::unsetInArray($newDataArray, $removeOptions); - } - - $data = Utils\Util::merge($savedDataArray, $newDataArray); - if ($isJSON) { - $data = Utils\Json::encode($data, JSON_PRETTY_PRINT); - } - - if ($isReturn) { - return $data; - } - - return $this->putContents($path, $data); - } - - /** - * Merge PHP content and save it to a file - * - * @param string | array $path - * @param string $content JSON string - * @param string | array $removeOptions - List of unset keys from content - * @return bool - */ - public function mergeContentsPHP($path, $content, $removeOptions = null) - { - $data = $this->mergeContents($path, $content, false, $removeOptions, true); - - return $this->putContentsPHP($path, $data); - } - - /** - * Append the content to the end of the file - * - * @param string | array $path - * @param mixed $data - * - * @return bool - */ - public function appendContents($path, $data) - { - return $this->putContents($path, $data, FILE_APPEND | LOCK_EX); - } - - /** - * Unset some element of content data - * - * @param string | array $path - * @param array | string $unsets [description] - * @return bool - */ - public function unsetContents($path, $unsets, $isJSON = true) - { - $currentData = $this->getContents($path); - if ($currentData == false) { - $GLOBALS['log']->notice('FileManager::unsetContents: File ['.$this->concatPaths($path).'] does not exist.'); - return false; - } - - $currentDataArray = Utils\Json::getArrayData($currentData); - - $unsettedData = Utils\Util::unsetInArray($currentDataArray, $unsets); - - if ($isJSON) { - return $this->putContentsJson($path, $unsettedData); - } - - return $this->putContents($path, $unsettedData); - } - - - /** - * Concat paths - * @param string | array $paths Ex. array('pathPart1', 'pathPart2', 'pathPart3') - * @return string - */ - protected function concatPaths($paths) - { - if (is_string($paths)) { - return $paths; - } - - $fullPath = ''; - foreach ($paths as $path) { - $fullPath = Utils\Util::concatPath($fullPath, $path); - } - - return $fullPath; - } - - /** - * Create a new dir - * - * @param string | array $path - * @param int $permission - ex. 0755 - * @return bool - */ - public function mkdir($path, $permission = null) - { - $fullPath = $this->concatPaths($path); - - if (file_exists($fullPath) && is_dir($path)) { - return true; - } - - if (!isset($permission)) { - $defaultPermissions = $this->getPermissionUtils()->getDefaultPermissions(); - $permission = (string) $defaultPermissions['dir']; - $permission = base_convert($permission, 8, 10); - } - - try { - $result = mkdir($fullPath, $permission, true); - } catch (\Exception $e) { - $GLOBALS['log']->critical('Permission denied: unable to create the folder on the server - '.$fullPath); - } - - return isset($result) ? $result : false; - } - - /** - * Copy files from one direcoty to another - * Ex. $sourcePath = 'data/uploads/extensions/file.json', $destPath = 'data/uploads/backup', result will be data/uploads/backup/data/uploads/backup/file.json. - * - * @param string $sourcePath - * @param string $destPath - * @param boolean $recursively - * @param array $fileList - list of files that should be copied - * @param boolean $copyOnlyFiles - copy only files, instead of full path with directories, Ex. $sourcePath = 'data/uploads/extensions/file.json', $destPath = 'data/uploads/backup', result will be 'data/uploads/backup/file.json' - * @return boolen - */ - public function copy($sourcePath, $destPath, $recursively = false, array $fileList = null, $copyOnlyFiles = false) - { - $sourcePath = $this->concatPaths($sourcePath); - $destPath = $this->concatPaths($destPath); - - if (isset($fileList)) { - if (!empty($sourcePath)) { - foreach ($fileList as &$fileName) { - $fileName = $this->concatPaths(array($sourcePath, $fileName)); - } - } - } else { - $fileList = is_file($sourcePath) ? (array) $sourcePath : $this->getFileList($sourcePath, $recursively, '', 'file', true); - } - - /** Check permission before copying */ - $permissionDeniedList = array(); - foreach ($fileList as $file) { - - if ($copyOnlyFiles) { - $file = pathinfo($file, PATHINFO_BASENAME); - } - - $destFile = $this->concatPaths(array($destPath, $file)); - - $isFileExists = file_exists($destFile); - - if ($this->checkCreateFile($destFile) === false) { - $permissionDeniedList[] = $destFile; - } else if (!$isFileExists) { - $this->removeFile($destFile); - } - } - /** END */ - - if (!empty($permissionDeniedList)) { - $betterPermissionList = $this->getPermissionUtils()->arrangePermissionList($permissionDeniedList); - throw new Error("Permission denied in
". implode(",
", $betterPermissionList)); - } - - $res = true; - foreach ($fileList as $file) { - - if ($copyOnlyFiles) { - $file = pathinfo($file, PATHINFO_BASENAME); - } - - $sourceFile = is_file($sourcePath) ? $sourcePath : $this->concatPaths(array($sourcePath, $file)); - $destFile = $this->concatPaths(array($destPath, $file)); - - $res &= copy($sourceFile, $destFile); - } - - return $res; - } - - /** - * Create a new file if not exists with all folders in the path. - * - * @param string $filePath - * @return string - */ - protected function checkCreateFile($filePath) - { - $defaultPermissions = $this->getPermissionUtils()->getDefaultPermissions(); - - if (file_exists($filePath)) { - - if (!in_array($this->getPermissionUtils()->getCurrentPermission($filePath), array($defaultPermissions['file'], $defaultPermissions['dir']))) { - return $this->getPermissionUtils()->setDefaultPermissions($filePath, true); - } - return true; - } - - $pathParts = pathinfo($filePath); - if (!file_exists($pathParts['dirname'])) { - $dirPermission = $defaultPermissions['dir']; - $dirPermission = is_string($dirPermission) ? base_convert($dirPermission,8,10) : $dirPermission; - - if (!mkdir($pathParts['dirname'], $dirPermission, true)) { - throw new Error('Permission denied: unable to create a folder on the server - '.$pathParts['dirname']); - } - } - - if (touch($filePath)) { - return $this->getPermissionUtils()->setDefaultPermissions($filePath, true); - } - - return false; - } - - /** - * Remove file/files by given path - * - * @param array $filePaths - File paths list - * @param string $dirPath - directory path - * @return bool - */ - public function removeFile($filePaths, $dirPath = null) - { - if (!is_array($filePaths)) { - $filePaths = (array) $filePaths; - } - - $result = true; - foreach ($filePaths as $filePath) { - if (isset($dirPath)) { - $filePath = Utils\Util::concatPath($dirPath, $filePath); - } - - if (file_exists($filePath) && is_file($filePath)) { - $result &= unlink($filePath); - } - } - - return $result; - } - - /** - * Remove all files inside given path - * - * @param string $dirPath - directory path - * @param bool $removeWithDir - if remove with directory - * - * @return bool - */ - public function removeInDir($dirPath, $removeWithDir = false) - { - $fileList = $this->getFileList($dirPath, false); - - $result = true; - if (is_array($fileList)) { - foreach ($fileList as $file) { - $fullPath = Utils\Util::concatPath($dirPath, $file); - if (is_dir($fullPath)) { - $result &= $this->removeInDir($fullPath, true); - } else if (file_exists($fullPath)) { - $result &= unlink($fullPath); - } - } - } - - if ($removeWithDir) { - if (file_exists($dirPath)) { - rmdir($dirPath); - } - } - - return $result; - } - - /** - * Remove items (files or directories) - * - * @param string | array $items - * @param string $dirPath - * @return boolean - */ - public function remove($items, $dirPath = null) - { - if (!is_array($items)) { - $items = (array) $items; - } - - $result = true; - foreach ($items as $item) { - if (isset($dirPath)) { - $item = Utils\Util::concatPath($dirPath, $item); - } - - if (is_dir($item)) { - $result = $this->removeInDir($item, true); - } else { - $result = $this->removeFile($item); - } - } - - return $result; - } - - /** - * Get a filename without the file extension - * - * @param string $filename - * @param string $ext - extension, ex. '.json' - * - * @return array - */ - public function getFileName($fileName, $ext='') - { - if (empty($ext)) { - $fileName= substr($fileName, 0, strrpos($fileName, '.', -1)); - } - else { - if (substr($ext, 0, 1)!='.') { - $ext= '.'.$ext; - } - - if (substr($fileName, -(strlen($ext)))==$ext) { - $fileName= substr($fileName, 0, -(strlen($ext))); - } - } - - $exFileName = explode('/', Utils\Util::toFormat($fileName, '/')); - - return end($exFileName); - } - - - /** - * Get a directory name from the path - * - * @param string $path - * @param bool $isFullPath - * - * @return array - */ - public function getDirName($path, $isFullPath = true) - { - $pathInfo = pathinfo($path); - - if (!$isFullPath) { - $pieces = explode('/', $pathInfo['dirname']); - - return $pieces[count($pieces)-1]; - } - - return $pathInfo['dirname']; - } - - /** - * Return content of PHP file - * - * @param string $varName - name of variable which contains the content - * @param array $content - * - * @return string | false - */ - public function getPHPFormat($content) - { - if (empty($content)) { - return false; - } - - return ' $config->get('defaultPermissions'), + 'permissionMap' => $config->get('permissionMap'), + ); + } + + $this->permission = new Permission($this, $params); + } + + public function getPermissionUtils() + { + return $this->permission; + } + + /** + * Get a list of files in specified directory + * + * @param string $path string - Folder path, Ex. myfolder + * @param bool | int $recursively - Find files in subfolders + * @param string $filter - Filter for files. Use regular expression, Ex. \.json$ + * @param bool $onlyFileType [null, true, false] - Filter for type of files/directories. If TRUE - returns only file list, if FALSE - only directory list + * @param bool $isReturnSingleArray - if need to return a single array of file list + * + * @return array + */ + public function getFileList($path, $recursively = false, $filter = '', $onlyFileType = null, $isReturnSingleArray = false) + { + if (!file_exists($path)) { + return false; + } + + $result = array(); + + $cdir = scandir($path); + foreach ($cdir as $key => $value) + { + if (!in_array($value,array(".", ".."))) + { + $add = false; + if (is_dir($path . Utils\Util::getSeparator() . $value)) { + if ($recursively || (is_int($recursively) && $recursively!=0) ) { + $nextRecursively = is_int($recursively) ? ($recursively-1) : $recursively; + $result[$value] = $this->getFileList($path . Utils\Util::getSeparator() . $value, $nextRecursively, $filter, $onlyFileType); + } + else if (!isset($onlyFileType) || !$onlyFileType){ /*save only directories*/ + $add = true; + } + } + else if (!isset($onlyFileType) || $onlyFileType) { /*save only files*/ + $add = true; + } + + if ($add) { + if (!empty($filter)) { + if (preg_match('/'.$filter.'/i', $value)) { + $result[] = $value; + } + } + else { + $result[] = $value; + } + } + + } + } + + if ($isReturnSingleArray) { + return $this->getSingeFileList($result, $onlyFileType); + } + + return $result; + } + + /** + * Convert file list to a single array + * + * @param aray $fileList + * @param bool $onlyFileType [null, true, false] - Filter for type of files/directories. + * @param string $parentDirName + * + * @return aray + */ + protected function getSingeFileList(array $fileList, $onlyFileType = null, $parentDirName = '') + { + $singleFileList = array(); + foreach($fileList as $dirName => $fileName) { + + if (is_array($fileName)) { + $currentDir = Utils\Util::concatPath($parentDirName, $dirName); + + if (!isset($onlyFileType) || $onlyFileType == $this->isFile($currentDir)) { + $singleFileList[] = $currentDir; + } + + $singleFileList = array_merge($singleFileList, $this->getSingeFileList($fileName, $onlyFileType, $currentDir)); + + } else { + $currentFileName = Utils\Util::concatPath($parentDirName, $fileName); + + if (!isset($onlyFileType) || $onlyFileType == $this->isFile($currentFileName)) { + $singleFileList[] = $currentFileName; + } + } + } + + return $singleFileList; + } + + /** + * Reads entire file into a string + * + * @param string | array $path Ex. 'path.php' OR array('dir', 'path.php') + * @param boolean $useIncludePath + * @param resource $context + * @param integer $offset + * @param integer $maxlen + * @return mixed + */ + public function getContents($path, $useIncludePath = false, $context = null, $offset = -1, $maxlen = null) + { + $fullPath = $this->concatPaths($path); + + if (file_exists($fullPath)) { + + if (strtolower(substr($fullPath, -4))=='.php') { + return include($fullPath); + } else { + if (isset($maxlen)) { + return file_get_contents($fullPath, $useIncludePath, $context, $offset, $maxlen); + } else { + return file_get_contents($fullPath, $useIncludePath, $context, $offset); + } + } + + } + + return false; + } + + /** + * Write data to a file + * + * @param string | array $path + * @param mixed $data + * @param integer $flags + * @param resource $context + * + * @return bool + */ + public function putContents($path, $data, $flags = 0, $context = null) + { + $fullPath = $this->concatPaths($path); //todo remove after changing the params + + if ($this->checkCreateFile($fullPath) === false) { + throw new Error('Permission denied in '. $fullPath); + } + + $res = (file_put_contents($fullPath, $data, $flags, $context) !== FALSE); + if ($res && function_exists('opcache_invalidate')) { + opcache_invalidate($fullPath); + } + + return $res; + } + + /** + * Save PHP content to file + * + * @param string | array $path + * @param string $data + * + * @return bool + */ + public function putContentsPHP($path, $data) + { + return $this->putContents($path, $this->getPHPFormat($data)); + } + + /** + * Save JSON content to file + * + * @param string | array $path + * @param string $data + * @param integer $flags + * @param resource $context + * + * @return bool + */ + public function putContentsJson($path, $data) + { + if (!Utils\Json::isJSON($data)) { + $data = Utils\Json::encode($data, JSON_PRETTY_PRINT); + } + + return $this->putContents($path, $data); + } + + /** + * Merge file content and save it to a file + * + * @param string | array $path + * @param string $content JSON string + * @param bool $isJSON + * @param string | array $removeOptions - List of unset keys from content + * @param bool $isReturn - Is result to be returned or stored + * + * @return bool | array + */ + public function mergeContents($path, $content, $isJSON = false, $removeOptions = null, $isReturn = false) + { + $fileContent = $this->getContents($path); + + $savedDataArray = Utils\Json::getArrayData($fileContent); + $newDataArray = Utils\Json::getArrayData($content); + + if (isset($removeOptions)) { + $savedDataArray = Utils\Util::unsetInArray($savedDataArray, $removeOptions); + $newDataArray = Utils\Util::unsetInArray($newDataArray, $removeOptions); + } + + $data = Utils\Util::merge($savedDataArray, $newDataArray); + if ($isJSON) { + $data = Utils\Json::encode($data, JSON_PRETTY_PRINT); + } + + if ($isReturn) { + return $data; + } + + return $this->putContents($path, $data); + } + + /** + * Merge PHP content and save it to a file + * + * @param string | array $path + * @param string $content JSON string + * @param string | array $removeOptions - List of unset keys from content + * @return bool + */ + public function mergeContentsPHP($path, $content, $removeOptions = null) + { + $data = $this->mergeContents($path, $content, false, $removeOptions, true); + + return $this->putContentsPHP($path, $data); + } + + /** + * Append the content to the end of the file + * + * @param string | array $path + * @param mixed $data + * + * @return bool + */ + public function appendContents($path, $data) + { + return $this->putContents($path, $data, FILE_APPEND | LOCK_EX); + } + + /** + * Unset some element of content data + * + * @param string | array $path + * @param array | string $unsets [description] + * @return bool + */ + public function unsetContents($path, $unsets, $isJSON = true) + { + $currentData = $this->getContents($path); + if ($currentData == false) { + $GLOBALS['log']->notice('FileManager::unsetContents: File ['.$this->concatPaths($path).'] does not exist.'); + return false; + } + + $currentDataArray = Utils\Json::getArrayData($currentData); + + $unsettedData = Utils\Util::unsetInArray($currentDataArray, $unsets); + + if ($isJSON) { + return $this->putContentsJson($path, $unsettedData); + } + + return $this->putContents($path, $unsettedData); + } + + + /** + * Concat paths + * @param string | array $paths Ex. array('pathPart1', 'pathPart2', 'pathPart3') + * @return string + */ + protected function concatPaths($paths) + { + if (is_string($paths)) { + return $paths; + } + + $fullPath = ''; + foreach ($paths as $path) { + $fullPath = Utils\Util::concatPath($fullPath, $path); + } + + return $fullPath; + } + + /** + * Create a new dir + * + * @param string | array $path + * @param int $permission - ex. 0755 + * @return bool + */ + public function mkdir($path, $permission = null) + { + $fullPath = $this->concatPaths($path); + + if (file_exists($fullPath) && is_dir($path)) { + return true; + } + + if (!isset($permission)) { + $defaultPermissions = $this->getPermissionUtils()->getDefaultPermissions(); + $permission = (string) $defaultPermissions['dir']; + $permission = base_convert($permission, 8, 10); + } + + try { + $result = mkdir($fullPath, $permission, true); + } catch (\Exception $e) { + $GLOBALS['log']->critical('Permission denied: unable to create the folder on the server - '.$fullPath); + } + + return isset($result) ? $result : false; + } + + /** + * Copy files from one direcoty to another + * Ex. $sourcePath = 'data/uploads/extensions/file.json', $destPath = 'data/uploads/backup', result will be data/uploads/backup/data/uploads/backup/file.json. + * + * @param string $sourcePath + * @param string $destPath + * @param boolean $recursively + * @param array $fileList - list of files that should be copied + * @param boolean $copyOnlyFiles - copy only files, instead of full path with directories, Ex. $sourcePath = 'data/uploads/extensions/file.json', $destPath = 'data/uploads/backup', result will be 'data/uploads/backup/file.json' + * @return boolen + */ + public function copy($sourcePath, $destPath, $recursively = false, array $fileList = null, $copyOnlyFiles = false) + { + $sourcePath = $this->concatPaths($sourcePath); + $destPath = $this->concatPaths($destPath); + + if (isset($fileList)) { + if (!empty($sourcePath)) { + foreach ($fileList as &$fileName) { + $fileName = $this->concatPaths(array($sourcePath, $fileName)); + } + } + } else { + $fileList = is_file($sourcePath) ? (array) $sourcePath : $this->getFileList($sourcePath, $recursively, '', true, true); + } + + /** Check permission before copying */ + $permissionDeniedList = array(); + foreach ($fileList as $file) { + + if ($copyOnlyFiles) { + $file = pathinfo($file, PATHINFO_BASENAME); + } + + $destFile = $this->concatPaths(array($destPath, $file)); + + $isFileExists = file_exists($destFile); + + if ($this->checkCreateFile($destFile) === false) { + $permissionDeniedList[] = $destFile; + } else if (!$isFileExists) { + $this->removeFile($destFile); + } + } + /** END */ + + if (!empty($permissionDeniedList)) { + $betterPermissionList = $this->getPermissionUtils()->arrangePermissionList($permissionDeniedList); + throw new Error("Permission denied in
". implode(",
", $betterPermissionList)); + } + + $res = true; + foreach ($fileList as $file) { + + if ($copyOnlyFiles) { + $file = pathinfo($file, PATHINFO_BASENAME); + } + + $sourceFile = is_file($sourcePath) ? $sourcePath : $this->concatPaths(array($sourcePath, $file)); + $destFile = $this->concatPaths(array($destPath, $file)); + + if (file_exists($sourceFile)) { + $res &= copy($sourceFile, $destFile); + } + } + + return $res; + } + + /** + * Create a new file if not exists with all folders in the path. + * + * @param string $filePath + * @return string + */ + protected function checkCreateFile($filePath) + { + $defaultPermissions = $this->getPermissionUtils()->getDefaultPermissions(); + + if (file_exists($filePath)) { + + if (!in_array($this->getPermissionUtils()->getCurrentPermission($filePath), array($defaultPermissions['file'], $defaultPermissions['dir']))) { + return $this->getPermissionUtils()->setDefaultPermissions($filePath, true); + } + return true; + } + + $pathParts = pathinfo($filePath); + if (!file_exists($pathParts['dirname'])) { + $dirPermission = $defaultPermissions['dir']; + $dirPermission = is_string($dirPermission) ? base_convert($dirPermission,8,10) : $dirPermission; + + if (!mkdir($pathParts['dirname'], $dirPermission, true)) { + throw new Error('Permission denied: unable to create a folder on the server - '.$pathParts['dirname']); + } + } + + if (touch($filePath)) { + return $this->getPermissionUtils()->setDefaultPermissions($filePath, true); + } + + return false; + } + + /** + * Remove file/files by given path + * + * @param array $filePaths - File paths list + * @return bool + */ + public function unlink($filePaths) + { + return $this->removeFile($filePaths); + } + + public function rmdir($dirPaths) + { + if (!is_array($dirPaths)) { + $dirPaths = (array) $dirPaths; + } + + $result = true; + foreach ($dirPaths as $dirPath) { + if (is_dir($dirPath) && is_writable($dirPath)) { + $result &= rmdir($dirPath); + } + } + + return (bool) $result; + } + + /** + * Remove file/files by given path + * + * @param array $filePaths - File paths list + * @param string $dirPath - directory path + * @return bool + */ + public function removeFile($filePaths, $dirPath = null) + { + if (!is_array($filePaths)) { + $filePaths = (array) $filePaths; + } + + $result = true; + foreach ($filePaths as $filePath) { + if (isset($dirPath)) { + $filePath = Utils\Util::concatPath($dirPath, $filePath); + } + + if (file_exists($filePath) && is_file($filePath)) { + $result &= unlink($filePath); + } + } + + return $result; + } + + /** + * Remove all files inside given path + * + * @param string $dirPath - directory path + * @param bool $removeWithDir - if remove with directory + * + * @return bool + */ + public function removeInDir($dirPath, $removeWithDir = false) + { + $fileList = $this->getFileList($dirPath, false); + + $result = true; + if (is_array($fileList)) { + foreach ($fileList as $file) { + $fullPath = Utils\Util::concatPath($dirPath, $file); + if (is_dir($fullPath)) { + $result &= $this->removeInDir($fullPath, true); + } else if (file_exists($fullPath)) { + $result &= unlink($fullPath); + } + } + } + + if ($removeWithDir) { + $result &= $this->rmdir($dirPath); + } + + return (bool) $result; + } + + /** + * Remove items (files or directories) + * + * @param string | array $items + * @param string $dirPath + * @return boolean + */ + public function remove($items, $dirPath = null, $removeEmptyDirs = false) + { + if (!is_array($items)) { + $items = (array) $items; + } + + $result = true; + foreach ($items as $item) { + if (isset($dirPath)) { + $item = Utils\Util::concatPath($dirPath, $item); + } + + if (is_dir($item)) { + $result &= $this->removeInDir($item, true); + } else { + $result &= $this->removeFile($item); + } + + if ($removeEmptyDirs) { + $result &= $this->removeEmptyDirs($item); + } + } + + return (bool) $result; + } + + /** + * Remove empty parent directories if they are empty + * @param string $path + * @return bool + */ + protected function removeEmptyDirs($path) + { + $parentDirName = $this->getParentDirName($path); + + $res = true; + if ($this->isDirEmpty($parentDirName)) { + $res &= $this->rmdir($parentDirName); + $res &= $this->removeEmptyDirs($parentDirName); + } + + return (bool) $res; + } + + /** + * Check if $filename is file. If $filename doesn'ot exist, check by pathinfo + * + * @param string $filename + * @return boolean + */ + public function isFile($filename) + { + if (file_exists($filename)) { + return is_file($filename); + } + + $fileExtension = pathinfo($filename, PATHINFO_EXTENSION); + if (!empty($fileExtension)) { + return true; + } + + return false; + } + + /** + * Check if directory is empty + * @param string $path + * @return boolean + */ + public function isDirEmpty($path) + { + if (is_dir($path)) { + $fileList = $this->getFileList($path, true); + + if (is_array($fileList) && empty($fileList)) { + return true; + } + } + + return false; + } + + /** + * Get a filename without the file extension + * + * @param string $filename + * @param string $ext - extension, ex. '.json' + * + * @return array + */ + public function getFileName($fileName, $ext='') + { + if (empty($ext)) { + $fileName= substr($fileName, 0, strrpos($fileName, '.', -1)); + } + else { + if (substr($ext, 0, 1)!='.') { + $ext= '.'.$ext; + } + + if (substr($fileName, -(strlen($ext)))==$ext) { + $fileName= substr($fileName, 0, -(strlen($ext))); + } + } + + $exFileName = explode('/', Utils\Util::toFormat($fileName, '/')); + + return end($exFileName); + } + + /** + * Get a directory name from the path + * + * @param string $path + * @param bool $isFullPath + * + * @return array + */ + public function getDirName($path, $isFullPath = true, $useIsDir = true) + { + $dirName = preg_replace('/\/$/i', '', $path); + $dirName = ($useIsDir && is_dir($dirName)) ? $dirName : pathinfo($dirName, PATHINFO_DIRNAME); + + if (!$isFullPath) { + $pieces = explode('/', $dirName); + $dirName = $pieces[count($pieces)-1]; + } + + return $dirName; + } + + /** + * Get parent dir name/path + * + * @param string $path + * @param boolean $isFullPath + * @return string + */ + public function getParentDirName($path, $isFullPath = true) + { + return $this->getDirName($path, $isFullPath, false); + } + + /** + * Return content of PHP file + * + * @param string $varName - name of variable which contains the content + * @param array $content + * + * @return string | false + */ + public function getPHPFormat($content) + { + if (empty($content)) { + return false; + } + + return ''; - } + } } diff --git a/application/Espo/Core/Utils/File/Permission.php b/application/Espo/Core/Utils/File/Permission.php index efcc763d91..54339d828e 100644 --- a/application/Espo/Core/Utils/File/Permission.php +++ b/application/Espo/Core/Utils/File/Permission.php @@ -23,583 +23,583 @@ namespace Espo\Core\Utils\File; use Espo\Core\Utils, - Espo\Core\Exceptions\Error; + Espo\Core\Exceptions\Error; class Permission { - private $fileManager; - - /** - * Last permission error - * - * @var array | string - */ - protected $permissionError = null; - - protected $permissionErrorRules = null; - - protected $params = array( - 'defaultPermissions' => array ( - 'dir' => '0775', - 'file' => '0664', - 'user' => '', - 'group' => '', - ), - 'permissionMap' => array( - - /** array('0664', '0775') */ - 'writable' => array( - 'data', - 'custom', - ), - - /** array('0644', '0755') */ - 'readable' => array( - 'api', - 'application', - 'client', - 'vendor', - 'index.php', - 'cron.php', - 'rebuild.php', - 'main.html', - 'reset.html', - ), - ), - ); - - protected $permissionRules = array( - 'writable' => array('0664', '0775'), - 'readable' => array('0644', '0755'), - ); - - - public function __construct(Manager $fileManager, array $params = null) - { - $this->fileManager = $fileManager; - if (isset($params)) { - $this->params = $params; - } - } - - protected function getFileManager() - { - return $this->fileManager; - } - - protected function getParams() - { - return $this->params; - } - - - /** - * Get default settings - * - * @return object - */ - public function getDefaultPermissions() - { - $params = $this->getParams(); - return $params['defaultPermissions']; - } - - - public function getPermissionRules() - { - return $this->permissionRules; - } - - /** - * Set default permission - * - * @param string $path - * @param bool $recurse - * - * @return bool - */ - public function setDefaultPermissions($path, $recurse = false) - { - if (!file_exists($path)) { - return false; - } - - $permission = $this->getDefaultPermissions(); - - $result = $this->chmod($path, array($permission['file'], $permission['dir']), $recurse); - if (!empty($permission['user'])) { - $result &= $this->chown($path, $permission['user'], $recurse); - } - if (!empty($permission['group'])) { - $result &= $this->chgrp($path, $permission['group'], $recurse); - } - - return $result; - } - - - /** - * Get current permissions - * - * @param string $filename - * @return string | bool - */ - public function getCurrentPermission($filePath) - { - if (!file_exists($filePath)) { - return false; - } - - $fileInfo= stat($filePath); - - return substr(base_convert($fileInfo['mode'],10,8), -4); - } - - /** - * Change permissions - * - * @param string $filename - * @param int | array $octal - ex. 0755, array(0644, 0755), array('file'=>0644, 'dir'=>0755) - * @param bool $recurse - * - * @return bool - */ - public function chmod($path, $octal, $recurse = false) - { - if (!file_exists($path)) { - return false; - } - - //check the input format - $permission= array(); - if (is_array($octal)) { - $count= 0; - $rule= array('file', 'dir'); - foreach ($octal as $key => $val) { - $pKey= strval($key); - if (!in_array($pKey, $rule)) { - $pKey= $rule[$count]; - } - - if (!empty($pKey)) { - $permission[$pKey]= $val; - } - $count++; - } - } - elseif (is_int((int)$octal)) { - $permission= array( - 'file' => $octal, - 'dir' => $octal, - ); - } - else { - return false; - } - - //conver to octal value - foreach($permission as $key => $val) { - if (is_string($val)) { - $permission[$key]= base_convert($val,8,10); - } - } - - //Set permission for non-recursive request - if (!$recurse) { - if (is_dir($path)) { - return $this->chmodReal($path, $permission['dir']); - } - return $this->chmodReal($path, $permission['file']); - } - - //Recursive permission - return $this->chmodRecurse($path, $permission['file'], $permission['dir']); - } - - - /** - * Change permissions recursive - * - * @param string $filename - * @param int $fileOctal - ex. 0644 - * @param int $dirOctal - ex. 0755 - * - * @return bool - */ - protected function chmodRecurse($path, $fileOctal = 0644, $dirOctal = 0755) - { - if (!file_exists($path)) { - return false; - } - - if (is_file($path)) { - return $this->chmodReal($path, $fileOctal); - } - - if (is_dir($path)) { - $allFiles = $this->getFileManager()->getFileList($path); - - foreach ($items as $item) { - $this->chmodRecurse($path. Utils\Util::getSeparator() .$item, $fileOctal, $dirOctal); - } - - return $this->chmodReal($path, $dirOctal); - } - - return false; - } - - - - - - /** - * Change owner permission - * - * @param string $path - * @param int | string $user - * @param bool $recurse - * - * @return bool - */ - public function chown($path, $user='', $recurse=false) - { - if (!file_exists($path)) { - return false; - } - - if (empty($user)) { - $user = $this->getDefaultOwner(); - } - - //Set chown for non-recursive request - if (!$recurse) { - return $this->chownReal($path, $user); - } - - //Recursive chown - return $this->chownRecurse($path, $user); - } - - /** - * Change owner permission recursive - * - * @param string $path - * @param string $user - * - * @return bool - */ - protected function chownRecurse($path, $user) - { - if (!file_exists($path)) { - return false; - } - - $allFiles = $this->getFileManager()->getFileList($path); - - foreach ($items as $item) { - $this->chownRecurse($path. Utils\Util::getSeparator() .$item, $user); - } - - return $this->chownReal($path, $user); - } - - /** - * Change group permission - * - * @param string $path - * @param int | string $group - * @param bool $recurse - * - * @return bool - */ - public function chgrp($path, $group = null, $recurse = false) - { - if (!file_exists($path)) { - return false; - } - - if (!isset($group)) { - $group = $this->getDefaultGroup(); - } - - //Set chgrp for non-recursive request - if (!$recurse) { - return $this->chgrpReal($path, $group); - } - - //Recursive chown - return $this->chgrpRecurse($path, $group); - } - - /** - * Change group permission recursive - * - * @param string $filename - * @param int $fileOctal - ex. 0644 - * @param int $dirOctal - ex. 0755 - * - * @return bool - */ - protected function chgrpRecurse($path, $group) { - - if (!file_exists($path)) { - return false; - } - - $allFiles = $this->getFileManager()->getFileList($path); - - foreach ($items as $item) { - $this->chgrpRecurse($path. Utils\Util::getSeparator() .$item, $group); - } - - return $this->chgrpReal($path, $group); - } - - - /** - * Change permissions recursive - * - * @param string $filename - * @param int $mode - ex. 0644 - * - * @return bool - */ - protected function chmodReal($filename, $mode) - { - try { - $result = chmod($filename, $mode); - } catch (\Exception $e) { - $result = false; - } - - if (!$result) { - $this->chown($filename, $this->getDefaultOwner(true)); - $this->chgrp($filename, $this->getDefaultGroup(true)); - - try { - $result = chmod($filename, $mode); - } catch (\Exception $e) { - throw new Error($e->getMessage()); - } - } - - return $result; - } - - protected function chownReal($path, $user) - { - try { - $result = chown($path, $user); - } catch (\Exception $e) { - throw new Error($e->getMessage()); - } - - return $result; - } - - protected function chgrpReal($path, $group) - { - try { - $result = chgrp($path, $group); - } catch (\Exception $e) { - throw new Error($e->getMessage()); - } - - return $result; - } - - /** - * Get default owner user - * - * @return int - owner id - */ - public function getDefaultOwner($usePosix = false) - { - $defaultPermissions = $this->getDefaultPermissions(); - - $owner = $defaultPermissions['user']; - if (empty($owner) && $usePosix) { - $owner = function_exists('posix_getuid') ? posix_getuid() : null; - } - - if (empty($owner)) { - return false; - } - - return $owner; - } - - /** - * Get default group user - * - * @return int - group id - */ - public function getDefaultGroup($usePosix = false) - { - $defaultPermissions = $this->getDefaultPermissions(); - - $group = $defaultPermissions['group']; - if (empty($group) && $usePosix) { - $group = function_exists('posix_getegid') ? posix_getegid() : null; - } - - if (empty($group)) { - return false; - } - - return $group; - } - - /** - * Set permission regarding defined in permissionMap - * - * @return bool - */ - public function setMapPermission($mode = null) - { - $this->permissionError = array(); - $this->permissionErrorRules = array(); - - $params = $this->getParams(); - - $permissionRules = $this->permissionRules; - if (isset($mode)) { - foreach ($permissionRules as &$value) { - $value = $mode; - } - } - - $result = true; - foreach ($params['permissionMap'] as $type => $items) { - - $permission = $permissionRules[$type]; - - foreach ($items as $item) { - - if (file_exists($item)) { - - try { - $this->chmod($item, $permission, true); - } catch (\Exception $e) { - } - - $res = is_readable($item); - - /** check is wtitable */ - if ($type == 'writable') { - - $res &= is_writable($item); - - if (is_dir($item)) { - $name = uniqid(); - - try { - $res &= $this->getFileManager()->putContents(array($item, $name), 'test'); - $res &= $this->getFileManager()->removeFile($name, $item); - } catch (\Exception $e) { - $res = false; - } - } - } - - if (!$res) { - $result = false; - $this->permissionError[] = $item; - $this->permissionErrorRules[$item] = $permission; - } - } - } - } - - return $result; - } - - /** - * Get last permission error - * - * @return array | string - */ - public function getLastError() - { - return $this->permissionError; - } - - /** - * Get last permission error rules - * - * @return array | string - */ - public function getLastErrorRules() - { - return $this->permissionErrorRules; - } - - /** - * Arrange permission file list - * e.g. array('application/Espo/Controllers/Email.php', 'application/Espo/Controllers/Import.php'), result is array('application/Espo/Controllers') - * - * @param array $fileList - * @return array - */ - public function arrangePermissionList($fileList) - { - $betterList = array(); - foreach ($fileList as $fileName) { - - $pathInfo = pathinfo($fileName); - $dirname = $pathInfo['dirname']; - - $currentPath = $fileName; - if ($this->getSearchCount($dirname, $fileList) > 1) { - $currentPath = $dirname; - } - - if (!$this->isItemIncludes($currentPath, $betterList)) { - $betterList[] = $currentPath; - } - } - - return $betterList; - } - - /** - * Get count of a search string in a array - * - * @param string $search - * @param array $array - * @return bool - */ - protected function getSearchCount($search, array $array) - { - $search = $this->getPregQuote($search); - - $number = 0; - foreach ($array as $value) { - if (preg_match('/^'.$search.'/', $value)) { - $number++; - } - } - - return $number; - } - - protected function isItemIncludes($item, $array) - { - foreach ($array as $value) { - $value = $this->getPregQuote($value); - if (preg_match('/^'.$value.'/', $item)) { - return true; - } - } - - return false; - } - - protected function getPregQuote($string) - { - return preg_quote($string, '/-+=.'); - } + private $fileManager; + + /** + * Last permission error + * + * @var array | string + */ + protected $permissionError = null; + + protected $permissionErrorRules = null; + + protected $params = array( + 'defaultPermissions' => array ( + 'dir' => '0775', + 'file' => '0664', + 'user' => '', + 'group' => '', + ), + 'permissionMap' => array( + + /** array('0664', '0775') */ + 'writable' => array( + 'data', + 'custom', + ), + + /** array('0644', '0755') */ + 'readable' => array( + 'api', + 'application', + 'client', + 'vendor', + 'index.php', + 'cron.php', + 'rebuild.php', + 'main.html', + 'reset.html', + ), + ), + ); + + protected $permissionRules = array( + 'writable' => array('0664', '0775'), + 'readable' => array('0644', '0755'), + ); + + + public function __construct(Manager $fileManager, array $params = null) + { + $this->fileManager = $fileManager; + if (isset($params)) { + $this->params = $params; + } + } + + protected function getFileManager() + { + return $this->fileManager; + } + + protected function getParams() + { + return $this->params; + } + + + /** + * Get default settings + * + * @return object + */ + public function getDefaultPermissions() + { + $params = $this->getParams(); + return $params['defaultPermissions']; + } + + + public function getPermissionRules() + { + return $this->permissionRules; + } + + /** + * Set default permission + * + * @param string $path + * @param bool $recurse + * + * @return bool + */ + public function setDefaultPermissions($path, $recurse = false) + { + if (!file_exists($path)) { + return false; + } + + $permission = $this->getDefaultPermissions(); + + $result = $this->chmod($path, array($permission['file'], $permission['dir']), $recurse); + if (!empty($permission['user'])) { + $result &= $this->chown($path, $permission['user'], $recurse); + } + if (!empty($permission['group'])) { + $result &= $this->chgrp($path, $permission['group'], $recurse); + } + + return $result; + } + + + /** + * Get current permissions + * + * @param string $filename + * @return string | bool + */ + public function getCurrentPermission($filePath) + { + if (!file_exists($filePath)) { + return false; + } + + $fileInfo= stat($filePath); + + return substr(base_convert($fileInfo['mode'],10,8), -4); + } + + /** + * Change permissions + * + * @param string $filename + * @param int | array $octal - ex. 0755, array(0644, 0755), array('file'=>0644, 'dir'=>0755) + * @param bool $recurse + * + * @return bool + */ + public function chmod($path, $octal, $recurse = false) + { + if (!file_exists($path)) { + return false; + } + + //check the input format + $permission= array(); + if (is_array($octal)) { + $count= 0; + $rule= array('file', 'dir'); + foreach ($octal as $key => $val) { + $pKey= strval($key); + if (!in_array($pKey, $rule)) { + $pKey= $rule[$count]; + } + + if (!empty($pKey)) { + $permission[$pKey]= $val; + } + $count++; + } + } + elseif (is_int((int)$octal)) { + $permission= array( + 'file' => $octal, + 'dir' => $octal, + ); + } + else { + return false; + } + + //conver to octal value + foreach($permission as $key => $val) { + if (is_string($val)) { + $permission[$key]= base_convert($val,8,10); + } + } + + //Set permission for non-recursive request + if (!$recurse) { + if (is_dir($path)) { + return $this->chmodReal($path, $permission['dir']); + } + return $this->chmodReal($path, $permission['file']); + } + + //Recursive permission + return $this->chmodRecurse($path, $permission['file'], $permission['dir']); + } + + + /** + * Change permissions recursive + * + * @param string $filename + * @param int $fileOctal - ex. 0644 + * @param int $dirOctal - ex. 0755 + * + * @return bool + */ + protected function chmodRecurse($path, $fileOctal = 0644, $dirOctal = 0755) + { + if (!file_exists($path)) { + return false; + } + + if (is_file($path)) { + return $this->chmodReal($path, $fileOctal); + } + + if (is_dir($path)) { + $allFiles = $this->getFileManager()->getFileList($path); + + foreach ($items as $item) { + $this->chmodRecurse($path. Utils\Util::getSeparator() .$item, $fileOctal, $dirOctal); + } + + return $this->chmodReal($path, $dirOctal); + } + + return false; + } + + + + + + /** + * Change owner permission + * + * @param string $path + * @param int | string $user + * @param bool $recurse + * + * @return bool + */ + public function chown($path, $user='', $recurse=false) + { + if (!file_exists($path)) { + return false; + } + + if (empty($user)) { + $user = $this->getDefaultOwner(); + } + + //Set chown for non-recursive request + if (!$recurse) { + return $this->chownReal($path, $user); + } + + //Recursive chown + return $this->chownRecurse($path, $user); + } + + /** + * Change owner permission recursive + * + * @param string $path + * @param string $user + * + * @return bool + */ + protected function chownRecurse($path, $user) + { + if (!file_exists($path)) { + return false; + } + + $allFiles = $this->getFileManager()->getFileList($path); + + foreach ($items as $item) { + $this->chownRecurse($path. Utils\Util::getSeparator() .$item, $user); + } + + return $this->chownReal($path, $user); + } + + /** + * Change group permission + * + * @param string $path + * @param int | string $group + * @param bool $recurse + * + * @return bool + */ + public function chgrp($path, $group = null, $recurse = false) + { + if (!file_exists($path)) { + return false; + } + + if (!isset($group)) { + $group = $this->getDefaultGroup(); + } + + //Set chgrp for non-recursive request + if (!$recurse) { + return $this->chgrpReal($path, $group); + } + + //Recursive chown + return $this->chgrpRecurse($path, $group); + } + + /** + * Change group permission recursive + * + * @param string $filename + * @param int $fileOctal - ex. 0644 + * @param int $dirOctal - ex. 0755 + * + * @return bool + */ + protected function chgrpRecurse($path, $group) { + + if (!file_exists($path)) { + return false; + } + + $allFiles = $this->getFileManager()->getFileList($path); + + foreach ($items as $item) { + $this->chgrpRecurse($path. Utils\Util::getSeparator() .$item, $group); + } + + return $this->chgrpReal($path, $group); + } + + + /** + * Change permissions recursive + * + * @param string $filename + * @param int $mode - ex. 0644 + * + * @return bool + */ + protected function chmodReal($filename, $mode) + { + try { + $result = chmod($filename, $mode); + } catch (\Exception $e) { + $result = false; + } + + if (!$result) { + $this->chown($filename, $this->getDefaultOwner(true)); + $this->chgrp($filename, $this->getDefaultGroup(true)); + + try { + $result = chmod($filename, $mode); + } catch (\Exception $e) { + throw new Error($e->getMessage()); + } + } + + return $result; + } + + protected function chownReal($path, $user) + { + try { + $result = chown($path, $user); + } catch (\Exception $e) { + throw new Error($e->getMessage()); + } + + return $result; + } + + protected function chgrpReal($path, $group) + { + try { + $result = chgrp($path, $group); + } catch (\Exception $e) { + throw new Error($e->getMessage()); + } + + return $result; + } + + /** + * Get default owner user + * + * @return int - owner id + */ + public function getDefaultOwner($usePosix = false) + { + $defaultPermissions = $this->getDefaultPermissions(); + + $owner = $defaultPermissions['user']; + if (empty($owner) && $usePosix) { + $owner = function_exists('posix_getuid') ? posix_getuid() : null; + } + + if (empty($owner)) { + return false; + } + + return $owner; + } + + /** + * Get default group user + * + * @return int - group id + */ + public function getDefaultGroup($usePosix = false) + { + $defaultPermissions = $this->getDefaultPermissions(); + + $group = $defaultPermissions['group']; + if (empty($group) && $usePosix) { + $group = function_exists('posix_getegid') ? posix_getegid() : null; + } + + if (empty($group)) { + return false; + } + + return $group; + } + + /** + * Set permission regarding defined in permissionMap + * + * @return bool + */ + public function setMapPermission($mode = null) + { + $this->permissionError = array(); + $this->permissionErrorRules = array(); + + $params = $this->getParams(); + + $permissionRules = $this->permissionRules; + if (isset($mode)) { + foreach ($permissionRules as &$value) { + $value = $mode; + } + } + + $result = true; + foreach ($params['permissionMap'] as $type => $items) { + + $permission = $permissionRules[$type]; + + foreach ($items as $item) { + + if (file_exists($item)) { + + try { + $this->chmod($item, $permission, true); + } catch (\Exception $e) { + } + + $res = is_readable($item); + + /** check is wtitable */ + if ($type == 'writable') { + + $res &= is_writable($item); + + if (is_dir($item)) { + $name = uniqid(); + + try { + $res &= $this->getFileManager()->putContents(array($item, $name), 'test'); + $res &= $this->getFileManager()->removeFile($name, $item); + } catch (\Exception $e) { + $res = false; + } + } + } + + if (!$res) { + $result = false; + $this->permissionError[] = $item; + $this->permissionErrorRules[$item] = $permission; + } + } + } + } + + return $result; + } + + /** + * Get last permission error + * + * @return array | string + */ + public function getLastError() + { + return $this->permissionError; + } + + /** + * Get last permission error rules + * + * @return array | string + */ + public function getLastErrorRules() + { + return $this->permissionErrorRules; + } + + /** + * Arrange permission file list + * e.g. array('application/Espo/Controllers/Email.php', 'application/Espo/Controllers/Import.php'), result is array('application/Espo/Controllers') + * + * @param array $fileList + * @return array + */ + public function arrangePermissionList($fileList) + { + $betterList = array(); + foreach ($fileList as $fileName) { + + $pathInfo = pathinfo($fileName); + $dirname = $pathInfo['dirname']; + + $currentPath = $fileName; + if ($this->getSearchCount($dirname, $fileList) > 1) { + $currentPath = $dirname; + } + + if (!$this->isItemIncludes($currentPath, $betterList)) { + $betterList[] = $currentPath; + } + } + + return $betterList; + } + + /** + * Get count of a search string in a array + * + * @param string $search + * @param array $array + * @return bool + */ + protected function getSearchCount($search, array $array) + { + $search = $this->getPregQuote($search); + + $number = 0; + foreach ($array as $value) { + if (preg_match('/^'.$search.'/', $value)) { + $number++; + } + } + + return $number; + } + + protected function isItemIncludes($item, $array) + { + foreach ($array as $value) { + $value = $this->getPregQuote($value); + if (preg_match('/^'.$value.'/', $item)) { + return true; + } + } + + return false; + } + + protected function getPregQuote($string) + { + return preg_quote($string, '/-+=.'); + } } diff --git a/application/Espo/Core/Utils/File/Unifier.php b/application/Espo/Core/Utils/File/Unifier.php index 355a3c215f..6d1eebff94 100644 --- a/application/Espo/Core/Utils/File/Unifier.php +++ b/application/Espo/Core/Utils/File/Unifier.php @@ -26,148 +26,148 @@ use Espo\Core\Utils; class Unifier { - private $fileManager; + private $fileManager; - protected $params = array( - 'unsetFileName' => 'unset.json', - 'defaultsPath' => 'application/Espo/Core/defaults', - ); + protected $params = array( + 'unsetFileName' => 'unset.json', + 'defaultsPath' => 'application/Espo/Core/defaults', + ); - public function __construct(\Espo\Core\Utils\File\Manager $fileManager) - { - $this->fileManager = $fileManager; - } + public function __construct(\Espo\Core\Utils\File\Manager $fileManager) + { + $this->fileManager = $fileManager; + } - protected function getFileManager() - { - return $this->fileManager; - } + protected function getFileManager() + { + return $this->fileManager; + } - /** - * Unite file content to the file - * - * @param string $name - * @param array $paths - * @param boolean $recursively Note: only for first level of sub directory, other levels of sub directories will be ignored - * - * @return array - */ - public function unify($name, $paths, $recursively = false) - { - $content = $this->unifySingle($paths['corePath'], $name, $recursively); + /** + * Unite file content to the file + * + * @param string $name + * @param array $paths + * @param boolean $recursively Note: only for first level of sub directory, other levels of sub directories will be ignored + * + * @return array + */ + public function unify($name, $paths, $recursively = false) + { + $content = $this->unifySingle($paths['corePath'], $name, $recursively); - if (!empty($paths['modulePath'])) { - $customDir = strstr($paths['modulePath'], '{*}', true); - $dirList = $this->getFileManager()->getFileList($customDir, false, '', 'dir'); + if (!empty($paths['modulePath'])) { + $customDir = strstr($paths['modulePath'], '{*}', true); + $dirList = $this->getFileManager()->getFileList($customDir, false, '', false); - foreach ($dirList as $dirName) { - $curPath = str_replace('{*}', $dirName, $paths['modulePath']); - $content = Utils\Util::merge($content, $this->unifySingle($curPath, $name, $recursively, $dirName)); - } - } + foreach ($dirList as $dirName) { + $curPath = str_replace('{*}', $dirName, $paths['modulePath']); + $content = Utils\Util::merge($content, $this->unifySingle($curPath, $name, $recursively, $dirName)); + } + } - if (!empty($paths['customPath'])) { - $content = Utils\Util::merge($content, $this->unifySingle($paths['customPath'], $name, $recursively)); - } + if (!empty($paths['customPath'])) { + $content = Utils\Util::merge($content, $this->unifySingle($paths['customPath'], $name, $recursively)); + } - return $content; - } + return $content; + } - /** - * Unite file content to the file for one directory [NOW ONLY FOR METADATA, NEED TO CHECK FOR LAYOUTS AND OTHERS] - * - * @param string $dirPath - * @param string $type - name of type array("metadata", "layouts"), ex. $this->name - * @param bool $recursively - Note: only for first level of sub directory, other levels of sub directories will be ignored - * @param string $moduleName - name of module if exists - * - * @return string - content of the files - */ - protected function unifySingle($dirPath, $type, $recursively = false, $moduleName = '') - { - if (empty($dirPath) || !file_exists($dirPath)) { - return false; - } - $unsetFileName = $this->params['unsetFileName']; + /** + * Unite file content to the file for one directory [NOW ONLY FOR METADATA, NEED TO CHECK FOR LAYOUTS AND OTHERS] + * + * @param string $dirPath + * @param string $type - name of type array("metadata", "layouts"), ex. $this->name + * @param bool $recursively - Note: only for first level of sub directory, other levels of sub directories will be ignored + * @param string $moduleName - name of module if exists + * + * @return string - content of the files + */ + protected function unifySingle($dirPath, $type, $recursively = false, $moduleName = '') + { + if (empty($dirPath) || !file_exists($dirPath)) { + return false; + } + $unsetFileName = $this->params['unsetFileName']; - //get matadata files - $fileList = $this->getFileManager()->getFileList($dirPath, $recursively, '\.json$'); + //get matadata files + $fileList = $this->getFileManager()->getFileList($dirPath, $recursively, '\.json$'); - $dirName = $this->getFileManager()->getDirName($dirPath, false); - $defaultValues = $this->loadDefaultValues($dirName, $type); + $dirName = $this->getFileManager()->getDirName($dirPath, false); + $defaultValues = $this->loadDefaultValues($dirName, $type); - $content = array(); - $unsets = array(); - foreach($fileList as $dirName => $fileName) { + $content = array(); + $unsets = array(); + foreach($fileList as $dirName => $fileName) { - if (is_array($fileName)) { /*get content from files in a sub directory*/ - $content[$dirName]= $this->unifySingle(Utils\Util::concatPath($dirPath,$dirName), $type, false, $moduleName); //only first level of a sub directory + if (is_array($fileName)) { /*get content from files in a sub directory*/ + $content[$dirName]= $this->unifySingle(Utils\Util::concatPath($dirPath,$dirName), $type, false, $moduleName); //only first level of a sub directory - } else { /*get content from a single file*/ - if ($fileName == $unsetFileName) { - $fileContent = $this->getFileManager()->getContents(array($dirPath, $fileName)); - $unsets = Utils\Json::getArrayData($fileContent); - continue; - } /*END: Save data from unset.json*/ + } else { /*get content from a single file*/ + if ($fileName == $unsetFileName) { + $fileContent = $this->getFileManager()->getContents(array($dirPath, $fileName)); + $unsets = Utils\Json::getArrayData($fileContent); + continue; + } /*END: Save data from unset.json*/ - $mergedValues = $this->unifyGetContents(array($dirPath, $fileName), $defaultValues); + $mergedValues = $this->unifyGetContents(array($dirPath, $fileName), $defaultValues); - if (!empty($mergedValues)) { - $name = $this->getFileManager()->getFileName($fileName, '.json'); - $content[$name] = $mergedValues; - } - } - } + if (!empty($mergedValues)) { + $name = $this->getFileManager()->getFileName($fileName, '.json'); + $content[$name] = $mergedValues; + } + } + } - //unset content - $content = Utils\Util::unsetInArray($content, $unsets); - //END: unset content + //unset content + $content = Utils\Util::unsetInArray($content, $unsets); + //END: unset content - return $content; - } + return $content; + } - /** - * Helpful method for get content from files for unite Files - * - * @param string | array $paths - * @param string | array() $defaults - It can be a string like ["metadata","layouts"] OR an array with default values - * - * @return array - */ - protected function unifyGetContents($paths, $defaults) - { - $fileContent = $this->getFileManager()->getContents($paths); + /** + * Helpful method for get content from files for unite Files + * + * @param string | array $paths + * @param string | array() $defaults - It can be a string like ["metadata","layouts"] OR an array with default values + * + * @return array + */ + protected function unifyGetContents($paths, $defaults) + { + $fileContent = $this->getFileManager()->getContents($paths); - $decoded = Utils\Json::getArrayData($fileContent, null); + $decoded = Utils\Json::getArrayData($fileContent, null); - if (!isset($decoded)) { - $GLOBALS['log']->emergency('Syntax error in '.Utils\Util::concatPath($paths)); - return array(); - } + if (!isset($decoded)) { + $GLOBALS['log']->emergency('Syntax error in '.Utils\Util::concatPath($paths)); + return array(); + } - return $decoded; - } + return $decoded; + } - /** - * Load default values for selected type [metadata, layouts] - * - * @param string $name - * @param string $type - [metadata, layouts] - * - * @return array - */ - protected function loadDefaultValues($name, $type = 'metadata') - { - $defaultPath = $this->params['defaultsPath']; + /** + * Load default values for selected type [metadata, layouts] + * + * @param string $name + * @param string $type - [metadata, layouts] + * + * @return array + */ + protected function loadDefaultValues($name, $type = 'metadata') + { + $defaultPath = $this->params['defaultsPath']; - $defaultValue = $this->getFileManager()->getContents( array($defaultPath, $type, $name.'.json') ); - if ($defaultValue !== false) { - //return default array - return Utils\Json::decode($defaultValue, true); - } + $defaultValue = $this->getFileManager()->getContents( array($defaultPath, $type, $name.'.json') ); + if ($defaultValue !== false) { + //return default array + return Utils\Json::decode($defaultValue, true); + } - return array(); - } + return array(); + } } diff --git a/application/Espo/Core/Utils/File/ZipArchive.php b/application/Espo/Core/Utils/File/ZipArchive.php index 0c55578db0..46bb414d6c 100644 --- a/application/Espo/Core/Utils/File/ZipArchive.php +++ b/application/Espo/Core/Utils/File/ZipArchive.php @@ -26,56 +26,56 @@ use Espo\Core\Exceptions\Error; class ZipArchive { - private $fileManager; + private $fileManager; - public function __construct(Manager $fileManager = null) - { - if (!isset($fileManager)) { - $fileManager = new Manager(); - } + public function __construct(Manager $fileManager = null) + { + if (!isset($fileManager)) { + $fileManager = new Manager(); + } - $this->fileManager = $fileManager; - } + $this->fileManager = $fileManager; + } - protected function getFileManager() - { - return $this->fileManager; - } + protected function getFileManager() + { + return $this->fileManager; + } - public function zip($sourcePath, $file) - { + public function zip($sourcePath, $file) + { - } + } - /** - * Unzip archive - * - * @param string $file Path to .zip file - * @param [type] $destinationPath - * @return bool - */ - public function unzip($file, $destinationPath) - { - if (!class_exists('\ZipArchive')) { - throw new Error("Class ZipArchive does not installed. Cannot unzip the file."); - } + /** + * Unzip archive + * + * @param string $file Path to .zip file + * @param [type] $destinationPath + * @return bool + */ + public function unzip($file, $destinationPath) + { + if (!class_exists('\ZipArchive')) { + throw new Error("Class ZipArchive does not installed. Cannot unzip the file."); + } - $zip = new \ZipArchive; - $res = $zip->open($file); + $zip = new \ZipArchive; + $res = $zip->open($file); - if ($res === TRUE) { + if ($res === TRUE) { - $this->getFileManager()->mkdir($destinationPath); + $this->getFileManager()->mkdir($destinationPath); - $zip->extractTo($destinationPath); - $zip->close(); + $zip->extractTo($destinationPath); + $zip->close(); - return true; - } + return true; + } - return false; - } + return false; + } } \ No newline at end of file diff --git a/application/Espo/Core/Utils/Json.php b/application/Espo/Core/Utils/Json.php index 340cb58d01..af4d1565e4 100644 --- a/application/Espo/Core/Utils/Json.php +++ b/application/Espo/Core/Utils/Json.php @@ -24,161 +24,161 @@ namespace Espo\Core\Utils; class Json { - /** - * JSON encode a string - * - * @param string $value - * @param int $options Default 0 - * @param int $depth Default 512 - * @return string - */ - public static function encode($value, $options = 0, $depth = 512) - { - if (version_compare(phpversion(), '5.5.0', '>=')) { - $json = json_encode($value, $options, $depth); - } - elseif (version_compare(phpversion(), '5.3.0', '>=')) { - /*Check if options are supported for this version of PHP*/ - if (is_int($options)) { - $json = json_encode($value, $options); - } - else { - $json = json_encode($value); - } - } - else { - $json = json_encode($value); - } + /** + * JSON encode a string + * + * @param string $value + * @param int $options Default 0 + * @param int $depth Default 512 + * @return string + */ + public static function encode($value, $options = 0, $depth = 512) + { + if (version_compare(phpversion(), '5.5.0', '>=')) { + $json = json_encode($value, $options, $depth); + } + elseif (version_compare(phpversion(), '5.3.0', '>=')) { + /*Check if options are supported for this version of PHP*/ + if (is_int($options)) { + $json = json_encode($value, $options); + } + else { + $json = json_encode($value); + } + } + else { + $json = json_encode($value); + } - $error = self::getLastError(); - if ($json === null || $error) { - $GLOBALS['log']->error('Json::encode():' . $error . ' - ' . print_r($value, true)); - } + $error = self::getLastError(); + if ($json === null || $error) { + $GLOBALS['log']->error('Json::encode():' . $error . ' - ' . print_r($value, true)); + } - return $json; - } + return $json; + } - /** - * JSON decode a string (Fixed problem with "\") - * - * @param string $json - * @param bool $assoc Default false - * @param int $depth Default 512 - * @param int $options Default 0 - * @return object - */ - public static function decode($json, $assoc = false, $depth = 512, $options = 0) - { - if (is_array($json)) { - $GLOBALS['log']->warning('Json::decode() - JSON cannot be decoded - '.$json); - return false; - } + /** + * JSON decode a string (Fixed problem with "\") + * + * @param string $json + * @param bool $assoc Default false + * @param int $depth Default 512 + * @param int $options Default 0 + * @return object + */ + public static function decode($json, $assoc = false, $depth = 512, $options = 0) + { + if (is_array($json)) { + $GLOBALS['log']->warning('Json::decode() - JSON cannot be decoded - '.$json); + return false; + } - if(version_compare(phpversion(), '5.4.0', '>=')) { - $json = json_decode($json, $assoc, $depth, $options); - } - elseif(version_compare(phpversion(), '5.3.0', '>=')) { - $json = json_decode($json, $assoc, $depth); - } - else { - $json = json_decode($json, $assoc); - } + if(version_compare(phpversion(), '5.4.0', '>=')) { + $json = json_decode($json, $assoc, $depth, $options); + } + elseif(version_compare(phpversion(), '5.3.0', '>=')) { + $json = json_decode($json, $assoc, $depth); + } + else { + $json = json_decode($json, $assoc); + } - $error = self::getLastError(); - if ($json === null || $error) { - $GLOBALS['log']->error('Json::decode():' . $error); - } + $error = self::getLastError(); + if ($json === null || $error) { + $GLOBALS['log']->error('Json::decode():' . $error); + } - return $json; - } + return $json; + } - /** - * Check if the string is JSON - * - * @param string $json - * @return bool - */ - public static function isJSON($json) - { - if ($json === '[]' || $json === '{}') { - return true; - } else if (is_array($json)) { - return false; - } + /** + * Check if the string is JSON + * + * @param string $json + * @return bool + */ + public static function isJSON($json) + { + if ($json === '[]' || $json === '{}') { + return true; + } else if (is_array($json)) { + return false; + } - return static::decode($json) != null; - } + return static::decode($json) != null; + } - /** - * Get an array data (if JSON convert to array) - * - * @param mixed $data - can be JSON, array - * - * @return array - */ - public static function getArrayData($data, $returns = array()) - { - if (is_array($data)) { - return $data; - } - else if (static::isJSON($data)) { - return static::decode($data, true); - } + /** + * Get an array data (if JSON convert to array) + * + * @param mixed $data - can be JSON, array + * + * @return array + */ + public static function getArrayData($data, $returns = array()) + { + if (is_array($data)) { + return $data; + } + else if (static::isJSON($data)) { + return static::decode($data, true); + } - return $returns; - } + return $returns; + } - protected static function getLastError($error = null) - { - if (!isset($error)) { - $error = json_last_error(); - } + protected static function getLastError($error = null) + { + if (!isset($error)) { + $error = json_last_error(); + } - switch ($error) { - case JSON_ERROR_NONE: - return false; - break; + switch ($error) { + case JSON_ERROR_NONE: + return false; + break; - case JSON_ERROR_DEPTH: - return 'The maximum stack depth has been exceeded'; - break; + case JSON_ERROR_DEPTH: + return 'The maximum stack depth has been exceeded'; + break; - case JSON_ERROR_STATE_MISMATCH: - return 'Invalid or malformed JSON'; - break; + case JSON_ERROR_STATE_MISMATCH: + return 'Invalid or malformed JSON'; + break; - case JSON_ERROR_CTRL_CHAR: - return 'Control character error, possibly incorrectly encoded'; - break; + case JSON_ERROR_CTRL_CHAR: + return 'Control character error, possibly incorrectly encoded'; + break; - case JSON_ERROR_SYNTAX: - return 'Syntax error, malformed JSON'; - break; + case JSON_ERROR_SYNTAX: + return 'Syntax error, malformed JSON'; + break; - case JSON_ERROR_UTF8: - return 'Malformed UTF-8 characters, possibly incorrectly encoded'; - break; + case JSON_ERROR_UTF8: + return 'Malformed UTF-8 characters, possibly incorrectly encoded'; + break; - /* Only for PHP 5.5.0 - case JSON_ERROR_RECURSION: - return 'One or more recursive references in the value to be encoded'; - break; - case JSON_ERROR_INF_OR_NAN: - return 'One or more NAN or INF values in the value to be encoded'; - break; - case JSON_ERROR_UNSUPPORTED_TYPE: - return 'A value of a type that cannot be encoded was given'; - break; - */ + /* Only for PHP 5.5.0 + case JSON_ERROR_RECURSION: + return 'One or more recursive references in the value to be encoded'; + break; + case JSON_ERROR_INF_OR_NAN: + return 'One or more NAN or INF values in the value to be encoded'; + break; + case JSON_ERROR_UNSUPPORTED_TYPE: + return 'A value of a type that cannot be encoded was given'; + break; + */ - default: - return 'Unknown error'; - break; - } - } + default: + return 'Unknown error'; + break; + } + } } diff --git a/application/Espo/Core/Utils/Language.php b/application/Espo/Core/Utils/Language.php index abe599192b..e89a29c163 100644 --- a/application/Espo/Core/Utils/Language.php +++ b/application/Espo/Core/Utils/Language.php @@ -23,251 +23,251 @@ namespace Espo\Core\Utils; use \Espo\Core\Utils\Util, - \Espo\Core\Exceptions\NotFound, - \Espo\Core\Exceptions\Error; + \Espo\Core\Exceptions\NotFound, + \Espo\Core\Exceptions\Error; class Language { - private $fileManager; - private $config; - private $preferences; - private $unifier; + private $fileManager; + private $config; + private $preferences; + private $unifier; - private $data = null; + private $data = null; - private $name = 'i18n'; + private $name = 'i18n'; - private $currentLanguage = null; + private $currentLanguage = null; - protected $cacheFile = 'data/cache/application/languages/{*}.php'; + protected $cacheFile = 'data/cache/application/languages/{*}.php'; - protected $defaultLanguage = 'en_US'; + protected $defaultLanguage = 'en_US'; - /** + /** * @var array */ - private $paths = array( - 'corePath' => 'application/Espo/Resources/i18n', - 'modulePath' => 'application/Espo/Modules/{*}/Resources/i18n', - 'customPath' => 'custom/Espo/Custom/Resources/i18n', - ); + private $paths = array( + 'corePath' => 'application/Espo/Resources/i18n', + 'modulePath' => 'application/Espo/Modules/{*}/Resources/i18n', + 'customPath' => 'custom/Espo/Custom/Resources/i18n', + ); - public function __construct(\Espo\Core\Utils\File\Manager $fileManager, \Espo\Core\Utils\Config $config, \Espo\Entities\Preferences $preferences = null) - { - $this->fileManager = $fileManager; - $this->config = $config; - $this->preferences = $preferences; + public function __construct(\Espo\Core\Utils\File\Manager $fileManager, \Espo\Core\Utils\Config $config, \Espo\Entities\Preferences $preferences = null) + { + $this->fileManager = $fileManager; + $this->config = $config; + $this->preferences = $preferences; - $this->unifier = new \Espo\Core\Utils\File\Unifier($this->fileManager); - } + $this->unifier = new \Espo\Core\Utils\File\Unifier($this->fileManager); + } - protected function getFileManager() - { - return $this->fileManager; - } + protected function getFileManager() + { + return $this->fileManager; + } - protected function getConfig() - { - return $this->config; - } + protected function getConfig() + { + return $this->config; + } - protected function getPreferences() - { - return $this->preferences; - } + protected function getPreferences() + { + return $this->preferences; + } - protected function getUnifier() - { - return $this->unifier; - } + protected function getUnifier() + { + return $this->unifier; + } - public function getLanguage() - { - if (!isset($this->currentLanguage) && isset($this->preferences)) { - $this->currentLanguage = $this->getPreferences()->get('language'); - } + public function getLanguage() + { + if (!isset($this->currentLanguage) && isset($this->preferences)) { + $this->currentLanguage = $this->getPreferences()->get('language'); + } - if (empty($this->currentLanguage)) { - $this->currentLanguage = $this->getConfig()->get('language'); - } + if (empty($this->currentLanguage)) { + $this->currentLanguage = $this->getConfig()->get('language'); + } - return $this->currentLanguage; - } + return $this->currentLanguage; + } - public function setLanguage($language) - { - $this->currentLanguage = $language; - } + public function setLanguage($language) + { + $this->currentLanguage = $language; + } - protected function getLangCacheFile() - { - $langCacheFile = str_replace('{*}', $this->getLanguage(), $this->cacheFile); + protected function getLangCacheFile() + { + $langCacheFile = str_replace('{*}', $this->getLanguage(), $this->cacheFile); - return $langCacheFile; - } + return $langCacheFile; + } - /** - * Translate label/labels - * - * @param string $label name of label - * @param string $category - * @param string $scope - * @param array $requiredOptions List of required options. - * Ex., $requiredOptions = array('en_US', 'de_DE') - * "language" option has only array('en_US' => 'English (United States)',) - * Result will be array('en_US' => 'English (United States)', 'de_DE' => 'de_DE',) - * @return string | array - */ - public function translate($label, $category = 'labels', $scope = 'Global', $requiredOptions = null) - { - if (is_array($label)) { - $translated = array(); + /** + * Translate label/labels + * + * @param string $label name of label + * @param string $category + * @param string $scope + * @param array $requiredOptions List of required options. + * Ex., $requiredOptions = array('en_US', 'de_DE') + * "language" option has only array('en_US' => 'English (United States)',) + * Result will be array('en_US' => 'English (United States)', 'de_DE' => 'de_DE',) + * @return string | array + */ + public function translate($label, $category = 'labels', $scope = 'Global', $requiredOptions = null) + { + if (is_array($label)) { + $translated = array(); - foreach ($label as $subLabel) { - $translated[$subLabel] = $this->translate($subLabel, $category, $scope, $requiredOptions); - } + foreach ($label as $subLabel) { + $translated[$subLabel] = $this->translate($subLabel, $category, $scope, $requiredOptions); + } - return $translated; - } + return $translated; + } - $key = $scope.'.'.$category.'.'.$label; - $translated = $this->get($key); + $key = $scope.'.'.$category.'.'.$label; + $translated = $this->get($key); - if (!isset($translated)) { - $key = 'Global.'.$category.'.'.$label; - $translated = $this->get($key, $label); - } + if (!isset($translated)) { + $key = 'Global.'.$category.'.'.$label; + $translated = $this->get($key, $label); + } - if (is_array($translated) && isset($requiredOptions)) { + if (is_array($translated) && isset($requiredOptions)) { - $translated = array_intersect_key($translated, array_flip($requiredOptions)); + $translated = array_intersect_key($translated, array_flip($requiredOptions)); - $optionKeys = array_keys($translated); - foreach ($requiredOptions as $option) { - if (!in_array($option, $optionKeys)) { - $translated[$option] = $option; - } - } - } + $optionKeys = array_keys($translated); + foreach ($requiredOptions as $option) { + if (!in_array($option, $optionKeys)) { + $translated[$option] = $option; + } + } + } - return $translated; - } + return $translated; + } - public function translateOption($value, $field, $scope) - { - $options = $this->get($scope. '.options.' . $field); - if (array_key_exists($value, $options)) { - return $options[$value]; - } - return $value; - } + public function translateOption($value, $field, $scope) + { + $options = $this->get($scope. '.options.' . $field); + if (array_key_exists($value, $options)) { + return $options[$value]; + } + return $value; + } - public function get($key = null, $returns = null) - { - $data = $this->getData(); + public function get($key = null, $returns = null) + { + $data = $this->getData(); - if (!isset($data) || $data === false) { - throw new Error('Language: current language ['.$this->getLanguage().'] does not found'); - } + if (!isset($data) || $data === false) { + throw new Error('Language: current language ['.$this->getLanguage().'] does not found'); + } - return Util::getValueByKey($data, $key, $returns); - } + return Util::getValueByKey($data, $key, $returns); + } - public function getAll() - { - return $this->get(); - } + public function getAll() + { + return $this->get(); + } - /** - * Get data of Unifier language files - * - * @return array - */ - protected function getData() - { - if (!isset($this->data)) { - $this->init(); - } + /** + * Get data of Unifier language files + * + * @return array + */ + protected function getData() + { + if (!isset($this->data)) { + $this->init(); + } - return $this->data; - } + return $this->data; + } - public function set($label, $value, $category = 'labels', $scope = 'Global') - { - $path = $this->paths['customPath']; - $currentLanguage = $this->getLanguage(); + public function set($label, $value, $category = 'labels', $scope = 'Global') + { + $path = $this->paths['customPath']; + $currentLanguage = $this->getLanguage(); - $data = $this->normalizeDefs($label, $value, $category); + $data = $this->normalizeDefs($label, $value, $category); - $result = $this->getFileManager()->mergeContents(array($path, $currentLanguage, $scope.'.json'), $data, true); - if ($result === false) { - throw new Error("Error saving languages. See log file for details."); - } + $result = $this->getFileManager()->mergeContents(array($path, $currentLanguage, $scope.'.json'), $data, true); + if ($result === false) { + throw new Error("Error saving languages. See log file for details."); + } - $this->init(true); + $this->init(true); return $result; - } + } - public function delete($label, $category = 'labels', $scope = 'Global') - { - $path = $this->paths['customPath']; - $currentLanguage = $this->getLanguage(); + public function delete($label, $category = 'labels', $scope = 'Global') + { + $path = $this->paths['customPath']; + $currentLanguage = $this->getLanguage(); - $unsets = array( - $category => $label, - ); + $unsets = array( + $category => $label, + ); - $result = $this->getFileManager()->unsetContents(array($path, $currentLanguage, $scope.'.json'), $unsets, true); + $result = $this->getFileManager()->unsetContents(array($path, $currentLanguage, $scope.'.json'), $unsets, true); - $this->init(true); + $this->init(true); - return $result; - } + return $result; + } - protected function init($reload = false) - { - if ($reload || !file_exists($this->getLangCacheFile()) || !$this->getConfig()->get('useCache')) { - $this->fullData = $this->getUnifier()->unify($this->name, $this->paths, true); + protected function init($reload = false) + { + if ($reload || !file_exists($this->getLangCacheFile()) || !$this->getConfig()->get('useCache')) { + $this->fullData = $this->getUnifier()->unify($this->name, $this->paths, true); - $result = true; - foreach ($this->fullData as $i18nName => $i18nData) { - $i18nCacheFile = str_replace('{*}', $i18nName, $this->cacheFile); + $result = true; + foreach ($this->fullData as $i18nName => $i18nData) { + $i18nCacheFile = str_replace('{*}', $i18nName, $this->cacheFile); - if ($i18nName != $this->defaultLanguage) { - $i18nData = Util::merge($this->fullData[$this->defaultLanguage], $i18nData); - } - $result &= $this->getFileManager()->putContentsPHP($i18nCacheFile, $i18nData); - } + if ($i18nName != $this->defaultLanguage) { + $i18nData = Util::merge($this->fullData[$this->defaultLanguage], $i18nData); + } + $result &= $this->getFileManager()->putContentsPHP($i18nCacheFile, $i18nData); + } - if ($result == false) { - throw new Error('Language::init() - Cannot save data to a cache'); - } - } + if ($result == false) { + throw new Error('Language::init() - Cannot save data to a cache'); + } + } - $this->data = $this->getFileManager()->getContents($this->getLangCacheFile()); - } + $this->data = $this->getFileManager()->getContents($this->getLangCacheFile()); + } - protected function normalizeDefs($label, $value, $category) - { - if (!is_array($label)) { - $label = array( - $label => $value, - ); - } + protected function normalizeDefs($label, $value, $category) + { + if (!is_array($label)) { + $label = array( + $label => $value, + ); + } - $data = array( - $category => $label, - ); + $data = array( + $category => $label, + ); - return $data; - } + return $data; + } diff --git a/application/Espo/Core/Utils/Layout.php b/application/Espo/Core/Utils/Layout.php index 07c78e323e..b839990244 100644 --- a/application/Espo/Core/Utils/Layout.php +++ b/application/Espo/Core/Utils/Layout.php @@ -24,150 +24,150 @@ namespace Espo\Core\Utils; class Layout { - private $fileManager; - private $metadata; - - /** + private $fileManager; + private $metadata; + + /** * @var string - uses for loading default values */ - private $name = 'layout'; + private $name = 'layout'; - protected $params = array( - 'defaultsPath' => 'application/Espo/Core/defaults', - ); + protected $params = array( + 'defaultsPath' => 'application/Espo/Core/defaults', + ); - /** + /** * @var array - path to layout files */ - private $paths = array( - 'corePath' => 'application/Espo/Resources/layouts', - 'modulePath' => 'application/Espo/Modules/{*}/Resources/layouts', - 'customPath' => 'custom/Espo/Custom/Resources/layouts', - ); - + private $paths = array( + 'corePath' => 'application/Espo/Resources/layouts', + 'modulePath' => 'application/Espo/Modules/{*}/Resources/layouts', + 'customPath' => 'custom/Espo/Custom/Resources/layouts', + ); + - public function __construct(\Espo\Core\Utils\File\Manager $fileManager, \Espo\Core\Utils\Metadata $metadata) - { - $this->fileManager = $fileManager; - $this->metadata = $metadata; - } + public function __construct(\Espo\Core\Utils\File\Manager $fileManager, \Espo\Core\Utils\Metadata $metadata) + { + $this->fileManager = $fileManager; + $this->metadata = $metadata; + } - protected function getFileManager() - { - return $this->fileManager; - } + protected function getFileManager() + { + return $this->fileManager; + } - protected function getMetadata() - { - return $this->metadata; - } + protected function getMetadata() + { + return $this->metadata; + } - /** + /** * Get Layout context - * - * @param $controller - * @param $name - * - * @return json - */ - public function get($controller, $name) - { - $fileFullPath = Util::concatPath($this->getLayoutPath($controller, true), $name.'.json'); - if (!file_exists($fileFullPath)) { - $fileFullPath = Util::concatPath($this->getLayoutPath($controller), $name.'.json'); - } - - if (!file_exists($fileFullPath)) { - //load defaults - $defaultPath = $this->params['defaultsPath']; - $fileFullPath = Util::concatPath( Util::concatPath($defaultPath, $this->name), $name.'.json' ); - //END: load defaults - - if (!file_exists($fileFullPath)) { - return false; - } - } - - return $this->getFileManager()->getContents($fileFullPath); - } - - - /** - * Set Layout data - * Ex. $controller= Account, $name= detail then will be created a file layoutFolder/Account/detail.json * - * @param JSON string $data - * @param string $controller - ex. Account - * @param string $name - detail - * - * @return bool - */ - public function set($data, $controller, $name) - { - if (empty($controller) || empty($name)) { - return false; - } - - $layoutPath = $this->getLayoutPath($controller, true); - - if (!Json::isJSON($data)) { - $data = Json::encode($data); - } + * @param $controller + * @param $name + * + * @return json + */ + public function get($controller, $name) + { + $fileFullPath = Util::concatPath($this->getLayoutPath($controller, true), $name.'.json'); + if (!file_exists($fileFullPath)) { + $fileFullPath = Util::concatPath($this->getLayoutPath($controller), $name.'.json'); + } + + if (!file_exists($fileFullPath)) { + //load defaults + $defaultPath = $this->params['defaultsPath']; + $fileFullPath = Util::concatPath( Util::concatPath($defaultPath, $this->name), $name.'.json' ); + //END: load defaults + + if (!file_exists($fileFullPath)) { + return false; + } + } + + return $this->getFileManager()->getContents($fileFullPath); + } + + + /** + * Set Layout data + * Ex. $controller= Account, $name= detail then will be created a file layoutFolder/Account/detail.json + * + * @param JSON string $data + * @param string $controller - ex. Account + * @param string $name - detail + * + * @return bool + */ + public function set($data, $controller, $name) + { + if (empty($controller) || empty($name)) { + return false; + } + + $layoutPath = $this->getLayoutPath($controller, true); + + if (!Json::isJSON($data)) { + $data = Json::encode($data); + } return $this->getFileManager()->putContents(array($layoutPath, $name.'.json'), $data); - } + } - /** - * Merge layout data - * Ex. $controller= Account, $name= detail then will be created a file layoutFolder/Account/detail.json + /** + * Merge layout data + * Ex. $controller= Account, $name= detail then will be created a file layoutFolder/Account/detail.json * - * @param JSON string $data - * @param string $controller - ex. Account - * @param string $name - detail - * - * @return bool - */ - public function merge($data, $controller, $name) - { - $prevData = $this->get($controller, $name); - - $prevDataArray= Json::getArrayData($prevData); - $dataArray= Json::getArrayData($data); + * @param JSON string $data + * @param string $controller - ex. Account + * @param string $name - detail + * + * @return bool + */ + public function merge($data, $controller, $name) + { + $prevData = $this->get($controller, $name); + + $prevDataArray= Json::getArrayData($prevData); + $dataArray= Json::getArrayData($data); - $data= Util::merge($prevDataArray, $dataArray); - $data= Json::encode($data); + $data= Util::merge($prevDataArray, $dataArray); + $data= Json::encode($data); return $this->set($data, $controller, $name); - } + } /** * Get Layout path, ex. application/Modules/Crm/Layouts/Account * - * @param string $entityName - * @param bool $isCustom - if need to check custom folder - * - * @return string - */ - protected function getLayoutPath($entityName, $isCustom = false) - { - $path = $this->paths['customPath']; + * @param string $entityName + * @param bool $isCustom - if need to check custom folder + * + * @return string + */ + protected function getLayoutPath($entityName, $isCustom = false) + { + $path = $this->paths['customPath']; - if (!$isCustom) { - $moduleName = $this->getMetadata()->getScopeModuleName($entityName); - - $path = $this->paths['corePath']; - if ($moduleName !== false) { - $path = str_replace('{*}', $moduleName, $this->paths['modulePath']); - } - } - + if (!$isCustom) { + $moduleName = $this->getMetadata()->getScopeModuleName($entityName); + + $path = $this->paths['corePath']; + if ($moduleName !== false) { + $path = str_replace('{*}', $moduleName, $this->paths['modulePath']); + } + } + $path = Util::concatPath($path, $entityName); - return $path; - } + return $path; + } } diff --git a/application/Espo/Core/Utils/Log/Monolog/Handler/RotatingFileHandler.php b/application/Espo/Core/Utils/Log/Monolog/Handler/RotatingFileHandler.php index c9a48a507e..b617035a55 100644 --- a/application/Espo/Core/Utils/Log/Monolog/Handler/RotatingFileHandler.php +++ b/application/Espo/Core/Utils/Log/Monolog/Handler/RotatingFileHandler.php @@ -26,92 +26,92 @@ use Monolog\Logger; class RotatingFileHandler extends StreamHandler { - /** - * Date format as a part of filename - * @var string - */ - protected $dateFormat = 'Y-m-d'; + /** + * Date format as a part of filename + * @var string + */ + protected $dateFormat = 'Y-m-d'; - /** - * Filename format - * @var string - */ - protected $filenameFormat = '{filename}-{date}'; + /** + * Filename format + * @var string + */ + protected $filenameFormat = '{filename}-{date}'; - protected $filename; + protected $filename; - protected $maxFiles; + protected $maxFiles; - public function __construct($filename, $maxFiles = 0, $level = Logger::DEBUG, $bubble = true) - { - $this->filename = $filename; - $this->maxFiles = (int) $maxFiles; + public function __construct($filename, $maxFiles = 0, $level = Logger::DEBUG, $bubble = true) + { + $this->filename = $filename; + $this->maxFiles = (int) $maxFiles; - parent::__construct($this->getTimedFilename(), $level, $bubble); + parent::__construct($this->getTimedFilename(), $level, $bubble); - $this->rotate(); - } + $this->rotate(); + } - public function setFilenameFormat($filenameFormat, $dateFormat) - { - $this->filenameFormat = $filenameFormat; - $this->dateFormat = $dateFormat; - } + public function setFilenameFormat($filenameFormat, $dateFormat) + { + $this->filenameFormat = $filenameFormat; + $this->dateFormat = $dateFormat; + } - protected function rotate() - { - if (0 === $this->maxFiles) { - return; //unlimited number of files for 0 - } + protected function rotate() + { + if (0 === $this->maxFiles) { + return; //unlimited number of files for 0 + } - $filePattern = $this->getFilePattern(); - $dirPath = $this->getFileManager()->getDirName($this->filename); - $logFiles = $this->getFileManager()->getFileList($dirPath, false, $filePattern, 'file'); + $filePattern = $this->getFilePattern(); + $dirPath = $this->getFileManager()->getDirName($this->filename); + $logFiles = $this->getFileManager()->getFileList($dirPath, false, $filePattern, true); - if (!empty($logFiles) && count($logFiles) > $this->maxFiles) { + if (!empty($logFiles) && count($logFiles) > $this->maxFiles) { - usort($logFiles, function($a, $b) { - return strcmp($b, $a); - }); + usort($logFiles, function($a, $b) { + return strcmp($b, $a); + }); - $logFilesToBeRemoved = array_slice($logFiles, $this->maxFiles); + $logFilesToBeRemoved = array_slice($logFiles, $this->maxFiles); - $this->getFileManager()->removeFile($logFilesToBeRemoved, $dirPath); - } - } + $this->getFileManager()->removeFile($logFilesToBeRemoved, $dirPath); + } + } - protected function getTimedFilename() - { - $fileInfo = pathinfo($this->filename); - $timedFilename = str_replace( - array('{filename}', '{date}'), - array($fileInfo['filename'], date($this->dateFormat)), - $fileInfo['dirname'] . '/' . $this->filenameFormat - ); + protected function getTimedFilename() + { + $fileInfo = pathinfo($this->filename); + $timedFilename = str_replace( + array('{filename}', '{date}'), + array($fileInfo['filename'], date($this->dateFormat)), + $fileInfo['dirname'] . '/' . $this->filenameFormat + ); - if (!empty($fileInfo['extension'])) { - $timedFilename .= '.'.$fileInfo['extension']; - } + if (!empty($fileInfo['extension'])) { + $timedFilename .= '.'.$fileInfo['extension']; + } - return $timedFilename; - } + return $timedFilename; + } - protected function getFilePattern() - { - $fileInfo = pathinfo($this->filename); - $glob = str_replace( - array('{filename}', '{date}'), - array($fileInfo['filename'], '.*'), - $this->filenameFormat - ); + protected function getFilePattern() + { + $fileInfo = pathinfo($this->filename); + $glob = str_replace( + array('{filename}', '{date}'), + array($fileInfo['filename'], '.*'), + $this->filenameFormat + ); - if (!empty($fileInfo['extension'])) { - $glob .= '\.'.$fileInfo['extension']; - } + if (!empty($fileInfo['extension'])) { + $glob .= '\.'.$fileInfo['extension']; + } - $glob = '^'.$glob.'$'; + $glob = '^'.$glob.'$'; - return $glob; - } + return $glob; + } } \ No newline at end of file diff --git a/application/Espo/Core/Utils/Log/Monolog/Handler/StreamHandler.php b/application/Espo/Core/Utils/Log/Monolog/Handler/StreamHandler.php index e611a7be49..6052c7af99 100644 --- a/application/Espo/Core/Utils/Log/Monolog/Handler/StreamHandler.php +++ b/application/Espo/Core/Utils/Log/Monolog/Handler/StreamHandler.php @@ -26,61 +26,61 @@ use Monolog\Logger; class StreamHandler extends \Monolog\Handler\StreamHandler { - protected $fileManager; + protected $fileManager; - protected $maxErrorMessageLength = 5000; + protected $maxErrorMessageLength = 5000; - public function __construct($url, $level = Logger::DEBUG, $bubble = true) - { - parent::__construct($url, $level, $bubble); + public function __construct($url, $level = Logger::DEBUG, $bubble = true) + { + parent::__construct($url, $level, $bubble); - $this->fileManager = new \Espo\Core\Utils\File\Manager(); - } + $this->fileManager = new \Espo\Core\Utils\File\Manager(); + } - protected function getFileManager() - { - return $this->fileManager; - } + protected function getFileManager() + { + return $this->fileManager; + } - protected function write(array $record) - { - if (!$this->url) { - throw new \LogicException('Missing logger path, the stream can not be opened. Please check logger options in the data/config.php.'); - } + protected function write(array $record) + { + if (!$this->url) { + throw new \LogicException('Missing logger path, the stream can not be opened. Please check logger options in the data/config.php.'); + } - $this->errorMessage = null; + $this->errorMessage = null; - set_error_handler(array($this, 'customErrorHandler')); - $this->getFileManager()->appendContents($this->url, $this->pruneMessage($record)); - restore_error_handler(); + set_error_handler(array($this, 'customErrorHandler')); + $this->getFileManager()->appendContents($this->url, $this->pruneMessage($record)); + restore_error_handler(); - if (isset($this->errorMessage)) { - throw new \UnexpectedValueException(sprintf('The stream or file "%s" could not be opened: '.$this->errorMessage, $this->url)); - } - } + if (isset($this->errorMessage)) { + throw new \UnexpectedValueException(sprintf('The stream or file "%s" could not be opened: '.$this->errorMessage, $this->url)); + } + } - private function customErrorHandler($code, $msg) - { - $this->errorMessage = $msg; - } + private function customErrorHandler($code, $msg) + { + $this->errorMessage = $msg; + } - /** - * Cut the error message depends on maxErrorMessageLength - * - * @param array $record - * @return string - */ - protected function pruneMessage(array $record) - { - $message = (string) $record['message']; + /** + * Cut the error message depends on maxErrorMessageLength + * + * @param array $record + * @return string + */ + protected function pruneMessage(array $record) + { + $message = (string) $record['message']; - if (strlen($message) > $this->maxErrorMessageLength) { - $record['message'] = substr($message, 0, $this->maxErrorMessageLength) . '...'; - $record['formatted'] = $this->getFormatter()->format($record); - } + if (strlen($message) > $this->maxErrorMessageLength) { + $record['message'] = substr($message, 0, $this->maxErrorMessageLength) . '...'; + $record['formatted'] = $this->getFormatter()->format($record); + } - return (string) $record['formatted']; - } + return (string) $record['formatted']; + } } \ No newline at end of file diff --git a/application/Espo/Core/Utils/Log/Monolog/Logger.php b/application/Espo/Core/Utils/Log/Monolog/Logger.php index d11badc768..a382f7634b 100644 --- a/application/Espo/Core/Utils/Log/Monolog/Logger.php +++ b/application/Espo/Core/Utils/Log/Monolog/Logger.php @@ -24,25 +24,25 @@ namespace Espo\Core\Utils\Log\Monolog; class Logger extends \Monolog\Logger { - protected $defaultLevelName = 'DEBUG'; + protected $defaultLevelName = 'DEBUG'; - /** - * Get Level Code - * @param string $level Ex. DEBUG, ... - * @return int - */ - public function getLevelCode($levelName) + /** + * Get Level Code + * @param string $level Ex. DEBUG, ... + * @return int + */ + public function getLevelCode($levelName) { - $levelName = strtoupper($levelName); + $levelName = strtoupper($levelName); - $levels = $this->getLevels(); + $levels = $this->getLevels(); - if (isset($levels[$levelName])) { - return $levels[$levelName]; - } + if (isset($levels[$levelName])) { + return $levels[$levelName]; + } - return $levels[$this->defaultLevelName]; + return $levels[$this->defaultLevelName]; } diff --git a/application/Espo/Core/Utils/Metadata.php b/application/Espo/Core/Utils/Metadata.php index 06acc37400..12b73e1c0b 100644 --- a/application/Espo/Core/Utils/Metadata.php +++ b/application/Espo/Core/Utils/Metadata.php @@ -26,408 +26,408 @@ use Espo\Core\Exceptions\Error; class Metadata { - protected $meta = null; + protected $meta = null; - protected $scopes = array(); + protected $scopes = array(); - private $config; - private $unifier; - private $fileManager; - private $converter; + private $config; + private $unifier; + private $fileManager; + private $converter; - /** - * @var string - uses for loading default values - */ - private $name = 'metadata'; + /** + * @var string - uses for loading default values + */ + private $name = 'metadata'; - private $cacheFile = 'data/cache/application/metadata.php'; + private $cacheFile = 'data/cache/application/metadata.php'; - private $paths = array( - 'corePath' => 'application/Espo/Resources/metadata', - 'modulePath' => 'application/Espo/Modules/{*}/Resources/metadata', - 'customPath' => 'custom/Espo/Custom/Resources/metadata', - ); + private $paths = array( + 'corePath' => 'application/Espo/Resources/metadata', + 'modulePath' => 'application/Espo/Modules/{*}/Resources/metadata', + 'customPath' => 'custom/Espo/Custom/Resources/metadata', + ); - protected $ormMeta = null; + protected $ormMeta = null; - private $ormCacheFile = 'data/cache/application/ormMetadata.php'; + private $ormCacheFile = 'data/cache/application/ormMetadata.php'; - private $moduleList = null; + private $moduleList = null; - public function __construct(\Espo\Core\Utils\Config $config, \Espo\Core\Utils\File\Manager $fileManager) - { - $this->config = $config; - $this->fileManager = $fileManager; + public function __construct(\Espo\Core\Utils\Config $config, \Espo\Core\Utils\File\Manager $fileManager) + { + $this->config = $config; + $this->fileManager = $fileManager; - $this->unifier = new \Espo\Core\Utils\File\Unifier($this->fileManager); + $this->unifier = new \Espo\Core\Utils\File\Unifier($this->fileManager); - $this->converter = new \Espo\Core\Utils\Database\Converter($this, $this->fileManager); + $this->converter = new \Espo\Core\Utils\Database\Converter($this, $this->fileManager); - $this->init(!$this->isCached()); - } + $this->init(!$this->isCached()); + } - protected function getConfig() - { - return $this->config; - } + protected function getConfig() + { + return $this->config; + } - protected function getUnifier() - { - return $this->unifier; - } + protected function getUnifier() + { + return $this->unifier; + } - protected function getFileManager() - { - return $this->fileManager; - } + protected function getFileManager() + { + return $this->fileManager; + } - protected function getConverter() - { - return $this->converter; - } + protected function getConverter() + { + return $this->converter; + } - public function isCached() - { - if (!$this->getConfig()->get('useCache')) { - return false; - } + public function isCached() + { + if (!$this->getConfig()->get('useCache')) { + return false; + } - if (file_exists($this->cacheFile)) { - return true; - } + if (file_exists($this->cacheFile)) { + return true; + } - return false; - } + return false; + } - public function init($reload = false) - { - $data = $this->getMetadataOnly(false, $reload); - if ($data === false) { - $GLOBALS['log']->emergency('Metadata:init() - metadata has not been created'); - } + public function init($reload = false) + { + $data = $this->getMetadataOnly(false, $reload); + if ($data === false) { + $GLOBALS['log']->emergency('Metadata:init() - metadata has not been created'); + } - $this->meta = $data; + $this->meta = $data; - if ($reload) { - //save medatada to a cache file - $isSaved = $this->getFileManager()->putContentsPHP($this->cacheFile, $data); - if ($isSaved === false) { - $GLOBALS['log']->emergency('Metadata:init() - metadata has not been saved to a cache file'); - } - } - } + if ($reload) { + //save medatada to a cache file + $isSaved = $this->getFileManager()->putContentsPHP($this->cacheFile, $data); + if ($isSaved === false) { + $GLOBALS['log']->emergency('Metadata:init() - metadata has not been saved to a cache file'); + } + } + } - /** - * Get unified metadata - * - * @return array - */ - protected function getData() - { - if (!isset($this->meta)) { - $this->init(); - } + /** + * Get unified metadata + * + * @return array + */ + protected function getData() + { + if (!isset($this->meta)) { + $this->init(); + } - return $this->meta; - } + return $this->meta; + } - /** - * Get Metadata - * - * @param string $key - * @param mixed $default - * - * @return array - */ - public function get($key = null, $default = null) - { - return Util::getValueByKey($this->getData(), $key, $default); - } + /** + * Get Metadata + * + * @param string $key + * @param mixed $default + * + * @return array + */ + public function get($key = null, $default = null) + { + return Util::getValueByKey($this->getData(), $key, $default); + } - /** - * Get All Metadata context - * - * @param $isJSON - * @param bool $reload - * - * @return json | array - */ - public function getAll($isJSON = false, $reload = false) - { - if ($reload) { - $this->init(); - } + /** + * Get All Metadata context + * + * @param $isJSON + * @param bool $reload + * + * @return json | array + */ + public function getAll($isJSON = false, $reload = false) + { + if ($reload) { + $this->init(); + } - if ($isJSON) { - return Json::encode($this->meta); - } - return $this->meta; - } + if ($isJSON) { + return Json::encode($this->meta); + } + return $this->meta; + } - /** - * Get Metadata only without saving it to the a file and database sync - * - * @param $isJSON - * @param bool $reload - * - * @return json | array - */ - public function getMetadataOnly($isJSON = true, $reload = false) - { - $data = false; - if (!file_exists($this->cacheFile) || $reload) { - $data = $this->getUnifier()->unify($this->name, $this->paths, true); + /** + * Get Metadata only without saving it to the a file and database sync + * + * @param $isJSON + * @param bool $reload + * + * @return json | array + */ + public function getMetadataOnly($isJSON = true, $reload = false) + { + $data = false; + if (!file_exists($this->cacheFile) || $reload) { + $data = $this->getUnifier()->unify($this->name, $this->paths, true); - if ($data === false) { - $GLOBALS['log']->emergency('Metadata:getMetadata() - metadata unite file cannot be created'); - } + if ($data === false) { + $GLOBALS['log']->emergency('Metadata:getMetadata() - metadata unite file cannot be created'); + } - $data = $this->setLanguageFromConfig($data); - } - else if (file_exists($this->cacheFile)) { - $data = $this->getFileManager()->getContents($this->cacheFile); - } + $data = $this->setLanguageFromConfig($data); + } + else if (file_exists($this->cacheFile)) { + $data = $this->getFileManager()->getContents($this->cacheFile); + } - if ($isJSON) { - $data = Json::encode($data); - } + if ($isJSON) { + $data = Json::encode($data); + } - return $data; - } + return $data; + } - /** - * Set language list and default for Settings, Preferences metadata - * - * @param array $data Meta - * @return array $data - */ - protected function setLanguageFromConfig($data) - { - $entityList = array( - 'Settings', - 'Preferences', - ); + /** + * Set language list and default for Settings, Preferences metadata + * + * @param array $data Meta + * @return array $data + */ + protected function setLanguageFromConfig($data) + { + $entityList = array( + 'Settings', + 'Preferences', + ); - $languageList = $this->getConfig()->get('languageList'); - $language = $this->getConfig()->get('language'); + $languageList = $this->getConfig()->get('languageList'); + $language = $this->getConfig()->get('language'); - foreach ($entityList as $entityName) { - if (isset($data['entityDefs'][$entityName]['fields']['language'])) { - $data['entityDefs'][$entityName]['fields']['language']['options'] = $languageList; - $data['entityDefs'][$entityName]['fields']['language']['default'] = $language; - } - } + foreach ($entityList as $entityName) { + if (isset($data['entityDefs'][$entityName]['fields']['language'])) { + $data['entityDefs'][$entityName]['fields']['language']['options'] = $languageList; + $data['entityDefs'][$entityName]['fields']['language']['default'] = $language; + } + } - return $data; - } + return $data; + } - /** - * Set Metadata data - * Ex. $type= menu, $scope= Account then will be created a file metadataFolder/menu/Account.json - * - * @param JSON string $data - * @param string $type - ex. menu - * @param string $scope - Account - * - * @return bool - */ - public function set($data, $type, $scope) - { - $path = $this->paths['customPath']; + /** + * Set Metadata data + * Ex. $type= menu, $scope= Account then will be created a file metadataFolder/menu/Account.json + * + * @param JSON string $data + * @param string $type - ex. menu + * @param string $scope - Account + * + * @return bool + */ + public function set($data, $type, $scope) + { + $path = $this->paths['customPath']; - $result = $this->getFileManager()->mergeContents(array($path, $type, $scope.'.json'), $data, true); - if ($result === false) { - throw new Error("Error saving metadata. See log file for details."); - } + $result = $this->getFileManager()->mergeContents(array($path, $type, $scope.'.json'), $data, true); + if ($result === false) { + throw new Error("Error saving metadata. See log file for details."); + } - $this->init(true); + $this->init(true); return $result; - } + } - /** - * Unset some fields and other stuff in metadat - * - * @param array | string $unsets Ex. 'fields.name' - * @param string $type Ex. 'entityDefs' - * @param string $scope - * @return bool - */ - public function delete($unsets, $type, $scope) - { - $path = $this->paths['customPath']; + /** + * Unset some fields and other stuff in metadat + * + * @param array | string $unsets Ex. 'fields.name' + * @param string $type Ex. 'entityDefs' + * @param string $scope + * @return bool + */ + public function delete($unsets, $type, $scope) + { + $path = $this->paths['customPath']; - $result = $this->getFileManager()->unsetContents(array($path, $type, $scope.'.json'), $unsets, true); + $result = $this->getFileManager()->unsetContents(array($path, $type, $scope.'.json'), $unsets, true); - if ($result == false) { - $GLOBALS['log']->warning('Delete metadata items available only for custom code.'); - } + if ($result == false) { + $GLOBALS['log']->warning('Delete metadata items available only for custom code.'); + } - $this->init(true); + $this->init(true); - return $result; - } + return $result; + } - public function getOrmMetadata($reload = false) - { - if (!empty($this->ormMeta) && !$reload) { - return $this->ormMeta; - } + public function getOrmMetadata($reload = false) + { + if (!empty($this->ormMeta) && !$reload) { + return $this->ormMeta; + } - if (!file_exists($this->ormCacheFile) || !$this->getConfig()->get('useCache') || $reload) { - $this->getConverter()->process(); - } + if (!file_exists($this->ormCacheFile) || !$this->getConfig()->get('useCache') || $reload) { + $this->getConverter()->process(); + } - $this->ormMeta = $this->getFileManager()->getContents($this->ormCacheFile); + $this->ormMeta = $this->getFileManager()->getContents($this->ormCacheFile); - return $this->ormMeta; - } + return $this->ormMeta; + } - public function setOrmMetadata(array $ormMeta) - { - $result = $this->getFileManager()->putContentsPHP($this->ormCacheFile, $ormMeta); - if ($result == false) { - throw new \Espo\Core\Exceptions\Error('Metadata::setOrmMetadata() - Cannot save ormMetadata to a file'); - } + public function setOrmMetadata(array $ormMeta) + { + $result = $this->getFileManager()->putContentsPHP($this->ormCacheFile, $ormMeta); + if ($result == false) { + throw new \Espo\Core\Exceptions\Error('Metadata::setOrmMetadata() - Cannot save ormMetadata to a file'); + } - $this->ormMeta = $ormMeta; + $this->ormMeta = $ormMeta; - return $result; - } + return $result; + } - /** - * Get Entity path, ex. Espo.Entities.Account or Modules\Crm\Entities\MyModule - * - * @param string $entityName - * @param bool $delim - delimiter - * - * @return string - */ - public function getEntityPath($entityName, $delim = '\\') - { - $path = $this->getScopePath($entityName, $delim); + /** + * Get Entity path, ex. Espo.Entities.Account or Modules\Crm\Entities\MyModule + * + * @param string $entityName + * @param bool $delim - delimiter + * + * @return string + */ + public function getEntityPath($entityName, $delim = '\\') + { + $path = $this->getScopePath($entityName, $delim); - return implode($delim, array($path, 'Entities', Util::normilizeClassName(ucfirst($entityName)))); - } + return implode($delim, array($path, 'Entities', Util::normilizeClassName(ucfirst($entityName)))); + } - public function getRepositoryPath($entityName, $delim = '\\') - { - $path = $this->getScopePath($entityName, $delim); + public function getRepositoryPath($entityName, $delim = '\\') + { + $path = $this->getScopePath($entityName, $delim); - return implode($delim, array($path, 'Repositories', Util::normilizeClassName(ucfirst($entityName)))); - } + return implode($delim, array($path, 'Repositories', Util::normilizeClassName(ucfirst($entityName)))); + } - /** - * Get Scopes - * - * @return array - */ - public function getScopes() - { - if (!empty($this->scopes)) { - return $this->scopes; - } + /** + * Get Scopes + * + * @return array + */ + public function getScopes() + { + if (!empty($this->scopes)) { + return $this->scopes; + } - $metadata = $this->getMetadataOnly(false); + $metadata = $this->getMetadataOnly(false); - $scopes = array(); - foreach ($metadata['scopes'] as $name => $details) { - $scopes[$name] = isset($details['module']) ? $details['module'] : false; - } + $scopes = array(); + foreach ($metadata['scopes'] as $name => $details) { + $scopes[$name] = isset($details['module']) ? $details['module'] : false; + } - return $this->scopes = $scopes; - } + return $this->scopes = $scopes; + } - /** - * Get Module List - * - * @return array - */ - public function getModuleList() - { - if (is_null($this->moduleList)) { - $this->moduleList = array(); - $scopes = $this->getScopes(); + /** + * Get Module List + * + * @return array + */ + public function getModuleList() + { + if (is_null($this->moduleList)) { + $this->moduleList = array(); + $scopes = $this->getScopes(); - // TODO order - foreach ($scopes as $moduleName) { - if (!empty($moduleName)) { - if (!in_array($moduleName, $this->moduleList)) { - $this->moduleList[] = $moduleName; - } - } - } - } - return $this->moduleList; - } + // TODO order + foreach ($scopes as $moduleName) { + if (!empty($moduleName)) { + if (!in_array($moduleName, $this->moduleList)) { + $this->moduleList[] = $moduleName; + } + } + } + } + return $this->moduleList; + } - /** - * Get module name if it's a custom module or empty string for core entity - * - * @param string $scopeName - * - * @return string - */ - public function getScopeModuleName($scopeName) - { - return $this->get('scopes.' . $scopeName . '.module', false); - } + /** + * Get module name if it's a custom module or empty string for core entity + * + * @param string $scopeName + * + * @return string + */ + public function getScopeModuleName($scopeName) + { + return $this->get('scopes.' . $scopeName . '.module', false); + } - /** - * Get Scope path, ex. "Modules/Crm" for Account - * - * @param string $scopeName - * @param string $delim - delimiter - * - * @return string - */ - public function getScopePath($scopeName, $delim = '/') - { - $moduleName = $this->getScopeModuleName($scopeName); + /** + * Get Scope path, ex. "Modules/Crm" for Account + * + * @param string $scopeName + * @param string $delim - delimiter + * + * @return string + */ + public function getScopePath($scopeName, $delim = '/') + { + $moduleName = $this->getScopeModuleName($scopeName); - $path = ($moduleName !== false) ? 'Espo/Modules/'.$moduleName : 'Espo'; + $path = ($moduleName !== false) ? 'Espo/Modules/'.$moduleName : 'Espo'; - if ($delim != '/') { - $path = str_replace('/', $delim, $path); - } + if ($delim != '/') { + $path = str_replace('/', $delim, $path); + } - return $path; - } + return $path; + } - /** - * Check if scope exists - * - * @param string $scopeName - * - * @return bool - */ - public function isScopeExists($scopeName) - { - $scopeModuleMap= $this->getScopes(); + /** + * Check if scope exists + * + * @param string $scopeName + * + * @return bool + */ + public function isScopeExists($scopeName) + { + $scopeModuleMap= $this->getScopes(); - $lowerEntityName= strtolower($scopeName); - foreach($scopeModuleMap as $rowEntityName => $rowModuleName) { - if ($lowerEntityName == strtolower($rowEntityName)) { - return true; - } - } + $lowerEntityName= strtolower($scopeName); + foreach($scopeModuleMap as $rowEntityName => $rowModuleName) { + if ($lowerEntityName == strtolower($rowEntityName)) { + return true; + } + } - return false; - } + return false; + } } diff --git a/application/Espo/Core/Utils/Metadata/Utils.php b/application/Espo/Core/Utils/Metadata/Utils.php index 7c30046aa8..3d65781c40 100644 --- a/application/Espo/Core/Utils/Metadata/Utils.php +++ b/application/Espo/Core/Utils/Metadata/Utils.php @@ -24,83 +24,83 @@ namespace Espo\Core\Utils\Metadata; class Utils { - private $metadata; + private $metadata; - public function __construct(\Espo\Core\Utils\Metadata $metadata) - { - $this->metadata = $metadata; - } + public function __construct(\Espo\Core\Utils\Metadata $metadata) + { + $this->metadata = $metadata; + } - protected function getMetadata() - { - return $this->metadata; - } + protected function getMetadata() + { + return $this->metadata; + } - /** - * Get field defenition by type in metadata, "fields" key - * - * @param array | string $fieldDef - It can be a string or field defenition from entityDefs - * @return array | null - */ - public function getFieldDefsByType($fieldDef) - { - if (is_string($fieldDef)) { - $fieldDef = array('type' => $fieldDef); - } + /** + * Get field defenition by type in metadata, "fields" key + * + * @param array | string $fieldDef - It can be a string or field defenition from entityDefs + * @return array | null + */ + public function getFieldDefsByType($fieldDef) + { + if (is_string($fieldDef)) { + $fieldDef = array('type' => $fieldDef); + } - if (isset($fieldDef['dbType'])) { - return $this->getMetadata()->get('fields.'.$fieldDef['dbType']); - } else if (isset($fieldDef['type'])) { - return $this->getMetadata()->get('fields.'.$fieldDef['type']); - } + if (isset($fieldDef['dbType'])) { + return $this->getMetadata()->get('fields.'.$fieldDef['dbType']); + } else if (isset($fieldDef['type'])) { + return $this->getMetadata()->get('fields.'.$fieldDef['type']); + } - return null; - } + return null; + } - public function getFieldDefsInFieldMeta($fieldDef) - { - $fieldDefsByType = $this->getFieldDefsByType($fieldDef); - if (isset($fieldDefsByType['fieldDefs'])) { - return $fieldDefsByType['fieldDefs']; - } + public function getFieldDefsInFieldMeta($fieldDef) + { + $fieldDefsByType = $this->getFieldDefsByType($fieldDef); + if (isset($fieldDefsByType['fieldDefs'])) { + return $fieldDefsByType['fieldDefs']; + } - return null; - } + return null; + } - /** - * Get link definition defined in 'fields' metadata. In linkDefs can be used as value (e.g. "type": "hasChildren") and/or variables (e.g. "entityName":"{entity}"). Variables should be defined into fieldDefs (in 'entityDefs' metadata). - * - * @param string $entityName - * @param array $fieldDef - * @param array $linkFieldDefsByType - * @return array | null - */ - public function getLinkDefsInFieldMeta($entityName, $fieldDef, array $linkFieldDefsByType = null) - { - if (!isset($fieldDefsByType)) { - $fieldDefsByType = $this->getFieldDefsByType($fieldDef); - if (!isset($fieldDefsByType['linkDefs'])) { - return null; - } - $linkFieldDefsByType = $fieldDefsByType['linkDefs']; - } + /** + * Get link definition defined in 'fields' metadata. In linkDefs can be used as value (e.g. "type": "hasChildren") and/or variables (e.g. "entityName":"{entity}"). Variables should be defined into fieldDefs (in 'entityDefs' metadata). + * + * @param string $entityName + * @param array $fieldDef + * @param array $linkFieldDefsByType + * @return array | null + */ + public function getLinkDefsInFieldMeta($entityName, $fieldDef, array $linkFieldDefsByType = null) + { + if (!isset($fieldDefsByType)) { + $fieldDefsByType = $this->getFieldDefsByType($fieldDef); + if (!isset($fieldDefsByType['linkDefs'])) { + return null; + } + $linkFieldDefsByType = $fieldDefsByType['linkDefs']; + } - foreach ($linkFieldDefsByType as $paramName => &$paramValue) { - if (preg_match('/{(.*?)}/', $paramValue, $matches)) { - if (in_array($matches[1], array_keys($fieldDef))) { - $value = $fieldDef[$matches[1]]; - } else if (strtolower($matches[1]) == 'entity') { - $value = $entityName; - } + foreach ($linkFieldDefsByType as $paramName => &$paramValue) { + if (preg_match('/{(.*?)}/', $paramValue, $matches)) { + if (in_array($matches[1], array_keys($fieldDef))) { + $value = $fieldDef[$matches[1]]; + } else if (strtolower($matches[1]) == 'entity') { + $value = $entityName; + } - if (isset($value)) { - $paramValue = str_replace('{'.$matches[1].'}', $value, $paramValue); - } - } - } + if (isset($value)) { + $paramValue = str_replace('{'.$matches[1].'}', $value, $paramValue); + } + } + } - return $linkFieldDefsByType; - } + return $linkFieldDefsByType; + } } diff --git a/application/Espo/Core/Utils/PasswordHash.php b/application/Espo/Core/Utils/PasswordHash.php new file mode 100644 index 0000000000..237d0763b8 --- /dev/null +++ b/application/Espo/Core/Utils/PasswordHash.php @@ -0,0 +1,105 @@ +config = $config; + } + + protected function getConfig() + { + return $this->config; + } + + /** + * Get hash of a pawword + * + * @param string $password + * @return string + */ + public function hash($password, $useMd5 = true) + { + $salt = $this->getSalt(); + + if ($useMd5) { + $password = md5($password); + } + + $hash = crypt($password, $salt); + $hash = str_replace($salt, '', $hash); + + return $hash; + } + + /** + * Get a salt from config and normalize it + * + * @return string + */ + protected function getSalt() + { + $salt = $this->getConfig()->get('passwordSalt'); + if (!isset($salt)) { + throw new Error('Option "passwordSalt" does not exist in config.php'); + } + + $salt = $this->normalizeSalt($salt); + + return $salt; + } + + /** + * Convert salt in format in accordance to $saltFormat + * + * @param string $salt + * @return string + */ + protected function normalizeSalt($salt) + { + return str_replace("{0}", $salt, $this->saltFormat); + } + + /** + * Generate a new salt + * + * @return string + */ + public function generateSalt() + { + return substr(md5(uniqid()), 0, 16); + } +} \ No newline at end of file diff --git a/application/Espo/Core/Utils/Route.php b/application/Espo/Core/Utils/Route.php index a6e736edee..b1b4a8d8e9 100644 --- a/application/Espo/Core/Utils/Route.php +++ b/application/Espo/Core/Utils/Route.php @@ -24,153 +24,153 @@ namespace Espo\Core\Utils; class Route { - protected $data = null; + protected $data = null; - private $fileManager; - private $config; - private $metadata; + private $fileManager; + private $config; + private $metadata; - protected $cacheFile = 'data/cache/application/routes.php'; + protected $cacheFile = 'data/cache/application/routes.php'; - protected $paths = array( - 'corePath' => 'application/Espo/Resources/routes.json', - 'modulePath' => 'application/Espo/Modules/{*}/Resources/routes.json', - 'customPath' => 'custom/Espo/Custom/Resources/routes.json', - ); + protected $paths = array( + 'corePath' => 'application/Espo/Resources/routes.json', + 'modulePath' => 'application/Espo/Modules/{*}/Resources/routes.json', + 'customPath' => 'custom/Espo/Custom/Resources/routes.json', + ); - public function __construct(Config $config, Metadata $metadata, File\Manager $fileManager) - { - $this->config = $config; - $this->metadata = $metadata; - $this->fileManager = $fileManager; - } + public function __construct(Config $config, Metadata $metadata, File\Manager $fileManager) + { + $this->config = $config; + $this->metadata = $metadata; + $this->fileManager = $fileManager; + } - protected function getConfig() - { - return $this->config; - } + protected function getConfig() + { + return $this->config; + } - protected function getFileManager() - { - return $this->fileManager; - } + protected function getFileManager() + { + return $this->fileManager; + } - protected function getMetadata() - { - return $this->metadata; - } + protected function getMetadata() + { + return $this->metadata; + } - public function get($key = '', $returns = null) - { - if (!isset($this->data)) { - $this->init(); - } - - if (empty($key)) { - return $this->data; + public function get($key = '', $returns = null) + { + if (!isset($this->data)) { + $this->init(); } - $keys = explode('.', $key); + if (empty($key)) { + return $this->data; + } - $lastRoute = $this->data; - foreach($keys as $keyName) { - if (isset($lastRoute[$keyName]) && is_array($lastRoute)) { - $lastRoute = $lastRoute[$keyName]; - } else { - return $returns; - } - } + $keys = explode('.', $key); - return $lastRoute; - } + $lastRoute = $this->data; + foreach($keys as $keyName) { + if (isset($lastRoute[$keyName]) && is_array($lastRoute)) { + $lastRoute = $lastRoute[$keyName]; + } else { + return $returns; + } + } + + return $lastRoute; + } - public function getAll() - { - return $this->get(); - } + public function getAll() + { + return $this->get(); + } - protected function init() - { - if (file_exists($this->cacheFile) && $this->getConfig()->get('useCache')) { - $this->data = $this->getFileManager()->getContents($this->cacheFile); - } else { - $this->data = $this->unify(); + protected function init() + { + if (file_exists($this->cacheFile) && $this->getConfig()->get('useCache')) { + $this->data = $this->getFileManager()->getContents($this->cacheFile); + } else { + $this->data = $this->unify(); - $result = $this->getFileManager()->putContentsPHP($this->cacheFile, $this->data); - if ($result == false) { - throw new \Espo\Core\Exceptions\Error('Route - Cannot save unified routes'); - } - } - } + $result = $this->getFileManager()->putContentsPHP($this->cacheFile, $this->data); + if ($result == false) { + throw new \Espo\Core\Exceptions\Error('Route - Cannot save unified routes'); + } + } + } - protected function unify() - { - $data = array(); + protected function unify() + { + $data = array(); - $data = $this->getAddData($data, $this->paths['customPath']); + $data = $this->getAddData($data, $this->paths['customPath']); - foreach ($this->getMetadata()->getModuleList() as $moduleName) { - $modulePath = str_replace('{*}', $moduleName, $this->paths['modulePath']); - $data = $this->getAddData($data, $modulePath); - } + foreach ($this->getMetadata()->getModuleList() as $moduleName) { + $modulePath = str_replace('{*}', $moduleName, $this->paths['modulePath']); + $data = $this->getAddData($data, $modulePath); + } - $data = $this->getAddData($data, $this->paths['corePath']); - - return $data; - } - - protected function getAddData($currData, $routeFile) - { - if (file_exists($routeFile)) { - $content= $this->getFileManager()->getContents($routeFile); - $arrayContent = Json::getArrayData($content); - if (empty($arrayContent)) { - $GLOBALS['log']->error('Route::unify() - Empty file or syntax error - ['.$routeFile.']'); - return $currData; - } - - $currData = $this->addToData($currData, $arrayContent); - } - - return $currData; - } - - - protected function addToData($data, $newData) - { - if (!is_array($newData)) { - return $data; - } - - foreach($newData as $route) { - - $route['route'] = $this->adjustPath($route['route']); - - $data[] = $route; - } + $data = $this->getAddData($data, $this->paths['corePath']); return $data; - } + } + + protected function getAddData($currData, $routeFile) + { + if (file_exists($routeFile)) { + $content= $this->getFileManager()->getContents($routeFile); + $arrayContent = Json::getArrayData($content); + if (empty($arrayContent)) { + $GLOBALS['log']->error('Route::unify() - Empty file or syntax error - ['.$routeFile.']'); + return $currData; + } + + $currData = $this->addToData($currData, $arrayContent); + } + + return $currData; + } + + + protected function addToData($data, $newData) + { + if (!is_array($newData)) { + return $data; + } + + foreach($newData as $route) { + + $route['route'] = $this->adjustPath($route['route']); + + $data[] = $route; + } + + return $data; + } /** * Check and adjust the route path - * - * @param string $routePath - it can be "/App/user", "App/user" - * - * @return string - "/App/user" - */ + * + * @param string $routePath - it can be "/App/user", "App/user" + * + * @return string - "/App/user" + */ protected function adjustPath($routePath) { - $routePath = trim($routePath); + $routePath = trim($routePath); - if ( substr($routePath,0,1) != '/') { - return '/'.$routePath; - } + if ( substr($routePath,0,1) != '/') { + return '/'.$routePath; + } - return $routePath; + return $routePath; } } \ No newline at end of file diff --git a/application/Espo/Core/Utils/System.php b/application/Espo/Core/Utils/System.php index dfc1d84dae..1ba458c5bf 100644 --- a/application/Espo/Core/Utils/System.php +++ b/application/Espo/Core/Utils/System.php @@ -24,81 +24,81 @@ namespace Espo\Core\Utils; class System { - /** - * Get web server name - * - * @return string Ex. "microsoft-iis", "nginx", "apache" - */ - public function getServerType() - { - $serverSoft = $_SERVER['SERVER_SOFTWARE']; + /** + * Get web server name + * + * @return string Ex. "microsoft-iis", "nginx", "apache" + */ + public function getServerType() + { + $serverSoft = $_SERVER['SERVER_SOFTWARE']; - preg_match('/^(.*?)\//i', $serverSoft, $match); - if (empty($match[1])) { - preg_match('/^(.*)\/?/i', $serverSoft, $match); - } - $serverName = strtolower( trim($match[1]) ); + preg_match('/^(.*?)\//i', $serverSoft, $match); + if (empty($match[1])) { + preg_match('/^(.*)\/?/i', $serverSoft, $match); + } + $serverName = strtolower( trim($match[1]) ); - return $serverName; - } + return $serverName; + } - /** - * Get Operating System of web server. Details http://en.wikipedia.org/wiki/Uname - * - * @return string Ex. "windows", "mac", "linux" - */ - public function getOS() - { - $osList = array( - 'windows' => array( - 'win', - 'UWIN', - ), - 'mac' => array( - 'mac', - 'darwin', - ), - 'linux' => array( - 'linux', - 'cygwin', - 'GNU', - 'FreeBSD', - 'OpenBSD', - 'NetBSD', - ), - ); + /** + * Get Operating System of web server. Details http://en.wikipedia.org/wiki/Uname + * + * @return string Ex. "windows", "mac", "linux" + */ + public function getOS() + { + $osList = array( + 'windows' => array( + 'win', + 'UWIN', + ), + 'mac' => array( + 'mac', + 'darwin', + ), + 'linux' => array( + 'linux', + 'cygwin', + 'GNU', + 'FreeBSD', + 'OpenBSD', + 'NetBSD', + ), + ); - $sysOS = strtolower(PHP_OS); + $sysOS = strtolower(PHP_OS); - foreach ($osList as $osName => $osSystem) { - if (preg_match('/^('.implode('|', $osSystem).')/i', $sysOS)) { - return $osName; - } - } + foreach ($osList as $osName => $osSystem) { + if (preg_match('/^('.implode('|', $osSystem).')/i', $sysOS)) { + return $osName; + } + } - return false; - } + return false; + } - /** - * Get root directory of EspoCRM - * - * @return string - */ - public function getRootDir() - { - $bPath = realpath('bootstrap.php'); - $rootDir = dirname($bPath); + /** + * Get root directory of EspoCRM + * + * @return string + */ + public function getRootDir() + { + $bPath = realpath('bootstrap.php'); + $rootDir = dirname($bPath); - return $rootDir; - } + return $rootDir; + } - /** - * Get path to PHP - * - * @return string - */ - public function getPhpBin() - { - return (defined("PHP_BINDIR"))? PHP_BINDIR.DIRECTORY_SEPARATOR.'php' : 'php'; - } + /** + * Get path to PHP + * + * @return string + */ + public function getPhpBin() + { + return (defined("PHP_BINDIR"))? PHP_BINDIR.DIRECTORY_SEPARATOR.'php' : 'php'; + } } \ No newline at end of file diff --git a/application/Espo/Core/Utils/Util.php b/application/Espo/Core/Utils/Util.php index ecf05a7f57..502918b2cb 100644 --- a/application/Espo/Core/Utils/Util.php +++ b/application/Espo/Core/Utils/Util.php @@ -25,403 +25,416 @@ namespace Espo\Core\Utils; class Util { - /** - * @var string - default directory separator - */ - protected static $separator = DIRECTORY_SEPARATOR; + /** + * @var string - default directory separator + */ + protected static $separator = DIRECTORY_SEPARATOR; - protected static $reservedWords = array('Case'); + protected static $reservedWords = array('Case'); - /** - * Get a folder separator - * - * @return string - */ - public static function getSeparator() - { - return static::$separator; - } + /** + * Get a folder separator + * + * @return string + */ + public static function getSeparator() + { + return static::$separator; + } - /** - * Convert to format with defined delimeter - * ex. Espo/Utils to Espo\Utils - * - * @param string $name - * @param string $delim - delimiter - * - * @return string - */ - public static function toFormat($name, $delim = '/') - { - return preg_replace("/[\/\\\]/", $delim, $name); - } + /** + * Convert to format with defined delimeter + * ex. Espo/Utils to Espo\Utils + * + * @param string $name + * @param string $delim - delimiter + * + * @return string + */ + public static function toFormat($name, $delim = '/') + { + return preg_replace("/[\/\\\]/", $delim, $name); + } - /** - * Convert name to Camel Case format, ex. camel-case to camelCase - * @param string $name - * @param boolean $capitaliseFirstChar - * @param string $symbol - * @return string - */ - public static function toCamelCase($name, $capitaliseFirstChar = false, $symbol = '-') - { - if($capitaliseFirstChar) { - $name[0] = strtoupper($name[0]); - } - return preg_replace_callback('/'.$symbol.'([a-z])/', 'static::toCamelCaseConversion', $name); - } + /** + * Convert name to Camel Case format, ex. camel_case to camelCase + * + * @param string $name + * @param string $symbol + * @param boolean $capitaliseFirstChar + * + * @return string + */ + public static function toCamelCase($name, $symbol = '_', $capitaliseFirstChar = false) + { + if($capitaliseFirstChar) { + $name[0] = strtoupper($name[0]); + } + return preg_replace_callback('/'.$symbol.'([a-z])/', 'static::toCamelCaseConversion', $name); + } - protected static function toCamelCaseConversion($matches) - { - return strtoupper($matches[1]); - } + protected static function toCamelCaseConversion($matches) + { + return strtoupper($matches[1]); + } - /** - * Convert name from Camel Case format. - * ex. camelCase to camel-case - * - * @param string $name - * - * @return string - */ - public static function fromCamelCase($name, $symbol = '-') - { - $name[0] = strtolower($name[0]); - return preg_replace_callback('/([A-Z])/', function ($matches) use ($symbol) { - return $symbol . strtolower($matches[1]); - }, $name); - } + /** + * Convert name from Camel Case format. + * ex. camelCase to camel-case + * + * @param string $name + * + * @return string + */ + public static function fromCamelCase($name, $symbol = '_') + { + $name[0] = strtolower($name[0]); + return preg_replace_callback('/([A-Z])/', function ($matches) use ($symbol) { + return $symbol . strtolower($matches[1]); + }, $name); + } - /** - * Convert name from Camel Case format to underscore. - * ex. camelCase to camel_case - * - * @param string $name - * - * @return string - */ - public static function toUnderScore($name) - { - return static::fromCamelCase($name, '_'); - } + /** + * Convert name from Camel Case format to underscore. + * ex. camelCase to camel_case + * + * @param string $name + * + * @return string + */ + public static function toUnderScore($name) + { + return static::fromCamelCase($name, '_'); + } - /** - * Merge arrays recursively (default PHP function is not suitable) - * - * @param array $currentArray - * @param array $newArray - chief array (priority is same as for array_merge()) - * - * @return array - */ - public static function merge($currentArray, $newArray) - { - $mergeIdentifier = '__APPEND__'; + /** + * Merge arrays recursively (default PHP function is not suitable) + * + * @param array $currentArray + * @param array $newArray - chief array (priority is same as for array_merge()) + * + * @return array + */ + public static function merge($currentArray, $newArray) + { + $mergeIdentifier = '__APPEND__'; - if (is_array($currentArray) && (!is_array($newArray) || empty($newArray))) { - return $currentArray; - } else if ((!is_array($currentArray) || empty($currentArray)) && is_array($newArray)) { - return $newArray; - } else if ((!is_array($currentArray) || empty($currentArray)) && (!is_array($newArray) || empty($newArray))) { - return array(); - } + if (is_array($currentArray) && (!is_array($newArray) || empty($newArray))) { + return $currentArray; + } else if ((!is_array($currentArray) || empty($currentArray)) && is_array($newArray)) { + return $newArray; + } else if ((!is_array($currentArray) || empty($currentArray)) && (!is_array($newArray) || empty($newArray))) { + return array(); + } - /** add root items from currentArray */ - foreach ($currentArray as $currentName => $currentValue) { + /** add root items from currentArray */ + foreach ($currentArray as $currentName => $currentValue) { - if (!array_key_exists($currentName, $newArray)) { + if (!array_key_exists($currentName, $newArray)) { - $newArray[$currentName] = $currentValue; + $newArray[$currentName] = $currentValue; - } else if (is_array($currentValue) && is_array($newArray[$currentName])) { + } else if (is_array($currentValue) && is_array($newArray[$currentName])) { - /** check __APPEND__ identifier */ - $appendKey = array_search($mergeIdentifier, $newArray[$currentName], true); - if ($appendKey !== false) { - unset($newArray[$currentName][$appendKey]); - $newArray[$currentName] = array_merge($currentValue, $newArray[$currentName]); - } else if (!static::isSingleArray($newArray[$currentName])) { - $newArray[$currentName] = static::merge($currentValue, $newArray[$currentName]); - } + /** check __APPEND__ identifier */ + $appendKey = array_search($mergeIdentifier, $newArray[$currentName], true); + if ($appendKey !== false) { + unset($newArray[$currentName][$appendKey]); + $newArray[$currentName] = array_merge($currentValue, $newArray[$currentName]); + } else if (!static::isSingleArray($newArray[$currentName])) { + $newArray[$currentName] = static::merge($currentValue, $newArray[$currentName]); + } - } - } + } + } - return $newArray; - } + return $newArray; + } - /** - * Get a full path of the file - * - * @param string | array $folderPath - Folder path, Ex. myfolder - * @param string $filePath - File path, Ex. file.json - * - * @return string - */ - public static function concatPath($folderPath, $filePath = null) - { - if (is_array($folderPath)) { - $fullPath = ''; - foreach ($folderPath as $path) { - $fullPath = static::concatPath($fullPath, $path); - } - return $fullPath; - } + /** + * Get a full path of the file + * + * @param string | array $folderPath - Folder path, Ex. myfolder + * @param string $filePath - File path, Ex. file.json + * + * @return string + */ + public static function concatPath($folderPath, $filePath = null) + { + if (is_array($folderPath)) { + $fullPath = ''; + foreach ($folderPath as $path) { + $fullPath = static::concatPath($fullPath, $path); + } + return static::fixPath($fullPath); + } - if (empty($filePath)) { - return $folderPath; - } - if (empty($folderPath)) { - return $filePath; - } + if (empty($filePath)) { + return static::fixPath($folderPath); + } + if (empty($folderPath)) { + return static::fixPath($filePath); + } - if (substr($folderPath, -1) == static::getSeparator()) { - return $folderPath . $filePath; - } - return $folderPath . static::getSeparator() . $filePath; - } + if (substr($folderPath, -1) == static::getSeparator() || substr($folderPath, -1) == '/') { + return static::fixPath($folderPath . $filePath); + } + return $folderPath . static::getSeparator() . $filePath; + } - /** - * Convert array to object format recursively - * - * @param array $array - * @return object - */ - public static function arrayToObject($array) - { - if (is_array($array)) { - return (object) array_map("static::arrayToObject", $array); - } else { - return $array; // Return an object - } - } + /** + * Fix path separator + * + * @param string $path + * @return string + */ + public static function fixPath($path) + { + return str_replace('/', static::getSeparator(), $path); + } - /** - * Convert object to array format recursively - * - * @param object $object - * @return array - */ - public static function objectToArray($object) - { - if (is_object($object)) { - $object = (array) $object; - } + /** + * Convert array to object format recursively + * + * @param array $array + * @return object + */ + public static function arrayToObject($array) + { + if (is_array($array)) { + return (object) array_map("static::arrayToObject", $array); + } else { + return $array; // Return an object + } + } - return is_array($object) ? array_map("static::objectToArray", $object) : $object; - } + /** + * Convert object to array format recursively + * + * @param object $object + * @return array + */ + public static function objectToArray($object) + { + if (is_object($object)) { + $object = (array) $object; + } - /** - * Appends 'Obj' if name is reserved PHP word. - * - * @param string $name - * @return string - */ - public static function normilizeClassName($name) - { - if (in_array($name, self::$reservedWords)) { - $name .= 'Obj'; - } - return $name; - } + return is_array($object) ? array_map("static::objectToArray", $object) : $object; + } - /** - * Get Naming according to prefix or postfix type - * - * @param string $name - * @param string $prePostFix - * @param string $type - * - * @return string - */ - public static function getNaming($name, $prePostFix, $type = 'prefix', $symbol = '-') - { - if ($type == 'prefix') { - return static::toCamelCase($prePostFix.$symbol.$name, false, $symbol); - } else if ($type == 'postfix') { - return static::toCamelCase($name.$symbol.$prePostFix, false, $symbol); - } + /** + * Appends 'Obj' if name is reserved PHP word. + * + * @param string $name + * @return string + */ + public static function normilizeClassName($name) + { + if (in_array($name, self::$reservedWords)) { + $name .= 'Obj'; + } + return $name; + } - return null; - } + /** + * Get Naming according to prefix or postfix type + * + * @param string $name + * @param string $prePostFix + * @param string $type + * + * @return string + */ + public static function getNaming($name, $prePostFix, $type = 'prefix', $symbol = '_') + { + if ($type == 'prefix') { + return static::toCamelCase($prePostFix.$symbol.$name, $symbol); + } else if ($type == 'postfix') { + return static::toCamelCase($name.$symbol.$prePostFix, $symbol); + } - /** - * Replace $search in array recursively - * - * @param string $search - * @param string $replace - * @param string $array - * @param string $isKeys - * - * @return array - */ - public static function replaceInArray($search = '', $replace = '', $array = false, $isKeys = true) - { - if (!is_array($array)) { - return str_replace($search, $replace, $array); - } + return null; + } - $newArr = array(); - foreach ($array as $key => $value) { - $addKey = $key; - if ($isKeys) { //Replace keys - $addKey = str_replace($search, $replace, $key); - } + /** + * Replace $search in array recursively + * + * @param string $search + * @param string $replace + * @param string $array + * @param string $isKeys + * + * @return array + */ + public static function replaceInArray($search = '', $replace = '', $array = false, $isKeys = true) + { + if (!is_array($array)) { + return str_replace($search, $replace, $array); + } - // Recurse - $newArr[$addKey] = static::replaceInArray($search, $replace, $value, $isKeys); - } + $newArr = array(); + foreach ($array as $key => $value) { + $addKey = $key; + if ($isKeys) { //Replace keys + $addKey = str_replace($search, $replace, $key); + } - return $newArr; - } + // Recurse + $newArr[$addKey] = static::replaceInArray($search, $replace, $value, $isKeys); + } - /** - * Unset content items defined in the unset.json - * - * @param array $content - * @param string | array $unsets in format - * array( - * 'EntityName1' => array( 'unset1', 'unset2' ), - * 'EntityName2' => array( 'unset1', 'unset2' ), - * ) - * OR - * array('EntityName1.unset1', 'EntityName1.unset2', .....) - * OR - * 'EntityName1.unset1' - * - * @return array - */ - public static function unsetInArray(array $content, $unsets) - { - if (empty($unsets)) { - return $content; - } + return $newArr; + } - if (is_string($unsets)) { - $unsets = (array) $unsets; - } + /** + * Unset content items defined in the unset.json + * + * @param array $content + * @param string | array $unsets in format + * array( + * 'EntityName1' => array( 'unset1', 'unset2' ), + * 'EntityName2' => array( 'unset1', 'unset2' ), + * ) + * OR + * array('EntityName1.unset1', 'EntityName1.unset2', .....) + * OR + * 'EntityName1.unset1' + * + * @return array + */ + public static function unsetInArray(array $content, $unsets) + { + if (empty($unsets)) { + return $content; + } - foreach($unsets as $rootKey => $unsetItem){ - $unsetItem = is_array($unsetItem) ? $unsetItem : (array) $unsetItem; + if (is_string($unsets)) { + $unsets = (array) $unsets; + } - foreach($unsetItem as $unsetSett){ - if (!empty($unsetSett)){ - $keyItems = explode('.', $unsetSett); - $currVal = isset($content[$rootKey]) ? "\$content['{$rootKey}']" : "\$content"; + foreach($unsets as $rootKey => $unsetItem){ + $unsetItem = is_array($unsetItem) ? $unsetItem : (array) $unsetItem; - $lastKey = array_pop($keyItems); - foreach($keyItems as $keyItem){ - $currVal .= "['{$keyItem}']"; - } + foreach($unsetItem as $unsetSett){ + if (!empty($unsetSett)){ + $keyItems = explode('.', $unsetSett); + $currVal = isset($content[$rootKey]) ? "\$content['{$rootKey}']" : "\$content"; - $unsetElem = $currVal . "['{$lastKey}']"; + $lastKey = array_pop($keyItems); + foreach($keyItems as $keyItem){ + $currVal .= "['{$keyItem}']"; + } - $currVal = " - if (isset({$unsetElem}) || ( is_array({$currVal}) && array_key_exists({$lastKey}, {$currVal}) )) { - unset({$unsetElem}); - } "; - eval($currVal); - } - } - } + $unsetElem = $currVal . "['{$lastKey}']"; - return $content; - } + $currVal = " + if (isset({$unsetElem}) || ( is_array({$currVal}) && array_key_exists({$lastKey}, {$currVal}) )) { + unset({$unsetElem}); + } "; + eval($currVal); + } + } + } - /** - * Get class name from the file path - * - * @param string $filePath - * - * @return string - */ - public static function getClassName($filePath) - { - $className = preg_replace('/\.php$/i', '', $filePath); - $className = preg_replace('/^(application|custom)\//i', '', $className); - $className = '\\'.static::toFormat($className, '\\'); + return $content; + } - return $className; - } + /** + * Get class name from the file path + * + * @param string $filePath + * + * @return string + */ + public static function getClassName($filePath) + { + $className = preg_replace('/\.php$/i', '', $filePath); + $className = preg_replace('/^(application|custom)\//i', '', $className); + $className = '\\'.static::toFormat($className, '\\'); - /** - * Return values of defined $key. - * - * @param array $array - * @param string $key Ex. of key is "entityDefs", "entityDefs.User" - * @param mixed $default - * @return mixed - */ - public static function getValueByKey(array $array, $key = null, $default = null) - { - if (!isset($key) || empty($key)) { - return $array; - } + return $className; + } - $keys = explode('.', $key); + /** + * Return values of defined $key. + * + * @param array $array + * @param string $key Ex. of key is "entityDefs", "entityDefs.User" + * @param mixed $default + * @return mixed + */ + public static function getValueByKey(array $array, $key = null, $default = null) + { + if (!isset($key) || empty($key)) { + return $array; + } - $lastItem = $array; - foreach($keys as $keyName) { - if (isset($lastItem[$keyName]) && is_array($lastItem)) { - $lastItem = $lastItem[$keyName]; - } else { - return $default; - } - } + $keys = explode('.', $key); - return $lastItem; - } + $lastItem = $array; + foreach($keys as $keyName) { + if (isset($lastItem[$keyName]) && is_array($lastItem)) { + $lastItem = $lastItem[$keyName]; + } else { + return $default; + } + } - /** - * Check if two variables are equals - * - * @param mixed $var1 - * @param mixed $var2 - * @return boolean - */ - public static function isEquals($var1, $var2) - { - if (is_array($var1)) { - static::ksortRecursive($var1); - } - if (is_array($var2)) { - static::ksortRecursive($var2); - } + return $lastItem; + } - return ($var1 === $var2); - } + /** + * Check if two variables are equals + * + * @param mixed $var1 + * @param mixed $var2 + * @return boolean + */ + public static function isEquals($var1, $var2) + { + if (is_array($var1)) { + static::ksortRecursive($var1); + } + if (is_array($var2)) { + static::ksortRecursive($var2); + } - /** - * Sort array recursively - * @param array $array - * @return bool - */ - public static function ksortRecursive(&$array) - { - if (!is_array($array)) { - return false; - } + return ($var1 === $var2); + } - ksort($array); - foreach ($array as $key => $value) { - static::ksortRecursive($array[$key]); - } + /** + * Sort array recursively + * @param array $array + * @return bool + */ + public static function ksortRecursive(&$array) + { + if (!is_array($array)) { + return false; + } - return true; - } + ksort($array); + foreach ($array as $key => $value) { + static::ksortRecursive($array[$key]); + } - public static function isSingleArray(array $array) - { - foreach ($array as $key => $value) { - if (!is_int($key)) { - return false; - } - } + return true; + } - return true; - } + public static function isSingleArray(array $array) + { + foreach ($array as $key => $value) { + if (!is_int($key)) { + return false; + } + } + + return true; + } } diff --git a/application/Espo/Core/defaults/config.php b/application/Espo/Core/defaults/config.php index 31e6e67053..5206f0b7bf 100644 --- a/application/Espo/Core/defaults/config.php +++ b/application/Espo/Core/defaults/config.php @@ -21,79 +21,79 @@ ************************************************************************/ return array ( - 'database' => - array ( - 'driver' => 'pdo_mysql', - 'host' => 'localhost', - 'port' => '', - 'dbname' => '', - 'user' => '', - 'password' => '', - ), - 'useCache' => true, - 'recordsPerPage' => 20, - 'recordsPerPageSmall' => 5, - 'applicationName' => 'EspoCRM', - 'version' => '@@version', - 'timeZone' => 'UTC', - 'dateFormat' => 'MM/DD/YYYY', - 'timeFormat' => 'HH:mm', - 'weekStart' => 0, - 'thousandSeparator' => ',', - 'decimalMark' => '.', - 'exportDelimiter' => ';', - 'currencyList' => - array ( - ), - 'defaultCurrency' => 'USD', - 'baseCurrency' => 'USD', - 'currencyRates' => array( - ), - 'outboundEmailIsShared' => true, - 'outboundEmailFromName' => 'EspoCRM', - 'outboundEmailFromAddress' => '', - 'smtpServer' => '', - 'smtpPort' => 25, - 'smtpAuth' => true, - 'smtpSecurity' => '', - 'smtpUsername' => '', - 'smtpPassword' => '', - 'languageList' => array( - 'en_US', - 'de_DE', - 'es_ES', - 'fr_FR', - 'nl_NL', - 'tr_TR', - 'ro_RO', - 'ru_RU', - 'pl_PL', - 'pt_BR', - 'vi_VN' - ), - 'language' => 'en_US', - 'logger' => - array ( - 'path' => 'data/logs/espo.log', - 'level' => 'ERROR', /** DEBUG, INFO, NOTICE, WARNING, ERROR, CRITICAL, ALERT, EMERGENCY */ - 'isRotate' => true, /** rotate log files every day */ - 'maxRotateFiles' => 30, /** max number of rotate files */ - ), - 'authenticationMethod' => 'Espo', - 'globalSearchEntityList' => - array ( - 0 => 'Account', - 1 => 'Contact', - 2 => 'Lead', - 3 => 'Opportunity', - ), - "tabList" => array("Account", "Contact", "Lead", "Opportunity", "Calendar", "Meeting", "Call", "Task", "Case", "Email"), - "quickCreateList" => array("Account", "Contact", "Lead", "Opportunity", "Meeting", "Call", "Task", "Case"), - 'calendarDefaultEntity' => 'Meeting', - 'disableExport' => false, - 'assignmentEmailNotifications' => false, - 'assignmentEmailNotificationsEntityList' => array('Lead', 'Opportunity', 'Task', 'Case'), - 'emailMessageMaxSize' => 10, - 'isInstalled' => false, + 'database' => + array ( + 'driver' => 'pdo_mysql', + 'host' => 'localhost', + 'port' => '', + 'dbname' => '', + 'user' => '', + 'password' => '', + ), + 'useCache' => true, + 'recordsPerPage' => 20, + 'recordsPerPageSmall' => 5, + 'applicationName' => 'EspoCRM', + 'version' => '@@version', + 'timeZone' => 'UTC', + 'dateFormat' => 'MM/DD/YYYY', + 'timeFormat' => 'HH:mm', + 'weekStart' => 0, + 'thousandSeparator' => ',', + 'decimalMark' => '.', + 'exportDelimiter' => ';', + 'currencyList' => + array ( + ), + 'defaultCurrency' => 'USD', + 'baseCurrency' => 'USD', + 'currencyRates' => array( + ), + 'outboundEmailIsShared' => true, + 'outboundEmailFromName' => 'EspoCRM', + 'outboundEmailFromAddress' => '', + 'smtpServer' => '', + 'smtpPort' => 25, + 'smtpAuth' => true, + 'smtpSecurity' => '', + 'smtpUsername' => '', + 'smtpPassword' => '', + 'languageList' => array( + 'en_US', + 'de_DE', + 'es_ES', + 'fr_FR', + 'nl_NL', + 'tr_TR', + 'ro_RO', + 'ru_RU', + 'pl_PL', + 'pt_BR', + 'vi_VN' + ), + 'language' => 'en_US', + 'logger' => + array ( + 'path' => 'data/logs/espo.log', + 'level' => 'WARNING', /** DEBUG, INFO, NOTICE, WARNING, ERROR, CRITICAL, ALERT, EMERGENCY */ + 'isRotate' => true, /** rotate log files every day */ + 'maxRotateFiles' => 30, /** max number of rotate files */ + ), + 'authenticationMethod' => 'Espo', + 'globalSearchEntityList' => + array ( + 0 => 'Account', + 1 => 'Contact', + 2 => 'Lead', + 3 => 'Opportunity', + ), + "tabList" => array("Account", "Contact", "Lead", "Opportunity", "Calendar", "Meeting", "Call", "Task", "Case", "Email"), + "quickCreateList" => array("Account", "Contact", "Lead", "Opportunity", "Meeting", "Call", "Task", "Case"), + 'calendarDefaultEntity' => 'Meeting', + 'disableExport' => false, + 'assignmentEmailNotifications' => false, + 'assignmentEmailNotificationsEntityList' => array('Lead', 'Opportunity', 'Task', 'Case'), + 'emailMessageMaxSize' => 10, + 'isInstalled' => false, ); diff --git a/application/Espo/Core/defaults/layout/detail.json b/application/Espo/Core/defaults/layout/detail.json index 992d2ea1ba..2b813b000f 100644 --- a/application/Espo/Core/defaults/layout/detail.json +++ b/application/Espo/Core/defaults/layout/detail.json @@ -1,6 +1,6 @@ [{ - "label":"Overview", - "rows": [ - [{"name":"name"}] - ] + "label":"Overview", + "rows": [ + [{"name":"name"}] + ] }] diff --git a/application/Espo/Core/defaults/layout/detailSmall.json b/application/Espo/Core/defaults/layout/detailSmall.json index fca42b50da..0305a5ee76 100644 --- a/application/Espo/Core/defaults/layout/detailSmall.json +++ b/application/Espo/Core/defaults/layout/detailSmall.json @@ -1,6 +1,6 @@ [{ - "label":"", - "rows": [ - [{"name":"name"}] - ] + "label":"", + "rows": [ + [{"name":"name"}] + ] }] diff --git a/application/Espo/Core/defaults/systemConfig.php b/application/Espo/Core/defaults/systemConfig.php index 94d79e5005..b40179a649 100644 --- a/application/Espo/Core/defaults/systemConfig.php +++ b/application/Espo/Core/defaults/systemConfig.php @@ -21,99 +21,100 @@ ************************************************************************/ return array ( - 'defaultPermissions' => - array ( - 'dir' => '0775', - 'file' => '0664', - 'user' => '', - 'group' => '', - ), + 'defaultPermissions' => + array ( + 'dir' => '0775', + 'file' => '0664', + 'user' => '', + 'group' => '', + ), - 'permissionMap' => array( + 'permissionMap' => array( - /** array('0664', '0775') */ - 'writable' => array( - 'data', - 'custom', - ), + /** array('0664', '0775') */ + 'writable' => array( + 'data', + 'custom', + ), - /** array('0644', '0755') */ - 'readable' => array( - 'api', - 'application', - 'client', - 'vendor', - 'index.php', - 'cron.php', - 'rebuild.php', - 'main.html', - 'reset.html', - ), - ), - 'cron' => array( - 'maxJobNumber' => 15, /** Max number of jobs per one execution */ - 'jobPeriod' => 7800, /** Period for jobs, ex. if cron executed at 15:35, it will execute all pending jobs for times from 14:05 to 15:35 */ - 'minExecutionTime' => 50, /** to avoid too frequency execution **/ - ), - 'crud' => array( - 'get' => 'read', - 'post' => 'create', - 'put' => 'update', - 'patch' => 'patch', - 'delete' => 'delete', - ), - 'systemUser' => array( - 'id' => 'system', - 'userName' => 'system', - 'firstName' => '', - 'lastName' => 'System', - ), - 'systemItems' => - array ( - 'systemItems', - 'adminItems', - 'configPath', - 'cachePath', - 'database', - 'crud', - 'logger', - 'isInstalled', - 'defaultPermissions', - 'systemUser', - 'permissionMap', - 'permissionRules', - ), - 'adminItems' => - array ( - 'devMode', - 'outboundEmailIsShared', - 'outboundEmailFromName', - 'outboundEmailFromAddress', - 'smtpServer', - 'smtpPort', - 'smtpAuth', - 'smtpSecurity', - 'smtpUsername', - 'smtpPassword', - 'cron', - 'authenticationMethod', - 'ldapHost', - 'ldapPort', - 'ldapSecurity', - 'ldapAuth', - 'ldapUsername', - 'ldapPassword', - 'ldapBindRequiresDn', - 'ldapBaseDn', - 'ldapUserLoginFilter', - 'ldapAccountCanonicalForm', - 'ldapAccountDomainName', - 'ldapAccountDomainNameShort', - 'ldapAccountFilterFormat', - 'ldapTryUsernameSplit', - 'ldapOptReferrals', - 'ldapCreateEspoUser', - ), - 'isInstalled' => false, + /** array('0644', '0755') */ + 'readable' => array( + 'api', + 'application', + 'client', + 'vendor', + 'index.php', + 'cron.php', + 'rebuild.php', + 'main.html', + 'reset.html', + ), + ), + 'cron' => array( + 'maxJobNumber' => 15, /** Max number of jobs per one execution */ + 'jobPeriod' => 7800, /** Period for jobs, ex. if cron executed at 15:35, it will execute all pending jobs for times from 14:05 to 15:35 */ + 'minExecutionTime' => 50, /** to avoid too frequency execution **/ + ), + 'crud' => array( + 'get' => 'read', + 'post' => 'create', + 'put' => 'update', + 'patch' => 'patch', + 'delete' => 'delete', + ), + 'systemUser' => array( + 'id' => 'system', + 'userName' => 'system', + 'firstName' => '', + 'lastName' => 'System', + ), + 'systemItems' => + array ( + 'systemItems', + 'adminItems', + 'configPath', + 'cachePath', + 'database', + 'crud', + 'logger', + 'isInstalled', + 'defaultPermissions', + 'systemUser', + 'permissionMap', + 'permissionRules', + 'passwordSalt', + ), + 'adminItems' => + array ( + 'devMode', + 'outboundEmailIsShared', + 'outboundEmailFromName', + 'outboundEmailFromAddress', + 'smtpServer', + 'smtpPort', + 'smtpAuth', + 'smtpSecurity', + 'smtpUsername', + 'smtpPassword', + 'cron', + 'authenticationMethod', + 'ldapHost', + 'ldapPort', + 'ldapSecurity', + 'ldapAuth', + 'ldapUsername', + 'ldapPassword', + 'ldapBindRequiresDn', + 'ldapBaseDn', + 'ldapUserLoginFilter', + 'ldapAccountCanonicalForm', + 'ldapAccountDomainName', + 'ldapAccountDomainNameShort', + 'ldapAccountFilterFormat', + 'ldapTryUsernameSplit', + 'ldapOptReferrals', + 'ldapCreateEspoUser', + ), + 'isInstalled' => false, ); diff --git a/application/Espo/Entities/Email.php b/application/Espo/Entities/Email.php index 1139f45b50..73baacb0ef 100644 --- a/application/Espo/Entities/Email.php +++ b/application/Espo/Entities/Email.php @@ -25,75 +25,80 @@ namespace Espo\Entities; class Email extends \Espo\Core\ORM\Entity { - protected function getSubject() - { - return $this->get('name'); - } - - protected function setSubject($value) - { - return $this->set('name', $value); - } - - public function addAttachment(\Espo\Entities\Attachment $attachment) - { - if (!empty($this->id)) { - $attachment->set('parentId', $this->id); - $attachment->set('parentType', 'Email'); - if ($this->entityManager->saveEntity($attachment)) { - return true; - } - } - } - - public function getBodyPlainForSending() - { - $bodyPlain = $this->get('bodyPlain'); - if (!empty($bodyPlain)) { - return $bodyPlain; - } + protected function _getSubject() + { + return $this->get('name'); + } + + protected function _setSubject($value) + { + return $this->set('name', $value); + } + + public function addAttachment(\Espo\Entities\Attachment $attachment) + { + if (!empty($this->id)) { + $attachment->set('parentId', $this->id); + $attachment->set('parentType', 'Email'); + if ($this->entityManager->saveEntity($attachment)) { + return true; + } + } + } + + public function getBodyPlain() + { + $bodyPlain = $this->get('bodyPlain'); + if (!empty($bodyPlain)) { + return $bodyPlain; + } - $body = $this->get('body'); - - $breaks = array("
","
","
","
","<br />","<br/>","<br>"); - $body = str_ireplace($breaks, "\r\n", $body); - $body = strip_tags($body); - return $body; - } - - public function getBodyForSending() - { - $body = $this->get('body'); - if (!empty($body)) { - $attachmentList = $this->getInlineAttachments(); - foreach ($attachmentList as $attachment) { - $body = str_replace("?entryPoint=attachment&id={$attachment->id}", "cid:{$attachment->id}", $body); - } - } - - $body = str_replace("", "
", $body); - - return $body; - } - - public function getInlineAttachments() - { - $attachmentList = array(); - $body = $this->get('body'); - if (!empty($body)) { - if (preg_match_all("/\?entryPoint=attachment&id=([^&=\"']+)/", $body, $matches)) { - if (!empty($matches[1]) && is_array($matches[1])) { - foreach($matches[1] as $id) { - $attachment = $this->entityManager->getEntity('Attachment', $id); - if ($attachment) { - $attachmentList[] = $attachment; - } - } - } - } - - } - return $attachmentList; - } + $body = $this->get('body'); + + $breaks = array("
","
","
","
","<br />","<br/>","<br>"); + $body = str_ireplace($breaks, "\r\n", $body); + $body = strip_tags($body); + return $body; + } + + public function getBodyPlainForSending() + { + return $this->getBodyPlain(); + } + + public function getBodyForSending() + { + $body = $this->get('body'); + if (!empty($body)) { + $attachmentList = $this->getInlineAttachments(); + foreach ($attachmentList as $attachment) { + $body = str_replace("?entryPoint=attachment&id={$attachment->id}", "cid:{$attachment->id}", $body); + } + } + + $body = str_replace("
", "
", $body); + + return $body; + } + + public function getInlineAttachments() + { + $attachmentList = array(); + $body = $this->get('body'); + if (!empty($body)) { + if (preg_match_all("/\?entryPoint=attachment&id=([^&=\"']+)/", $body, $matches)) { + if (!empty($matches[1]) && is_array($matches[1])) { + foreach($matches[1] as $id) { + $attachment = $this->entityManager->getEntity('Attachment', $id); + if ($attachment) { + $attachmentList[] = $attachment; + } + } + } + } + + } + return $attachmentList; + } } diff --git a/application/Espo/Entities/EmailAddress.php b/application/Espo/Entities/EmailAddress.php index 18377e5179..4224adf847 100644 --- a/application/Espo/Entities/EmailAddress.php +++ b/application/Espo/Entities/EmailAddress.php @@ -27,13 +27,13 @@ use Espo\Core\Exceptions\Error; class EmailAddress extends \Espo\Core\ORM\Entity { - protected function setName($value) - { - if (empty($value)) { - throw new Error("Not valid email address '{$value}'"); - } - $this->valuesContainer['name'] = $value; - $this->set('lower', strtolower($value)); - } + protected function _setName($value) + { + if (empty($value)) { + throw new Error("Not valid email address '{$value}'"); + } + $this->valuesContainer['name'] = $value; + $this->set('lower', strtolower($value)); + } } diff --git a/application/Espo/Entities/Extension.php b/application/Espo/Entities/Extension.php index abad6e82e9..2f17e2b202 100644 --- a/application/Espo/Entities/Extension.php +++ b/application/Espo/Entities/Extension.php @@ -23,7 +23,7 @@ namespace Espo\Entities; class Extension extends \Espo\Core\ORM\Entity -{ - +{ + } diff --git a/application/Espo/Entities/ExternalAccount.php b/application/Espo/Entities/ExternalAccount.php index e52c51e256..f60c87a562 100644 --- a/application/Espo/Entities/ExternalAccount.php +++ b/application/Espo/Entities/ExternalAccount.php @@ -23,6 +23,6 @@ namespace Espo\Entities; class ExternalAccount extends Integration -{ +{ } diff --git a/application/Espo/Entities/Integration.php b/application/Espo/Entities/Integration.php index 0471893328..2de706b84e 100644 --- a/application/Espo/Entities/Integration.php +++ b/application/Espo/Entities/Integration.php @@ -23,153 +23,153 @@ 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 = $this->get('data'); - } else { - $data = new \stdClass(); - } - if (isset($data->$name)) { - return $data->$name; - } - } - return null; - } - - public function clear($name) - { - parent::clear($name); - - $data = $this->get('data'); - if (empty($data)) { - $data = new \stdClass(); - } - unset($data->$name); - $this->set('data', $data); - } - - 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 { - if (!$this->get('enabled')) { - return; - } - $data = $this->get('data'); - if (empty($data)) { - $data = new \stdClass(); - } - $data->$name = $value; - $this->set('data', $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 instanceof \stdClass)) { - $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; - case self::JSON_OBJECT: - $value = is_string($value) ? json_decode($value) : $value; - if (!($value instanceof \stdClass) && !is_array($value)) { - $value = null; - } - break; - default: - break; - } - } - } - +{ + 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 = $this->get('data'); + } else { + $data = new \stdClass(); + } + if (isset($data->$name)) { + return $data->$name; + } + } + return null; + } + + public function clear($name) + { + parent::clear($name); + + $data = $this->get('data'); + if (empty($data)) { + $data = new \stdClass(); + } + unset($data->$name); + $this->set('data', $data); + } + + 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 { + if (!$this->get('enabled')) { + return; + } + $data = $this->get('data'); + if (empty($data)) { + $data = new \stdClass(); + } + $data->$name = $value; + $this->set('data', $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 instanceof \stdClass)) { + $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; + case self::JSON_OBJECT: + $value = is_string($value) ? json_decode($value) : $value; + if (!($value instanceof \stdClass) && !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 = $this->get('data'); - if (empty($data)) { - $data = new \stdClass(); - } - - $dataArr = get_object_vars($data); + $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 = $this->get('data'); + if (empty($data)) { + $data = new \stdClass(); + } + + $dataArr = get_object_vars($data); - $arr = array_merge($arr, $dataArr); - return $arr; - } - + $arr = array_merge($arr, $dataArr); + return $arr; + } + } diff --git a/application/Espo/Entities/Note.php b/application/Espo/Entities/Note.php index d58e8eb25b..15fd55579a 100644 --- a/application/Espo/Entities/Note.php +++ b/application/Espo/Entities/Note.php @@ -24,21 +24,21 @@ namespace Espo\Entities; class Note extends \Espo\Core\ORM\Entity { - public function loadAttachments() - { - $collection = $this->get('attachments'); - $ids = array(); - $names = new \stdClass(); - $types = new \stdClass(); - foreach ($collection as $e) { - $id = $e->id; - $ids[] = $id; - $names->$id = $e->get('name'); - $types->$id = $e->get('type'); - } - $this->set('attachmentsIds', $ids); - $this->set('attachmentsNames', $names); - $this->set('attachmentsTypes', $types); - } + public function loadAttachments() + { + $collection = $this->get('attachments'); + $ids = array(); + $names = new \stdClass(); + $types = new \stdClass(); + foreach ($collection as $e) { + $id = $e->id; + $ids[] = $id; + $names->$id = $e->get('name'); + $types->$id = $e->get('type'); + } + $this->set('attachmentsIds', $ids); + $this->set('attachmentsNames', $names); + $this->set('attachmentsTypes', $types); + } } diff --git a/application/Espo/Entities/PhoneNumber.php b/application/Espo/Entities/PhoneNumber.php index 7ee7e7e9bc..6374ba741e 100644 --- a/application/Espo/Entities/PhoneNumber.php +++ b/application/Espo/Entities/PhoneNumber.php @@ -26,12 +26,12 @@ use Espo\Core\Exceptions\Error; class PhoneNumber extends \Espo\Core\ORM\Entity { - protected function setName($value) - { - if (empty($value)) { - throw new Error("Phone number can't be empty"); - } - $this->valuesContainer['name'] = $value; - } + protected function _setName($value) + { + if (empty($value)) { + throw new Error("Phone number can't be empty"); + } + $this->valuesContainer['name'] = $value; + } } diff --git a/application/Espo/Entities/Preferences.php b/application/Espo/Entities/Preferences.php index 0afa6d4049..458f61b1c0 100644 --- a/application/Espo/Entities/Preferences.php +++ b/application/Espo/Entities/Preferences.php @@ -25,21 +25,21 @@ namespace Espo\Entities; class Preferences extends \Espo\Core\ORM\Entity { - public function getSmtpParams() - { - $smtpParams = array(); - $smtpParams['server'] = $this->get('smtpServer'); - if ($smtpParams['server']) { - $smtpParams['port'] = $this->get('smtpPort'); - $smtpParams['server'] = $this->get('smtpServer'); - $smtpParams['auth'] = $this->get('smtpAuth'); - $smtpParams['security'] = $this->get('smtpSecurity'); - $smtpParams['username'] = $this->get('smtpUsername'); - $smtpParams['password'] = $this->get('smtpPassword'); - return $smtpParams; - } else { - return false; - } - } + public function getSmtpParams() + { + $smtpParams = array(); + $smtpParams['server'] = $this->get('smtpServer'); + if ($smtpParams['server']) { + $smtpParams['port'] = $this->get('smtpPort'); + $smtpParams['server'] = $this->get('smtpServer'); + $smtpParams['auth'] = $this->get('smtpAuth'); + $smtpParams['security'] = $this->get('smtpSecurity'); + $smtpParams['username'] = $this->get('smtpUsername'); + $smtpParams['password'] = $this->get('smtpPassword'); + return $smtpParams; + } else { + return false; + } + } } diff --git a/application/Espo/Entities/User.php b/application/Espo/Entities/User.php index f8723d73be..27f7006f92 100644 --- a/application/Espo/Entities/User.php +++ b/application/Espo/Entities/User.php @@ -23,9 +23,9 @@ namespace Espo\Entities; class User extends \Espo\Core\Entities\Person -{ - public function isAdmin() - { - return $this->get('isAdmin'); - } +{ + public function isAdmin() + { + return $this->get('isAdmin'); + } } diff --git a/application/Espo/EntryPoints/Attachment.php b/application/Espo/EntryPoints/Attachment.php index 2f001ebf0a..097d21b3ce 100644 --- a/application/Espo/EntryPoints/Attachment.php +++ b/application/Espo/EntryPoints/Attachment.php @@ -28,44 +28,44 @@ use \Espo\Core\Exceptions\BadRequest; class Attachment extends \Espo\Core\EntryPoints\Base { - public static $authRequired = true; - - public function run() - { - $id = $_GET['id']; - if (empty($id)) { - throw new BadRequest(); - } - - $attachment = $this->getEntityManager()->getEntity('Attachment', $id); - - if (!$attachment) { - throw new NotFound(); - } - - if ($attachment->get('parentId') && $attachment->get('parentType')) { - $parent = $this->getEntityManager()->getEntity($attachment->get('parentType'), $attachment->get('parentId')); - if (!$this->getAcl()->check($parent)) { - throw new Forbidden(); - } - } - - $fileName = "data/upload/{$attachment->id}"; - - if (!file_exists($fileName)) { - throw new NotFound(); - } - - if ($attachment->get('type')) { - header('Content-Type: ' . $attachment->get('type')); - } - - header('Pragma: public'); - header('Content-Length: ' . filesize($fileName)); - ob_clean(); - flush(); - readfile($fileName); - exit; - } + public static $authRequired = true; + + public function run() + { + $id = $_GET['id']; + if (empty($id)) { + throw new BadRequest(); + } + + $attachment = $this->getEntityManager()->getEntity('Attachment', $id); + + if (!$attachment) { + throw new NotFound(); + } + + if ($attachment->get('parentId') && $attachment->get('parentType')) { + $parent = $this->getEntityManager()->getEntity($attachment->get('parentType'), $attachment->get('parentId')); + if (!$this->getAcl()->check($parent)) { + throw new Forbidden(); + } + } + + $fileName = "data/upload/{$attachment->id}"; + + if (!file_exists($fileName)) { + throw new NotFound(); + } + + if ($attachment->get('type')) { + header('Content-Type: ' . $attachment->get('type')); + } + + header('Pragma: public'); + header('Content-Length: ' . filesize($fileName)); + ob_clean(); + flush(); + readfile($fileName); + exit; + } } diff --git a/application/Espo/EntryPoints/Download.php b/application/Espo/EntryPoints/Download.php index 99a5ef0ef5..5fdd7573da 100644 --- a/application/Espo/EntryPoints/Download.php +++ b/application/Espo/EntryPoints/Download.php @@ -28,59 +28,59 @@ use \Espo\Core\Exceptions\BadRequest; class Download extends \Espo\Core\EntryPoints\Base { - public static $authRequired = true; - - protected $fileTypesToShowInline = array( - 'application/pdf', - ); - - public function run() - { - $id = $_GET['id']; - if (empty($id)) { - throw new BadRequest(); - } - - $attachment = $this->getEntityManager()->getEntity('Attachment', $id); - - if (!$attachment) { - throw new NotFound(); - } - - if ($attachment->get('parentId') && $attachment->get('parentType')) { - $parent = $this->getEntityManager()->getEntity($attachment->get('parentType'), $attachment->get('parentId')); - if (!$this->getAcl()->check($parent)) { - throw new Forbidden(); - } - } - - $fileName = "data/upload/{$attachment->id}"; - - if (!file_exists($fileName)) { - throw new NotFound(); - } - - $type = $attachment->get('type'); - - $disposition = 'attachment'; - if (in_array($type, $this->fileTypesToShowInline)) { - $disposition = 'inline'; - } - - - header('Content-Description: File Transfer'); - if ($type) { - header('Content-Type: ' . $type); - } - header('Content-Disposition: ' . $disposition . '; filename=' . $attachment->get('name')); - header('Expires: 0'); - header('Cache-Control: must-revalidate'); - header('Pragma: public'); - header('Content-Length: ' . filesize($fileName)); - ob_clean(); - flush(); - readfile($fileName); - exit; - } + public static $authRequired = true; + + protected $fileTypesToShowInline = array( + 'application/pdf', + ); + + public function run() + { + $id = $_GET['id']; + if (empty($id)) { + throw new BadRequest(); + } + + $attachment = $this->getEntityManager()->getEntity('Attachment', $id); + + if (!$attachment) { + throw new NotFound(); + } + + if ($attachment->get('parentId') && $attachment->get('parentType')) { + $parent = $this->getEntityManager()->getEntity($attachment->get('parentType'), $attachment->get('parentId')); + if (!$this->getAcl()->check($parent)) { + throw new Forbidden(); + } + } + + $fileName = "data/upload/{$attachment->id}"; + + if (!file_exists($fileName)) { + throw new NotFound(); + } + + $type = $attachment->get('type'); + + $disposition = 'attachment'; + if (in_array($type, $this->fileTypesToShowInline)) { + $disposition = 'inline'; + } + + + header('Content-Description: File Transfer'); + if ($type) { + header('Content-Type: ' . $type); + } + header('Content-Disposition: ' . $disposition . '; filename=' . $attachment->get('name')); + header('Expires: 0'); + header('Cache-Control: must-revalidate'); + header('Pragma: public'); + header('Content-Length: ' . filesize($fileName)); + ob_clean(); + flush(); + readfile($fileName); + exit; + } } diff --git a/application/Espo/EntryPoints/Image.php b/application/Espo/EntryPoints/Image.php index 976a768ce0..eb356615ab 100644 --- a/application/Espo/EntryPoints/Image.php +++ b/application/Espo/EntryPoints/Image.php @@ -29,166 +29,166 @@ use \Espo\Core\Exceptions\Error; class Image extends \Espo\Core\EntryPoints\Base { - public static $authRequired = true; - - protected $allowedFileTypes = array( - 'image/jpeg', - 'image/png', - 'image/gif', - ); - - protected $imageSizes = array( - 'x-small' => array(64, 64), - 'small' => array(128, 128), - 'medium' => array(256, 256), - 'large' => array(512, 512), - 'x-large' => array(864, 864), - 'xx-large' => array(1024, 1024), - ); - - - public function run() - { - $id = $_GET['id']; - if (empty($id)) { - throw new BadRequest(); - } - - $size = null; - if (!empty($_GET['size'])) { - $size = $_GET['size']; - } - - $this->show($id, $size); - } - - protected function show($id, $size) - { - $attachment = $this->getEntityManager()->getEntity('Attachment', $id); - - if (!$attachment) { - throw new NotFound(); - } - - if ($attachment->get('parentId') && $attachment->get('parentType')) { - $parent = $this->getEntityManager()->getEntity($attachment->get('parentType'), $attachment->get('parentId')); - if ($parent && !$this->getAcl()->check($parent)) { - throw new Forbidden(); - } - } - - $filePath = "data/upload/{$attachment->id}"; - - $fileType = $attachment->get('type'); - - if (!file_exists($filePath)) { - throw new NotFound(); - } - - if (!in_array($fileType, $this->allowedFileTypes)) { - throw new Error(); - } - - if (!empty($size)) { - if (!empty($this->imageSizes[$size])) { - $thumbFilePath = "data/upload/thumbs/{$attachment->id}_{$size}"; - - if (!file_exists($thumbFilePath)) { - $targetImage = $this->getThumbImage($filePath, $fileType, $size); - ob_start(); - - switch ($fileType) { - case 'image/jpeg': - imagejpeg($targetImage); - break; - case 'image/png': - imagepng($targetImage); - break; - case 'image/gif': - imagegif($targetImage); - break; - } - $contents = ob_get_contents(); - ob_end_clean(); - imagedestroy($targetImage); - $this->getContainer()->get('fileManager')->putContents($thumbFilePath, $contents); - } - $filePath = $thumbFilePath; - - } else { - throw new Error(); - } - } - - if (!empty($size)) { - $fileName = $attachment->id . '_' . $size . '.jpg'; - } else { - $fileName = $attachment->get('name'); - } - header('Content-Disposition:inline;filename="'.$fileName.'"'); - if (!empty($fileType)) { - header('Content-Type: ' . $fileType); - } - header('Pragma: public'); - $fileSize = filesize($filePath); - if ($fileSize) { - header('Content-Length: ' . $fileSize); - } - ob_clean(); - flush(); - readfile($filePath); - exit; - } - - protected function getThumbImage($filePath, $fileType, $size) - { - list($originalWidth, $originalHeight) = getimagesize($filePath); - list($width, $height) = $this->imageSizes[$size]; - - - if ($originalWidth <= $width && $originalHeight <= $height) { - $targetWidth = $originalWidth; - $targetHeight = $originalHeight; - } else { - if ($originalWidth > $originalHeight) { - $targetWidth = $width; - $targetHeight = $originalHeight / ($originalWidth / $width); - if ($targetHeight > $height) { - $targetHeight = $height; - $targetWidth = $originalWidth / ($originalHeight / $height); - } - } else { - $targetHeight = $height; - $targetWidth = $originalWidth / ($originalHeight / $height); - if ($targetWidth > $width) { - $targetWidth = $width; - $targetHeight = $originalHeight / ($originalWidth / $width); - } - } - } - - $targetImage = imagecreatetruecolor($targetWidth, $targetHeight); - switch ($fileType) { - case 'image/jpeg': - $sourceImage = imagecreatefromjpeg($filePath); - imagecopyresized($targetImage, $sourceImage, 0, 0, 0, 0, $targetWidth, $targetHeight, $originalWidth, $originalHeight); - break; - case 'image/png': - $sourceImage = imagecreatefrompng($filePath); - imagealphablending($targetImage, false); - imagesavealpha($targetImage, true); - $transparent = imagecolorallocatealpha($targetImage, 255, 255, 255, 127); - imagefilledrectangle($targetImage, 0, 0, $targetWidth, $targetHeight, $transparent); - imagecopyresampled($targetImage, $sourceImage, 0, 0, 0, 0, $targetWidth, $targetHeight, $originalWidth, $originalHeight); - break; - case 'image/gif': - $sourceImage = imagecreatefromgif($filePath); - imagecopyresized($targetImage, $sourceImage, 0, 0, 0, 0, $targetWidth, $targetHeight, $originalWidth, $originalHeight); - break; - } - - - return $targetImage; - } + public static $authRequired = true; + + protected $allowedFileTypes = array( + 'image/jpeg', + 'image/png', + 'image/gif', + ); + + protected $imageSizes = array( + 'x-small' => array(64, 64), + 'small' => array(128, 128), + 'medium' => array(256, 256), + 'large' => array(512, 512), + 'x-large' => array(864, 864), + 'xx-large' => array(1024, 1024), + ); + + + public function run() + { + $id = $_GET['id']; + if (empty($id)) { + throw new BadRequest(); + } + + $size = null; + if (!empty($_GET['size'])) { + $size = $_GET['size']; + } + + $this->show($id, $size); + } + + protected function show($id, $size) + { + $attachment = $this->getEntityManager()->getEntity('Attachment', $id); + + if (!$attachment) { + throw new NotFound(); + } + + if ($attachment->get('parentId') && $attachment->get('parentType')) { + $parent = $this->getEntityManager()->getEntity($attachment->get('parentType'), $attachment->get('parentId')); + if ($parent && !$this->getAcl()->check($parent)) { + throw new Forbidden(); + } + } + + $filePath = "data/upload/{$attachment->id}"; + + $fileType = $attachment->get('type'); + + if (!file_exists($filePath)) { + throw new NotFound(); + } + + if (!in_array($fileType, $this->allowedFileTypes)) { + throw new Error(); + } + + if (!empty($size)) { + if (!empty($this->imageSizes[$size])) { + $thumbFilePath = "data/upload/thumbs/{$attachment->id}_{$size}"; + + if (!file_exists($thumbFilePath)) { + $targetImage = $this->getThumbImage($filePath, $fileType, $size); + ob_start(); + + switch ($fileType) { + case 'image/jpeg': + imagejpeg($targetImage); + break; + case 'image/png': + imagepng($targetImage); + break; + case 'image/gif': + imagegif($targetImage); + break; + } + $contents = ob_get_contents(); + ob_end_clean(); + imagedestroy($targetImage); + $this->getContainer()->get('fileManager')->putContents($thumbFilePath, $contents); + } + $filePath = $thumbFilePath; + + } else { + throw new Error(); + } + } + + if (!empty($size)) { + $fileName = $attachment->id . '_' . $size . '.jpg'; + } else { + $fileName = $attachment->get('name'); + } + header('Content-Disposition:inline;filename="'.$fileName.'"'); + if (!empty($fileType)) { + header('Content-Type: ' . $fileType); + } + header('Pragma: public'); + $fileSize = filesize($filePath); + if ($fileSize) { + header('Content-Length: ' . $fileSize); + } + ob_clean(); + flush(); + readfile($filePath); + exit; + } + + protected function getThumbImage($filePath, $fileType, $size) + { + list($originalWidth, $originalHeight) = getimagesize($filePath); + list($width, $height) = $this->imageSizes[$size]; + + + if ($originalWidth <= $width && $originalHeight <= $height) { + $targetWidth = $originalWidth; + $targetHeight = $originalHeight; + } else { + if ($originalWidth > $originalHeight) { + $targetWidth = $width; + $targetHeight = $originalHeight / ($originalWidth / $width); + if ($targetHeight > $height) { + $targetHeight = $height; + $targetWidth = $originalWidth / ($originalHeight / $height); + } + } else { + $targetHeight = $height; + $targetWidth = $originalWidth / ($originalHeight / $height); + if ($targetWidth > $width) { + $targetWidth = $width; + $targetHeight = $originalHeight / ($originalWidth / $width); + } + } + } + + $targetImage = imagecreatetruecolor($targetWidth, $targetHeight); + switch ($fileType) { + case 'image/jpeg': + $sourceImage = imagecreatefromjpeg($filePath); + imagecopyresized($targetImage, $sourceImage, 0, 0, 0, 0, $targetWidth, $targetHeight, $originalWidth, $originalHeight); + break; + case 'image/png': + $sourceImage = imagecreatefrompng($filePath); + imagealphablending($targetImage, false); + imagesavealpha($targetImage, true); + $transparent = imagecolorallocatealpha($targetImage, 255, 255, 255, 127); + imagefilledrectangle($targetImage, 0, 0, $targetWidth, $targetHeight, $transparent); + imagecopyresampled($targetImage, $sourceImage, 0, 0, 0, 0, $targetWidth, $targetHeight, $originalWidth, $originalHeight); + break; + case 'image/gif': + $sourceImage = imagecreatefromgif($filePath); + imagecopyresized($targetImage, $sourceImage, 0, 0, 0, 0, $targetWidth, $targetHeight, $originalWidth, $originalHeight); + break; + } + + + return $targetImage; + } } diff --git a/application/Espo/EntryPoints/LogoImage.php b/application/Espo/EntryPoints/LogoImage.php index b332bd64ee..f0573739bc 100644 --- a/application/Espo/EntryPoints/LogoImage.php +++ b/application/Espo/EntryPoints/LogoImage.php @@ -29,24 +29,24 @@ use \Espo\Core\Exceptions\Error; class LogoImage extends Image { - public static $authRequired = false; - - public function run() - { - $this->imageSizes['small-logo'] = array(173, 38); - - $id = $this->getConfig()->get('companyLogoId'); - - if (empty($id)) { - throw new NotFound(); - } - - $size = null; - if (!empty($_GET['size'])) { - $size = $_GET['size']; - } - - $this->show($id, $size); - } + public static $authRequired = false; + + public function run() + { + $this->imageSizes['small-logo'] = array(173, 38); + + $id = $this->getConfig()->get('companyLogoId'); + + if (empty($id)) { + throw new NotFound(); + } + + $size = null; + if (!empty($_GET['size'])) { + $size = $_GET['size']; + } + + $this->show($id, $size); + } } diff --git a/application/Espo/Hooks/Common/AssignmentEmailNotification.php b/application/Espo/Hooks/Common/AssignmentEmailNotification.php index 4191222c62..34f422231b 100644 --- a/application/Espo/Hooks/Common/AssignmentEmailNotification.php +++ b/application/Espo/Hooks/Common/AssignmentEmailNotification.php @@ -25,34 +25,34 @@ namespace Espo\Hooks\Common; use Espo\ORM\Entity; class AssignmentEmailNotification extends \Espo\Core\Hooks\Base -{ - - public function afterSave(Entity $entity) - { - if ( - $this->getConfig()->get('assignmentEmailNotifications') - && - in_array($entity->getEntityName(), $this->getConfig()->get('assignmentEmailNotificationsEntityList', array())) - ) { - - $userId = $entity->get('assignedUserId'); - if (!empty($userId) && $userId != $this->getUser()->id && $entity->isFieldChanged('assignedUserId')) { - $job = $this->getEntityManager()->getEntity('Job'); - $job->set(array( - 'serviceName' => 'EmailNotification', - 'method' => 'notifyAboutAssignmentJob', - 'data' => json_encode(array( - 'userId' => $userId, - 'assignerUserId' => $this->getUser()->id, - 'entityId' => $entity->id, - 'entityType' => $entity->getEntityName() - )), - 'executeTime' => date('Y-m-d H:i:s'), - )); - $this->getEntityManager()->saveEntity($job); - } - } - } +{ + + public function afterSave(Entity $entity) + { + if ( + $this->getConfig()->get('assignmentEmailNotifications') + && + in_array($entity->getEntityName(), $this->getConfig()->get('assignmentEmailNotificationsEntityList', array())) + ) { + + $userId = $entity->get('assignedUserId'); + if (!empty($userId) && $userId != $this->getUser()->id && $entity->isFieldChanged('assignedUserId')) { + $job = $this->getEntityManager()->getEntity('Job'); + $job->set(array( + 'serviceName' => 'EmailNotification', + 'method' => 'notifyAboutAssignmentJob', + 'data' => json_encode(array( + 'userId' => $userId, + 'assignerUserId' => $this->getUser()->id, + 'entityId' => $entity->id, + 'entityType' => $entity->getEntityName() + )), + 'executeTime' => date('Y-m-d H:i:s'), + )); + $this->getEntityManager()->saveEntity($job); + } + } + } } diff --git a/application/Espo/Hooks/Common/Stream.php b/application/Espo/Hooks/Common/Stream.php index 362ecae555..9368ece447 100644 --- a/application/Espo/Hooks/Common/Stream.php +++ b/application/Espo/Hooks/Common/Stream.php @@ -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\Hooks\Common; @@ -26,142 +26,154 @@ use Espo\ORM\Entity; class Stream extends \Espo\Core\Hooks\Base { - protected $streamService = null; - - protected $auditedFieldsCache = array(); - - protected $statusDefs = array( - 'Lead' => 'status', - 'Case' => 'status', - 'Opportunity' => 'stage', - ); - - protected function init() - { - $this->dependencies[] = 'serviceFactory'; - } - - protected function getServiceFactory() - { - return $this->getInjection('serviceFactory'); - } - - protected function checkHasStream(Entity $entity) - { - $entityName = $entity->getEntityName(); - return $this->getMetadata()->get("scopes.{$entityName}.stream"); - } - - public function afterRemove(Entity $entity) - { - if ($this->checkHasStream($entity)) { - $this->getStreamService()->unfollowAllUsersFromEntity($entity); - } - } - - protected function isLinkObservableInStream($scope, $link) - { - return $this->getMetadata()->get("scopes.{$scope}.stream") && - in_array($link, $this->getMetadata()->get("entityDefs.Note.streamRelated.{$scope}", array())); - } - - protected function handleCreateRelated(Entity $entity) - { - $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 (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 (in_array($scope, $scopeNotifiedList) || !$this->isLinkObservableInStream($scope, $foreign)) { - continue; - } - $this->getStreamService()->noteCreateRelated($entity, $scope, $entityId); - $scopeNotifiedList[] = $scope; - - } - } else if ($defs['type'] == 'hasMany') { - $foreign = $defs['foreign']; - $scope = $defs['entity']; - $entityIds = $entity->get($link . 'Ids'); - if (!empty($scope) && is_array($entityIds) && !empty($entityIds)) { - if (in_array($scope, $scopeNotifiedList) || !$this->isLinkObservableInStream($scope, $foreign)) { - continue; - } - $entityId = $entityIds[0]; - $this->getStreamService()->noteCreateRelated($entity, $scope, $entityId); - $scopeNotifiedList[] = $scope; - } - } - } - } - - public function afterSave(Entity $entity) - { - $entityName = $entity->getEntityName(); - - if ($this->checkHasStream($entity)) { - if (!$entity->isFetched()) { - - $assignedUserId = $entity->get('assignedUserId'); - $createdById = $entity->get('createdById'); - - if (!empty($createdById)) { - $this->getStreamService()->followEntity($entity, $createdById); - } - - if (!empty($assignedUserId) && $createdById != $assignedUserId) { - $this->getStreamService()->followEntity($entity, $assignedUserId); - } - $this->getStreamService()->noteCreate($entity); - - } else { - if ($entity->isFieldChanged('assignedUserId')) { - $assignedUserId = $entity->get('assignedUserId'); - if (!empty($assignedUserId)) { - $this->getStreamService()->followEntity($entity, $assignedUserId); - $this->getStreamService()->noteAssign($entity); - } - } - $this->getStreamService()->handleAudited($entity); - - if (array_key_exists($entityName, $this->statusDefs)) { - $field = $this->statusDefs[$entityName]; - $value = $entity->get($field); - if (!empty($value) && $value != $entity->getFetched($field)) { - $this->getStreamService()->noteStatus($entity, $field); - } - } - } + protected $streamService = null; - } - - if (!$entity->isFetched() && $this->getMetadata()->get("scopes.{$entityName}.tab")) { - $this->handleCreateRelated($entity); - } - } - - protected function getStreamService() - { - if (empty($this->streamService)) { - $this->streamService = $this->getServiceFactory()->create('Stream'); - } - return $this->streamService; - } + protected $auditedFieldsCache = array(); + + protected $hasStreamCache = array(); + + protected $isLinkObservableInStreamCache = array(); + + protected $statusDefs = array( + 'Lead' => 'status', + 'Case' => 'status', + 'Opportunity' => 'stage', + ); + + protected function init() + { + $this->dependencies[] = 'serviceFactory'; + } + + protected function getServiceFactory() + { + return $this->getInjection('serviceFactory'); + } + + protected function checkHasStream(Entity $entity) + { + $entityName = $entity->getEntityName(); + if (!array_key_exists($entityName, $this->hasStreamCache)) { + $this->hasStreamCache[$entityName] = $this->getMetadata()->get("scopes.{$entityName}.stream"); + } + return $this->hasStreamCache[$entityName]; + } + + protected function isLinkObservableInStream($scope, $link) + { + $key = $scope . '__' . $link; + if (!array_key_exists($key, $this->isLinkObservableInStreamCache)) { + $this->isLinkObservableInStreamCache[$key] = $this->getMetadata()->get("scopes.{$scope}.stream") && + in_array($link, $this->getMetadata()->get("entityDefs.Note.streamRelated.{$scope}", array())); + } + + return $this->isLinkObservableInStreamCache[$key]; + } + + public function afterRemove(Entity $entity) + { + if ($this->checkHasStream($entity)) { + $this->getStreamService()->unfollowAllUsersFromEntity($entity); + } + } + + protected function handleCreateRelated(Entity $entity) + { + $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 (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 (in_array($scope, $scopeNotifiedList) || !$this->isLinkObservableInStream($scope, $foreign)) { + continue; + } + $this->getStreamService()->noteCreateRelated($entity, $scope, $entityId); + $scopeNotifiedList[] = $scope; + + } + } else if ($defs['type'] == 'hasMany') { + $foreign = $defs['foreign']; + $scope = $defs['entity']; + $entityIds = $entity->get($link . 'Ids'); + if (!empty($scope) && is_array($entityIds) && !empty($entityIds)) { + if (in_array($scope, $scopeNotifiedList) || !$this->isLinkObservableInStream($scope, $foreign)) { + continue; + } + $entityId = $entityIds[0]; + $this->getStreamService()->noteCreateRelated($entity, $scope, $entityId); + $scopeNotifiedList[] = $scope; + } + } + } + } + + public function afterSave(Entity $entity) + { + $entityName = $entity->getEntityName(); + + if ($this->checkHasStream($entity)) { + if ($entity->isNew()) { + + $assignedUserId = $entity->get('assignedUserId'); + $createdById = $entity->get('createdById'); + + if (!empty($createdById)) { + $this->getStreamService()->followEntity($entity, $createdById); + } + + if (!empty($assignedUserId) && $createdById != $assignedUserId) { + $this->getStreamService()->followEntity($entity, $assignedUserId); + } + $this->getStreamService()->noteCreate($entity); + + } else { + if ($entity->isFieldChanged('assignedUserId')) { + $assignedUserId = $entity->get('assignedUserId'); + if (!empty($assignedUserId)) { + $this->getStreamService()->followEntity($entity, $assignedUserId); + $this->getStreamService()->noteAssign($entity); + } + } + $this->getStreamService()->handleAudited($entity); + + if (array_key_exists($entityName, $this->statusDefs)) { + $field = $this->statusDefs[$entityName]; + $value = $entity->get($field); + if (!empty($value) && $value != $entity->getFetched($field)) { + $this->getStreamService()->noteStatus($entity, $field); + } + } + } + + } + + if ($entity->isNew() && $this->getMetadata()->get("scopes.{$entityName}.tab")) { + $this->handleCreateRelated($entity); + } + } + + protected function getStreamService() + { + if (empty($this->streamService)) { + $this->streamService = $this->getServiceFactory()->create('Stream'); + } + return $this->streamService; + } } diff --git a/application/Espo/Hooks/Note/Mentions.php b/application/Espo/Hooks/Note/Mentions.php index aca031423b..25a4752c2c 100644 --- a/application/Espo/Hooks/Note/Mentions.php +++ b/application/Espo/Hooks/Note/Mentions.php @@ -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\Hooks\Note; @@ -26,84 +26,84 @@ use Espo\ORM\Entity; class Mentions extends \Espo\Core\Hooks\Base { - public static $order = 9; - - protected $notificationService = null; - - protected function init() - { - $this->dependencies[] = 'serviceFactory'; - } - - protected function getServiceFactory() - { - return $this->getInjection('serviceFactory'); - } - - protected function addMentionData($entity) - { - $post = $entity->get('post'); - - $mentionData = new \stdClass(); - - $previousMentionList = array(); - if ($entity->isFetched()) { - $data = $entity->get('data'); - if (!empty($data) && !empty($data->mentions)) { - $previousMentionList = array_keys(get_object_vars($data->mentions)); - } - } - - preg_match_all('/(@\w+)/', $post, $matches); - - if (is_array($matches) && !empty($matches[0]) && is_array($matches[0])) { - foreach ($matches[0] as $item) { - $userName = substr($item, 1); - $user = $this->getEntityManager()->getRepository('User')->where(array('userName' => $userName))->findOne(); - if ($user) { - $m = array( - 'id' => $user->id, - 'name' => $user->get('name'), - 'userName' => $user->get('userName'), - '_scope' => $user->getEntityName() - ); - $mentionData->$item = (object) $m; - if (!in_array($item, $previousMentionList)) { - $this->notifyAboutMention($entity, $user); - } - } - } - } - - $data = $entity->get('data'); - if (empty($data)) { - $data = new \stdClass(); - } - $data->mentions = $mentionData; - - $entity->set('data', $data); - } - - public function beforeSave(Entity $entity) - { - if ($entity->get('type') == 'Post') { - $post = $entity->get('post'); - - $this->addMentionData($entity); - } - } - - protected function notifyAboutMention(Entity $entity, \Espo\Entities\User $user) - { - $this->getNotificationService()->notifyAboutMentionInPost($user->id, $entity->id); - } - - protected function getNotificationService() - { - if (empty($this->notificationService)) { - $this->notificationService = $this->getServiceFactory()->create('Notification'); - } - return $this->notificationService; - } + public static $order = 9; + + protected $notificationService = null; + + protected function init() + { + $this->dependencies[] = 'serviceFactory'; + } + + protected function getServiceFactory() + { + return $this->getInjection('serviceFactory'); + } + + protected function addMentionData($entity) + { + $post = $entity->get('post'); + + $mentionData = new \stdClass(); + + $previousMentionList = array(); + if (!$entity->isNew()) { + $data = $entity->get('data'); + if (!empty($data) && !empty($data->mentions)) { + $previousMentionList = array_keys(get_object_vars($data->mentions)); + } + } + + preg_match_all('/(@\w+)/', $post, $matches); + + if (is_array($matches) && !empty($matches[0]) && is_array($matches[0])) { + foreach ($matches[0] as $item) { + $userName = substr($item, 1); + $user = $this->getEntityManager()->getRepository('User')->where(array('userName' => $userName))->findOne(); + if ($user) { + $m = array( + 'id' => $user->id, + 'name' => $user->get('name'), + 'userName' => $user->get('userName'), + '_scope' => $user->getEntityName() + ); + $mentionData->$item = (object) $m; + if (!in_array($item, $previousMentionList)) { + $this->notifyAboutMention($entity, $user); + } + } + } + } + + $data = $entity->get('data'); + if (empty($data)) { + $data = new \stdClass(); + } + $data->mentions = $mentionData; + + $entity->set('data', $data); + } + + public function beforeSave(Entity $entity) + { + if ($entity->get('type') == 'Post') { + $post = $entity->get('post'); + + $this->addMentionData($entity); + } + } + + protected function notifyAboutMention(Entity $entity, \Espo\Entities\User $user) + { + $this->getNotificationService()->notifyAboutMentionInPost($user->id, $entity->id); + } + + protected function getNotificationService() + { + if (empty($this->notificationService)) { + $this->notificationService = $this->getServiceFactory()->create('Notification'); + } + return $this->notificationService; + } } diff --git a/application/Espo/Hooks/Note/Notifications.php b/application/Espo/Hooks/Note/Notifications.php index 4d59d77e9d..1219482a3d 100644 --- a/application/Espo/Hooks/Note/Notifications.php +++ b/application/Espo/Hooks/Note/Notifications.php @@ -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\Hooks\Note; @@ -26,80 +26,80 @@ use Espo\ORM\Entity; class Notifications extends \Espo\Core\Hooks\Base { - protected $notificationService = null; - - public static $order = 14; - - protected function init() - { - $this->dependencies[] = 'serviceFactory'; - } - - protected function getServiceFactory() - { - return $this->getInjection('serviceFactory'); - } - - protected function getMentionedUserList($entity) - { - $mentionedUserList = array(); - $data = $entity->get('data'); - if (($data instanceof \stdClass) && ($data->mentions instanceof \stdClass)) { - $mentions = get_object_vars($data->mentions); - foreach ($mentions as $d) { - $mentionedUserList[] = $d->id; - } - } - return $mentionedUserList; - } - - public function afterSave(Entity $entity) - { - if (!$entity->isFetched()) { + protected $notificationService = null; - $parentType = $entity->get('parentType'); - $parentId = $entity->get('parentId'); - - if ($parentType && $parentId) { + public static $order = 14; - $mentionedUserList = $this->getMentionedUserList($entity); - - $pdo = $this->getEntityManager()->getPDO(); - $sql = " - SELECT user_id AS userId - FROM subscription - WHERE entity_id = " . $pdo->quote($parentId) . " AND entity_type = " . $pdo->quote($parentType); - $sth = $pdo->prepare($sql); - $sth->execute(); - $userIdList = array(); - while ($row = $sth->fetch(\PDO::FETCH_ASSOC)) { - if ($this->getUser()->id != $row['userId'] && !in_array($row['userId'], $mentionedUserList)) { - $userIdList[] = $row['userId']; - } - } - if (!empty($userIdList)) { - $job = $this->getEntityManager()->getEntity('Job'); - $job->set(array( - 'serviceName' => 'Notification', - 'method' => 'notifyAboutNoteFromJob', - 'data' => array( - 'userIdList' => $userIdList, - 'noteId' => $entity->id - ), - 'executeTime' => date('Y-m-d H:i:s'), - )); - $this->getEntityManager()->saveEntity($job); - } - } - } - } - - protected function getNotificationService() - { - if (empty($this->notificationService)) { - $this->notificationService = $this->getServiceFactory()->create('Notification'); - } - return $this->notificationService; - } + protected function init() + { + $this->dependencies[] = 'serviceFactory'; + } + + protected function getServiceFactory() + { + return $this->getInjection('serviceFactory'); + } + + protected function getMentionedUserList($entity) + { + $mentionedUserList = array(); + $data = $entity->get('data'); + if (($data instanceof \stdClass) && ($data->mentions instanceof \stdClass)) { + $mentions = get_object_vars($data->mentions); + foreach ($mentions as $d) { + $mentionedUserList[] = $d->id; + } + } + return $mentionedUserList; + } + + public function afterSave(Entity $entity) + { + if ($entity->isNew()) { + + $parentType = $entity->get('parentType'); + $parentId = $entity->get('parentId'); + + if ($parentType && $parentId) { + + $mentionedUserList = $this->getMentionedUserList($entity); + + $pdo = $this->getEntityManager()->getPDO(); + $sql = " + SELECT user_id AS userId + FROM subscription + WHERE entity_id = " . $pdo->quote($parentId) . " AND entity_type = " . $pdo->quote($parentType); + $sth = $pdo->prepare($sql); + $sth->execute(); + $userIdList = array(); + while ($row = $sth->fetch(\PDO::FETCH_ASSOC)) { + if ($this->getUser()->id != $row['userId'] && !in_array($row['userId'], $mentionedUserList)) { + $userIdList[] = $row['userId']; + } + } + if (!empty($userIdList)) { + $job = $this->getEntityManager()->getEntity('Job'); + $job->set(array( + 'serviceName' => 'Notification', + 'method' => 'notifyAboutNoteFromJob', + 'data' => array( + 'userIdList' => $userIdList, + 'noteId' => $entity->id + ), + 'executeTime' => date('Y-m-d H:i:s'), + )); + $this->getEntityManager()->saveEntity($job); + } + } + } + } + + protected function getNotificationService() + { + if (empty($this->notificationService)) { + $this->notificationService = $this->getServiceFactory()->create('Notification'); + } + return $this->notificationService; + } } diff --git a/application/Espo/Modules/Crm/Business/CaseDistribution/LeastBusy.php b/application/Espo/Modules/Crm/Business/CaseDistribution/LeastBusy.php index 03d20264e3..c07852f106 100644 --- a/application/Espo/Modules/Crm/Business/CaseDistribution/LeastBusy.php +++ b/application/Espo/Modules/Crm/Business/CaseDistribution/LeastBusy.php @@ -18,58 +18,66 @@ * * 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\Business\CaseDistribution; class LeastBusy { - protected $entityManager; - - public function __construct($entityManager) - { - $this->entityManager = $entityManager; - } - - protected function getEntityManager() - { - return $this->entityManager; - } - - public function getUser($team) - { - $userList = $team->get('users'); - if (count($userList) == 0) { - return false; - } - - $countHash = array(); - - foreach ($userList as $user) { - $count = $this->getEntityManager()->getRepository('Case')->where(array( - 'assignedUserId' => $user->id, - 'status<>' => array('Closed', 'Rejected', 'Duplicated') - ))->count(); - $countHash[$user->id] = $count; - } - - $foundUserId = false; - $min = false; - foreach ($countHash as $userId => $count) { - if ($min === false) { - $min = $count; - $foundUserId = $userId; - } else { - if ($count < $min) { - $min = $clunt; - $foundUserId = $userId; - } - } - } - - if ($foundUserId !== false) { - return $this->getEntityManager()->getEntity('User', $foundUserId); - } - } + protected $entityManager; + + public function __construct($entityManager) + { + $this->entityManager = $entityManager; + } + + protected function getEntityManager() + { + return $this->entityManager; + } + + public function getUser($team, $targetUserPosition = null) + { + $params = array(); + if (!empty($targetUserPosition)) { + $params['additionalColumnsConditions'] = array( + 'role' => $targetUserPosition + ); + } + + $userList = $team->get('users', $params); + + if (count($userList) == 0) { + return false; + } + + $countHash = array(); + + foreach ($userList as $user) { + $count = $this->getEntityManager()->getRepository('Case')->where(array( + 'assignedUserId' => $user->id, + 'status<>' => array('Closed', 'Rejected', 'Duplicated') + ))->count(); + $countHash[$user->id] = $count; + } + + $foundUserId = false; + $min = false; + foreach ($countHash as $userId => $count) { + if ($min === false) { + $min = $count; + $foundUserId = $userId; + } else { + if ($count < $min) { + $min = $clunt; + $foundUserId = $userId; + } + } + } + + if ($foundUserId !== false) { + return $this->getEntityManager()->getEntity('User', $foundUserId); + } + } } diff --git a/application/Espo/Modules/Crm/Business/CaseDistribution/RoundRobin.php b/application/Espo/Modules/Crm/Business/CaseDistribution/RoundRobin.php index 788281ca5e..68c726140a 100644 --- a/application/Espo/Modules/Crm/Business/CaseDistribution/RoundRobin.php +++ b/application/Espo/Modules/Crm/Business/CaseDistribution/RoundRobin.php @@ -18,54 +18,62 @@ * * 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\Business\CaseDistribution; class RoundRobin { - protected $entityManager; - - public function __construct($entityManager) - { - $this->entityManager = $entityManager; - } - - protected function getEntityManager() - { - return $this->entityManager; - } - - public function getUser($team) - { - $userList = $team->get('users'); - if (count($userList) == 0) { - return false; - } - - $userIdList = array(); - - foreach ($userList as $user) { - $userIdList[] = $user->id; - } - - - $case = $this->getEntityManager()->getRepository('Case')->where(array( - 'assignedUserId' => $userIdList, - ))->order('createdAt', 'DESC')->findOne(); - - if (empty($case)) { - $num = 0; - } else { - $num = array_search($case->get('assignedUserId'), $userIdList); - if ($num === false || $num == count($userIdList) - 1) { - $num = 0; - } else { - $num++; - } - } - - return $this->getEntityManager()->getEntity('User', $userIdList[$num]); - } + protected $entityManager; + + public function __construct($entityManager) + { + $this->entityManager = $entityManager; + } + + protected function getEntityManager() + { + return $this->entityManager; + } + + public function getUser($team, $targetUserPosition = null) + { + $params = array(); + if (!empty($targetUserPosition)) { + $params['additionalColumnsConditions'] = array( + 'role' => $targetUserPosition + ); + } + + $userList = $team->get('users', $params); + + if (count($userList) == 0) { + return false; + } + + $userIdList = array(); + + foreach ($userList as $user) { + $userIdList[] = $user->id; + } + + + $case = $this->getEntityManager()->getRepository('Case')->where(array( + 'assignedUserId' => $userIdList, + ))->order('createdAt', 'DESC')->findOne(); + + if (empty($case)) { + $num = 0; + } else { + $num = array_search($case->get('assignedUserId'), $userIdList); + if ($num === false || $num == count($userIdList) - 1) { + $num = 0; + } else { + $num++; + } + } + + return $this->getEntityManager()->getEntity('User', $userIdList[$num]); + } } diff --git a/application/Espo/Modules/Crm/Business/Event/Ics.php b/application/Espo/Modules/Crm/Business/Event/Ics.php index 76ca43a904..e6fcc4a4ec 100644 --- a/application/Espo/Modules/Crm/Business/Event/Ics.php +++ b/application/Espo/Modules/Crm/Business/Event/Ics.php @@ -4,172 +4,172 @@ namespace Espo\Modules\Crm\Business\Event; class Ics { - private $_d_end; + private $_d_end; - private $_d_start; + private $_d_start; - private $_s_address; + private $_s_address; - private $_s_description; + private $_s_description; - private $_s_html; - - private $_s_who; - - private $_s_email; + private $_s_html; + + private $_s_who; + + private $_s_email; - private $_s_uri; - - private $_s_uid; + private $_s_uri; + + private $_s_uid; - private $_s_summary; + private $_s_summary; - private $_s_output; + private $_s_output; - private $_s_prodid; - - public function __construct($prodid, array $attributes = array()) - { - if (!is_string($prodid) || $prodid === '') { - throw new \Exception('PRODID is required'); - } + private $_s_prodid; + + public function __construct($prodid, array $attributes = array()) + { + if (!is_string($prodid) || $prodid === '') { + throw new \Exception('PRODID is required'); + } - $this->_s_prodid = $prodid; + $this->_s_prodid = $prodid; - foreach ($attributes as $key => $value) { - $this->$key = $value; - } - } - - public function __set($name, $value) - { - switch ($name) { - case 'startDate': - $this->_d_start = $value; - break; + foreach ($attributes as $key => $value) { + $this->$key = $value; + } + } + + public function __set($name, $value) + { + switch ($name) { + case 'startDate': + $this->_d_start = $value; + break; - case 'endDate': - $this->_d_end = $value; - break; + case 'endDate': + $this->_d_end = $value; + break; - case 'address': - $this->_s_address = $value; - break; + case 'address': + $this->_s_address = $value; + break; - case 'summary': - $this->_s_summary = $value; - break; - - case 'who': - $this->_s_who = $value; - break; - - case 'email': - $this->_s_email = $value; - break; + case 'summary': + $this->_s_summary = $value; + break; + + case 'who': + $this->_s_who = $value; + break; + + case 'email': + $this->_s_email = $value; + break; - case 'uri': - $this->_s_uri = $value; - break; - - case 'uid': - $this->_s_uid = $value; - break; + case 'uri': + $this->_s_uri = $value; + break; + + case 'uid': + $this->_s_uid = $value; + break; - case 'description': - $this->_s_description = $value; - break; + case 'description': + $this->_s_description = $value; + break; - case 'html': - $this->_s_html = $value; - break; - } + case 'html': + $this->_s_html = $value; + break; + } - return $this; - } - - public function __get($name) { - switch ($name) - { - case 'startDate': - return $this->_d_start; - break; + return $this; + } + + public function __get($name) { + switch ($name) + { + case 'startDate': + return $this->_d_start; + break; - case 'endDate': - return $this->_d_end; - break; + case 'endDate': + return $this->_d_end; + break; - case 'address': - return $this->_s_address; - break; + case 'address': + return $this->_s_address; + break; - case 'summary': - return $this->_s_summary; - break; + case 'summary': + return $this->_s_summary; + break; - case 'uri': - return $this->_s_uri; - break; - - case 'who': - return $this->_s_who; - break; - - case 'email': - return $this->_s_email; - break; - - case 'uid': - return $this->_s_uid; - break; + case 'uri': + return $this->_s_uri; + break; + + case 'who': + return $this->_s_who; + break; + + case 'email': + return $this->_s_email; + break; + + case 'uid': + return $this->_s_uid; + break; - case 'description': - return $this->_s_description; - break; + case 'description': + return $this->_s_description; + break; - case 'html': - return $this->_s_html; - break; - } - } - - public function get() - { - ($this->_s_output) ? $this->_s_output : $this->_generate(); + case 'html': + return $this->_s_html; + break; + } + } + + public function get() + { + ($this->_s_output) ? $this->_s_output : $this->_generate(); - return $this->_s_output; - } - - private function _generate() - { - $this->_s_output = "BEGIN:VCALENDAR\n". - "VERSION:2.0\n". - "PRODID:-".$this->_s_prodid."\n". - "METHOD:REQUEST\n". - "BEGIN:VEVENT\n". - "DTSTART:".$this->_dateToCal($this->startDate)."\n". - "DTEND:".$this->_dateToCal($this->endDate)."\n". - "SUMMARY:New ".$this->_escapeString($this->summary)."\n". - "LOCATION:".$this->_escapeString($this->address)."\n". - "ORGANIZER;CN=".$this->_escapeString($this->who).":MAILTO:" . $this->_escapeString($this->email)."\n". - "DESCRIPTION:".$this->_escapeString($this->description)."\n". - "X-ALT-DESC;FMTTYPE=text/html:".$this->_escapeString($this->html)."\n". - "URL;VALUE=URI:".$this->_escapeString($this->uri)."\n". - "UID:".$this->uid."\n". - "SEQUENCE:0\n". - "DTSTAMP:".$this->_dateToCal(time())."\n". - "END:VEVENT\n". - "END:VCALENDAR\n"; - } - - private function _dateToCal($timestamp) - { - return date('Ymd\THis\Z', ($timestamp) ? $timestamp : time()); - } + return $this->_s_output; + } + + private function _generate() + { + $this->_s_output = "BEGIN:VCALENDAR\n". + "VERSION:2.0\n". + "PRODID:-".$this->_s_prodid."\n". + "METHOD:REQUEST\n". + "BEGIN:VEVENT\n". + "DTSTART:".$this->_dateToCal($this->startDate)."\n". + "DTEND:".$this->_dateToCal($this->endDate)."\n". + "SUMMARY:New ".$this->_escapeString($this->summary)."\n". + "LOCATION:".$this->_escapeString($this->address)."\n". + "ORGANIZER;CN=".$this->_escapeString($this->who).":MAILTO:" . $this->_escapeString($this->email)."\n". + "DESCRIPTION:".$this->_escapeString($this->description)."\n". + "X-ALT-DESC;FMTTYPE=text/html:".$this->_escapeString($this->html)."\n". + "URL;VALUE=URI:".$this->_escapeString($this->uri)."\n". + "UID:".$this->uid."\n". + "SEQUENCE:0\n". + "DTSTAMP:".$this->_dateToCal(time())."\n". + "END:VEVENT\n". + "END:VCALENDAR\n"; + } + + private function _dateToCal($timestamp) + { + return date('Ymd\THis\Z', ($timestamp) ? $timestamp : time()); + } - private function _escapeString($string) - { - return preg_replace('/([\,;])/','\\\$1', ($string) ? $string : ''); - } + private function _escapeString($string) + { + return preg_replace('/([\,;])/','\\\$1', ($string) ? $string : ''); + } } diff --git a/application/Espo/Modules/Crm/Business/Event/Invitations.php b/application/Espo/Modules/Crm/Business/Event/Invitations.php index ee042db6c5..27e2727904 100644 --- a/application/Espo/Modules/Crm/Business/Event/Invitations.php +++ b/application/Espo/Modules/Crm/Business/Event/Invitations.php @@ -6,126 +6,153 @@ use \Espo\ORM\Entity; class Invitations { - protected $entityManager; - - protected $mailSender; - - protected $config; - - protected $dateTime; - - protected $language; - - protected $fileManager; - - protected $ics; - - public function __construct($entityManager, $mailSender, $config, $dateTime, $language, $fileManager) - { - $this->entityManager = $entityManager; - $this->mailSender = $mailSender; - $this->config = $config; - $this->dateTime = $dateTime; - $this->language = $language; - $this->fileManager = $fileManager; - } - - protected function getEntityManager() - { - return $this->entityManager; - } - - protected function parseInvitationTemplate($contents, $entity, $invitee = null, $uid = null) - { - $contents = str_replace('{name}', $entity->get('name'), $contents); - $contents = str_replace('{eventType}', strtolower($this->language->translate($entity->getEntityName(), 'scopeNames')), $contents); - $contents = str_replace('{dateStart}', $this->dateTime->convertSystemDateTimeToGlobal($entity->get('dateStart')), $contents); - if ($invitee) { - $contents = str_replace('{inviteeName}', $invitee->get('name'), $contents); - } - if ($uid) { - $siteUrl = rtrim($this->config->get('siteUrl'), '/'); - $contents = str_replace('{acceptLink}', $siteUrl . '?entryPoint=eventConfirmation&action=accept&uid=' . $uid->get('name'), $contents); - $contents = str_replace('{declineLink}', $siteUrl . '?entryPoint=eventConfirmation&action=decline&uid=' . $uid->get('name'), $contents); - } - return $contents; - } - - public function sendInvitation(Entity $entity, Entity $invitee, $link) - { - $uid = $this->getEntityManager()->getEntity('UniqueId'); - $uid->set('data', json_encode(array( - 'eventType' => $entity->getEntityName(), - 'eventId' => $entity->id, - 'inviteeId' => $invitee->id, - 'inviteeType' => $invitee->getEntityName(), - 'link' => $link - ))); - $this->getEntityManager()->saveEntity($uid); + protected $entityManager; + + protected $smtpParams; - $email = $this->getEntityManager()->getEntity('Email'); - $email->set('to', $invitee->get('emailAddress')); + protected $mailSender; + + protected $config; + + protected $dateTime; + + protected $language; + + protected $fileManager; + + protected $ics; + + public function __construct($entityManager, $smtpParams, $mailSender, $config, $dateTime, $language, $fileManager) + { + $this->entityManager = $entityManager; + $this->smtpParams = $smtpParams; + $this->mailSender = $mailSender; + $this->config = $config; + $this->dateTime = $dateTime; + $this->language = $language; + $this->fileManager = $fileManager; + } + + protected function getEntityManager() + { + return $this->entityManager; + } + + protected function parseInvitationTemplate($contents, $entity, $invitee = null, $uid = null) + { + $contents = str_replace('{name}', $entity->get('name'), $contents); + $contents = str_replace('{eventType}', strtolower($this->language->translate($entity->getEntityName(), 'scopeNames')), $contents); + $contents = str_replace('{dateStart}', $this->dateTime->convertSystemDateTimeToGlobal($entity->get('dateStart')), $contents); + if ($invitee) { + $contents = str_replace('{inviteeName}', $invitee->get('name'), $contents); + } + if ($uid) { + $siteUrl = rtrim($this->config->get('siteUrl'), '/'); + $contents = str_replace('{acceptLink}', $siteUrl . '?entryPoint=eventConfirmation&action=accept&uid=' . $uid->get('name'), $contents); + $contents = str_replace('{declineLink}', $siteUrl . '?entryPoint=eventConfirmation&action=decline&uid=' . $uid->get('name'), $contents); + } + return $contents; + } + + public function sendInvitation(Entity $entity, Entity $invitee, $link) + { + $uid = $this->getEntityManager()->getEntity('UniqueId'); + $uid->set('data', json_encode(array( + 'eventType' => $entity->getEntityName(), + 'eventId' => $entity->id, + 'inviteeId' => $invitee->id, + 'inviteeType' => $invitee->getEntityName(), + 'link' => $link + ))); + $this->getEntityManager()->saveEntity($uid); - $subjectTplFileName = 'custom/Espo/Custom/Resources/templates/InvitationSubject.tpl'; - if (!file_exists($subjectTplFileName)) { - $subjectTplFileName = 'application/Espo/Modules/Crm/Resources/templates/InvitationSubject.tpl'; - } - $subjectTpl = file_get_contents($subjectTplFileName); + $emailAddress = $invitee->get('emailAddress'); + if (empty($emailAddress)) { + return; + } - $bodyTplFileName = 'custom/Espo/Custom/Resources/templates/InvitationBody.tpl'; - if (!file_exists($bodyTplFileName)) { - $bodyTplFileName = 'application/Espo/Modules/Crm/Resources/templates/InvitationBody.tpl'; - } - $bodyTpl = file_get_contents($bodyTplFileName); + $email = $this->getEntityManager()->getEntity('Email'); + $email->set('to', $emailAddress); + + $systemLanguage = $this->config->get('language'); - $subject = $this->parseInvitationTemplate($subjectTpl, $entity, $invitee, $uid); - $subject = str_replace(array("\n", "\r"), '', $subject); - - $body = $this->parseInvitationTemplate($bodyTpl, $entity, $invitee, $uid); + $subjectTplFileName = 'custom/Espo/Custom/Resources/templates/InvitationSubject.'.$systemLanguage.'.tpl'; + if (!file_exists($subjectTplFileName)) { + $subjectTplFileName = 'application/Espo/Modules/Crm/Resources/templates/InvitationSubject.'.$systemLanguage.'.tpl'; + } + if (!file_exists($subjectTplFileName)) { + $subjectTplFileName = 'custom/Espo/Custom/Resources/templates/InvitationSubject.en_US.tpl'; + } + if (!file_exists($subjectTplFileName)) { + $subjectTplFileName = 'application/Espo/Modules/Crm/Resources/templates/InvitationSubject.en_US.tpl'; + } + $subjectTpl = file_get_contents($subjectTplFileName); - $email->set('subject', $subject); - $email->set('body', $body); - $email->set('isHtml', true); - $this->getEntityManager()->saveEntity($email); - - $attachment = $this->getEntityManager()->getEntity('Attachment'); - $attachment->set(array( - 'name' => 'event.ics', - 'type' => 'text/calendar', - 'contents' => $this->getIscContents($entity), - )); - - $email->addAttachment($attachment); + $bodyTplFileName = 'custom/Espo/Custom/Resources/templates/InvitationBody.'.$systemLanguage.'.tpl'; + if (!file_exists($bodyTplFileName)) { + $bodyTplFileName = 'application/Espo/Modules/Crm/Resources/templates/InvitationBody.'.$systemLanguage.'.tpl'; + } + if (!file_exists($bodyTplFileName)) { + $bodyTplFileName = 'custom/Espo/Custom/Resources/templates/InvitationBody.en_US.tpl'; + } + if (!file_exists($bodyTplFileName)) { + $bodyTplFileName = 'application/Espo/Modules/Crm/Resources/templates/InvitationBody.en_US.tpl'; + } + $bodyTpl = file_get_contents($bodyTplFileName); - $emailSender = $this->mailSender; - $emailSender->send($email); - - $this->getEntityManager()->removeEntity($email); - } - - protected function getIscContents(Entity $entity) - { - $user = $entity->get('assignedUser'); - - $who = ''; - $email = ''; - if ($user) { - $who = $user->get('name'); - $email = $user->get('emailAddress'); - } - - $ics = new Ics('//EspoCRM//EspoCRM Calendar//EN', array( - 'startDate' => strtotime($entity->get('dateStart')), - 'endDate' => strtotime($entity->get('dateEnd')), - 'uid' => $entity->id, - 'summary' => $entity->get('name'), - 'who' => $who, - 'email' => $email, - 'description' => $entity->get('description'), - )); - - return $ics->get(); - } - + $subject = $this->parseInvitationTemplate($subjectTpl, $entity, $invitee, $uid); + $subject = str_replace(array("\n", "\r"), '', $subject); + + $body = $this->parseInvitationTemplate($bodyTpl, $entity, $invitee, $uid); + + $email->set('subject', $subject); + $email->set('body', $body); + $email->set('isHtml', true); + $this->getEntityManager()->saveEntity($email); + + $attachmentName = ucwords($this->language->translate($entity->getEntityName(), 'scopeNames')).'.ics'; + $attachment = $this->getEntityManager()->getEntity('Attachment'); + $attachment->set(array( + 'name' => $attachmentName, + 'type' => 'text/calendar', + 'contents' => $this->getIscContents($entity), + )); + + $email->addAttachment($attachment); + + $emailSender = $this->mailSender; + + if ($this->smtpParams) { + $emailSender->useSmtp($this->smtpParams); + } + $emailSender->send($email); + + $this->getEntityManager()->removeEntity($email); + } + + protected function getIscContents(Entity $entity) + { + $user = $entity->get('assignedUser'); + + $who = ''; + $email = ''; + if ($user) { + $who = $user->get('name'); + $email = $user->get('emailAddress'); + } + + $ics = new Ics('//EspoCRM//EspoCRM Calendar//EN', array( + 'startDate' => strtotime($entity->get('dateStart')), + 'endDate' => strtotime($entity->get('dateEnd')), + 'uid' => $entity->id, + 'summary' => $entity->get('name'), + 'who' => $who, + 'email' => $email, + 'description' => $entity->get('description'), + )); + + return $ics->get(); + } + } diff --git a/application/Espo/Modules/Crm/Controllers/Activities.php b/application/Espo/Modules/Crm/Controllers/Activities.php index 6803081ba7..4213e428cd 100644 --- a/application/Espo/Modules/Crm/Controllers/Activities.php +++ b/application/Espo/Modules/Crm/Controllers/Activities.php @@ -23,55 +23,64 @@ namespace Espo\Modules\Crm\Controllers; use \Espo\Core\Exceptions\Error, - \Espo\Core\Exceptions\Forbidden, - \Espo\Core\Exceptions\BadRequest; + \Espo\Core\Exceptions\Forbidden, + \Espo\Core\Exceptions\BadRequest; class Activities extends \Espo\Core\Controllers\Base { - public static $defaultAction = 'index'; - - public function actionListCalendarEvents($params, $data, $request) - { - $from = $request->get('from'); - $to = $request->get('to'); - - if (empty($from) || empty($to)) { - throw new BadRequest(); - } - - - $service = $this->getService('Activities'); - return $service->getEvents($this->getUser()->id, $from, $to); - } + public static $defaultAction = 'index'; + + public function actionListCalendarEvents($params, $data, $request) + { + if (!$this->getAcl()->check('Calendar')) { + throw new Forbidden(); + } - public function actionList($params, $data, $request) - { - $name = $params['name']; - $entityName = $params['scope']; - $id = $params['id']; - - $offset = intval($request->get('offset')); - $maxSize = intval($request->get('maxSize')); - $asc = $request->get('asc') === 'true'; - $sortBy = $request->get('sortBy'); - $where = $request->get('where'); - - $scope = null; - if (!empty($where) && !empty($where['scope']) && $where['scope'] !== 'false') { - $scope = $where['scope']; - } - - $service = $this->getService('Activities'); + $from = $request->get('from'); + $to = $request->get('to'); + + if (empty($from) || empty($to)) { + throw new BadRequest(); + } + + + $service = $this->getService('Activities'); + return $service->getEvents($this->getUser()->id, $from, $to); + } - $methodName = 'get' . ucfirst($name); - - return $service->$methodName($entityName, $id, array( - 'scope' => $scope, - 'offset' => $offset, - 'maxSize' => $maxSize, - 'asc' => $asc, - 'sortBy' => $sortBy, - )); - } + public function actionList($params, $data, $request) + { + $name = $params['name']; + + if (!in_array($name, array('activities', 'history'))) { + throw new BadRequest(); + } + + $entityName = $params['scope']; + $id = $params['id']; + + $offset = intval($request->get('offset')); + $maxSize = intval($request->get('maxSize')); + $asc = $request->get('asc') === 'true'; + $sortBy = $request->get('sortBy'); + $where = $request->get('where'); + + $scope = null; + if (!empty($where) && !empty($where['scope']) && $where['scope'] !== 'false') { + $scope = $where['scope']; + } + + $service = $this->getService('Activities'); + + $methodName = 'get' . ucfirst($name); + + return $service->$methodName($entityName, $id, array( + 'scope' => $scope, + 'offset' => $offset, + 'maxSize' => $maxSize, + 'asc' => $asc, + 'sortBy' => $sortBy, + )); + } } diff --git a/application/Espo/Modules/Crm/Controllers/Call.php b/application/Espo/Modules/Crm/Controllers/Call.php index d664c225e6..4124913784 100644 --- a/application/Espo/Modules/Crm/Controllers/Call.php +++ b/application/Espo/Modules/Crm/Controllers/Call.php @@ -29,23 +29,23 @@ use \Espo\Core\Exceptions\NotFound; class Call extends \Espo\Core\Controllers\Record { - public function actionSendInvitations($params, $data) - { - if (empty($data['id'])) { - throw new BadRequest(); - } - - $entity = $this->getRecordService()->getEntity($data['id']); - - if (!$entity) { - throw new NotFound(); - } - - if (!$this->getAcl()->check($entity, 'edit')) { - throw new Forbidden(); - } - - return $this->getRecordService()->sendInvitations($entity); - } + public function actionSendInvitations($params, $data) + { + if (empty($data['id'])) { + throw new BadRequest(); + } + + $entity = $this->getRecordService()->getEntity($data['id']); + + if (!$entity) { + throw new NotFound(); + } + + if (!$this->getAcl()->check($entity, 'edit')) { + throw new Forbidden(); + } + + return $this->getRecordService()->sendInvitations($entity); + } } diff --git a/application/Espo/Modules/Crm/Controllers/CaseObj.php b/application/Espo/Modules/Crm/Controllers/CaseObj.php index 9b11dda50d..879e8b97d0 100644 --- a/application/Espo/Modules/Crm/Controllers/CaseObj.php +++ b/application/Espo/Modules/Crm/Controllers/CaseObj.php @@ -24,6 +24,6 @@ namespace Espo\Modules\Crm\Controllers; class CaseObj extends \Espo\Core\Controllers\Record { - protected $name = 'Case'; + protected $name = 'Case'; } diff --git a/application/Espo/Modules/Crm/Controllers/InboundEmail.php b/application/Espo/Modules/Crm/Controllers/InboundEmail.php index 8f47587aa0..5698ea5566 100644 --- a/application/Espo/Modules/Crm/Controllers/InboundEmail.php +++ b/application/Espo/Modules/Crm/Controllers/InboundEmail.php @@ -24,24 +24,24 @@ namespace Espo\Modules\Crm\Controllers; class InboundEmail extends \Espo\Core\Controllers\Record { - protected function checkControllerAccess() - { - if (!$this->getUser()->isAdmin()) { - throw new Forbidden(); - } - } - - 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') - )); + protected function checkControllerAccess() + { + if (!$this->getUser()->isAdmin()) { + throw new Forbidden(); + } + } + + 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') + )); - } + } } diff --git a/application/Espo/Modules/Crm/Controllers/Lead.php b/application/Espo/Modules/Crm/Controllers/Lead.php index 4e9dae9b94..4fec44aa8b 100644 --- a/application/Espo/Modules/Crm/Controllers/Lead.php +++ b/application/Espo/Modules/Crm/Controllers/Lead.php @@ -27,16 +27,16 @@ use \Espo\Core\Exceptions\BadRequest; class Lead extends \Espo\Core\Controllers\Record { - public function actionConvert($params, $data) - { - if (empty($data['id'])) { - throw new BadRequest(); - } - $entity = $this->getRecordService()->convert($data['id'], $data['records']); - - if (!empty($entity)) { - return $entity->toArray(); - } - throw new Error(); - } + public function actionConvert($params, $data) + { + if (empty($data['id'])) { + throw new BadRequest(); + } + $entity = $this->getRecordService()->convert($data['id'], $data['records']); + + if (!empty($entity)) { + return $entity->toArray(); + } + throw new Error(); + } } diff --git a/application/Espo/Modules/Crm/Controllers/Meeting.php b/application/Espo/Modules/Crm/Controllers/Meeting.php index d3aa4ce1aa..35e3492e91 100644 --- a/application/Espo/Modules/Crm/Controllers/Meeting.php +++ b/application/Espo/Modules/Crm/Controllers/Meeting.php @@ -27,25 +27,25 @@ use \Espo\Core\Exceptions\BadRequest; use \Espo\Core\Exceptions\NotFound; class Meeting extends \Espo\Core\Controllers\Record -{ - - public function actionSendInvitations($params, $data) - { - if (empty($data['id'])) { - throw new BadRequest(); - } - - $entity = $this->getRecordService()->getEntity($data['id']); - - if (!$entity) { - throw new NotFound(); - } - - if (!$this->getAcl()->check($entity, 'edit')) { - throw new Forbidden(); - } - - return $this->getRecordService()->sendInvitations($entity); - } +{ + + public function actionSendInvitations($params, $data) + { + if (empty($data['id'])) { + throw new BadRequest(); + } + + $entity = $this->getRecordService()->getEntity($data['id']); + + if (!$entity) { + throw new NotFound(); + } + + if (!$this->getAcl()->check($entity, 'edit')) { + throw new Forbidden(); + } + + return $this->getRecordService()->sendInvitations($entity); + } } diff --git a/application/Espo/Modules/Crm/Controllers/Opportunity.php b/application/Espo/Modules/Crm/Controllers/Opportunity.php index 180bf15349..6c09c3ae86 100644 --- a/application/Espo/Modules/Crm/Controllers/Opportunity.php +++ b/application/Espo/Modules/Crm/Controllers/Opportunity.php @@ -22,38 +22,61 @@ namespace Espo\Modules\Crm\Controllers; +use \Espo\Core\Exceptions\Error; +use \Espo\Core\Exceptions\Forbidden; + class Opportunity extends \Espo\Core\Controllers\Record { - public function actionReportByLeadSource($params, $data, $request) - { - $dateFrom = $request->get('dateFrom'); - $dateTo = $request->get('dateTo'); - - return $this->getService('Opportunity')->reportByLeadSource($dateFrom, $dateTo); - } - - public function actionReportByStage($params, $data, $request) - { - $dateFrom = $request->get('dateFrom'); - $dateTo = $request->get('dateTo'); - - return $this->getService('Opportunity')->reportByStage($dateFrom, $dateTo); - } - - public function actionReportSalesByMonth($params, $data, $request) - { - $dateFrom = $request->get('dateFrom'); - $dateTo = $request->get('dateTo'); - - return $this->getService('Opportunity')->reportSalesByMonth($dateFrom, $dateTo); - } - - public function actionReportSalesPipeline($params, $data, $request) - { - $dateFrom = $request->get('dateFrom'); - $dateTo = $request->get('dateTo'); - - return $this->getService('Opportunity')->reportSalesPipeline($dateFrom, $dateTo); - } + public function actionReportByLeadSource($params, $data, $request) + { + $level = $this->getAcl()->getLevel('Opportunity', 'read'); + if (!$level || $level == 'own') { + throw new Forbidden(); + } + + $dateFrom = $request->get('dateFrom'); + $dateTo = $request->get('dateTo'); + + return $this->getService('Opportunity')->reportByLeadSource($dateFrom, $dateTo); + } + + public function actionReportByStage($params, $data, $request) + { + $level = $this->getAcl()->getLevel('Opportunity', 'read'); + if (!$level || $level == 'own') { + throw new Forbidden(); + } + + $dateFrom = $request->get('dateFrom'); + $dateTo = $request->get('dateTo'); + + return $this->getService('Opportunity')->reportByStage($dateFrom, $dateTo); + } + + public function actionReportSalesByMonth($params, $data, $request) + { + $level = $this->getAcl()->getLevel('Opportunity', 'read'); + if (!$level || $level == 'own') { + throw new Forbidden(); + } + + $dateFrom = $request->get('dateFrom'); + $dateTo = $request->get('dateTo'); + + return $this->getService('Opportunity')->reportSalesByMonth($dateFrom, $dateTo); + } + + public function actionReportSalesPipeline($params, $data, $request) + { + $level = $this->getAcl()->getLevel('Opportunity', 'read'); + if (!$level || $level == 'own') { + throw new Forbidden(); + } + + $dateFrom = $request->get('dateFrom'); + $dateTo = $request->get('dateTo'); + + return $this->getService('Opportunity')->reportSalesPipeline($dateFrom, $dateTo); + } } diff --git a/application/Espo/Modules/Crm/Controllers/Target.php b/application/Espo/Modules/Crm/Controllers/Target.php index 031f82534a..0b18f87586 100644 --- a/application/Espo/Modules/Crm/Controllers/Target.php +++ b/application/Espo/Modules/Crm/Controllers/Target.php @@ -24,22 +24,22 @@ namespace Espo\Modules\Crm\Controllers; use \Espo\Core\Exceptions\Error; use \Espo\Core\Exceptions\BadRequest; - + class Target extends \Espo\Core\Controllers\Record { - - public function actionConvert($params, $data) - { - - if (empty($data['id'])) { - throw new BadRequest(); - } - $entity = $this->getRecordService()->convert($data['id']); - - if (!empty($entity)) { - return $entity->toArray(); - } - throw new Error(); - } + + public function actionConvert($params, $data) + { + + if (empty($data['id'])) { + throw new BadRequest(); + } + $entity = $this->getRecordService()->convert($data['id']); + + if (!empty($entity)) { + return $entity->toArray(); + } + throw new Error(); + } } diff --git a/application/Espo/Modules/Crm/Entities/CaseObj.php b/application/Espo/Modules/Crm/Entities/CaseObj.php index 2444e82f8b..d3308aa380 100644 --- a/application/Espo/Modules/Crm/Entities/CaseObj.php +++ b/application/Espo/Modules/Crm/Entities/CaseObj.php @@ -25,6 +25,6 @@ namespace Espo\Modules\Crm\Entities; class CaseObj extends \Espo\Core\ORM\Entity { - protected $entityName = 'Case'; + protected $entityName = 'Case'; } diff --git a/application/Espo/Modules/Crm/Entities/Target.php b/application/Espo/Modules/Crm/Entities/Target.php index 0c710b22bd..214c88d7ea 100644 --- a/application/Espo/Modules/Crm/Entities/Target.php +++ b/application/Espo/Modules/Crm/Entities/Target.php @@ -24,6 +24,6 @@ namespace Espo\Modules\Crm\Entities; class Target extends \Espo\Core\Entities\Person { - + } diff --git a/application/Espo/Modules/Crm/EntryPoints/EventConfirmation.php b/application/Espo/Modules/Crm/EntryPoints/EventConfirmation.php index 4a540c6607..6964fc1da7 100644 --- a/application/Espo/Modules/Crm/EntryPoints/EventConfirmation.php +++ b/application/Espo/Modules/Crm/EntryPoints/EventConfirmation.php @@ -31,66 +31,66 @@ use \Espo\Core\Exceptions\Error; class EventConfirmation extends \Espo\Core\EntryPoints\Base { - public static $authRequired = false; - - public function run() - { - $uid = $_GET['uid']; - $action = $_GET['action']; - if (empty($uid) || empty($action)) { - throw new BadRequest(); - } - - if (!in_array($action, array('accept', 'decline'))) { - throw new BadRequest(); - } - - $uniqueId = $this->getEntityManager()->getRepository('UniqueId')->where(array('name' => $uid))->findOne(); - - if (!$uniqueId) { - throw new NotFound(); - return; - } - - $data = json_decode($uniqueId->get('data')); - - $eventType = $data->eventType; - $eventId = $data->eventId; - $inviteeType = $data->inviteeType; - $inviteeId = $data->inviteeId; - $link = $data->link; - - if (!empty($eventType) && !empty($eventId) && !empty($inviteeType) && !empty($inviteeId) && !empty($link)) { - $event = $this->getEntityManager()->getEntity($eventType, $eventId); - $invitee = $this->getEntityManager()->getEntity($inviteeType, $inviteeId); - if ($event && $invitee) { - $relDefs = $event->getRelations(); - $tableName = Util::toUnderscore($relDefs[$link]['relationName']); - - $status = 'None'; - if ($action == 'accept') { - $status = 'Accepted'; - } else if ($action == 'decline') { - $status = 'Declined'; - } - - $pdo = $this->getEntityManager()->getPDO(); - $sql = " - UPDATE `{$tableName}` SET status = '{$status}' - WHERE ".strtolower($eventType)."_id = '{$eventId}' AND ".strtolower($inviteeType)."_id = '{$inviteeId}' - "; + public static $authRequired = false; + + public function run() + { + $uid = $_GET['uid']; + $action = $_GET['action']; + if (empty($uid) || empty($action)) { + throw new BadRequest(); + } + + if (!in_array($action, array('accept', 'decline'))) { + throw new BadRequest(); + } + + $uniqueId = $this->getEntityManager()->getRepository('UniqueId')->where(array('name' => $uid))->findOne(); + + if (!$uniqueId) { + throw new NotFound(); + return; + } + + $data = json_decode($uniqueId->get('data')); + + $eventType = $data->eventType; + $eventId = $data->eventId; + $inviteeType = $data->inviteeType; + $inviteeId = $data->inviteeId; + $link = $data->link; + + if (!empty($eventType) && !empty($eventId) && !empty($inviteeType) && !empty($inviteeId) && !empty($link)) { + $event = $this->getEntityManager()->getEntity($eventType, $eventId); + $invitee = $this->getEntityManager()->getEntity($inviteeType, $inviteeId); + if ($event && $invitee) { + $relDefs = $event->getRelations(); + $tableName = Util::toUnderscore($relDefs[$link]['relationName']); + + $status = 'None'; + if ($action == 'accept') { + $status = 'Accepted'; + } else if ($action == 'decline') { + $status = 'Declined'; + } + + $pdo = $this->getEntityManager()->getPDO(); + $sql = " + UPDATE `{$tableName}` SET status = '{$status}' + WHERE ".strtolower($eventType)."_id = '{$eventId}' AND ".strtolower($inviteeType)."_id = '{$inviteeId}' + "; - $sth = $pdo->prepare($sql); - $sth->execute(); - - $this->getEntityManager()->getRepository('UniqueId')->remove($uniqueId); - - echo $status; - return; - } - } - - throw new Error(); - } + $sth = $pdo->prepare($sql); + $sth->execute(); + + $this->getEntityManager()->getRepository('UniqueId')->remove($uniqueId); + + echo $status; + return; + } + } + + throw new Error(); + } } diff --git a/application/Espo/Modules/Crm/Jobs/CheckInboundEmails.php b/application/Espo/Modules/Crm/Jobs/CheckInboundEmails.php index e4481f2a46..37481d313f 100644 --- a/application/Espo/Modules/Crm/Jobs/CheckInboundEmails.php +++ b/application/Espo/Modules/Crm/Jobs/CheckInboundEmails.php @@ -26,25 +26,25 @@ use \Espo\Core\Exceptions; class CheckInboundEmails extends \Espo\Core\Jobs\Base { - public function run() - { - $service = $this->getServiceFactory()->create('InboundEmail'); - $collection = $this->getEntityManager()->getRepository('InboundEmail')->where(array('status' => 'Active'))->find(); - foreach ($collection as $entity) { - 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; - } + public function run() + { + $service = $this->getServiceFactory()->create('InboundEmail'); + $collection = $this->getEntityManager()->getRepository('InboundEmail')->where(array('status' => 'Active'))->find(); + foreach ($collection as $entity) { + 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; + } } diff --git a/application/Espo/Modules/Crm/Repositories/Call.php b/application/Espo/Modules/Crm/Repositories/Call.php index 8801c2401b..d3747be783 100644 --- a/application/Espo/Modules/Crm/Repositories/Call.php +++ b/application/Espo/Modules/Crm/Repositories/Call.php @@ -25,26 +25,26 @@ namespace Espo\Modules\Crm\Repositories; use Espo\ORM\Entity; class Call extends \Espo\Core\ORM\Repositories\RDB -{ - protected function beforeSave(Entity $entity) - { - parent::beforeSave($entity); - - $parentId = $entity->get('parentId'); - $parentType = $entity->get('parentType'); - if (!empty($parentId) || !empty($parentType)) { - $parent = $this->getEntityManager()->getEntity($parentType, $parentId); - if (!empty($parent)) { - if ($parent->getEntityName() == 'Account') { - $accountId = $parent->id; - } else if ($parent->has('accountId')) { - $accountId = $parent->get('accountId'); - } - if (!empty($accountId)) { - $entity->set('accountId', $accountId); - } - } - } - } +{ + protected function beforeSave(Entity $entity) + { + parent::beforeSave($entity); + + $parentId = $entity->get('parentId'); + $parentType = $entity->get('parentType'); + if (!empty($parentId) || !empty($parentType)) { + $parent = $this->getEntityManager()->getEntity($parentType, $parentId); + if (!empty($parent)) { + if ($parent->getEntityName() == 'Account') { + $accountId = $parent->id; + } else if ($parent->has('accountId')) { + $accountId = $parent->get('accountId'); + } + if (!empty($accountId)) { + $entity->set('accountId', $accountId); + } + } + } + } } diff --git a/application/Espo/Modules/Crm/Repositories/Contact.php b/application/Espo/Modules/Crm/Repositories/Contact.php index b7677a2e04..a844fe09d0 100644 --- a/application/Espo/Modules/Crm/Repositories/Contact.php +++ b/application/Espo/Modules/Crm/Repositories/Contact.php @@ -25,71 +25,71 @@ namespace Espo\Modules\Crm\Repositories; use Espo\ORM\Entity; class Contact extends \Espo\Core\ORM\Repositories\RDB -{ - public function handleSelectParams(&$params) - { - parent::handleSelectParams($params); - - if (empty($params['customJoin'])) { - $params['customJoin'] = ''; - } - - $params['customJoin'] .= " - LEFT JOIN `account_contact` AS accountContact - ON accountContact.contact_id = contact.id AND accountContact.account_id = contact.account_id AND accountContact.deleted = 0 - "; - } - - public function save(Entity $entity) - { - $result = parent::save($entity); - - $accountIdChanged = $entity->has('accountId') && $entity->get('accountId') != $entity->getFetched('accountId'); - $titleChanged = $entity->has('title') && $entity->get('title') != $entity->getFetched('title'); - - if ($accountIdChanged) { - $accountId = $entity->get('accountId'); - if (empty($accountId)) { - $this->unrelate($entity, 'accounts', $entity->getFetched('accountId')); - return $result; - } - } - - if ($titleChanged) { - if (empty($accountId)) { - $accountId = $entity->getFetched('accountId'); - if (empty($accountId)) { - return $result; - } - } - } - - - if ($accountIdChanged || $titleChanged) { - $pdo = $this->getEntityManager()->getPDO(); - - $sql = " - SELECT id, role FROM account_contact - WHERE - account_id = ".$pdo->quote($accountId)." AND - contact_id = ".$pdo->quote($entity->id)." AND - deleted = 0 - "; - $sth = $pdo->prepare($sql); - if ($row = $sth->fetch()) { - if ($titleChanged && $entity->get('title') != $row['role']) { - $this->updateRelation($entity, 'accounts', $accountId, array( - 'role' => $entity->get('title') - )); - } - } else { - $this->relate($entity, 'accounts', $accountId, array( - 'role' => $entity->get('title') - )); - } - } - - return $result; - } +{ + public function handleSelectParams(&$params) + { + parent::handleSelectParams($params); + + if (empty($params['customJoin'])) { + $params['customJoin'] = ''; + } + + $params['customJoin'] .= " + LEFT JOIN `account_contact` AS accountContact + ON accountContact.contact_id = contact.id AND accountContact.account_id = contact.account_id AND accountContact.deleted = 0 + "; + } + + public function save(Entity $entity) + { + $result = parent::save($entity); + + $accountIdChanged = $entity->has('accountId') && $entity->get('accountId') != $entity->getFetched('accountId'); + $titleChanged = $entity->has('title') && $entity->get('title') != $entity->getFetched('title'); + + if ($accountIdChanged) { + $accountId = $entity->get('accountId'); + if (empty($accountId)) { + $this->unrelate($entity, 'accounts', $entity->getFetched('accountId')); + return $result; + } + } + + if ($titleChanged) { + if (empty($accountId)) { + $accountId = $entity->getFetched('accountId'); + if (empty($accountId)) { + return $result; + } + } + } + + + if ($accountIdChanged || $titleChanged) { + $pdo = $this->getEntityManager()->getPDO(); + + $sql = " + SELECT id, role FROM account_contact + WHERE + account_id = ".$pdo->quote($accountId)." AND + contact_id = ".$pdo->quote($entity->id)." AND + deleted = 0 + "; + $sth = $pdo->prepare($sql); + if ($row = $sth->fetch()) { + if ($titleChanged && $entity->get('title') != $row['role']) { + $this->updateRelation($entity, 'accounts', $accountId, array( + 'role' => $entity->get('title') + )); + } + } else { + $this->relate($entity, 'accounts', $accountId, array( + 'role' => $entity->get('title') + )); + } + } + + return $result; + } } diff --git a/application/Espo/Modules/Crm/Repositories/Lead.php b/application/Espo/Modules/Crm/Repositories/Lead.php index 401211767b..e5f9b2cc97 100644 --- a/application/Espo/Modules/Crm/Repositories/Lead.php +++ b/application/Espo/Modules/Crm/Repositories/Lead.php @@ -25,8 +25,8 @@ namespace Espo\Modules\Crm\Repositories; use Espo\ORM\Entity; class Lead extends \Espo\Core\ORM\Repositories\RDB -{ - +{ + } diff --git a/application/Espo/Modules/Crm/Repositories/Meeting.php b/application/Espo/Modules/Crm/Repositories/Meeting.php index f9834b38cc..c1591433f1 100644 --- a/application/Espo/Modules/Crm/Repositories/Meeting.php +++ b/application/Espo/Modules/Crm/Repositories/Meeting.php @@ -25,26 +25,26 @@ namespace Espo\Modules\Crm\Repositories; use Espo\ORM\Entity; class Meeting extends \Espo\Core\ORM\Repositories\RDB -{ - protected function beforeSave(Entity $entity) - { - parent::beforeSave($entity); - - $parentId = $entity->get('parentId'); - $parentType = $entity->get('parentType'); - if (!empty($parentId) || !empty($parentType)) { - $parent = $this->getEntityManager()->getEntity($parentType, $parentId); - if (!empty($parent)) { - if ($parent->getEntityName() == 'Account') { - $accountId = $parent->id; - } else if ($parent->has('accountId')) { - $accountId = $parent->get('accountId'); - } - if (!empty($accountId)) { - $entity->set('accountId', $accountId); - } - } - } - } +{ + protected function beforeSave(Entity $entity) + { + parent::beforeSave($entity); + + $parentId = $entity->get('parentId'); + $parentType = $entity->get('parentType'); + if (!empty($parentId) || !empty($parentType)) { + $parent = $this->getEntityManager()->getEntity($parentType, $parentId); + if (!empty($parent)) { + if ($parent->getEntityName() == 'Account') { + $accountId = $parent->id; + } else if ($parent->has('accountId')) { + $accountId = $parent->get('accountId'); + } + if (!empty($accountId)) { + $entity->set('accountId', $accountId); + } + } + } + } } diff --git a/application/Espo/Modules/Crm/Repositories/Opportunity.php b/application/Espo/Modules/Crm/Repositories/Opportunity.php index 70224d1a82..a6325d7b7b 100644 --- a/application/Espo/Modules/Crm/Repositories/Opportunity.php +++ b/application/Espo/Modules/Crm/Repositories/Opportunity.php @@ -25,7 +25,7 @@ namespace Espo\Modules\Crm\Repositories; use Espo\ORM\Entity; class Opportunity extends \Espo\Core\ORM\Repositories\RDB -{ +{ } diff --git a/application/Espo/Modules/Crm/Resources/i18n/de_DE/Account.json b/application/Espo/Modules/Crm/Resources/i18n/de_DE/Account.json index 9d5671a504..e949116eed 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/de_DE/Account.json +++ b/application/Espo/Modules/Crm/Resources/i18n/de_DE/Account.json @@ -1,40 +1,42 @@ { - "fields": { - "name": "Name", - "emailAddress": "E-Mail", - "website": "Webseite", - "phoneNumber": "Telefon", - "billingAddress": "Rechnungsadresse", - "shippingAddress": "Lieferadresse", - "description": "Beschreibung", - "sicCode": "WKN Nummer", - "industry": "Branche", - "type": "Typ", - "contactRole": "Rolle" - }, - "links": { - "contacts": "Kontakte", - "opportunities": "Verkaufschancen", - "cases": "Fälle" - }, - "options": { - "type": { - "Customer": "Kunde", - "Investor": "Investor", - "Partner": "Partner", - "Reseller": "Wiederverkäufer" - }, - "industry": { - "Apparel": "Bekleidungsindustrie", - "Banking": "Bankwesen", - "Computer Software": "Computer Software", - "Education": "Bildungswesen", - "Electronics": "Elektronik", - "Finance": "Finanzsektor", - "Insurance": "Versicherung" - } - }, - "labels": { - "Create Account": "Neue Firma" - } + "fields": { + "name": "Name", + "emailAddress": "E-Mail", + "website": "Webseite", + "phoneNumber": "Telefon", + "billingAddress": "Rechnungsadresse", + "shippingAddress": "Lieferadresse", + "description": "Beschreibung", + "sicCode": "WKN Nummer", + "industry": "Branche", + "type": "Typ", + "contactRole": "Rolle" + }, + "links": { + "contacts": "Kontakte", + "opportunities": "Verkaufschancen", + "cases": "Fälle", + "documents": "Dokumente" + }, + "options": { + "type": { + "Customer": "Kunde", + "Investor": "Investor", + "Partner": "Partner", + "Reseller": "Wiederverkäufer" + }, + "industry": { + "Apparel": "Bekleidungsindustrie", + "Banking": "Bankwesen", + "Computer Software": "Computer Software", + "Education": "Bildungswesen", + "Electronics": "Elektronik", + "Finance": "Finanzsektor", + "Insurance": "Versicherung" + } + }, + "labels": { + "Create Account": "Firma erstellen", + "Copy Billing": "Rechnungsadresse kopieren" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/de_DE/Admin.json b/application/Espo/Modules/Crm/Resources/i18n/de_DE/Admin.json new file mode 100644 index 0000000000..50a6c732b0 --- /dev/null +++ b/application/Espo/Modules/Crm/Resources/i18n/de_DE/Admin.json @@ -0,0 +1,5 @@ +{ + "layouts": { + "detailConvert": "Interessent umwandeln" + } +} diff --git a/application/Espo/Modules/Crm/Resources/i18n/de_DE/Calendar.json b/application/Espo/Modules/Crm/Resources/i18n/de_DE/Calendar.json index 64d2c086a1..985360e760 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/de_DE/Calendar.json +++ b/application/Espo/Modules/Crm/Resources/i18n/de_DE/Calendar.json @@ -1,13 +1,13 @@ { - "modes": { - "month": "Monat", - "week": "Woche", - "day": "Tag", - "agendaWeek": "Woche", - "agendaDay": "Tag" - }, - "labels": { - "Today": "Heute", - "Create": "Erstellen" - } + "modes": { + "month": "Monat", + "week": "Woche", + "day": "Tag", + "agendaWeek": "Woche", + "agendaDay": "Tag" + }, + "labels": { + "Today": "Heute", + "Create": "Erstellen" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/de_DE/Call.json b/application/Espo/Modules/Crm/Resources/i18n/de_DE/Call.json index 35fc013cf1..d7edde684e 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/de_DE/Call.json +++ b/application/Espo/Modules/Crm/Resources/i18n/de_DE/Call.json @@ -1,39 +1,44 @@ { - "fields": { - "name": "Name", - "parent": "Bezieht sich auf", - "status": "Status", - "dateStart": "Startdatum", - "dateEnd": "Enddatum", - "direction": "Richtung", - "duration": "Dauer", - "description": "Beschreibung", - "users": "Benutzer", - "contacts": "Kontakte", - "leads": "Interessenten" - }, - "links": { - }, - "options": { - "status": { - "Planned": "Geplant", - "Held": "Durchgeführt", - "Not Held": "Nicht durchgeführt" - }, - "direction": { - "Outbound": "Ausgehend", - "Inbound": "Eingehend" - } - }, - "labels": { - "Create Call": "Neuer Anruf", - "Set Held": "Auf Gehalten setzen", - "Set Not Held": "Auf nicht gehalten setzen", - "Send Invitations": "Einladungen versenden" - }, - "presetFilters": { - "planned": "Geplant", - "held": "Durchgeführt", - "todays": "Heutige" - } + "fields": { + "name": "Name", + "parent": "Bezieht sich auf", + "status": "Status", + "dateStart": "Startdatum", + "dateEnd": "Enddatum", + "direction": "Richtung", + "duration": "Dauer", + "description": "Beschreibung", + "users": "Benutzer", + "contacts": "Kontakte", + "leads": "Interessenten" + }, + "links": { + }, + "options": { + "status": { + "Planned": "Geplant", + "Held": "Durchgeführt", + "Not Held": "Nicht durchgeführt" + }, + "direction": { + "Outbound": "Ausgehend", + "Inbound": "Eingehend" + }, + "acceptanceStatus": { + "None": "Kein(e)", + "Accepted": "Akzeptiert", + "Declined": "Abgelehnt" + } + }, + "labels": { + "Create Call": "Anruf erstellen", + "Set Held": "Auf gehalten setzen", + "Set Not Held": "Auf nicht gehalten setzen", + "Send Invitations": "Einladungen versenden" + }, + "presetFilters": { + "planned": "Geplant", + "held": "Durchgeführt", + "todays": "Heutige" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/de_DE/Case.json b/application/Espo/Modules/Crm/Resources/i18n/de_DE/Case.json index cb74530b73..3e79e427c4 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/de_DE/Case.json +++ b/application/Espo/Modules/Crm/Resources/i18n/de_DE/Case.json @@ -1,42 +1,42 @@ { - "fields": { - "name": "Name", - "number": "Nummer", - "status": "Status", - "account": "Firma", - "contact": "Kontakt", - "priority": "Priorität", - "type": "Typ", - "description": "Beschreibung" - }, - "links": { - }, - "options": { - "status": { - "New": "Neu", - "Assigned": "Zugewiesen", - "Pending": "Schwebend", - "Closed": "Abgeschlossen", - "Rejected": "Abgelehnt", - "Duplicate": "Duplizieren" - }, - "priority" : { - "Low": "Niedrig", - "Normal": "Normal", - "High": "Hoch", - "Urgent": "Dringend" - }, - "type": { - "Question": "Frage", - "Incident": "Vorfall", - "Problem": "Problem" - } - }, - "labels": { - "Create Case": "Neuer Fall" - }, - "presetFilters": { - "open": "Offen", - "closed": "Abgeschlossen" - } + "fields": { + "name": "Name", + "number": "Nummer", + "status": "Status", + "account": "Firma", + "contact": "Kontakt", + "priority": "Priorität", + "type": "Typ", + "description": "Beschreibung" + }, + "links": { + }, + "options": { + "status": { + "New": "Neu", + "Assigned": "Zugewiesen", + "Pending": "Schwebend", + "Closed": "Abgeschlossen", + "Rejected": "Abgelehnt", + "Duplicate": "Duplizieren" + }, + "priority" : { + "Low": "Niedrig", + "Normal": "Normal", + "High": "Hoch", + "Urgent": "Dringend" + }, + "type": { + "Question": "Frage", + "Incident": "Vorfall", + "Problem": "Problem" + } + }, + "labels": { + "Create Case": "Fall erstellen" + }, + "presetFilters": { + "open": "Offen", + "closed": "Abgeschlossen" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/de_DE/Contact.json b/application/Espo/Modules/Crm/Resources/i18n/de_DE/Contact.json index f381539646..2db67e5603 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/de_DE/Contact.json +++ b/application/Espo/Modules/Crm/Resources/i18n/de_DE/Contact.json @@ -1,31 +1,31 @@ { - "fields": { - "name": "Name", - "emailAddress": "E-Mail", - "title": "Funktion", - "account": "Firma", - "accounts": "Firmen", - "phoneNumber": "Telefon", - "accountType": "Firmentyp", - "doNotCall": "Nicht anrufen", - "address": "Adresse", - "opportunityRole": "Verkaufschance Rolle", - "accountRole": "Rolle", - "description": "Beschreibung" - }, - "links": { - "opportunities": "Verkaufschancen", - "cases": "Fälle" - }, - "labels": { - "Create Contact": "Neuer Kontakt" - }, - "options": { - "opportunityRole": { - "": "--Kein(e)--", - "Decision Maker": "Entscheider", - "Evaluator": "Vorentscheider", - "Influencer": "Einflussreiche Person" - } - } + "fields": { + "name": "Name", + "emailAddress": "E-Mail", + "title": "Funktion", + "account": "Firma", + "accounts": "Firmen", + "phoneNumber": "Telefon", + "accountType": "Firmentyp", + "doNotCall": "Nicht anrufen", + "address": "Adresse", + "opportunityRole": "Verkaufschance Rolle", + "accountRole": "Rolle", + "description": "Beschreibung" + }, + "links": { + "opportunities": "Verkaufschancen", + "cases": "Fälle" + }, + "labels": { + "Create Contact": "Kontakt erstellen" + }, + "options": { + "opportunityRole": { + "": "--Kein(e)--", + "Decision Maker": "Entscheider", + "Evaluator": "Vorentscheider", + "Influencer": "Einflussreiche Person" + } + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/de_DE/Document.json b/application/Espo/Modules/Crm/Resources/i18n/de_DE/Document.json new file mode 100644 index 0000000000..5fc4a1a3ad --- /dev/null +++ b/application/Espo/Modules/Crm/Resources/i18n/de_DE/Document.json @@ -0,0 +1,32 @@ +{ + "labels": { + "Create Document": "Dokument erstellen", + "Details": "Details" + }, + "fields": { + "name": "Name", + "status": "Status", + "file": "Datei", + "type": "Typ", + "source": "Quelle", + "publishDate": "Veröffentlichungsdatum", + "expirationDate": "Ablaufdatum", + "description": "Beschreibung" + }, + "links": { + "accounts": "Firmen", + "opportunities": "Verkaufschancen" + }, + "options": { + "status": { + "Active": "Aktiv", + "Draft": "Entwurf", + "Expired": "Abgelaufen", + "Canceled": "Storniert" + } + }, + "presetFilters": { + "active": "Aktiv", + "draft": "Entwurf" + } +} diff --git a/application/Espo/Modules/Crm/Resources/i18n/de_DE/Global.json b/application/Espo/Modules/Crm/Resources/i18n/de_DE/Global.json index e483b79b4f..caabd0642f 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/de_DE/Global.json +++ b/application/Espo/Modules/Crm/Resources/i18n/de_DE/Global.json @@ -1,81 +1,90 @@ { - "scopeNames": { - "Account": "Firma", - "Contact": "Kontakt", - "Lead": "Interessent", - "Target": "Zielkontakt", - "Opportunity": "Verkaufschance", - "Meeting": "Meeting", - "Calendar": "Kalender", - "Call": "Anruf", - "Task": "Aufgabe", - "Case": "Fall", - "InboundEmail": "Eingehende E-Mails" - }, - "scopeNamesPlural": { - "Account": "Firmen", - "Contact": "Kontakte", - "Lead": "Interessenten", - "Target": "Zielkontakte", - "Opportunity": "Verkaufschancen", - "Meeting": "Meetings", - "Calendar": "Kalender", - "Call": "Anrufe", - "Task": "Aufgaben", - "Case": "Fälle", - "InboundEmail": "Eingehende E-Mails" - }, - "dashlets": { - "Leads": "Meine Interessenten", - "Opportunities": "Meine Verkaufschancen", - "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", - "SalesPipeline": "Verkaufspipeline" - }, - "labels": { - "Create InboundEmail": "Eingehende E-Mail erstellen", - "Activities": "Aktivitäten", - "History": "Verlauf", - "Attendees": "Teilnehmer", - "Schedule Meeting": "Meeting planen", - "Schedule Call": "Anruf planen", - "Compose Email": "E-Mail erstellen", - "Log Meeting": "Meeting erfassen", - "Log Call": "Anruf erfassen", - "Archive Email": "E-Mail archivieren", - "Create Task": "Neue Aufgabe", - "Tasks": "Aufgaben" - }, - "fields": { - "billingAddressCity": "Ort", - "billingAddressCountry": "Land", - "billingAddressPostalCode": "PLZ", - "billingAddressState": "Bundesland", - "billingAddressStreet": "Straße", - "addressCity": "Ort", - "addressStreet": "Straße", - "addressCountry": "Land", - "addressState": "Bundesland", - "addressPostalCode": "PLZ", - "shippingAddressCity": "Ort (Lieferadresse)", - "shippingAddressStreet": "Straße (Lieferadresse)", - "shippingAddressCountry": "Land (Lieferadresse)", - "shippingAddressState": "Bundesland\/Kanton (Lieferadresse)", - "shippingAddressPostalCode": "PLZ (Lieferadresse)" - }, - "links": { - "contacts": "Kontakte", - "opportunities": "Verkaufschancen", - "leads": "Interessenten", - "meetings": "Meetings", - "calls": "Anrufe", - "tasks": "Aufgaben", - "emails": "E-Mails" - } + "scopeNames": { + "Account": "Firma", + "Contact": "Kontakt", + "Lead": "Interessent", + "Target": "Zielkontakt", + "Opportunity": "Verkaufschance", + "Meeting": "Meeting", + "Calendar": "Kalender", + "Call": "Anruf", + "Task": "Aufgabe", + "Case": "Fall", + "InboundEmail": "Eingehende E-Mails", + "Document": "Dokument" + }, + "scopeNamesPlural": { + "Account": "Firmen", + "Contact": "Kontakte", + "Lead": "Interessenten", + "Target": "Zielkontakte", + "Opportunity": "Verkaufschancen", + "Meeting": "Meetings", + "Calendar": "Kalender", + "Call": "Anrufe", + "Task": "Aufgaben", + "Case": "Fälle", + "InboundEmail": "Eingehende E-Mails", + "Document": "Dokumente" + }, + "dashlets": { + "Leads": "Meine Interessenten", + "Opportunities": "Meine Verkaufschancen", + "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", + "SalesPipeline": "Verkaufspipeline" + }, + "labels": { + "Create InboundEmail": "Eingehende E-Mail erstellen", + "Activities": "Aktivitäten", + "History": "Verlauf", + "Attendees": "Teilnehmer", + "Schedule Meeting": "Meeting planen", + "Schedule Call": "Anruf planen", + "Compose Email": "E-Mail erstellen", + "Log Meeting": "Meeting erfassen", + "Log Call": "Anruf erfassen", + "Archive Email": "E-Mail archivieren", + "Create Task": "Neue Aufgabe", + "Tasks": "Aufgaben" + }, + "fields": { + "billingAddressCity": "Ort", + "billingAddressCountry": "Land", + "billingAddressPostalCode": "PLZ", + "billingAddressState": "Bundesland/Kanton", + "billingAddressStreet": "Straße", + "addressCity": "Ort", + "addressStreet": "Straße", + "addressCountry": "Land", + "addressState": "Bundesland/Kanton", + "addressPostalCode": "PLZ", + "shippingAddressCity": "Ort (Lieferadresse)", + "shippingAddressStreet": "Straße (Lieferadresse)", + "shippingAddressCountry": "Land (Lieferadresse)", + "shippingAddressState": "Bundesland/Kanton (Lieferadresse)", + "shippingAddressPostalCode": "PLZ (Lieferadresse)" + }, + "links": { + "contacts": "Kontakte", + "opportunities": "Verkaufschancen", + "leads": "Interessenten", + "meetings": "Meetings", + "calls": "Anrufe", + "tasks": "Aufgaben", + "emails": "E-Mails", + "accounts": "Firmen", + "cases": "Fälle", + "documents": "Dokumente", + "account": "Firma", + "opportunity": "Verkaufschance", + "contact": "Kontakt", + "parent": "Bezieht sich auf" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/de_DE/InboundEmail.json b/application/Espo/Modules/Crm/Resources/i18n/de_DE/InboundEmail.json index a797d12b86..d6d1ec922e 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/de_DE/InboundEmail.json +++ b/application/Espo/Modules/Crm/Resources/i18n/de_DE/InboundEmail.json @@ -1,52 +1,52 @@ { - "fields": { - "name": "Name", - "team": "Team", - "status": "Status", - "assignToUser": "Mit Benutzer verknüpfen", - "host": "Host", - "username": "Benutzername", - "password": "Passwort", - "port": "Port", - "monitoredFolders": "Überwachter Ordner", - "trashFolder": "Papierkorb Ordner", - "ssl": "SSL", - "createCase": "Neuer Fall", - "reply": "Antworten", - "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": { - "status": { - "Active": "Aktiv", - "Inactive": "Inaktiv" - }, - "caseDistribution": { - "Direct-Assignment": "Direkte Zuordnung", - "Round-Robin": "Umlauf-Verfahren", - "Least-Busy": "geringste Auslastung" - } - }, - "labels": { - "Create InboundEmail": "Eingehende E-Mail erstellen", - "IMAP": "IMAP", - "Actions": "Aktionen", - "Main": "Wichtig" - }, - "messages": { - "couldNotConnectToImap": "Kann keine Verbindung zum IMAP Server herstellen" - } + "fields": { + "name": "Name", + "team": "Team", + "status": "Status", + "assignToUser": "Mit Benutzer verknüpfen", + "host": "Host", + "username": "Benutzername", + "password": "Passwort", + "port": "Port", + "monitoredFolders": "Überwachte Ordner", + "trashFolder": "Papierkorb Ordner", + "ssl": "SSL", + "createCase": "Fall erstellen", + "reply": "Antworten", + "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": { + "status": { + "Active": "Aktiv", + "Inactive": "Inaktiv" + }, + "caseDistribution": { + "Direct-Assignment": "Direkte Zuordnung", + "Round-Robin": "Umlauf-Verfahren", + "Least-Busy": "Geringste Auslastung" + } + }, + "labels": { + "Create InboundEmail": "Eingehende E-Mail erstellen", + "IMAP": "IMAP", + "Actions": "Aktionen", + "Main": "Wichtig" + }, + "messages": { + "couldNotConnectToImap": "Kann keine Verbindung zum IMAP Server herstellen" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/de_DE/Lead.json b/application/Espo/Modules/Crm/Resources/i18n/de_DE/Lead.json index a5ec914108..fd2ad50393 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/de_DE/Lead.json +++ b/application/Espo/Modules/Crm/Resources/i18n/de_DE/Lead.json @@ -1,50 +1,50 @@ { - "labels": { - "Converted To": "Umgewandelt zu", - "Create Lead": "Neuer Interessent", - "Convert": "Umwandeln" - }, - "fields": { - "name": "Name", - "emailAddress": "E-Mail", - "title": "Funktion", - "website": "Webseite", - "phoneNumber": "Telefon", - "accountName": "Firmenname", - "doNotCall": "Nicht anrufen", - "address": "Adresse", - "status": "Status", - "source": "Quelle", - "opportunityAmount": "Verkaufschance Betrag", - "opportunityAmountConverted": "Verkaufschance Betrag (konvertiert)", - "description": "Beschreibung", - "createdAccount": "Firma", - "createdContact": "Kontakt", - "createdOpportunity": "Verkaufschance" - }, - "links": { - }, - "options": { - "status": { - "New": "Neu", - "Assigned": "Zugewiesen", - "In Process": "In Arbeit", - "Converted": "Umgewandelt", - "Recycled": "Wiedereröffnet", - "Dead": "'Gestorben'" - }, - "source": { - "Call": "Anruf", - "Email": "E-Mail", - "Existing Customer": "Bestehender Kunde", - "Partner": "Partner", - "Public Relations": "Public Relations", - "Web Site": "Web Seite", - "Campaign": "Kampagne", - "Other": "Andere" - } - }, - "presetFilters": { - "active": "Aktiv" - } + "labels": { + "Converted To": "Umgewandelt zu", + "Create Lead": "Interessent erstellen", + "Convert": "Umwandeln" + }, + "fields": { + "name": "Name", + "emailAddress": "E-Mail", + "title": "Funktion", + "website": "Webseite", + "phoneNumber": "Telefon", + "accountName": "Firmenname", + "doNotCall": "Nicht anrufen", + "address": "Adresse", + "status": "Status", + "source": "Quelle", + "opportunityAmount": "Verkaufschance Betrag", + "opportunityAmountConverted": "Verkaufschance Betrag (konvertiert)", + "description": "Beschreibung", + "createdAccount": "Firma", + "createdContact": "Kontakt", + "createdOpportunity": "Verkaufschance" + }, + "links": { + }, + "options": { + "status": { + "New": "Neu", + "Assigned": "Zugewiesen", + "In Process": "In Arbeit", + "Converted": "Umgewandelt", + "Recycled": "Wiedereröffnet", + "Dead": "'Gestorben'" + }, + "source": { + "Call": "Anruf", + "Email": "E-Mail", + "Existing Customer": "Bestehender Kunde", + "Partner": "Partner", + "Public Relations": "Public Relations", + "Web Site": "Web Seite", + "Campaign": "Kampagne", + "Other": "Andere" + } + }, + "presetFilters": { + "active": "Aktiv" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/de_DE/Meeting.json b/application/Espo/Modules/Crm/Resources/i18n/de_DE/Meeting.json index c1d0121026..a23b7aeb6f 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/de_DE/Meeting.json +++ b/application/Espo/Modules/Crm/Resources/i18n/de_DE/Meeting.json @@ -1,36 +1,39 @@ { - "fields": { - "name": "Name", - "parent": "Bezieht sich auf", - "status": "Status", - "dateStart": "Startdatum", - "dateEnd": "Enddatum", - "duration": "Dauer", - "description": "Beschreibung", - "users": "Benutzer", - "contacts": "Kontakte", - "leads": "Interessenten" - }, - "links": { - }, - "options": { - "status": { - "Planned": "Geplant", - "Held": "Durchgeführt", - "Not Held": "Nicht durchgeführt" - } - }, - "labels": { - "Create Meeting": "Neues Meeting", - "Set Held": "Auf Gehalten setzen", - "Set Not Held": "Auf nicht gehalten setzen", - "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" - } + "fields": { + "name": "Name", + "parent": "Bezieht sich auf", + "status": "Status", + "dateStart": "Startdatum", + "dateEnd": "Enddatum", + "duration": "Dauer", + "description": "Beschreibung", + "users": "Benutzer", + "contacts": "Kontakte", + "leads": "Interessenten" + }, + "links": { + }, + "options": { + "status": { + "Planned": "Geplant", + "Held": "Durchgeführt", + "Not Held": "Nicht durchgeführt" + }, + "acceptanceStatus": { + "None": "Kein(e)", + "Accepted": "Akzeptiert", + "Declined": "Abgelehnt" + } + }, + "labels": { + "Create Meeting": "Meeting erstellen", + "Set Held": "Auf gehalten setzen", + "Set Not Held": "Auf nicht gehalten setzen", + "Send Invitations": "Einladungen versenden" + }, + "presetFilters": { + "planned": "Geplant", + "held": "Durchgeführt", + "todays": "Heutige" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/de_DE/Opportunity.json b/application/Espo/Modules/Crm/Resources/i18n/de_DE/Opportunity.json index 5a977bb8b4..5547295c7f 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/de_DE/Opportunity.json +++ b/application/Espo/Modules/Crm/Resources/i18n/de_DE/Opportunity.json @@ -1,39 +1,41 @@ { - "fields": { - "name": "Name", - "account": "Firma", - "stage": "Verkaufsphase", - "amount": "Betrag", - "probability": "Wahrscheinlichkeit (%)", - "leadSource": "Quelle", - "doNotCall": "Nicht anrufen", - "closeDate": "Abschlussdatum", - "contacts": "Kontakte", - "description": "Beschreibung", - "amountConverted": "Betrag (konvertiert)" - }, - "links": { - "contacts": "Kontakte" - }, - "options": { - "stage": { - "Prospecting": "Prospecting", - "Qualification": "Qualifikation", - "Needs Analysis": "Bedarfserhebung", - "Value Proposition": "Richtangebot", - "Id. Decision Makers": "Entscheider ident.", - "Perception Analysis": "Analyse Sichtweise", - "Proposal/Price Quote": "Preisangebot", - "Negotiation/Review": "Verhandlung\/Überarbeitung", - "Closed Won": "Gewonnen", - "Closed Lost": "Verloren" - } - }, - "labels": { - "Create Opportunity": "Neue Verkaufschance" - }, - "presetFilters": { - "open": "Offen", - "won": "Gewonnen" - } + "fields": { + "name": "Name", + "account": "Firma", + "stage": "Verkaufsphase", + "amount": "Betrag", + "probability": "Wahrscheinlichkeit (%)", + "leadSource": "Quelle", + "doNotCall": "Nicht anrufen", + "closeDate": "Abschlussdatum", + "contacts": "Kontakte", + "description": "Beschreibung", + "amountConverted": "Betrag (konvertiert)", + "amountWeightedConverted": "Betrag gewichtet" + }, + "links": { + "contacts": "Kontakte", + "documents": "Dokumente" + }, + "options": { + "stage": { + "Prospecting": "Prospecting", + "Qualification": "Qualifikation", + "Needs Analysis": "Bedarfserhebung", + "Value Proposition": "Richtangebot", + "Id. Decision Makers": "Entscheider ident.", + "Perception Analysis": "Analyse Sichtweise", + "Proposal/Price Quote": "Preisangebot", + "Negotiation/Review": "Verhandlung/Überarbeitung", + "Closed Won": "Gewonnen", + "Closed Lost": "Verloren" + } + }, + "labels": { + "Create Opportunity": "Verkaufschance erstellen" + }, + "presetFilters": { + "open": "Offen", + "won": "Gewonnen" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/de_DE/Target.json b/application/Espo/Modules/Crm/Resources/i18n/de_DE/Target.json index b9290a5ac1..522dffd609 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/de_DE/Target.json +++ b/application/Espo/Modules/Crm/Resources/i18n/de_DE/Target.json @@ -1,19 +1,19 @@ { - "fields": { - "name": "Name", - "emailAddress": "E-Mail", - "title": "Funktion", - "website": "Webseite", - "accountName": "Firmenname", - "phoneNumber": "Telefon", - "doNotCall": "Nicht anrufen", - "address": "Adresse", - "description": "Beschreibung" - }, - "links": { - }, - "labels": { - "Create Target": "Neuer Zielkontakt", - "Convert to Lead": "Zu Interessent umwandeln" - } + "fields": { + "name": "Name", + "emailAddress": "E-Mail", + "title": "Funktion", + "website": "Webseite", + "accountName": "Firmenname", + "phoneNumber": "Telefon", + "doNotCall": "Nicht anrufen", + "address": "Adresse", + "description": "Beschreibung" + }, + "links": { + }, + "labels": { + "Create Target": "Zielkontakt erstellen", + "Convert to Lead": "Zu Interessent umwandeln" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/de_DE/Task.json b/application/Espo/Modules/Crm/Resources/i18n/de_DE/Task.json index 99ce7f1eb1..c66c67b553 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/de_DE/Task.json +++ b/application/Espo/Modules/Crm/Resources/i18n/de_DE/Task.json @@ -1,37 +1,38 @@ { - "fields": { - "name": "Name", - "parent": "Bezieht sich auf", - "status": "Status", - "dateStart": "Startdatum", - "dateEnd": "Fällig am", - "priority": "Priorität", - "description": "Beschreibung", - "isOverdue": "Ist überfällig" - }, - "links": { - }, - "options": { - "status": { - "Not Started": "Nicht begonnen", - "Started": "In Bearbeitung", - "Completed": "Abgeschlossen", - "Canceled": "Storniert" - }, - "priority" : { - "Low": "Niedrig", - "Normal": "Normal", - "High": "Hoch", - "Urgent": "Dringend" - } - }, - "labels": { - "Create Task": "Neue Aufgabe" - }, - "presetFilters": { - "active": "Aktiv", - "completed": "Abgeschlossen", - "todays": "Heutige", - "overdue": "Überfällig" - } + "fields": { + "name": "Name", + "parent": "Bezieht sich auf", + "status": "Status", + "dateStart": "Startdatum", + "dateEnd": "Fällig am", + "priority": "Priorität", + "description": "Beschreibung", + "isOverdue": "Ist überfällig" + }, + "links": { + }, + "options": { + "status": { + "Not Started": "Nicht begonnen", + "Started": "In Bearbeitung", + "Completed": "Abgeschlossen", + "Canceled": "Storniert" + }, + "priority" : { + "Low": "Niedrig", + "Normal": "Normal", + "High": "Hoch", + "Urgent": "Dringend" + } + }, + "labels": { + "Create Task": "Neue Aufgabe", + "Complete": "Fertig" + }, + "presetFilters": { + "actual": "Tatsächlich", + "completed": "Abgeschlossen", + "todays": "Heutige", + "overdue": "Überfällig" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/en_US/Account.json b/application/Espo/Modules/Crm/Resources/i18n/en_US/Account.json index f3f0313121..b382599bc8 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/en_US/Account.json +++ b/application/Espo/Modules/Crm/Resources/i18n/en_US/Account.json @@ -1,42 +1,42 @@ { - "fields": { - "name": "Name", - "emailAddress": "Email", - "website": "Website", - "phoneNumber": "Phone", - "billingAddress": "Billing Address", - "shippingAddress": "Shipping Address", - "description": "Description", - "sicCode": "Sic Code", - "industry": "Industry", - "type": "Type", - "contactRole": "Role" - }, - "links": { - "contacts": "Contacts", - "opportunities": "Opportunities", - "cases": "Cases", - "documents": "Documents" - }, - "options": { - "type": { - "Customer": "Customer", - "Investor": "Investor", - "Partner": "Partner", - "Reseller": "Reseller" - }, - "industry": { - "Apparel": "Apparel", - "Banking": "Banking", - "Computer Software": "Computer Software", - "Education": "Education", - "Electronics": "Electronics", - "Finance": "Finance", - "Insurance": "Insurance" - } - }, - "labels": { - "Create Account": "Create Account", - "Copy Billing": "Copy Billing" - } + "fields": { + "name": "Name", + "emailAddress": "Email", + "website": "Website", + "phoneNumber": "Phone", + "billingAddress": "Billing Address", + "shippingAddress": "Shipping Address", + "description": "Description", + "sicCode": "Sic Code", + "industry": "Industry", + "type": "Type", + "contactRole": "Role" + }, + "links": { + "contacts": "Contacts", + "opportunities": "Opportunities", + "cases": "Cases", + "documents": "Documents" + }, + "options": { + "type": { + "Customer": "Customer", + "Investor": "Investor", + "Partner": "Partner", + "Reseller": "Reseller" + }, + "industry": { + "Apparel": "Apparel", + "Banking": "Banking", + "Computer Software": "Computer Software", + "Education": "Education", + "Electronics": "Electronics", + "Finance": "Finance", + "Insurance": "Insurance" + } + }, + "labels": { + "Create Account": "Create Account", + "Copy Billing": "Copy Billing" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/en_US/Admin.json b/application/Espo/Modules/Crm/Resources/i18n/en_US/Admin.json new file mode 100644 index 0000000000..cde2bff2bc --- /dev/null +++ b/application/Espo/Modules/Crm/Resources/i18n/en_US/Admin.json @@ -0,0 +1,5 @@ +{ + "layouts": { + "detailConvert": "Convert Lead" + } +} diff --git a/application/Espo/Modules/Crm/Resources/i18n/en_US/Calendar.json b/application/Espo/Modules/Crm/Resources/i18n/en_US/Calendar.json index 0a05d5cf23..a6dd884345 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/en_US/Calendar.json +++ b/application/Espo/Modules/Crm/Resources/i18n/en_US/Calendar.json @@ -1,13 +1,13 @@ { - "modes": { - "month": "Month", - "week": "Week", - "day": "Day", - "agendaWeek": "Week", - "agendaDay": "Day" - }, - "labels": { - "Today": "Today", - "Create": "Create" - } + "modes": { + "month": "Month", + "week": "Week", + "day": "Day", + "agendaWeek": "Week", + "agendaDay": "Day" + }, + "labels": { + "Today": "Today", + "Create": "Create" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/en_US/Call.json b/application/Espo/Modules/Crm/Resources/i18n/en_US/Call.json index 78cb294d23..f8836b5cb9 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/en_US/Call.json +++ b/application/Espo/Modules/Crm/Resources/i18n/en_US/Call.json @@ -1,44 +1,44 @@ { - "fields": { - "name": "Name", - "parent": "Parent", - "status": "Status", - "dateStart": "Date Start", - "dateEnd": "Date End", - "direction": "Direction", - "duration": "Duration", - "description": "Description", - "users": "Users", - "contacts": "Contacts", - "leads": "Leads" - }, - "links": { - }, - "options": { - "status": { - "Planned": "Planned", - "Held": "Held", - "Not Held": "Not Held" - }, - "direction": { - "Outbound": "Outbound", - "Inbound": "Inbound" - }, - "acceptanceStatus": { - "None": "None", - "Accepted": "Accepted", - "Declined": "Declined" - } - }, - "labels": { - "Create Call": "Create Call", - "Set Held": "Set Held", - "Set Not Held": "Set Not Held", - "Send Invitations": "Send Invitations" - }, - "presetFilters": { - "planned": "Planned", - "held": "Held", - "todays": "Today's" - } + "fields": { + "name": "Name", + "parent": "Parent", + "status": "Status", + "dateStart": "Date Start", + "dateEnd": "Date End", + "direction": "Direction", + "duration": "Duration", + "description": "Description", + "users": "Users", + "contacts": "Contacts", + "leads": "Leads" + }, + "links": { + }, + "options": { + "status": { + "Planned": "Planned", + "Held": "Held", + "Not Held": "Not Held" + }, + "direction": { + "Outbound": "Outbound", + "Inbound": "Inbound" + }, + "acceptanceStatus": { + "None": "None", + "Accepted": "Accepted", + "Declined": "Declined" + } + }, + "labels": { + "Create Call": "Create Call", + "Set Held": "Set Held", + "Set Not Held": "Set Not Held", + "Send Invitations": "Send Invitations" + }, + "presetFilters": { + "planned": "Planned", + "held": "Held", + "todays": "Today's" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/en_US/Case.json b/application/Espo/Modules/Crm/Resources/i18n/en_US/Case.json index 8b7289e39b..78cd8765f9 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/en_US/Case.json +++ b/application/Espo/Modules/Crm/Resources/i18n/en_US/Case.json @@ -1,42 +1,42 @@ { - "fields": { - "name": "Name", - "number": "Number", - "status": "Status", - "account": "Account", - "contact": "Contact", - "priority": "Priority", - "type": "Type", - "description": "Description" - }, - "links": { - }, - "options": { - "status": { - "New": "New", - "Assigned": "Assigned", - "Pending": "Pending", - "Closed": "Closed", - "Rejected": "Rejected", - "Duplicate": "Duplicate" - }, - "priority" : { - "Low": "Low", - "Normal": "Normal", - "High": "High", - "Urgent": "Urgent" - }, - "type": { - "Question": "Question", - "Incident": "Incident", - "Problem": "Problem" - } - }, - "labels": { - "Create Case": "Create Case" - }, - "presetFilters": { - "open": "Open", - "closed": "Closed" - } + "fields": { + "name": "Name", + "number": "Number", + "status": "Status", + "account": "Account", + "contact": "Contact", + "priority": "Priority", + "type": "Type", + "description": "Description" + }, + "links": { + }, + "options": { + "status": { + "New": "New", + "Assigned": "Assigned", + "Pending": "Pending", + "Closed": "Closed", + "Rejected": "Rejected", + "Duplicate": "Duplicate" + }, + "priority" : { + "Low": "Low", + "Normal": "Normal", + "High": "High", + "Urgent": "Urgent" + }, + "type": { + "Question": "Question", + "Incident": "Incident", + "Problem": "Problem" + } + }, + "labels": { + "Create Case": "Create Case" + }, + "presetFilters": { + "open": "Open", + "closed": "Closed" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/en_US/Contact.json b/application/Espo/Modules/Crm/Resources/i18n/en_US/Contact.json index 8f6fce3272..2908a84de3 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/en_US/Contact.json +++ b/application/Espo/Modules/Crm/Resources/i18n/en_US/Contact.json @@ -1,31 +1,31 @@ { - "fields": { - "name": "Name", - "emailAddress": "Email", - "title": "Title", - "account": "Account", - "accounts": "Accounts", - "phoneNumber": "Phone", - "accountType": "Account Type", - "doNotCall": "Do Not Call", - "address": "Address", - "opportunityRole": "Opportunity Role", - "accountRole": "Role", - "description": "Description" - }, - "links": { - "opportunities": "Opportunities", - "cases": "Cases" - }, - "labels": { - "Create Contact": "Create Contact" - }, - "options": { - "opportunityRole": { - "": "--None--", - "Decision Maker": "Decision Maker", - "Evaluator": "Evaluator", - "Influencer": "Influencer" - } - } + "fields": { + "name": "Name", + "emailAddress": "Email", + "title": "Title", + "account": "Account", + "accounts": "Accounts", + "phoneNumber": "Phone", + "accountType": "Account Type", + "doNotCall": "Do Not Call", + "address": "Address", + "opportunityRole": "Opportunity Role", + "accountRole": "Role", + "description": "Description" + }, + "links": { + "opportunities": "Opportunities", + "cases": "Cases" + }, + "labels": { + "Create Contact": "Create Contact" + }, + "options": { + "opportunityRole": { + "": "--None--", + "Decision Maker": "Decision Maker", + "Evaluator": "Evaluator", + "Influencer": "Influencer" + } + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/en_US/Document.json b/application/Espo/Modules/Crm/Resources/i18n/en_US/Document.json index bf5fb241bc..83099ff80c 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/en_US/Document.json +++ b/application/Espo/Modules/Crm/Resources/i18n/en_US/Document.json @@ -1,32 +1,32 @@ { - "labels": { - "Create Document": "Create Document", - "Details": "Details" - }, - "fields": { - "name": "Name", - "status": "Status", - "file": "File", - "type": "Type", - "source": "Source", - "publishDate": "Publish Date", - "expirationDate": "Expiration Date", - "description": "Description" - }, - "links": { - "accounts": "Accounts", - "opportunities": "Opportunities" - }, - "options": { - "status": { - "Active": "Active", - "Draft": "Draft", - "Expired": "Expired", - "Canceled": "Canceled" - } - }, - "presetFilters": { - "active": "Active", - "draft": "Draft" - } + "labels": { + "Create Document": "Create Document", + "Details": "Details" + }, + "fields": { + "name": "Name", + "status": "Status", + "file": "File", + "type": "Type", + "source": "Source", + "publishDate": "Publish Date", + "expirationDate": "Expiration Date", + "description": "Description" + }, + "links": { + "accounts": "Accounts", + "opportunities": "Opportunities" + }, + "options": { + "status": { + "Active": "Active", + "Draft": "Draft", + "Expired": "Expired", + "Canceled": "Canceled" + } + }, + "presetFilters": { + "active": "Active", + "draft": "Draft" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/en_US/Global.json b/application/Espo/Modules/Crm/Resources/i18n/en_US/Global.json index 5c941555db..4510503d90 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/en_US/Global.json +++ b/application/Espo/Modules/Crm/Resources/i18n/en_US/Global.json @@ -1,83 +1,90 @@ { - "scopeNames": { - "Account": "Account", - "Contact": "Contact", - "Lead": "Lead", - "Target": "Target", - "Opportunity": "Opportunity", - "Meeting": "Meeting", - "Calendar": "Calendar", - "Call": "Call", - "Task": "Task", - "Case": "Case", - "InboundEmail": "Inbound Email", - "Document": "Document" - }, - "scopeNamesPlural": { - "Account": "Accounts", - "Contact": "Contacts", - "Lead": "Leads", - "Target": "Targets", - "Opportunity": "Opportunities", - "Meeting": "Meetings", - "Calendar": "Calendar", - "Call": "Calls", - "Task": "Tasks", - "Case": "Cases", - "InboundEmail": "Inbound Emails", - "Document": "Documents" - }, - "dashlets": { - "Leads": "My Leads", - "Opportunities": "My Opportunities", - "Tasks": "My Tasks", - "Cases": "My Cases", - "Calendar": "Calendar", - "Calls": "My Calls", - "Meetings": "My Meetings", - "OpportunitiesByStage": "Opportunities by Stage", - "OpportunitiesByLeadSource": "Opportunities by Lead Source", - "SalesByMonth": "Sales by Month", - "SalesPipeline": "Sales Pipeline" - }, - "labels": { - "Create InboundEmail": "Create Inbound Email", - "Activities": "Activities", - "History": "History", - "Attendees": "Attendees", - "Schedule Meeting": "Schedule Meeting", - "Schedule Call": "Schedule Call", - "Compose Email": "Compose Email", - "Log Meeting": "Log Meeting", - "Log Call": "Log Call", - "Archive Email": "Archive Email", - "Create Task": "Create Task", - "Tasks": "Tasks" - }, - "fields": { - "billingAddressCity": "City", - "billingAddressCountry": "Country", - "billingAddressPostalCode": "Postal Code", - "billingAddressState": "State", - "billingAddressStreet": "Street", - "addressCity": "City", - "addressStreet": "Street", - "addressCountry": "Country", - "addressState": "State", - "addressPostalCode": "Postal Code", - "shippingAddressCity": "City (Shipping)", - "shippingAddressStreet": "Street (Shipping)", - "shippingAddressCountry": "Country (Shipping)", - "shippingAddressState": "State (Shipping)", - "shippingAddressPostalCode": "Postal Code (Shipping)" - }, - "links": { - "contacts": "Contacts", - "opportunities": "Opportunities", - "leads": "Leads", - "meetings": "Meetings", - "calls": "Calls", - "tasks": "Tasks", - "emails": "Emails" - } + "scopeNames": { + "Account": "Account", + "Contact": "Contact", + "Lead": "Lead", + "Target": "Target", + "Opportunity": "Opportunity", + "Meeting": "Meeting", + "Calendar": "Calendar", + "Call": "Call", + "Task": "Task", + "Case": "Case", + "InboundEmail": "Inbound Email", + "Document": "Document" + }, + "scopeNamesPlural": { + "Account": "Accounts", + "Contact": "Contacts", + "Lead": "Leads", + "Target": "Targets", + "Opportunity": "Opportunities", + "Meeting": "Meetings", + "Calendar": "Calendar", + "Call": "Calls", + "Task": "Tasks", + "Case": "Cases", + "InboundEmail": "Inbound Emails", + "Document": "Documents" + }, + "dashlets": { + "Leads": "My Leads", + "Opportunities": "My Opportunities", + "Tasks": "My Tasks", + "Cases": "My Cases", + "Calendar": "Calendar", + "Calls": "My Calls", + "Meetings": "My Meetings", + "OpportunitiesByStage": "Opportunities by Stage", + "OpportunitiesByLeadSource": "Opportunities by Lead Source", + "SalesByMonth": "Sales by Month", + "SalesPipeline": "Sales Pipeline" + }, + "labels": { + "Create InboundEmail": "Create Inbound Email", + "Activities": "Activities", + "History": "History", + "Attendees": "Attendees", + "Schedule Meeting": "Schedule Meeting", + "Schedule Call": "Schedule Call", + "Compose Email": "Compose Email", + "Log Meeting": "Log Meeting", + "Log Call": "Log Call", + "Archive Email": "Archive Email", + "Create Task": "Create Task", + "Tasks": "Tasks" + }, + "fields": { + "billingAddressCity": "City", + "billingAddressCountry": "Country", + "billingAddressPostalCode": "Postal Code", + "billingAddressState": "State", + "billingAddressStreet": "Street", + "addressCity": "City", + "addressStreet": "Street", + "addressCountry": "Country", + "addressState": "State", + "addressPostalCode": "Postal Code", + "shippingAddressCity": "City (Shipping)", + "shippingAddressStreet": "Street (Shipping)", + "shippingAddressCountry": "Country (Shipping)", + "shippingAddressState": "State (Shipping)", + "shippingAddressPostalCode": "Postal Code (Shipping)" + }, + "links": { + "contacts": "Contacts", + "opportunities": "Opportunities", + "leads": "Leads", + "meetings": "Meetings", + "calls": "Calls", + "tasks": "Tasks", + "emails": "Emails", + "accounts": "Accounts", + "cases": "Cases", + "documents": "Documents", + "account": "Account", + "opportunity": "Opportunity", + "contact": "Contact", + "parent": "Parent" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/en_US/InboundEmail.json b/application/Espo/Modules/Crm/Resources/i18n/en_US/InboundEmail.json index 207137fe44..783453b692 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/en_US/InboundEmail.json +++ b/application/Espo/Modules/Crm/Resources/i18n/en_US/InboundEmail.json @@ -1,52 +1,53 @@ { - "fields": { - "name": "Name", - "team": "Team", - "status": "Status", - "assignToUser": "Assign to User", - "host": "Host", - "username": "Username", - "password": "Password", - "port": "Port", - "monitoredFolders": "Monitored Folders", - "trashFolder": "Trash Folder", - "ssl": "SSL", - "createCase": "Create Case", - "reply": "Reply", - "caseDistribution": "Case Distribution", - "replyEmailTemplate": "Reply Email Template", - "replyFromAddress": "Reply From Address", - "replyToAddress": "Reply To Address", - "replyFromName": "Reply From Name" - }, - "tooltips": { - "reply": "Notify email senders that their emails has been received.", - "createCase": "Automatically create case from incoming emails.", - "replyToAddress": "Specify email address of this mailbox to make response come here.", - "caseDistribution": "How cases will be assigned to. Assigned directly to the user or among the team.", - "assignToUser": "User emails/cases will be assigned to.", - "team": "Team emails/cases will be related to." - }, - "links": { - }, - "options": { - "status": { - "Active": "Active", - "Inactive": "Inactive" - }, - "caseDistribution": { - "Direct-Assignment": "Direct-Assignment", - "Round-Robin": "Round-Robin", - "Least-Busy": "Least-Busy" - } - }, - "labels": { - "Create InboundEmail": "Create Inbound Email", - "IMAP": "IMAP", - "Actions": "Actions", - "Main": "Main" - }, - "messages": { - "couldNotConnectToImap": "Could not connect to IMAP server" - } + "fields": { + "name": "Name", + "team": "Team", + "status": "Status", + "assignToUser": "Assign to User", + "host": "Host", + "username": "Username", + "password": "Password", + "port": "Port", + "monitoredFolders": "Monitored Folders", + "trashFolder": "Trash Folder", + "ssl": "SSL", + "createCase": "Create Case", + "reply": "Reply", + "caseDistribution": "Case Distribution", + "replyEmailTemplate": "Reply Email Template", + "replyFromAddress": "Reply From Address", + "replyToAddress": "Reply To Address", + "replyFromName": "Reply From Name", + "targetUserPosition": "Target User Position" + }, + "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": { + "status": { + "Active": "Active", + "Inactive": "Inactive" + }, + "caseDistribution": { + "Direct-Assignment": "Direct-Assignment", + "Round-Robin": "Round-Robin", + "Least-Busy": "Least-Busy" + } + }, + "labels": { + "Create InboundEmail": "Create Inbound Email", + "IMAP": "IMAP", + "Actions": "Actions", + "Main": "Main" + }, + "messages": { + "couldNotConnectToImap": "Could not connect to IMAP server" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/en_US/Lead.json b/application/Espo/Modules/Crm/Resources/i18n/en_US/Lead.json index ff8b1ef300..b608450ab8 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/en_US/Lead.json +++ b/application/Espo/Modules/Crm/Resources/i18n/en_US/Lead.json @@ -1,50 +1,50 @@ { - "labels": { - "Converted To": "Converted To", - "Create Lead": "Create Lead", - "Convert": "Convert" - }, - "fields": { - "name": "Name", - "emailAddress": "Email", - "title": "Title", - "website": "Website", - "phoneNumber": "Phone", - "accountName": "Account Name", - "doNotCall": "Do Not Call", - "address": "Address", - "status": "Status", - "source": "Source", - "opportunityAmount": "Opportunity Amount", - "opportunityAmountConverted": "Opportunity Amount (converted)", - "description": "Description", - "createdAccount": "Account", - "createdContact": "Contact", - "createdOpportunity": "Opportunity" - }, - "links": { - }, - "options": { - "status": { - "New": "New", - "Assigned": "Assigned", - "In Process": "In Process", - "Converted": "Converted", - "Recycled": "Recycled", - "Dead": "Dead" - }, - "source": { - "Call": "Call", - "Email": "Email", - "Existing Customer": "Existing Customer", - "Partner": "Partner", - "Public Relations": "Public Relations", - "Web Site": "Web Site", - "Campaign": "Campaign", - "Other": "Other" - } - }, - "presetFilters": { - "active": "Active" - } + "labels": { + "Converted To": "Converted To", + "Create Lead": "Create Lead", + "Convert": "Convert" + }, + "fields": { + "name": "Name", + "emailAddress": "Email", + "title": "Title", + "website": "Website", + "phoneNumber": "Phone", + "accountName": "Account Name", + "doNotCall": "Do Not Call", + "address": "Address", + "status": "Status", + "source": "Source", + "opportunityAmount": "Opportunity Amount", + "opportunityAmountConverted": "Opportunity Amount (converted)", + "description": "Description", + "createdAccount": "Account", + "createdContact": "Contact", + "createdOpportunity": "Opportunity" + }, + "links": { + }, + "options": { + "status": { + "New": "New", + "Assigned": "Assigned", + "In Process": "In Process", + "Converted": "Converted", + "Recycled": "Recycled", + "Dead": "Dead" + }, + "source": { + "Call": "Call", + "Email": "Email", + "Existing Customer": "Existing Customer", + "Partner": "Partner", + "Public Relations": "Public Relations", + "Web Site": "Web Site", + "Campaign": "Campaign", + "Other": "Other" + } + }, + "presetFilters": { + "active": "Active" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/en_US/Meeting.json b/application/Espo/Modules/Crm/Resources/i18n/en_US/Meeting.json index 4695fe144c..ddfb732cbd 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/en_US/Meeting.json +++ b/application/Espo/Modules/Crm/Resources/i18n/en_US/Meeting.json @@ -1,41 +1,39 @@ { - "fields": { - "name": "Name", - "parent": "Parent", - "status": "Status", - "dateStart": "Date Start", - "dateEnd": "Date End", - "duration": "Duration", - "description": "Description", - "users": "Users", - "contacts": "Contacts", - "leads": "Leads" - }, - "links": { - }, - "options": { - "status": { - "Planned": "Planned", - "Held": "Held", - "Not Held": "Not Held" - }, - "acceptanceStatus": { - "None": "None", - "Accepted": "Accepted", - "Declined": "Declined" - } - }, - "labels": { - "Create Meeting": "Create Meeting", - "Set Held": "Set Held", - "Set Not Held": "Set Not Held", - "Send Invitations": "Send Invitations", - "Saved as Held": "Saved as Held", - "Saved as Not Held": "Saved as Not Held" - }, - "presetFilters": { - "planned": "Planned", - "held": "Held", - "todays": "Today's" - } + "fields": { + "name": "Name", + "parent": "Parent", + "status": "Status", + "dateStart": "Date Start", + "dateEnd": "Date End", + "duration": "Duration", + "description": "Description", + "users": "Users", + "contacts": "Contacts", + "leads": "Leads" + }, + "links": { + }, + "options": { + "status": { + "Planned": "Planned", + "Held": "Held", + "Not Held": "Not Held" + }, + "acceptanceStatus": { + "None": "None", + "Accepted": "Accepted", + "Declined": "Declined" + } + }, + "labels": { + "Create Meeting": "Create Meeting", + "Set Held": "Set Held", + "Set Not Held": "Set Not Held", + "Send Invitations": "Send Invitations" + }, + "presetFilters": { + "planned": "Planned", + "held": "Held", + "todays": "Today's" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/en_US/Opportunity.json b/application/Espo/Modules/Crm/Resources/i18n/en_US/Opportunity.json index fd1953f729..9e1cab09bf 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/en_US/Opportunity.json +++ b/application/Espo/Modules/Crm/Resources/i18n/en_US/Opportunity.json @@ -1,41 +1,41 @@ { - "fields": { - "name": "Name", - "account": "Account", - "stage": "Stage", - "amount": "Amount", - "probability": "Probability, %", - "leadSource": "Lead Source", - "doNotCall": "Do Not Call", - "closeDate": "Close Date", - "contacts": "Contacts", - "description": "Description", - "amountConverted": "Amount (converted)", - "amountWeightedConverted": "Amount Weighted" - }, - "links": { - "contacts": "Contacts", - "documents": "Documents" - }, - "options": { - "stage": { - "Prospecting": "Prospecting", - "Qualification": "Qualification", - "Needs Analysis": "Needs Analysis", - "Value Proposition": "Value Proposition", - "Id. Decision Makers": "Id. Decision Makers", - "Perception Analysis": "Perception Analysis", - "Proposal/Price Quote": "Proposal/Price Quote", - "Negotiation/Review": "Negotiation/Review", - "Closed Won": "Closed Won", - "Closed Lost": "Closed Lost" - } - }, - "labels": { - "Create Opportunity": "Create Opportunity" - }, - "presetFilters": { - "open": "Open", - "won": "Won" - } + "fields": { + "name": "Name", + "account": "Account", + "stage": "Stage", + "amount": "Amount", + "probability": "Probability, %", + "leadSource": "Lead Source", + "doNotCall": "Do Not Call", + "closeDate": "Close Date", + "contacts": "Contacts", + "description": "Description", + "amountConverted": "Amount (converted)", + "amountWeightedConverted": "Amount Weighted" + }, + "links": { + "contacts": "Contacts", + "documents": "Documents" + }, + "options": { + "stage": { + "Prospecting": "Prospecting", + "Qualification": "Qualification", + "Needs Analysis": "Needs Analysis", + "Value Proposition": "Value Proposition", + "Id. Decision Makers": "Id. Decision Makers", + "Perception Analysis": "Perception Analysis", + "Proposal/Price Quote": "Proposal/Price Quote", + "Negotiation/Review": "Negotiation/Review", + "Closed Won": "Closed Won", + "Closed Lost": "Closed Lost" + } + }, + "labels": { + "Create Opportunity": "Create Opportunity" + }, + "presetFilters": { + "open": "Open", + "won": "Won" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/en_US/Target.json b/application/Espo/Modules/Crm/Resources/i18n/en_US/Target.json index 153acf0958..c06b518df7 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/en_US/Target.json +++ b/application/Espo/Modules/Crm/Resources/i18n/en_US/Target.json @@ -1,19 +1,19 @@ { - "fields": { - "name": "Name", - "emailAddress": "Email", - "title": "Title", - "website": "Website", - "accountName": "Account Name", - "phoneNumber": "Phone", - "doNotCall": "Do Not Call", - "address": "Address", - "description": "Description" - }, - "links": { - }, - "labels": { - "Create Target": "Create Target", - "Convert to Lead": "Convert to Lead" - } + "fields": { + "name": "Name", + "emailAddress": "Email", + "title": "Title", + "website": "Website", + "accountName": "Account Name", + "phoneNumber": "Phone", + "doNotCall": "Do Not Call", + "address": "Address", + "description": "Description" + }, + "links": { + }, + "labels": { + "Create Target": "Create Target", + "Convert to Lead": "Convert to Lead" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/en_US/Task.json b/application/Espo/Modules/Crm/Resources/i18n/en_US/Task.json index 3248d1a4ec..18583ed216 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/en_US/Task.json +++ b/application/Espo/Modules/Crm/Resources/i18n/en_US/Task.json @@ -1,37 +1,38 @@ { - "fields": { - "name": "Name", - "parent": "Parent", - "status": "Status", - "dateStart": "Date Start", - "dateEnd": "Date Due", - "priority": "Priority", - "description": "Description", - "isOverdue": "Is Overdue" - }, - "links": { - }, - "options": { - "status": { - "Not Started": "Not Started", - "Started": "Started", - "Completed": "Completed", - "Canceled": "Canceled" - }, - "priority" : { - "Low": "Low", - "Normal": "Normal", - "High": "High", - "Urgent": "Urgent" - } - }, - "labels": { - "Create Task": "Create Task" - }, - "presetFilters": { - "actual": "Actual", - "completed": "Completed", - "todays": "Today's", - "overdue": "Overdue" - } + "fields": { + "name": "Name", + "parent": "Parent", + "status": "Status", + "dateStart": "Date Start", + "dateEnd": "Date Due", + "priority": "Priority", + "description": "Description", + "isOverdue": "Is Overdue" + }, + "links": { + }, + "options": { + "status": { + "Not Started": "Not Started", + "Started": "Started", + "Completed": "Completed", + "Canceled": "Canceled" + }, + "priority" : { + "Low": "Low", + "Normal": "Normal", + "High": "High", + "Urgent": "Urgent" + } + }, + "labels": { + "Create Task": "Create Task", + "Complete": "Complete" + }, + "presetFilters": { + "actual": "Actual", + "completed": "Completed", + "todays": "Today's", + "overdue": "Overdue" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/es_ES/Account.json b/application/Espo/Modules/Crm/Resources/i18n/es_ES/Account.json index c30c3b81f7..7706e1e03e 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/es_ES/Account.json +++ b/application/Espo/Modules/Crm/Resources/i18n/es_ES/Account.json @@ -1,40 +1,42 @@ { - "fields": { - "name": "Nombre", - "emailAddress": "Correo electrónico", - "website": "Sito Web", - "phone": "Teléfono", - "fax": "Fax", - "billingAddress": "Dirección de Facturación", - "shippingAddress": "Dirección de Envío", - "description": "Descripción", - "sicCode": "Sic Code", - "industry": "Industria", - "type": "Tipo" - }, - "links": { - "contacts": "Contactos", - "opportunities": "Oportunidades", - "cases": "Casos" - }, - "options": { - "type": { - "Customer": "Cliente", - "Investor": "Inversor", - "Partner": "Partner", - "Reseller": "REvendedor" - }, - "industry": { - "Apparel": "Apparel", - "Banking": "Banking", - "Computer Software": "Software", - "Education": "Educación", - "Electronics": "Electrónicos", - "Finance": "Finanzas", - "Insurance": "Seguros" - } - }, - "labels": { - "Create Account": "Crear Cuenta" - } + "fields": { + "name": "Asunto", + "emailAddress": "Correo electrónico", + "website": "Sito Web", + "phoneNumber": "Teléfono", + "billingAddress": "Dirección de Facturación", + "shippingAddress": "Dirección de Envío", + "description": "Descripción", + "sicCode": "Sic Code", + "industry": "Industria", + "type": "Tipo", + "contactRole": "Rol" + }, + "links": { + "contacts": "Contactos", + "opportunities": "Oportunidades", + "cases": "Casos", + "documents": "Documentos" + }, + "options": { + "type": { + "Customer": "Cliente", + "Investor": "Inversor", + "Partner": "Socio", + "Reseller": "Revendedor" + }, + "industry": { + "Apparel": "Vestuario", + "Banking": "Banca", + "Computer Software": "Software", + "Education": "Educación", + "Electronics": "Electrónicos", + "Finance": "Finanzas", + "Insurance": "Seguros" + } + }, + "labels": { + "Create Account": "Crear Cuenta", + "Copy Billing": "Copia Facturación" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/es_ES/Admin.json b/application/Espo/Modules/Crm/Resources/i18n/es_ES/Admin.json new file mode 100644 index 0000000000..cde2bff2bc --- /dev/null +++ b/application/Espo/Modules/Crm/Resources/i18n/es_ES/Admin.json @@ -0,0 +1,5 @@ +{ + "layouts": { + "detailConvert": "Convert Lead" + } +} diff --git a/application/Espo/Modules/Crm/Resources/i18n/es_ES/Calendar.json b/application/Espo/Modules/Crm/Resources/i18n/es_ES/Calendar.json index b41e3beed7..c6ac56c47f 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/es_ES/Calendar.json +++ b/application/Espo/Modules/Crm/Resources/i18n/es_ES/Calendar.json @@ -1,13 +1,13 @@ { - "modes": { - "month": "Mes", - "week": "Semana", - "day": "Día", - "agendaWeek": "Semana", - "agendaDay": "Día" - }, - "labels": { - "Today": "Hoy", - "Create": "Crear" - } + "modes": { + "month": "Mes", + "week": "Semana", + "day": "Día", + "agendaWeek": "Semana", + "agendaDay": "Día" + }, + "labels": { + "Today": "Hoy", + "Create": "Crear" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/es_ES/Call.json b/application/Espo/Modules/Crm/Resources/i18n/es_ES/Call.json index 1c2dbd39db..134e2d7b37 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/es_ES/Call.json +++ b/application/Espo/Modules/Crm/Resources/i18n/es_ES/Call.json @@ -1,34 +1,44 @@ { - "fields": { - "name": "Nombre", - "parent": "Padre", - "status": "Estado", - "dateStart": "Fecha de Comienzo", - "dateEnd": "Fecha de Finalización", - "direction": "Dirección", - "duration": "Duración", - "description": "Descripción", - "users": "Usuarios", - "contacts": "Contactos", - "leads": "Potenciales" - }, - "links": { - }, - "options": { - "status": { - "Planned": "Planeada", - "Held": "Celebrada", - "Not Held": "Sin Celebrar" - }, - "direction": { - "Outbound": "Saliente", - "Inbound": "Entrante" - } - }, - "labels": { - "Create Call": "Crear Llamada", - "Set Held": "Establecer Celebrada", - "Set Not Held": "Establecer no Celebrada", - "Send Invitations": "Enviar Invitaciones" - } + "fields": { + "name": "Asunto", + "parent": "Padre", + "status": "Estado", + "dateStart": "Fecha de Comienzo", + "dateEnd": "Fecha de Finalización", + "direction": "Dirección", + "duration": "Duración", + "description": "Descripción", + "users": "Usuarios", + "contacts": "Contactos", + "leads": "Potenciales" + }, + "links": { + }, + "options": { + "status": { + "Planned": "Planeada", + "Held": "Celebrada", + "Not Held": "Sin Celebrar" + }, + "direction": { + "Outbound": "Saliente", + "Inbound": "Entrante" + }, + "acceptanceStatus": { + "None": "Ninguno", + "Accepted": "Aceptado", + "Declined": "Rechazado" + } + }, + "labels": { + "Create Call": "Crear Llamada", + "Set Held": "Establecer Celebrada", + "Set Not Held": "Establecer no Celebrada", + "Send Invitations": "Enviar Invitaciones" + }, + "presetFilters": { + "planned": "Planeada", + "held": "Celebrada", + "todays": "De Hoy" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/es_ES/Case.json b/application/Espo/Modules/Crm/Resources/i18n/es_ES/Case.json index a332e4b571..6ba03a9722 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/es_ES/Case.json +++ b/application/Espo/Modules/Crm/Resources/i18n/es_ES/Case.json @@ -1,38 +1,42 @@ { - "fields": { - "name": "Nombre", - "number": "Número", - "status": "Estado", - "account": "Cuenta", - "contact": "Contacto", - "priority": "Prioridad", - "type": "Tipo", - "description": "Descripción" - }, - "links": { - }, - "options": { - "status": { - "New": "Nuevo", - "Assigned": "Asignado", - "Pending": "Pendiente", - "Closed": "Cerrado", - "Rejected": "Rechazado", - "Duplicate": "Duplicado" - }, - "priority" : { - "Low": "Baja", - "Normal": "Normal", - "High": "Alta", - "Urgent": "Urgente" - }, - "type": { - "Question": "Pregunta", - "Incident": "Incidente", - "Problem": "Problema" - } - }, - "labels": { - "Create Case": "Crear Caso" - } + "fields": { + "name": "Asunto", + "number": "Número", + "status": "Estado", + "account": "Cuenta", + "contact": "Contacto", + "priority": "Prioridad", + "type": "Tipo", + "description": "Descripción" + }, + "links": { + }, + "options": { + "status": { + "New": "Nuevo", + "Assigned": "Asignado", + "Pending": "Pendiente", + "Closed": "Cerrado", + "Rejected": "Rechazado", + "Duplicate": "Duplicar" + }, + "priority" : { + "Low": "Baja", + "Normal": "Normal", + "High": "Alta", + "Urgent": "Urgente" + }, + "type": { + "Question": "Pregunta", + "Incident": "Incidente", + "Problem": "Problema" + } + }, + "labels": { + "Create Case": "Crear Caso" + }, + "presetFilters": { + "open": "Abrir", + "closed": "Cerrado" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/es_ES/Contact.json b/application/Espo/Modules/Crm/Resources/i18n/es_ES/Contact.json index 3c93a7c113..faee8c3780 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/es_ES/Contact.json +++ b/application/Espo/Modules/Crm/Resources/i18n/es_ES/Contact.json @@ -1,22 +1,31 @@ { - "fields": { - "name": "Nombre", - "emailAddress": "Correo electrónico", - "title": "Título", - "account": "Cuenta", - "phone": "Teléfono", - "phoneOffice": "Phone (Office)", - "fax": "Fax", - "accountType": "Cuenta Tipo", - "doNotCall": "No Llamar", - "address": "Dirección", - "description": "Descripción" - }, - "links": { - "opportunities": "Oportunidades", - "cases": "Casos" - }, - "labels": { - "Create Contact": "Crear Contacto" - } + "fields": { + "name": "Asunto", + "emailAddress": "Correo electrónico", + "title": "Título", + "account": "Cuenta", + "accounts": "Cuentas", + "phoneNumber": "Teléfono", + "accountType": "Tipo de Cuenta", + "doNotCall": "No Llamar", + "address": "Dirección", + "opportunityRole": "Rol de Oportunidad", + "accountRole": "Rol", + "description": "Descripción" + }, + "links": { + "opportunities": "Oportunidades", + "cases": "Casos" + }, + "labels": { + "Create Contact": "Crear Contacto" + }, + "options": { + "opportunityRole": { + "": "--Ninguno--", + "Decision Maker": "Tomador de Desiciones", + "Evaluator": "Evaluador", + "Influencer": "Factor de Influencia" + } + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/es_ES/Document.json b/application/Espo/Modules/Crm/Resources/i18n/es_ES/Document.json new file mode 100644 index 0000000000..de59146a6f --- /dev/null +++ b/application/Espo/Modules/Crm/Resources/i18n/es_ES/Document.json @@ -0,0 +1,32 @@ +{ + "labels": { + "Create Document": "Crear Documento", + "Details": "Detalles" + }, + "fields": { + "name": "Asunto", + "status": "Estado", + "file": "Archivo", + "type": "Tipo", + "source": "Fuente", + "publishDate": "Publicar Fecha", + "expirationDate": "Fecha de Expiración", + "description": "Descripción" + }, + "links": { + "accounts": "Cuentas", + "opportunities": "Oportunidades" + }, + "options": { + "status": { + "Active": "Activo", + "Draft": "Borrador", + "Expired": "Expirado", + "Canceled": "Cancelado" + } + }, + "presetFilters": { + "active": "Activo", + "draft": "Borrador" + } +} diff --git a/application/Espo/Modules/Crm/Resources/i18n/es_ES/Global.json b/application/Espo/Modules/Crm/Resources/i18n/es_ES/Global.json index 8e73801a59..3f1160a178 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/es_ES/Global.json +++ b/application/Espo/Modules/Crm/Resources/i18n/es_ES/Global.json @@ -1,79 +1,90 @@ { - "scopeNames": { - "Account": "Cuenta", - "Contact": "Contacto", - "Lead": "Potenciales", - "Target": "Prospecto", - "Opportunity": "Opportunidad", - "Meeting": "Reunión", - "Calendar": "Calendario", - "Call": "Llamada", - "Task": "Tarea", - "Case": "Caso", - "InboundEmail": "Correo Entrante" - }, - "scopeNamesPlural": { - "Account": "Cuentas", - "Contact": "Contactos", - "Lead": "Potenciales", - "Targets": "Prospectos", - "Opportunity": "Oportunidades", - "Meeting": "Reuniones", - "Calendar": "Calendario", - "Call": "Llamadas", - "Task": "Tareas", - "Case": "Casos", - "InboundEmail": "Correos Entrantes" - }, - "dashlets": { - "Leads": "Mis potenciales", - "Opportunities": "Mis Opportunidades", - "Tasks": "Mis Tareas", - "Cases": "Mis Casos", - "Calendar": "Calendario", - "OpportunitiesByStage": "Oportunidades por Etapa", - "OpportunitiesByLeadSource": "Oportunidades de origen de cliente potencial", - "SalesByMonth": "Ventas por Mes", - "SalesPipeline": "Canalización de ventas" - }, - "labels": { - "Create InboundEmail": "Crear Correo Entrante", - "Activities": "Actividades", - "History": "Historia", - "Attendees": "Los asistentes", - "Schedule Meeting": "Reunión Programada", - "Schedule Call": "Llamada Programada", - "Compose Email": "Componer Correo", - "Log Meeting": "Log de Reunión", - "Log Call": "Log de Llamada", - "Archive Email": "Archivar Correo", - "Create Task": "Crear Tarea", - "Tasks": "Tareas" - }, - "fields": { - "billingAddressCity": "Ciudad", - "billingAddressCountry": "país", - "billingAddressPostalCode": "Código Postal", - "billingAddressState": "Estado/Distrito", - "billingAddressStreet": "Calle", - "addressCity": "Ciudad", - "addressStreet": "Calle", - "addressCountry": "país", - "addressState": "Estado/Distrito", - "addressPostalCode": "Código Postal", - "shippingAddressCity": "City (Shipping)", - "shippingAddressStreet": "Street (Shipping)", - "shippingAddressCountry": "Country (Shipping)", - "shippingAddressState": "State (Shipping)", - "shippingAddressPostalCode": "Postal Code (Shipping)" - }, - "links": { - "contacts": "Contactos", - "opportunities": "Oportunidades", - "leads": "Potenciales", - "meetings": "Reuniones", - "calls": "Llamadas", - "tasks": "Tareas", - "emails": "Correos" - } + "scopeNames": { + "Account": "Cuenta", + "Contact": "Contacto", + "Lead": "Potenciales", + "Target": "Objetivo", + "Opportunity": "Oportunidad", + "Meeting": "Reunión", + "Calendar": "Calendario", + "Call": "Llamada", + "Task": "Tarea", + "Case": "Caso", + "InboundEmail": "Correo Entrante", + "Document": "Documento" + }, + "scopeNamesPlural": { + "Account": "Cuentas", + "Contact": "Contactos", + "Lead": "Potenciales", + "Target": "Objetivos", + "Opportunity": "Oportunidades", + "Meeting": "Reuniones", + "Calendar": "Calendario", + "Call": "Llamadas", + "Task": "Tareas", + "Case": "Casos", + "InboundEmail": "Correos Entrantes", + "Document": "Documentos" + }, + "dashlets": { + "Leads": "Mis potenciales", + "Opportunities": "Mis Opportunidades", + "Tasks": "Mis Tareas", + "Cases": "Mis Casos", + "Calendar": "Calendario", + "Calls": "", + "Meetings": "", + "OpportunitiesByStage": "Oportunidades por Etapa", + "OpportunitiesByLeadSource": "Oportunidades de origen de cliente potencial", + "SalesByMonth": "Ventas por Mes", + "SalesPipeline": "Canalización de ventas" + }, + "labels": { + "Create InboundEmail": "Crear Correo Entrante", + "Activities": "Actividades", + "History": "Historia", + "Attendees": "Los asistentes", + "Schedule Meeting": "Reunión Programada", + "Schedule Call": "Llamada Programada", + "Compose Email": "Escribir Correo", + "Log Meeting": "Log de Reunión", + "Log Call": "Log de Llamada", + "Archive Email": "Archivar Correo", + "Create Task": "Crear Tarea", + "Tasks": "Tareas" + }, + "fields": { + "billingAddressCity": "Ciudad", + "billingAddressCountry": "país", + "billingAddressPostalCode": "Código Postal", + "billingAddressState": "Estado/Distrito", + "billingAddressStreet": "Calle", + "addressCity": "Ciudad", + "addressStreet": "Calle", + "addressCountry": "país", + "addressState": "Estado/Distrito", + "addressPostalCode": "Código Postal", + "shippingAddressCity": "Ciudad (Envío)", + "shippingAddressStreet": "Calle (Envío)", + "shippingAddressCountry": "País (Envío)", + "shippingAddressState": "Estado (Envío)", + "shippingAddressPostalCode": "Código Postal (Envío)" + }, + "links": { + "contacts": "Contactos", + "opportunities": "Oportunidades", + "leads": "Potenciales", + "meetings": "Reuniones", + "calls": "Llamadas", + "tasks": "Tareas", + "emails": "Correos", + "accounts": "Cuentas", + "cases": "Casos", + "documents": "Documentos", + "account": "Cuenta", + "opportunity": "Oportunidad", + "contact": "Contacto", + "parent": "Padre" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/es_ES/InboundEmail.json b/application/Espo/Modules/Crm/Resources/i18n/es_ES/InboundEmail.json index 7c97cb4c23..fa3cc81d4c 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/es_ES/InboundEmail.json +++ b/application/Espo/Modules/Crm/Resources/i18n/es_ES/InboundEmail.json @@ -1,43 +1,52 @@ { - "fields": { - "name": "Nombre", - "team": "Equipo", - "status": "Estado", - "assignToUser": "Asignado a Usuario", - "host": "Host", - "username": "Nombre de Usuario", - "password": "Contraseña", - "port": "Puerto", - "monitoredFolders": "Carpetas supervisadas", - "trashFolder": "Carpeta Basura", - "ssl": "SSL", - "createCase": "Crear Caso", - "reply": "Responder", - "caseDistribution": "Caso Distribución", - "replyEmailTemplate": "Responder De Plantilla", - "replyFromAddress": "Responder De Dirección", - "replyFromName": "Responder De Nombre" - }, - "links": { - }, - "options": { - "status": { - "Active": "Activo", - "Inactive": "Inactivo" - }, - "caseDistribution": { - "Direct-Assignment": "Asignación-Directa", - "Round-Robin": "Round-Robin", - "Least-Busy": "Least-Busy" - } - }, - "labels": { - "Create InboundEmail": "Crear Correo Entrante", - "IMAP": "IMAP", - "Actions": "Acciones", - "Main": "Principal" - }, - "messages": { - "couldNotConnectToImap": "No se pudo conectar con el servidor IMAP" - } + "fields": { + "name": "Asunto", + "team": "Equipo", + "status": "Estado", + "assignToUser": "Asignado a Usuario", + "host": "Host", + "username": "Nombre de Usuario", + "password": "Contraseña", + "port": "Puerto", + "monitoredFolders": "Carpetas supervisadas", + "trashFolder": "Carpeta Basura", + "ssl": "SSL", + "createCase": "Crear Caso", + "reply": "Responder", + "caseDistribution": "Caso Distribución", + "replyEmailTemplate": "Plantilla Responder", + "replyFromAddress": "Responder De Dirección", + "replyToAddress": "Responder a Dirección", + "replyFromName": "Responder De Nombre" + }, + "tooltips": { + "reply": "Notificar al remitente que sus emails han sido recividos", + "createCase": "Crear asunto de forma automática para correos recibidos", + "replyToAddress": "Especificar esta dirección de correo electrónico para que las respuestas lleguen aquí", + "caseDistribution": "Asignar directamente a los usuarios del equipo de que forma serán distribuidoslos asuntos.", + "assignToUser": "Email usuario/asunto será asignado a.", + "team": "Email Equipo/asunto estará relacionado con" + }, + "links": { + }, + "options": { + "status": { + "Active": "Activo", + "Inactive": "Inactivo" + }, + "caseDistribution": { + "Direct-Assignment": "Asignación-Directa", + "Round-Robin": "Round-Robin", + "Least-Busy": "Menos-Ocupado" + } + }, + "labels": { + "Create InboundEmail": "Crear Correo Entrante", + "IMAP": "IMAP", + "Actions": "Acciones", + "Main": "Principal" + }, + "messages": { + "couldNotConnectToImap": "No se pudo conectar con el servidor IMAP" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/es_ES/Lead.json b/application/Espo/Modules/Crm/Resources/i18n/es_ES/Lead.json index 49af26dd68..5d711ca0e5 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/es_ES/Lead.json +++ b/application/Espo/Modules/Crm/Resources/i18n/es_ES/Lead.json @@ -1,48 +1,50 @@ { - "labels": { - "Converted To": "Convertido a", - "Create Lead": "Crear Principal", - "Convert": "Convertir" - }, - "fields": { - "name": "Nombre", - "emailAddress": "Correo electrónico", - "title": "Título", - "website": "Sito Web", - "phone": "Teléfono", - "phoneOffice": "Phone (Office)", - "fax": "Fax", - "accountName": "Nombre de Cuenta", - "doNotCall": "No Llamar", - "address": "Dirección", - "status": "Estado", - "source": "Fuente", - "opportunityAmount": "Oportunidad Cantidad", - "description": "Descripción", - "createdAccount": "Cuenta", - "createdContact": "Contacto", - "createdOpportunity": "Opportunidad" - }, - "links": { - }, - "options": { - "status": { - "New": "Nuevo", - "Assigned": "Asignado", - "In Process": "En Proceso", - "Converted": "Convertido", - "Recycled": "Reciclado", - "Dead": "Muerto" - }, - "source": { - "Call": "Llamada", - "Email": "Correo electrónico", - "Existing Customer": "Cliente Existente", - "Partner": "Partner", - "Public Relations": "Relaciones Públicas", - "Web Site": "Sitio Web", - "Campaign": "Campaña", - "Other": "Otro" - } - } + "labels": { + "Converted To": "Convertido a", + "Create Lead": "Crear Principal", + "Convert": "Convertir" + }, + "fields": { + "name": "Asunto", + "emailAddress": "Correo electrónico", + "title": "Título", + "website": "Sito Web", + "phoneNumber": "Teléfono", + "accountName": "Nombre de Cuenta", + "doNotCall": "No Llamar", + "address": "Dirección", + "status": "Estado", + "source": "Fuente", + "opportunityAmount": "Costo de Oportunidad", + "opportunityAmountConverted": "Costo de Oportunidad (convertido)", + "description": "Descripción", + "createdAccount": "Cuenta", + "createdContact": "Contacto", + "createdOpportunity": "Oportunidad" + }, + "links": { + }, + "options": { + "status": { + "New": "Nuevo", + "Assigned": "Asignado", + "In Process": "En Proceso", + "Converted": "Convertido", + "Recycled": "Reciclado", + "Dead": "Muerto" + }, + "source": { + "Call": "Llamada", + "Email": "Correo electrónico", + "Existing Customer": "Cliente Existente", + "Partner": "Socio", + "Public Relations": "Relaciones Públicas", + "Web Site": "Sitio Web", + "Campaign": "Campaña", + "Other": "Otro" + } + }, + "presetFilters": { + "active": "Activo" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/es_ES/Meeting.json b/application/Espo/Modules/Crm/Resources/i18n/es_ES/Meeting.json index 9397c8d72f..0e614215de 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/es_ES/Meeting.json +++ b/application/Espo/Modules/Crm/Resources/i18n/es_ES/Meeting.json @@ -1,29 +1,39 @@ { - "fields": { - "name": "Nombre", - "parent": "Padre", - "status": "Estado", - "dateStart": "Fecha de Comienzo", - "dateEnd": "Fecha de Finalización", - "duration": "Duración", - "description": "Descripción", - "users": "Usuarios", - "contacts": "Contactos", - "leads": "Potenciales" - }, - "links": { - }, - "options": { - "status": { - "Planned": "Planeada", - "Held": "Celebrada", - "Not Held": "Sin Celebrar" - } - }, - "labels": { - "Create Meeting": "Crear Reunión", - "Set Held": "Establecer Celebrada", - "Set Not Held": "Establecer no Celebrada", - "Send Invitations": "Enviar Invitaciones" - } + "fields": { + "name": "Asunto", + "parent": "Padre", + "status": "Estado", + "dateStart": "Fecha de Comienzo", + "dateEnd": "Fecha de Finalización", + "duration": "Duración", + "description": "Descripción", + "users": "Usuarios", + "contacts": "Contactos", + "leads": "Potenciales" + }, + "links": { + }, + "options": { + "status": { + "Planned": "Planeada", + "Held": "Celebrada", + "Not Held": "Sin Celebrar" + }, + "acceptanceStatus": { + "None": "Ninguno", + "Accepted": "Aceptado", + "Declined": "Rechazado" + } + }, + "labels": { + "Create Meeting": "Crear Reunión", + "Set Held": "Establecer Celebrada", + "Set Not Held": "Establecer no Celebrada", + "Send Invitations": "Enviar Invitaciones" + }, + "presetFilters": { + "planned": "Planeada", + "held": "Celebrada", + "todays": "De Hoy" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/es_ES/Opportunity.json b/application/Espo/Modules/Crm/Resources/i18n/es_ES/Opportunity.json index ebb095ff66..0fdb8c64c7 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/es_ES/Opportunity.json +++ b/application/Espo/Modules/Crm/Resources/i18n/es_ES/Opportunity.json @@ -1,43 +1,41 @@ { - "fields": { - "name": "Nombre", - "account": "Cuenta", - "stage": "Etapa", - "amount": "Cantidad", - "probability": "Probabilidad, %", - "leadSource": "Fuente Principal", - "doNotCall": "No Llamar", - "closeDate": "Fecha de cierre", - "description": "Descripción" - }, - "links": { - "contacts": "Contactos" - }, - "options": { - "stage": { - "Prospecting": "Prospección", - "Qualification": "Calificación", - "Needs Analysis": "Análisis de Necesidades", - "Value Proposition": "Valor de la Propuesta", - "Id. Decision Makers": "Id. Tomadores de Decisiones", - "Perception Analysis": "Análisis de la Percepción", - "Proposal/Price Quote": "Propuesta/precio Presupuesto", - "Negotiation/Review": "Negociación/Revisión", - "Closed Won": "Cerrado Ganado", - "Closed Lost": "Cerrado Perdido" - }, - "leadSource": { - "Call": "Llamada", - "Email": "Correo electrónico", - "Existing Customer": "Cliente Existente", - "Partner": "Partner", - "Public Relations": "Relaciones Públicas", - "Web Site": "Sitio Web", - "Campaign": "Campaña", - "Other": "Otro" - } - }, - "labels": { - "Create Opportunity": "Crear Oportunidad" - } + "fields": { + "name": "Asunto", + "account": "Cuenta", + "stage": "Etapa", + "amount": "Cantidad", + "probability": "Probabilidad, %", + "leadSource": "Fuente Principal", + "doNotCall": "No Llamar", + "closeDate": "Fecha de cierre", + "contacts": "Contactos", + "description": "Descripción", + "amountConverted": "Cantidad (convertido)", + "amountWeightedConverted": "Cantidad Ponderada" + }, + "links": { + "contacts": "Contactos", + "documents": "Documentos" + }, + "options": { + "stage": { + "Prospecting": "Prospección", + "Qualification": "Calificación", + "Needs Analysis": "Análisis de Necesidades", + "Value Proposition": "Valor de la Propuesta", + "Id. Decision Makers": "Id. Tomadores de Decisiones", + "Perception Analysis": "Análisis de la Percepción", + "Proposal/Price Quote": "Propuesta/precio Presupuesto", + "Negotiation/Review": "Negociación/Revisión", + "Closed Won": "Cerrado Ganado", + "Closed Lost": "Cerrado Perdido" + } + }, + "labels": { + "Create Opportunity": "Crear Oportunidad" + }, + "presetFilters": { + "open": "Abrir", + "won": "Ganado" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/es_ES/Target.json b/application/Espo/Modules/Crm/Resources/i18n/es_ES/Target.json index dcb08ce94f..da4e4dfb69 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/es_ES/Target.json +++ b/application/Espo/Modules/Crm/Resources/i18n/es_ES/Target.json @@ -1,21 +1,19 @@ { - "fields": { - "name": "Nombre", - "emailAddress": "Correo electrónico", - "title": "Título", - "website": "Sito Web", - "accountName": "Nombre de Cuenta", - "phone": "Teléfono", - "phoneOffice": "Phone (Office)", - "fax": "Fax", - "doNotCall": "No Llamar", - "address": "Dirección", - "description": "Descripción" - }, - "links": { - }, - "labels": { - "Create Target": "Crear Prospecto", - "Convert to Lead": "Convertir en Lider" - } + "fields": { + "name": "Asunto", + "emailAddress": "Correo electrónico", + "title": "Título", + "website": "Sito Web", + "accountName": "Nombre de Cuenta", + "phoneNumber": "Teléfono", + "doNotCall": "No Llamar", + "address": "Dirección", + "description": "Descripción" + }, + "links": { + }, + "labels": { + "Create Target": "Crear Objetivo", + "Convert to Lead": "Convertir en Lider" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/es_ES/Task.json b/application/Espo/Modules/Crm/Resources/i18n/es_ES/Task.json index a481c926a5..a3bb239bef 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/es_ES/Task.json +++ b/application/Espo/Modules/Crm/Resources/i18n/es_ES/Task.json @@ -1,31 +1,38 @@ { - "fields": { - "name": "Nombre", - "parent": "Padre", - "status": "Estado", - "dateStart": "Fecha de Comienzo", - "dateEnd": "Fecha de vencimiento", - "priority": "Prioridad", - "description": "Descripción", - "isOverdue": "Atrasado" - }, - "links": { - }, - "options": { - "status": { - "Not Started": "Sin Empezar", - "Started": "Comenzado", - "Completed": "Completado", - "Canceled": "Cancelado" - }, - "priority" : { - "Low": "Baja", - "Normal": "Normal", - "High": "Alta", - "Urgent": "Urgente" - } - }, - "labels": { - "Create Task": "Crear Tarea" - } + "fields": { + "name": "Asunto", + "parent": "Padre", + "status": "Estado", + "dateStart": "Fecha de Comienzo", + "dateEnd": "Fecha de vencimiento", + "priority": "Prioridad", + "description": "Descripción", + "isOverdue": "Atrasado" + }, + "links": { + }, + "options": { + "status": { + "Not Started": "Sin Empezar", + "Started": "Comenzado", + "Completed": "Completado", + "Canceled": "Cancelado" + }, + "priority" : { + "Low": "Baja", + "Normal": "Normal", + "High": "Alta", + "Urgent": "Urgente" + } + }, + "labels": { + "Create Task": "Crear Tarea", + "Complete": "Complete" + }, + "presetFilters": { + "actual": "Actual", + "completed": "Completado", + "todays": "De Hoy", + "overdue": "Con Atraso" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/fr_FR/Account.json b/application/Espo/Modules/Crm/Resources/i18n/fr_FR/Account.json index e0d38388fc..bf3561fa3a 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/fr_FR/Account.json +++ b/application/Espo/Modules/Crm/Resources/i18n/fr_FR/Account.json @@ -1,40 +1,40 @@ { - "fields": { - "name": "Nom", - "emailAddress": "Email", - "website": "Site Web", - "phoneNumber": "Téléphone", - "billingAddress": "Adresse de Facturation", - "shippingAddress": "Adresse de Livraison", - "description": "Description", - "sicCode": "Code SIC", - "industry": "Industrie", - "type": "Type", - "contactRole": "Rôle" - }, - "links": { - "contacts": "Contacts", - "opportunities": "Opportunités", - "cases": "Tickets" - }, - "options": { - "type": { - "Customer": "Clients", - "Investor": "Investisseur", - "Partner": "Partenaire", - "Reseller": "Revendeur" - }, - "industry": { - "Apparel": "Vêtements", - "Banking": "Banque", - "Computer Software": "Logiciel Informatique", - "Education": "Education", - "Electronics": "Electronique", - "Finance": "Finance", - "Insurance": "Assurance" - } - }, - "labels": { - "Create Account": "Nouveau Compte" - } + "fields": { + "name": "Nom", + "emailAddress": "Email", + "website": "Site Web", + "phoneNumber": "Téléphone", + "billingAddress": "Adresse de Facturation", + "shippingAddress": "Adresse de Livraison", + "description": "Description", + "sicCode": "Code SIC", + "industry": "Industrie", + "type": "Type", + "contactRole": "Rôle" + }, + "links": { + "contacts": "Contacts", + "opportunities": "Opportunités", + "cases": "Tickets" + }, + "options": { + "type": { + "Customer": "Clients", + "Investor": "Investisseur", + "Partner": "Partenaire", + "Reseller": "Revendeur" + }, + "industry": { + "Apparel": "Vêtements", + "Banking": "Banque", + "Computer Software": "Logiciel Informatique", + "Education": "Education", + "Electronics": "Electronique", + "Finance": "Finance", + "Insurance": "Assurance" + } + }, + "labels": { + "Create Account": "Nouveau Compte" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/fr_FR/Calendar.json b/application/Espo/Modules/Crm/Resources/i18n/fr_FR/Calendar.json index 3d6af35b3c..54944d13d6 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/fr_FR/Calendar.json +++ b/application/Espo/Modules/Crm/Resources/i18n/fr_FR/Calendar.json @@ -1,13 +1,13 @@ { - "modes": { - "month": "Mois", - "week": "Semaine", - "day": "Jour", - "agendaWeek": "Semaine", - "agendaDay": "Jour" - }, - "labels": { - "Today": "Aujourd'hui", - "Create": "Créer" - } + "modes": { + "month": "Mois", + "week": "Semaine", + "day": "Jour", + "agendaWeek": "Semaine", + "agendaDay": "Jour" + }, + "labels": { + "Today": "Aujourd'hui", + "Create": "Créer" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/fr_FR/Call.json b/application/Espo/Modules/Crm/Resources/i18n/fr_FR/Call.json index 5723890e67..2a51043bd2 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/fr_FR/Call.json +++ b/application/Espo/Modules/Crm/Resources/i18n/fr_FR/Call.json @@ -1,34 +1,34 @@ { - "fields": { - "name": "Nom", - "parent": "Parent", - "status": "Statut", - "dateStart": "Date de Début", - "dateEnd": "Date de Fin", - "direction": "Direction", - "duration": "Durée", - "description": "Description", - "users": "Utilisateurs", - "contacts": "Contacts", - "leads": "Leads" - }, - "links": { - }, - "options": { - "status": { - "Planned": "Plannifié", - "Held": "Fait", - "Not Held": "Pas Fait" - }, - "direction": { - "Outbound": "Sortie", - "Inbound": "Entrée" - } - }, - "labels": { - "Create Call": "Générer l'appel", - "Set Held": "Marquer Fait", - "Set Not Held": "Marquer Pas Fait", - "Send Invitations": "Envoi d'Invitations" - } + "fields": { + "name": "Nom", + "parent": "Parent", + "status": "Statut", + "dateStart": "Date de Début", + "dateEnd": "Date de Fin", + "direction": "Direction", + "duration": "Durée", + "description": "Description", + "users": "Utilisateurs", + "contacts": "Contacts", + "leads": "Leads" + }, + "links": { + }, + "options": { + "status": { + "Planned": "Plannifié", + "Held": "Fait", + "Not Held": "Pas Fait" + }, + "direction": { + "Outbound": "Sortie", + "Inbound": "Entrée" + } + }, + "labels": { + "Create Call": "Générer l'appel", + "Set Held": "Marquer Fait", + "Set Not Held": "Marquer Pas Fait", + "Send Invitations": "Envoi d'Invitations" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/fr_FR/Case.json b/application/Espo/Modules/Crm/Resources/i18n/fr_FR/Case.json index b010a6cf39..23cb86a43b 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/fr_FR/Case.json +++ b/application/Espo/Modules/Crm/Resources/i18n/fr_FR/Case.json @@ -1,38 +1,38 @@ { - "fields": { - "name": "Nom", - "number": "Numéro", - "status": "Statut", - "account": "Compte", - "contact": "Contact", - "priority": "Priorité", - "type": "Type", - "description": "Description" - }, - "links": { - }, - "options": { - "status": { - "New": "Nouveau", - "Assigned": "Assigné", - "Pending": "En attente", - "Closed": "Fermé", - "Rejected": "Rejeté", - "Duplicate": "Doublon" - }, - "priority" : { - "Low": "Bas", - "Normal": "Normal", - "High": "Haut", - "Urgent": "Urgent" - }, - "type": { - "Question": "Question", - "Incident": "Incident", - "Problem": "Problème" - } - }, - "labels": { - "Create Case": "Créer un Ticket" - } + "fields": { + "name": "Nom", + "number": "Numéro", + "status": "Statut", + "account": "Compte", + "contact": "Contact", + "priority": "Priorité", + "type": "Type", + "description": "Description" + }, + "links": { + }, + "options": { + "status": { + "New": "Nouveau", + "Assigned": "Assigné", + "Pending": "En attente", + "Closed": "Fermé", + "Rejected": "Rejeté", + "Duplicate": "Doublon" + }, + "priority" : { + "Low": "Bas", + "Normal": "Normal", + "High": "Haut", + "Urgent": "Urgent" + }, + "type": { + "Question": "Question", + "Incident": "Incident", + "Problem": "Problème" + } + }, + "labels": { + "Create Case": "Créer un Ticket" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/fr_FR/Contact.json b/application/Espo/Modules/Crm/Resources/i18n/fr_FR/Contact.json index 1dd7606a00..2e3b71af71 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/fr_FR/Contact.json +++ b/application/Espo/Modules/Crm/Resources/i18n/fr_FR/Contact.json @@ -1,31 +1,31 @@ { - "fields": { - "name": "Nom", - "emailAddress": "Email", - "title": "Titre", - "account": "Compte", - "accounts": "Comptes", - "phoneNumber": "Téléphone", - "accountType": "Type de Compte", - "doNotCall": "Ne Pas Appeler", - "address": "Adresse", - "opportunityRole": "Rôle de Challenge", - "accountRole": "Rôle", - "description": "Description" - }, - "links": { - "opportunities": "Opportunités", - "cases": "Tickets" - }, - "labels": { - "Create Contact": "Créer un contact" - }, - "options": { - "opportunityRole": { - "": "--Aucun--", - "Decision Maker": "Décisionnaire", - "Evaluator": "*Evaluator", - "Influencer": "Prescripteur" - } - } + "fields": { + "name": "Nom", + "emailAddress": "Email", + "title": "Titre", + "account": "Compte", + "accounts": "Comptes", + "phoneNumber": "Téléphone", + "accountType": "Type de Compte", + "doNotCall": "Ne Pas Appeler", + "address": "Adresse", + "opportunityRole": "Rôle de Challenge", + "accountRole": "Rôle", + "description": "Description" + }, + "links": { + "opportunities": "Opportunités", + "cases": "Tickets" + }, + "labels": { + "Create Contact": "Créer un contact" + }, + "options": { + "opportunityRole": { + "": "--Aucun--", + "Decision Maker": "Décisionnaire", + "Evaluator": "*Evaluator", + "Influencer": "Prescripteur" + } + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/fr_FR/Global.json b/application/Espo/Modules/Crm/Resources/i18n/fr_FR/Global.json index 390662d866..aca873937a 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/fr_FR/Global.json +++ b/application/Espo/Modules/Crm/Resources/i18n/fr_FR/Global.json @@ -1,79 +1,79 @@ { - "scopeNames": { - "Account": "Compte", - "Contact": "Contact", - "Lead": "Lead", - "Target": "Cible", - "Opportunity": "Challenge", - "Meeting": "Rendez-vous", - "Calendar": "Calendrier", - "Call": "Appel", - "Task": "Tâche", - "Case": "Ticket", - "InboundEmail": "Email Entrant" - }, - "scopeNamesPlural": { - "Account": "Comptes", - "Contact": "Contacts", - "Lead": "Leads", - "Target": "Cibles", - "Opportunity": "Opportunités", - "Meeting": "Rendez-vous", - "Calendar": "Calendrier", - "Call": "Appels", - "Task": "Tâches", - "Case": "Tickets", - "InboundEmail": "Emails Entrants" - }, - "dashlets": { - "Leads": "My Leads", - "Opportunities": "Mes Challenges", - "Tasks": "Mes Tâches", - "Cases": "Mes Tickets", - "Calendar": "Calendrier", - "OpportunitiesByStage": "*Challenges par étages", - "OpportunitiesByLeadSource": "Challenges par Lead Source", - "SalesByMonth": "Ventes par Mois", - "SalesPipeline": "Tuyaux des ventes" - }, - "labels": { - "Create InboundEmail": "Créer une boîte email", - "Activities": "Activités", - "History": "Historique", - "Attendees": "Participants", - "Schedule Meeting": "Rendez-vous Planifiés", - "Schedule Call": "Appels Planifiés", - "Compose Email": "Créer un Email", - "Log Meeting": "Journal des Rendez-vous", - "Log Call": "Journal d'appels", - "Archive Email": "Archiver les Emails", - "Create Task": "Créer une tâche", - "Tasks": "Tâches" - }, - "fields": { - "billingAddressCity": "Ville", - "billingAddressCountry": "Pays", - "billingAddressPostalCode": "Code Postal", - "billingAddressState": "Département", - "billingAddressStreet": "Rue", - "addressCity": "Ville", - "addressStreet": "Rue", - "addressCountry": "Pays", - "addressState": "Département", - "addressPostalCode": "Code Postal", - "shippingAddressCity": "City (Shipping)", - "shippingAddressStreet": "Street (Shipping)", - "shippingAddressCountry": "Country (Shipping)", - "shippingAddressState": "State (Shipping)", - "shippingAddressPostalCode": "Postal Code (Shipping)" - }, - "links": { - "contacts": "Contacts", - "opportunities": "Opportunités", - "leads": "Leads", - "meetings": "Rendez-vous", - "calls": "Appels", - "tasks": "Tâches", - "emails": "Courriers" - } + "scopeNames": { + "Account": "Compte", + "Contact": "Contact", + "Lead": "Lead", + "Target": "Cible", + "Opportunity": "Challenge", + "Meeting": "Rendez-vous", + "Calendar": "Calendrier", + "Call": "Appel", + "Task": "Tâche", + "Case": "Ticket", + "InboundEmail": "Email Entrant" + }, + "scopeNamesPlural": { + "Account": "Comptes", + "Contact": "Contacts", + "Lead": "Leads", + "Target": "Cibles", + "Opportunity": "Opportunités", + "Meeting": "Rendez-vous", + "Calendar": "Calendrier", + "Call": "Appels", + "Task": "Tâches", + "Case": "Tickets", + "InboundEmail": "Emails Entrants" + }, + "dashlets": { + "Leads": "My Leads", + "Opportunities": "Mes Challenges", + "Tasks": "Mes Tâches", + "Cases": "Mes Tickets", + "Calendar": "Calendrier", + "OpportunitiesByStage": "*Challenges par étages", + "OpportunitiesByLeadSource": "Challenges par Lead Source", + "SalesByMonth": "Ventes par Mois", + "SalesPipeline": "Tuyaux des ventes" + }, + "labels": { + "Create InboundEmail": "Créer une boîte email", + "Activities": "Activités", + "History": "Historique", + "Attendees": "Participants", + "Schedule Meeting": "Rendez-vous Planifiés", + "Schedule Call": "Appels Planifiés", + "Compose Email": "Créer un Email", + "Log Meeting": "Journal des Rendez-vous", + "Log Call": "Journal d'appels", + "Archive Email": "Archiver les Emails", + "Create Task": "Créer une tâche", + "Tasks": "Tâches" + }, + "fields": { + "billingAddressCity": "Ville", + "billingAddressCountry": "Pays", + "billingAddressPostalCode": "Code Postal", + "billingAddressState": "Département", + "billingAddressStreet": "Rue", + "addressCity": "Ville", + "addressStreet": "Rue", + "addressCountry": "Pays", + "addressState": "Département", + "addressPostalCode": "Code Postal", + "shippingAddressCity": "City (Shipping)", + "shippingAddressStreet": "Street (Shipping)", + "shippingAddressCountry": "Country (Shipping)", + "shippingAddressState": "State (Shipping)", + "shippingAddressPostalCode": "Postal Code (Shipping)" + }, + "links": { + "contacts": "Contacts", + "opportunities": "Opportunités", + "leads": "Leads", + "meetings": "Rendez-vous", + "calls": "Appels", + "tasks": "Tâches", + "emails": "Courriers" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/fr_FR/InboundEmail.json b/application/Espo/Modules/Crm/Resources/i18n/fr_FR/InboundEmail.json index caadedc5cd..ee4b4472f1 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/fr_FR/InboundEmail.json +++ b/application/Espo/Modules/Crm/Resources/i18n/fr_FR/InboundEmail.json @@ -1,43 +1,43 @@ { - "fields": { - "name": "Nom", - "team": "Equipe", - "status": "Statut", - "assignToUser": "Assigné à l'Utilisateur", - "host": "Hôte", - "username": "Nom d'utilisateur", - "password": "Mot de Passe", - "port": "Porte", - "monitoredFolders": "Dossiers Surveillés", - "trashFolder": "Corbeille", - "ssl": "SSL", - "createCase": "Créer un Ticket", - "reply": "Répondre", - "caseDistribution": "Distribution de tickets", - "replyEmailTemplate": "Modèle de Réponse par Email", - "replyFromAddress": "Répondre Depuis l'Adresse", - "replyFromName": "Répondre Depuis le Nom" - }, - "links": { - }, - "options": { - "status": { - "Active": "Activer", - "Inactive": "Désactiver" - }, - "caseDistribution": { - "Direct-Assignment": "Assignation Directe", - "Round-Robin": "Round-Robin", - "Least-Busy": "Least-Busy" - } - }, - "labels": { - "Create InboundEmail": "Créer une boîte email", - "IMAP": "IMAP", - "Actions": "Actions", - "Main": "Principal" - }, - "messages": { - "couldNotConnectToImap": "Impossible de se connecter au serveur IMAP" - } + "fields": { + "name": "Nom", + "team": "Equipe", + "status": "Statut", + "assignToUser": "Assigné à l'Utilisateur", + "host": "Hôte", + "username": "Nom d'utilisateur", + "password": "Mot de Passe", + "port": "Porte", + "monitoredFolders": "Dossiers Surveillés", + "trashFolder": "Corbeille", + "ssl": "SSL", + "createCase": "Créer un Ticket", + "reply": "Répondre", + "caseDistribution": "Distribution de tickets", + "replyEmailTemplate": "Modèle de Réponse par Email", + "replyFromAddress": "Répondre Depuis l'Adresse", + "replyFromName": "Répondre Depuis le Nom" + }, + "links": { + }, + "options": { + "status": { + "Active": "Activer", + "Inactive": "Désactiver" + }, + "caseDistribution": { + "Direct-Assignment": "Assignation Directe", + "Round-Robin": "Round-Robin", + "Least-Busy": "Least-Busy" + } + }, + "labels": { + "Create InboundEmail": "Créer une boîte email", + "IMAP": "IMAP", + "Actions": "Actions", + "Main": "Principal" + }, + "messages": { + "couldNotConnectToImap": "Impossible de se connecter au serveur IMAP" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/fr_FR/Lead.json b/application/Espo/Modules/Crm/Resources/i18n/fr_FR/Lead.json index 38f97b05f2..a01f0d5a04 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/fr_FR/Lead.json +++ b/application/Espo/Modules/Crm/Resources/i18n/fr_FR/Lead.json @@ -1,46 +1,46 @@ { - "labels": { - "Converted To": "Convertir Vers", - "Create Lead": "Créer Lead", - "Convert": "Convertir" - }, - "fields": { - "name": "Nom", - "emailAddress": "Email", - "title": "Titre", - "website": "Site Web", - "phoneNumber": "Téléphone", - "accountName": "Nom du Compte", - "doNotCall": "Ne Pas Appeler", - "address": "Adresse", - "status": "Statut", - "source": "Source", - "opportunityAmount": "Montant du Challenge", - "description": "Description", - "createdAccount": "Compte", - "createdContact": "Contact", - "createdOpportunity": "Challenge" - }, - "links": { - }, - "options": { - "status": { - "New": "Nouveau", - "Assigned": "Assigné", - "In Process": "En Cours de Traitement", - "Converted": "Converti", - "Recycled": "Supprimé", - "Dead": "Mort" - }, - "source": { - "Call": "Appel", - "Email": "Email", - "Existing Customer": "Client Existant", - "Partner": "Partenaire", - "Public Relations": "Relations publiques", - "Web Site": "Site Web", - "Campaign": "Campagne", - "Other": "Autre" - } - } + "labels": { + "Converted To": "Convertir Vers", + "Create Lead": "Créer Lead", + "Convert": "Convertir" + }, + "fields": { + "name": "Nom", + "emailAddress": "Email", + "title": "Titre", + "website": "Site Web", + "phoneNumber": "Téléphone", + "accountName": "Nom du Compte", + "doNotCall": "Ne Pas Appeler", + "address": "Adresse", + "status": "Statut", + "source": "Source", + "opportunityAmount": "Montant du Challenge", + "description": "Description", + "createdAccount": "Compte", + "createdContact": "Contact", + "createdOpportunity": "Challenge" + }, + "links": { + }, + "options": { + "status": { + "New": "Nouveau", + "Assigned": "Assigné", + "In Process": "En Cours de Traitement", + "Converted": "Converti", + "Recycled": "Supprimé", + "Dead": "Mort" + }, + "source": { + "Call": "Appel", + "Email": "Email", + "Existing Customer": "Client Existant", + "Partner": "Partenaire", + "Public Relations": "Relations publiques", + "Web Site": "Site Web", + "Campaign": "Campagne", + "Other": "Autre" + } + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/fr_FR/Meeting.json b/application/Espo/Modules/Crm/Resources/i18n/fr_FR/Meeting.json index e8f2684935..75ead64b60 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/fr_FR/Meeting.json +++ b/application/Espo/Modules/Crm/Resources/i18n/fr_FR/Meeting.json @@ -1,29 +1,29 @@ { - "fields": { - "name": "Nom", - "parent": "Parent", - "status": "Statut", - "dateStart": "Date de Début", - "dateEnd": "Date de Fin", - "duration": "Durée", - "description": "Description", - "users": "Utilisateurs", - "contacts": "Contacts", - "leads": "Leads" - }, - "links": { - }, - "options": { - "status": { - "Planned": "Plannifié", - "Held": "Fait", - "Not Held": "Pas Fait" - } - }, - "labels": { - "Create Meeting": "Créer un Rendez-vous", - "Set Held": "Marquer Fait", - "Set Not Held": "Marquer Pas Fait", - "Send Invitations": "Envoi d'Invitations" - } + "fields": { + "name": "Nom", + "parent": "Parent", + "status": "Statut", + "dateStart": "Date de Début", + "dateEnd": "Date de Fin", + "duration": "Durée", + "description": "Description", + "users": "Utilisateurs", + "contacts": "Contacts", + "leads": "Leads" + }, + "links": { + }, + "options": { + "status": { + "Planned": "Plannifié", + "Held": "Fait", + "Not Held": "Pas Fait" + } + }, + "labels": { + "Create Meeting": "Créer un Rendez-vous", + "Set Held": "Marquer Fait", + "Set Not Held": "Marquer Pas Fait", + "Send Invitations": "Envoi d'Invitations" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/fr_FR/Opportunity.json b/application/Espo/Modules/Crm/Resources/i18n/fr_FR/Opportunity.json index 97d5dabe9f..2f9a1c9bcf 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/fr_FR/Opportunity.json +++ b/application/Espo/Modules/Crm/Resources/i18n/fr_FR/Opportunity.json @@ -1,34 +1,34 @@ { - "fields": { - "name": "Nom", - "account": "Compte", - "stage": "Etage", - "amount": "Montant", - "probability": "Probabilité, %", - "leadSource": "Lead Source", - "doNotCall": "Ne Pas Appeler", - "closeDate": "Date de fermeture", - "contacts": "Contacts", - "description": "Description" - }, - "links": { - "contacts": "Contacts" - }, - "options": { - "stage": { - "Prospecting": "En Prospection", - "Qualification": "Qualification", - "Needs Analysis": "Analyse des besoins", - "Value Proposition": "Montant de la Proposition", - "Id. Decision Makers": "Id. Décisionnaire", - "Perception Analysis": "Analyse de la perception", - "Proposal/Price Quote": "Proposition/Devis", - "Negotiation/Review": "Négociation/avis", - "Closed Won": "Closed Won", - "Closed Lost": "Closed Lost" - } - }, - "labels": { - "Create Opportunity": "Créer un Challenge" - } + "fields": { + "name": "Nom", + "account": "Compte", + "stage": "Etage", + "amount": "Montant", + "probability": "Probabilité, %", + "leadSource": "Lead Source", + "doNotCall": "Ne Pas Appeler", + "closeDate": "Date de fermeture", + "contacts": "Contacts", + "description": "Description" + }, + "links": { + "contacts": "Contacts" + }, + "options": { + "stage": { + "Prospecting": "En Prospection", + "Qualification": "Qualification", + "Needs Analysis": "Analyse des besoins", + "Value Proposition": "Montant de la Proposition", + "Id. Decision Makers": "Id. Décisionnaire", + "Perception Analysis": "Analyse de la perception", + "Proposal/Price Quote": "Proposition/Devis", + "Negotiation/Review": "Négociation/avis", + "Closed Won": "Closed Won", + "Closed Lost": "Closed Lost" + } + }, + "labels": { + "Create Opportunity": "Créer un Challenge" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/fr_FR/Target.json b/application/Espo/Modules/Crm/Resources/i18n/fr_FR/Target.json index d9239ee90b..4f1a262d52 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/fr_FR/Target.json +++ b/application/Espo/Modules/Crm/Resources/i18n/fr_FR/Target.json @@ -1,19 +1,19 @@ { - "fields": { - "name": "Nom", - "emailAddress": "Email", - "title": "Titre", - "website": "Site Web", - "accountName": "Nom du Compte", - "phoneNumber": "Téléphone", - "doNotCall": "Ne Pas Appeler", - "address": "Adresse", - "description": "Description" - }, - "links": { - }, - "labels": { - "Create Target": "Créer une Cible", - "Convert to Lead": "Convertir en Lead" - } + "fields": { + "name": "Nom", + "emailAddress": "Email", + "title": "Titre", + "website": "Site Web", + "accountName": "Nom du Compte", + "phoneNumber": "Téléphone", + "doNotCall": "Ne Pas Appeler", + "address": "Adresse", + "description": "Description" + }, + "links": { + }, + "labels": { + "Create Target": "Créer une Cible", + "Convert to Lead": "Convertir en Lead" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/fr_FR/Task.json b/application/Espo/Modules/Crm/Resources/i18n/fr_FR/Task.json index 494c0fc9d0..5aee05bb20 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/fr_FR/Task.json +++ b/application/Espo/Modules/Crm/Resources/i18n/fr_FR/Task.json @@ -1,31 +1,31 @@ { - "fields": { - "name": "Nom", - "parent": "Parent", - "status": "Statut", - "dateStart": "Date de Début", - "dateEnd": "Date d'échéance", - "priority": "Priorité", - "description": "Description", - "isOverdue": "Est en Retard" - }, - "links": { - }, - "options": { - "status": { - "Not Started": "Pas Commencé", - "Started": "Commencé", - "Completed": "Terminé", - "Canceled": "Annulé" - }, - "priority" : { - "Low": "Bas", - "Normal": "Normal", - "High": "Haut", - "Urgent": "Urgent" - } - }, - "labels": { - "Create Task": "Créer une tâche" - } + "fields": { + "name": "Nom", + "parent": "Parent", + "status": "Statut", + "dateStart": "Date de Début", + "dateEnd": "Date d'échéance", + "priority": "Priorité", + "description": "Description", + "isOverdue": "Est en Retard" + }, + "links": { + }, + "options": { + "status": { + "Not Started": "Pas Commencé", + "Started": "Commencé", + "Completed": "Terminé", + "Canceled": "Annulé" + }, + "priority" : { + "Low": "Bas", + "Normal": "Normal", + "High": "Haut", + "Urgent": "Urgent" + } + }, + "labels": { + "Create Task": "Créer une tâche" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/nl_NL/Account.json b/application/Espo/Modules/Crm/Resources/i18n/nl_NL/Account.json index ea0cc1bfae..c3e0c4c9d3 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/nl_NL/Account.json +++ b/application/Espo/Modules/Crm/Resources/i18n/nl_NL/Account.json @@ -5,17 +5,18 @@ "website": "Website", "phoneNumber": "Telefoon", "billingAddress": "Factuur Adres", - "shippingAddress": "Bezoek adres", + "shippingAddress": "Verzend Adres", "description": "Beschrijving", "sicCode": "Sic Code", "industry": "Industrie", "type": "Type", - "contactRole": "Voorwaarde" + "contactRole": "Rol" }, "links": { - "contacts": "Contactpersoon", + "contacts": "Contacten", "opportunities": "Kansen", - "cases": "Zaken" + "cases": "Casus", + "documents": "Documents" }, "options": { "type": { @@ -25,16 +26,17 @@ "Reseller": "Reseller" }, "industry": { - "Apparel": "Apparel", - "Banking": "Banking", + "Apparel": "Confectie", + "Banking": "Bankwezen", "Computer Software": "Computer Software", - "Education": "Educatie", + "Education": "Onderwijs", "Electronics": "Electronica", "Finance": "Finance", "Insurance": "Verzekeringen" } }, "labels": { - "Create Account": "Maak Relatie" + "Create Account": "Klant Aanmaken", + "Copy Billing": "Kopieer van Factuur" } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/nl_NL/Calendar.json b/application/Espo/Modules/Crm/Resources/i18n/nl_NL/Calendar.json index 23ed5c0708..a4074733e2 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/nl_NL/Calendar.json +++ b/application/Espo/Modules/Crm/Resources/i18n/nl_NL/Calendar.json @@ -8,6 +8,6 @@ }, "labels": { "Today": "Vandaag", - "Create": "Maak" + "Create": "Aanmaken" } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/nl_NL/Call.json b/application/Espo/Modules/Crm/Resources/i18n/nl_NL/Call.json index f566efcbb1..f1a726b517 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/nl_NL/Call.json +++ b/application/Espo/Modules/Crm/Resources/i18n/nl_NL/Call.json @@ -6,34 +6,39 @@ "dateStart": "Start Datum", "dateEnd": "Eind Datum", "direction": "Richting", - "duration": "Gedurende", + "duration": "Duur", "description": "Beschrijving", "users": "Gebruikers", - "contacts": "Contactpersoon", + "contacts": "Contacten", "leads": "Leads" }, "links": { }, "options": { "status": { - "Planned": "Plannen", - "Held": "Volgen", - "Not Held": "Niet volgen" + "Planned": "Gepland", + "Held": "Vasthouden", + "Not Held": "Niet Vasthouden" }, "direction": { "Outbound": "Uitgaande", "Inbound": "Binnenkomende" + }, + "acceptanceStatus": { + "None": "Geen", + "Accepted": "Geaccepteerd", + "Declined": "Geweigerd" } }, "labels": { - "Create Call": "Maak Call", + "Create Call": "Tel. Gesprek Aanmaken", "Set Held": "Vasthouden", "Set Not Held": "Niet Vasthouden", "Send Invitations": "Uitnodiging versturen" }, "presetFilters": { - "planned": "Plannen", - "held": "Volgen", + "planned": "Gepland", + "held": "Vasthouden", "todays": "Vandaag" } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/nl_NL/Case.json b/application/Espo/Modules/Crm/Resources/i18n/nl_NL/Case.json index b8134a0f7b..b8ef6d4089 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/nl_NL/Case.json +++ b/application/Espo/Modules/Crm/Resources/i18n/nl_NL/Case.json @@ -3,7 +3,7 @@ "name": "Record Naam", "number": "Nummer", "status": "Status", - "account": "Relatie", + "account": "Klant", "contact": "Contact", "priority": "Prioriteit", "type": "Type", @@ -15,14 +15,14 @@ "status": { "New": "Nieuw", "Assigned": "Toegewezen", - "Pending": "Pending", + "Pending": "In afwachting", "Closed": "Gesloten", "Rejected": "Geweigerd", "Duplicate": "Dupliceer" }, "priority" : { "Low": "Laag", - "Normal": "Normaal", + "Normal": "Standaard", "High": "Hoog", "Urgent": "Urgent" }, @@ -33,7 +33,7 @@ } }, "labels": { - "Create Case": "Maak Case" + "Create Case": "Casus Aanmaken" }, "presetFilters": { "open": "Open", diff --git a/application/Espo/Modules/Crm/Resources/i18n/nl_NL/Contact.json b/application/Espo/Modules/Crm/Resources/i18n/nl_NL/Contact.json index 933ea953ef..8e07bbb23f 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/nl_NL/Contact.json +++ b/application/Espo/Modules/Crm/Resources/i18n/nl_NL/Contact.json @@ -3,22 +3,22 @@ "name": "Record Naam", "emailAddress": "Email", "title": "Titel", - "account": "Relatie", - "accounts": "Relaties", + "account": "Klant", + "accounts": "Klanten", "phoneNumber": "Telefoon", - "accountType": "Relatie Type", + "accountType": "Klant Type", "doNotCall": "Niet Bellen", "address": "Adres", - "opportunityRole": "Opportunity Role", - "accountRole": "Voorwaarde", + "opportunityRole": "Kans Rol", + "accountRole": "Rol", "description": "Beschrijving" }, "links": { "opportunities": "Kansen", - "cases": "Zaken" + "cases": "Casus" }, "labels": { - "Create Contact": "Maak Contact" + "Create Contact": "Contact Aanmaken" }, "options": { "opportunityRole": { diff --git a/application/Espo/Modules/Crm/Resources/i18n/nl_NL/Document.json b/application/Espo/Modules/Crm/Resources/i18n/nl_NL/Document.json new file mode 100644 index 0000000000..c599bbe841 --- /dev/null +++ b/application/Espo/Modules/Crm/Resources/i18n/nl_NL/Document.json @@ -0,0 +1,32 @@ +{ + "labels": { + "Create Document": "Document Aanmaken", + "Details": "Details" + }, + "fields": { + "name": "Record Naam", + "status": "Status", + "file": "Bestand", + "type": "Type", + "source": "Bron", + "publishDate": "Publicatiedatum", + "expirationDate": "Vervaldatum", + "description": "Beschrijving" + }, + "links": { + "accounts": "Klanten", + "opportunities": "Kansen" + }, + "options": { + "status": { + "Active": "Actief", + "Draft": "Concept", + "Expired": "Vervallen", + "Canceled": "Geannuleerd" + } + }, + "presetFilters": { + "active": "Actief", + "draft": "Concept" + } +} diff --git a/application/Espo/Modules/Crm/Resources/i18n/nl_NL/Global.json b/application/Espo/Modules/Crm/Resources/i18n/nl_NL/Global.json index 25544be147..23fc41fd22 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/nl_NL/Global.json +++ b/application/Espo/Modules/Crm/Resources/i18n/nl_NL/Global.json @@ -1,76 +1,78 @@ { "scopeNames": { - "Account": "Relatie", + "Account": "Klant", "Contact": "Contact", "Lead": "Lead", - "Target": "Doel", + "Target": "Target", "Opportunity": "Kans", "Meeting": "Vergadering", "Calendar": "Kalender", - "Call": "Oproep", + "Call": "Tel. Gesprek", "Task": "Taak", - "Case": "Zaak", - "InboundEmail": "Binnenkomende Email" + "Case": "Casus", + "InboundEmail": "Binnenkomende Email", + "Document": "Document" }, "scopeNamesPlural": { - "Account": "Relaties", - "Contact": "Contactpersoon", + "Account": "Klanten", + "Contact": "Contacten", "Lead": "Leads", - "Target": "Doel", + "Target": "Targets", "Opportunity": "Kansen", "Meeting": "Afspraken", "Calendar": "Kalender", "Call": "Tel.gesprekken", "Task": "Taken", - "Case": "Zaken", - "InboundEmail": "Inkomende Emails" + "Case": "Casus", + "InboundEmail": "Inkomende Emails", + "Document": "Documents" }, "dashlets": { "Leads": "Mijn Leads", "Opportunities": "Mijn Kansen", "Tasks": "Mijn Taken", - "Cases": "Mijn Zaken", + "Cases": "Mijn Casus", "Calendar": "Kalender", "Calls": "Mijn Tel.gesprekken", "Meetings": "Mijn Afspraken", "OpportunitiesByStage": "Status van Kansen", - "OpportunitiesByLeadSource": "Kans van Lead bron", + "OpportunitiesByLeadSource": "Kansen per Leadbron", "SalesByMonth": "Verkopen per maand", "SalesPipeline": "Verkoop mogelijkheden" }, "labels": { - "Create InboundEmail": "Instellen Email Gebruiker", + "Create InboundEmail": "Email Gebruiker Instellen", "Activities": "Activiteiten", "History": "Historie", "Attendees": "Genodigden", - "Schedule Meeting": "Plan Afspraak", + "Schedule Meeting": "Afspraak Plannen", "Schedule Call": "Geplande Oproep", - "Compose Email": "Maak een Email", - "Log Meeting": "Leg afspraak vast", - "Log Call": "Leg tel.afspraak vast", + "Compose Email": "Email aanmaken", + "Log Meeting": "Afspraak vastleggen", + "Log Call": "Tel. Gesprek Vastleggen", "Archive Email": "Archiveer Email", - "Create Task": "Maak een Taak", + "Create Task": "Taak Aanmaken", "Tasks": "Taken" }, "fields": { "billingAddressCity": "Plaats", "billingAddressCountry": "Land", "billingAddressPostalCode": "Postcode", - "billingAddressState": "Deelstaat", + "billingAddressState": "Provincie", "billingAddressStreet": "Straat", "addressCity": "Plaats", "addressStreet": "Straat", "addressCountry": "Land", - "addressState": "Deelstaat", + "addressState": "Provincie", "addressPostalCode": "Postcode", - "shippingAddressCity": "City (Shipping)", - "shippingAddressStreet": "Street (Shipping)", - "shippingAddressCountry": "Country (Shipping)", - "shippingAddressState": "State (Shipping)", - "shippingAddressPostalCode": "Postal Code (Shipping)" + "shippingAddressCity": "Plaats (Verzending)", + "shippingAddressStreet": "Straat (Verzending)", + "shippingAddressCountry": "Land (Verzending)", + "shippingAddressState": "Provincie (Verzending)", + "shippingAddressPostalCode": "Postcode (Verzending)" }, "links": { - "contacts": "Contactpersoon", + "contacts": "Contacten", "opportunities": "Kansen", "leads": "Leads", "meetings": "Afspraken", diff --git a/application/Espo/Modules/Crm/Resources/i18n/nl_NL/InboundEmail.json b/application/Espo/Modules/Crm/Resources/i18n/nl_NL/InboundEmail.json index 49b55511f4..91a3e5c3e8 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/nl_NL/InboundEmail.json +++ b/application/Espo/Modules/Crm/Resources/i18n/nl_NL/InboundEmail.json @@ -1,47 +1,47 @@ { "fields": { "name": "Record Naam", - "team": "Team", + "team": "Groep", "status": "Status", "assignToUser": "Toegewezen aan gebruiker", "host": "Host", "username": "Gebruikersnaam", "password": "Wachtwoord", - "port": "Poort", + "port": "Port", "monitoredFolders": "Gecontroleerde Folders", "trashFolder": "Prullenbak Folder", "ssl": "SSL", - "createCase": "Maak Case", - "reply": "Antw.", - "caseDistribution": "Zaak Verdelen", + "createCase": "Casus Aanmaken", + "reply": "Antwoord", + "caseDistribution": "Verdeling Casus", "replyEmailTemplate": "Antw. Email Template", "replyFromAddress": "Antw. van Adres", - "replyToAddress": "Reply To Address", + "replyToAddress": "Antwoord Naar Adres", "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." + "reply": "Afzenders berichten wanneer de email goed is aangekomen", + "createCase": "Automatisch casus aanmaken van inkomende emails.", + "replyToAddress": "Specifeer het emailadres van deze mailbox waar reacties in worden ontvangen.", + "caseDistribution": "Hoe casus toegewezen worden. Direct toegewezen aan gebruiker of de groep.", + "assignToUser": "Emails/casus gebruiker worden toegewezen aan.", + "team": "Groep email/casus worden gekoppeld aan." }, "links": { }, "options": { "status": { - "Active": "Active", - "Inactive": "Inactive" + "Active": "Actief", + "Inactive": "Inactief" }, "caseDistribution": { "Direct-Assignment": "Directe-Toewijzing", "Round-Robin": "Round-Robin", - "Least-Busy": "Minst-Bezet" + "Least-Busy": "Minst-Druk" } }, "labels": { - "Create InboundEmail": "Instellen Email Gebruiker", + "Create InboundEmail": "Email Gebruiker Instellen", "IMAP": "IMAP", "Actions": "Acties", "Main": "Hoofd" diff --git a/application/Espo/Modules/Crm/Resources/i18n/nl_NL/Lead.json b/application/Espo/Modules/Crm/Resources/i18n/nl_NL/Lead.json index 3b029cd72b..79aeaeb218 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/nl_NL/Lead.json +++ b/application/Espo/Modules/Crm/Resources/i18n/nl_NL/Lead.json @@ -1,8 +1,8 @@ { "labels": { - "Converted To": "Vertaald naar", - "Create Lead": "Grote Lead", - "Convert": "Converteer" + "Converted To": "Geconverteerd naar", + "Create Lead": "Lead Aanmaken", + "Convert": "Converteren" }, "fields": { "name": "Record Naam", @@ -10,15 +10,15 @@ "title": "Titel", "website": "Website", "phoneNumber": "Telefoon", - "accountName": "Relatie Naam", + "accountName": "Naam Klant", "doNotCall": "Niet Bellen", "address": "Adres", "status": "Status", "source": "Bron", - "opportunityAmount": "Aantal uitdagingen", - "opportunityAmountConverted": "Opportunity Amount (converted)", + "opportunityAmount": "Bedrag Kansen", + "opportunityAmountConverted": "Bedrag Kans (geconverteerd)", "description": "Beschrijving", - "createdAccount": "Relatie", + "createdAccount": "Klant", "createdContact": "Contact", "createdOpportunity": "Kans" }, @@ -29,22 +29,22 @@ "New": "Nieuw", "Assigned": "Toegewezen", "In Process": "In Behandeling", - "Converted": "Converteren", + "Converted": "Geconverteerd", "Recycled": "Opnieuw verwerkt", "Dead": "Dood" }, "source": { - "Call": "Oproep", + "Call": "Tel. Gesprek", "Email": "Email", "Existing Customer": "Bestaande Klant", "Partner": "Partner", "Public Relations": "Public Relations", - "Web Site": "Web Pagina", + "Web Site": "Website", "Campaign": "Campagne", - "Other": "Ander" + "Other": "Overig" } }, "presetFilters": { - "active": "Active" + "active": "Actief" } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/nl_NL/Meeting.json b/application/Espo/Modules/Crm/Resources/i18n/nl_NL/Meeting.json index a40b377220..4249f8d3b5 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/nl_NL/Meeting.json +++ b/application/Espo/Modules/Crm/Resources/i18n/nl_NL/Meeting.json @@ -5,19 +5,24 @@ "status": "Status", "dateStart": "Start Datum", "dateEnd": "Eind Datum", - "duration": "Gedurende", + "duration": "Duur", "description": "Beschrijving", "users": "Gebruikers", - "contacts": "Contactpersoon", + "contacts": "Contacten", "leads": "Leads" }, "links": { }, "options": { "status": { - "Planned": "Plannen", - "Held": "Volgen", - "Not Held": "Niet volgen" + "Planned": "Gepland", + "Held": "Vasthouden", + "Not Held": "Niet Vasthouden" + }, + "acceptanceStatus": { + "None": "Geen", + "Accepted": "Geaccepteerd", + "Declined": "Geweigerd" } }, "labels": { @@ -25,12 +30,12 @@ "Set Held": "Vasthouden", "Set Not Held": "Niet Vasthouden", "Send Invitations": "Uitnodiging versturen", - "Saved as Held": "Opslaan Bewaren", - "Saved as Not Held": "Opslaan niet Bewaren" + "Saved as Held": "Opgeslagen als Vasthouden", + "Saved as Not Held": "Opslaan als Niet Vasthouden" }, "presetFilters": { - "planned": "Plannen", - "held": "Volgen", + "planned": "Gepland", + "held": "Vasthouden", "todays": "Vandaag" } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/nl_NL/Opportunity.json b/application/Espo/Modules/Crm/Resources/i18n/nl_NL/Opportunity.json index 759770efb5..f48a0b7fac 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/nl_NL/Opportunity.json +++ b/application/Espo/Modules/Crm/Resources/i18n/nl_NL/Opportunity.json @@ -1,36 +1,37 @@ { "fields": { "name": "Record Naam", - "account": "Relatie", - "stage": "Status", + "account": "Klant", + "stage": "Stadium", "amount": "Aantal", - "probability": "Naar waarschijnlijkheid, %", - "leadSource": "Lead Bron", + "probability": "Waarschijnlijkheid, %", + "leadSource": "Leadbron", "doNotCall": "Niet Bellen", "closeDate": "Datum gesloten", - "contacts": "Contactpersoon", + "contacts": "Contacten", "description": "Beschrijving", - "amountConverted": "Amount (converted)" + "amountConverted": "Bedrag (geconverteerd)" }, "links": { - "contacts": "Contactpersoon" + "contacts": "Contacten", + "documents": "Documents" }, "options": { "stage": { - "Prospecting": "Prospecting", - "Qualification": "Kwalificeren", - "Needs Analysis": "Benodigde Analyse", - "Value Proposition": "Waarde Schatting", + "Prospecting": "Prospectie", + "Qualification": "Kwalificatie", + "Needs Analysis": "Analyse behoefte", + "Value Proposition": "Waarde voorstel", "Id. Decision Makers": "Id. Beslissiers", "Perception Analysis": "Perceptie Analyse", - "Proposal/Price Quote": "Prijs/Voorstel", - "Negotiation/Review": "Onderhandeling/Herziening", + "Proposal/Price Quote": "Voorstel/Offerte", + "Negotiation/Review": "Onderhandeling/Beoordeling", "Closed Won": "Gesloten Gewonnen", "Closed Lost": "Gesloten Verloren" } }, "labels": { - "Create Opportunity": "Grote Uitdaging" + "Create Opportunity": "Kans aanmaken" }, "presetFilters": { "open": "Open", diff --git a/application/Espo/Modules/Crm/Resources/i18n/nl_NL/Target.json b/application/Espo/Modules/Crm/Resources/i18n/nl_NL/Target.json index 40255a1666..79ad644fde 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/nl_NL/Target.json +++ b/application/Espo/Modules/Crm/Resources/i18n/nl_NL/Target.json @@ -4,7 +4,7 @@ "emailAddress": "Email", "title": "Titel", "website": "Website", - "accountName": "Relatie Naam", + "accountName": "Naam Klant", "phoneNumber": "Telefoon", "doNotCall": "Niet Bellen", "address": "Adres", @@ -13,7 +13,7 @@ "links": { }, "labels": { - "Create Target": "Maak een doel", - "Convert to Lead": "Naar Lead omzetten" + "Create Target": "Target Aanmaken", + "Convert to Lead": "Naar Lead converteren" } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/nl_NL/Task.json b/application/Espo/Modules/Crm/Resources/i18n/nl_NL/Task.json index 758dfb711b..853ba57a06 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/nl_NL/Task.json +++ b/application/Espo/Modules/Crm/Resources/i18n/nl_NL/Task.json @@ -15,22 +15,22 @@ "status": { "Not Started": "Niet Gestart", "Started": "Gestart", - "Completed": "Beeindigd", + "Completed": "Voltooid", "Canceled": "Geannuleerd" }, "priority" : { "Low": "Laag", - "Normal": "Normaal", + "Normal": "Standaard", "High": "Hoog", "Urgent": "Urgent" } }, "labels": { - "Create Task": "Maak een Taak" + "Create Task": "Taak Aanmaken" }, "presetFilters": { - "active": "Active", - "completed": "Beeindigd", + "actual": "Werkelijke", + "completed": "Voltooid", "todays": "Vandaag", "overdue": "Laat" } diff --git a/application/Espo/Modules/Crm/Resources/i18n/pl_PL/Account.json b/application/Espo/Modules/Crm/Resources/i18n/pl_PL/Account.json index bbf862ede4..b8bb78a45c 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/pl_PL/Account.json +++ b/application/Espo/Modules/Crm/Resources/i18n/pl_PL/Account.json @@ -1,40 +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" - } + "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" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/pl_PL/Calendar.json b/application/Espo/Modules/Crm/Resources/i18n/pl_PL/Calendar.json index 01f567da28..857ffb9508 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/pl_PL/Calendar.json +++ b/application/Espo/Modules/Crm/Resources/i18n/pl_PL/Calendar.json @@ -1,13 +1,13 @@ { - "modes": { - "month": "Miesiąc", - "week": "Tydzień", - "day": "Dzień", - "agendaWeek": "Tydzień", - "agendaDay": "Dzień" - }, - "labels": { - "Today": "Dziś", - "Create": "Utwórz" - } + "modes": { + "month": "Miesiąc", + "week": "Tydzień", + "day": "Dzień", + "agendaWeek": "Tydzień", + "agendaDay": "Dzień" + }, + "labels": { + "Today": "Dziś", + "Create": "Utwórz" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/pl_PL/Call.json b/application/Espo/Modules/Crm/Resources/i18n/pl_PL/Call.json index 92e071ea8f..6398d7952b 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/pl_PL/Call.json +++ b/application/Espo/Modules/Crm/Resources/i18n/pl_PL/Call.json @@ -1,39 +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" - } + "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" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/pl_PL/Case.json b/application/Espo/Modules/Crm/Resources/i18n/pl_PL/Case.json index 0996b7460f..2110bd1bc7 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/pl_PL/Case.json +++ b/application/Espo/Modules/Crm/Resources/i18n/pl_PL/Case.json @@ -1,42 +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" - } + "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" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/pl_PL/Contact.json b/application/Espo/Modules/Crm/Resources/i18n/pl_PL/Contact.json index e77e2ed136..54d9818cd0 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/pl_PL/Contact.json +++ b/application/Espo/Modules/Crm/Resources/i18n/pl_PL/Contact.json @@ -1,31 +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" - } - } + "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" + } + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/pl_PL/Global.json b/application/Espo/Modules/Crm/Resources/i18n/pl_PL/Global.json index e25da86e1f..82209b234f 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/pl_PL/Global.json +++ b/application/Espo/Modules/Crm/Resources/i18n/pl_PL/Global.json @@ -1,81 +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" - } + "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" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/pl_PL/InboundEmail.json b/application/Espo/Modules/Crm/Resources/i18n/pl_PL/InboundEmail.json index c5baa624f4..8b10eb7e99 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/pl_PL/InboundEmail.json +++ b/application/Espo/Modules/Crm/Resources/i18n/pl_PL/InboundEmail.json @@ -1,52 +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" - } + "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" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/pl_PL/Lead.json b/application/Espo/Modules/Crm/Resources/i18n/pl_PL/Lead.json index 70a692ca35..29a703833b 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/pl_PL/Lead.json +++ b/application/Espo/Modules/Crm/Resources/i18n/pl_PL/Lead.json @@ -1,50 +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" - } + "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" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/pl_PL/Meeting.json b/application/Espo/Modules/Crm/Resources/i18n/pl_PL/Meeting.json index fe144d8b3c..56f1418f70 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/pl_PL/Meeting.json +++ b/application/Espo/Modules/Crm/Resources/i18n/pl_PL/Meeting.json @@ -1,36 +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" - } + "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" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/pl_PL/Opportunity.json b/application/Espo/Modules/Crm/Resources/i18n/pl_PL/Opportunity.json index 175d4aef64..676a14d600 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/pl_PL/Opportunity.json +++ b/application/Espo/Modules/Crm/Resources/i18n/pl_PL/Opportunity.json @@ -1,39 +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" - } + "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" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/pl_PL/Target.json b/application/Espo/Modules/Crm/Resources/i18n/pl_PL/Target.json index 41459111c2..946c3f05d8 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/pl_PL/Target.json +++ b/application/Espo/Modules/Crm/Resources/i18n/pl_PL/Target.json @@ -1,19 +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" - } + "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" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/pl_PL/Task.json b/application/Espo/Modules/Crm/Resources/i18n/pl_PL/Task.json index 339bf82d5e..f0ed0e4c2f 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/pl_PL/Task.json +++ b/application/Espo/Modules/Crm/Resources/i18n/pl_PL/Task.json @@ -1,37 +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" - } + "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" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/pt_BR/Account.json b/application/Espo/Modules/Crm/Resources/i18n/pt_BR/Account.json index 9da5b0ce94..e98a6c7d1c 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/pt_BR/Account.json +++ b/application/Espo/Modules/Crm/Resources/i18n/pt_BR/Account.json @@ -1,40 +1,40 @@ { - "fields": { - "name": "Nome", - "emailAddress": "E-mail", - "website": "Website", - "phoneNumber": "Telefone", - "billingAddress": "Endereço de Cobrança", - "shippingAddress": "Endereço de Entrega", - "description": "Descrição", - "sicCode": "CNPJ", - "industry": "Indústria", - "type": "Tipo", - "contactRole": "Regra" - }, - "links": { - "contacts": "Contatos", - "opportunities": "Oportunidades", - "cases": "Atendimentos" - }, - "options": { - "type": { - "Customer": "Cliente", - "Investor": "Investidor", - "Partner": "Parceiro", - "Reseller": "Revendedor" - }, - "industry": { - "Apparel": "Vestuário", - "Banking": "Banco", - "Computer Software": "Software", - "Education": "Educação", - "Electronics": "Eletrônicos", - "Finance": "Finanças", - "Insurance": "Seguros" - } - }, - "labels": { - "Create Account": "Criar Conta" - } + "fields": { + "name": "Nome", + "emailAddress": "E-mail", + "website": "Website", + "phoneNumber": "Telefone", + "billingAddress": "Endereço de Cobrança", + "shippingAddress": "Endereço de Entrega", + "description": "Descrição", + "sicCode": "CNPJ", + "industry": "Indústria", + "type": "Tipo", + "contactRole": "Regra" + }, + "links": { + "contacts": "Contatos", + "opportunities": "Oportunidades", + "cases": "Atendimentos" + }, + "options": { + "type": { + "Customer": "Cliente", + "Investor": "Investidor", + "Partner": "Parceiro", + "Reseller": "Revendedor" + }, + "industry": { + "Apparel": "Vestuário", + "Banking": "Banco", + "Computer Software": "Software", + "Education": "Educação", + "Electronics": "Eletrônicos", + "Finance": "Finanças", + "Insurance": "Seguros" + } + }, + "labels": { + "Create Account": "Criar Conta" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/pt_BR/Calendar.json b/application/Espo/Modules/Crm/Resources/i18n/pt_BR/Calendar.json index 0a6b9d1323..5b5abfc8cd 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/pt_BR/Calendar.json +++ b/application/Espo/Modules/Crm/Resources/i18n/pt_BR/Calendar.json @@ -1,13 +1,13 @@ { - "modes": { - "month": "Mês", - "week": "Semana", - "day": "Dia", - "agendaWeek": "Semana", - "agendaDay": "Dia" - }, - "labels": { - "Today": "Hoje", - "Create": "Criar" - } + "modes": { + "month": "Mês", + "week": "Semana", + "day": "Dia", + "agendaWeek": "Semana", + "agendaDay": "Dia" + }, + "labels": { + "Today": "Hoje", + "Create": "Criar" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/pt_BR/Call.json b/application/Espo/Modules/Crm/Resources/i18n/pt_BR/Call.json index 38384d30cc..76b136773a 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/pt_BR/Call.json +++ b/application/Espo/Modules/Crm/Resources/i18n/pt_BR/Call.json @@ -24,11 +24,11 @@ "Outbound": "Saída", "Inbound": "Entrada" }, - "acceptanceStatus": { - "None": "Nenhum", - "Accepted": "Aceita", - "Declined": "Rejeitada" - } + "acceptanceStatus": { + "None": "Nenhum", + "Accepted": "Aceita", + "Declined": "Rejeitada" + } }, "labels": { "Create Call": "Criar Ligação", @@ -36,9 +36,9 @@ "Set Not Held": "Marcar como não realizada", "Send Invitations": "Enviar Convites" }, - "presetFilters": { - "planned": "Planejado", - "held": "Realizado", - "todays": "Hoje" - } + "presetFilters": { + "planned": "Planejado", + "held": "Realizado", + "todays": "Hoje" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/pt_BR/Case.json b/application/Espo/Modules/Crm/Resources/i18n/pt_BR/Case.json index afa5b5605f..a95bb5955a 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/pt_BR/Case.json +++ b/application/Espo/Modules/Crm/Resources/i18n/pt_BR/Case.json @@ -35,8 +35,8 @@ "labels": { "Create Case": "Criar Atendimento" }, - "presetFilters": { - "open": "Aberto", - "closed": "Fechado" - } + "presetFilters": { + "open": "Aberto", + "closed": "Fechado" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/pt_BR/Contact.json b/application/Espo/Modules/Crm/Resources/i18n/pt_BR/Contact.json index 2308d284be..b9c373e969 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/pt_BR/Contact.json +++ b/application/Espo/Modules/Crm/Resources/i18n/pt_BR/Contact.json @@ -4,13 +4,13 @@ "emailAddress": "E-mail", "title": "Cargo", "account": "Conta", - "accounts": "Contas", + "accounts": "Contas", "phoneNumber": "Telefone", - "accountType": "Tipo de Conta", + "accountType": "Tipo de Conta", "doNotCall": "Não Ligar", "address": "Endereço", "opportunityRole": "Regra de Oportunidade", - "accountRole": "Regra", + "accountRole": "Regra", "description": "Descrição" }, "links": { @@ -20,12 +20,12 @@ "labels": { "Create Contact": "Criar Contato" }, - "options": { - "opportunityRole": { - "": "--Nenhum--", - "Decision Maker": "Tomador de Decisão", - "Evaluator": "Avaliador", - "Influencer": "Influenciador" - } - } + "options": { + "opportunityRole": { + "": "--Nenhum--", + "Decision Maker": "Tomador de Decisão", + "Evaluator": "Avaliador", + "Influencer": "Influenciador" + } + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/pt_BR/Global.json b/application/Espo/Modules/Crm/Resources/i18n/pt_BR/Global.json index d4046b53e3..9de96be9cf 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/pt_BR/Global.json +++ b/application/Espo/Modules/Crm/Resources/i18n/pt_BR/Global.json @@ -31,8 +31,8 @@ "Tasks": "Minhas Tarefas", "Cases": "Meus Atendimentos", "Calendar": "Calendário", - "Calls": "Minhas Ligações", - "Meetings": "Minhas Reuniões", + "Calls": "Minhas Ligações", + "Meetings": "Minhas Reuniões", "OpportunitiesByStage": "Oportunidades por Estágio", "OpportunitiesByLeadSource": "Oportunities por Origem do Lead", "SalesByMonth": "Vendas Por Mês", diff --git a/application/Espo/Modules/Crm/Resources/i18n/pt_BR/InboundEmail.json b/application/Espo/Modules/Crm/Resources/i18n/pt_BR/InboundEmail.json index dd357fbd7d..5e9eab5d59 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/pt_BR/InboundEmail.json +++ b/application/Espo/Modules/Crm/Resources/i18n/pt_BR/InboundEmail.json @@ -15,18 +15,18 @@ "reply": "Responder", "caseDistribution": "Distribuição do Atendimento", "replyEmailTemplate": "Template do E-mail de Resposta", - "replyFromAddress": "E-mail de Resposta (From)", - "replyToAddress": "Responder para o Endereço", + "replyFromAddress": "E-mail de Resposta (From)", + "replyToAddress": "Responder para o Endereço", "replyFromName": "Nome de Resposta (FromName)" }, - "tooltips": { - "reply": "Notificar rementente que seus e-mails foram recebidos.", - "createCase": "Criar automaticamente um atendimento para os e-mais recebidos.", - "replyToAddress": "Especifique o endereço de e-mail desta caixa postal para que as respostas cheguem aqui.", - "caseDistribution": "Como os atendimentos serão distribuídos. Assinados diretamente ao usuário ou entregues ao time.", - "assignToUser": "Usuário responsável pelos e-mails/atendimentos.", - "team": "Time que será relacionado aos e-mails/atendimentos." - }, + "tooltips": { + "reply": "Notificar rementente que seus e-mails foram recebidos.", + "createCase": "Criar automaticamente um atendimento para os e-mais recebidos.", + "replyToAddress": "Especifique o endereço de e-mail desta caixa postal para que as respostas cheguem aqui.", + "caseDistribution": "Como os atendimentos serão distribuídos. Assinados diretamente ao usuário ou entregues ao time.", + "assignToUser": "Usuário responsável pelos e-mails/atendimentos.", + "team": "Time que será relacionado aos e-mails/atendimentos." + }, "links": { }, "options": { diff --git a/application/Espo/Modules/Crm/Resources/i18n/pt_BR/Lead.json b/application/Espo/Modules/Crm/Resources/i18n/pt_BR/Lead.json index 1faf15dd74..def3c33bc8 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/pt_BR/Lead.json +++ b/application/Espo/Modules/Crm/Resources/i18n/pt_BR/Lead.json @@ -16,7 +16,7 @@ "status": "Status", "source": "Origem", "opportunityAmount": "Valor da Oportunidade", - "opportunityAmountConverted": "Valor da Oportunidade (convertido)", + "opportunityAmountConverted": "Valor da Oportunidade (convertido)", "description": "Descrição", "createdAccount": "Conta", "createdContact": "Contato", @@ -44,7 +44,7 @@ "Other": "Outro" } }, - "presetFilters": { - "active": "Ativo" - } + "presetFilters": { + "active": "Ativo" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/pt_BR/Meeting.json b/application/Espo/Modules/Crm/Resources/i18n/pt_BR/Meeting.json index 06a12c49a9..e28161e995 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/pt_BR/Meeting.json +++ b/application/Espo/Modules/Crm/Resources/i18n/pt_BR/Meeting.json @@ -19,23 +19,23 @@ "Held": "Realizada", "Not Held": "Não Realizada" }, - "acceptanceStatus": { - "None": "Nenhum", - "Accepted": "Aceita", - "Declined": "Rejeitada" - } + "acceptanceStatus": { + "None": "Nenhum", + "Accepted": "Aceita", + "Declined": "Rejeitada" + } }, "labels": { "Create Meeting": "Criar Reunião", "Set Held": "Marcar como realizada", "Set Not Held": "Marcar como não realizada", "Send Invitations": "Enviar convites", - "Saved as Held": "Salvo como realizada", - "Saved as Not Held": "Salvo como não realizada" - }, - "presetFilters": { - "planned": "Planejada", - "held": "Realizada", - "todays": "Hoje" - } + "Saved as Held": "Salvo como realizada", + "Saved as Not Held": "Salvo como não realizada" + }, + "presetFilters": { + "planned": "Planejada", + "held": "Realizada", + "todays": "Hoje" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/pt_BR/Opportunity.json b/application/Espo/Modules/Crm/Resources/i18n/pt_BR/Opportunity.json index 9052afe26d..afc2537294 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/pt_BR/Opportunity.json +++ b/application/Espo/Modules/Crm/Resources/i18n/pt_BR/Opportunity.json @@ -8,9 +8,9 @@ "leadSource": "Lead de Origem", "doNotCall": "Não ligar", "closeDate": "Data de Fechamento", - "contacts": "Contatos", + "contacts": "Contatos", "description": "Descrição", - "amountConverted": "Valor (convertido)" + "amountConverted": "Valor (convertido)" }, "links": { "contacts": "Contatos" @@ -32,8 +32,8 @@ "labels": { "Create Opportunity": "Criar Oportunidade" }, - "presetFilters": { - "open": "Aberta", - "won": "Ganha" - } + "presetFilters": { + "open": "Aberta", + "won": "Ganha" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/pt_BR/Task.json b/application/Espo/Modules/Crm/Resources/i18n/pt_BR/Task.json index 5e85477939..b24555b233 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/pt_BR/Task.json +++ b/application/Espo/Modules/Crm/Resources/i18n/pt_BR/Task.json @@ -28,10 +28,10 @@ "labels": { "Create Task": "Criar Tarefa" }, - "presetFilters": { - "active": "Ativa", - "completed": "Completa", - "todays": "Hoje", - "overdue": "Atrasada" - } + "presetFilters": { + "active": "Ativa", + "completed": "Completa", + "todays": "Hoje", + "overdue": "Atrasada" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/ro_RO/Account.json b/application/Espo/Modules/Crm/Resources/i18n/ro_RO/Account.json index 6dd184c42a..5850b4b2f4 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/ro_RO/Account.json +++ b/application/Espo/Modules/Crm/Resources/i18n/ro_RO/Account.json @@ -1,40 +1,40 @@ { - "fields": { - "name": "Nume", - "emailAddress": "Email", - "website": "Site Web", - "phoneNumber": "Telefon", - "billingAddress": "Adresa de Facturare", - "shippingAddress": "Adresa de Transport", - "description": "Descriere", - "sicCode": "Cod Sic", - "industry": "Industrie", - "type": "Tip", - "contactRole": "Rol" - }, - "links": { - "contacts": "Contacte", - "opportunities": "Oportunitati", - "cases": "Cazuri" - }, - "options": { - "type": { - "Customer": "Client", - "Investor": "Investitor", - "Partner": "Partener", - "Reseller": "Reseller" - }, - "industry": { - "Apparel": "Haine", - "Banking": "Banking", - "Computer Software": "Software Computer", - "Education": "Educatie", - "Electronics": "Electronice", - "Finance": "Finante", - "Insurance": "Asigurari" - } - }, - "labels": { - "Create Account": "Creare cont" - } + "fields": { + "name": "Nume", + "emailAddress": "Email", + "website": "Site Web", + "phoneNumber": "Telefon", + "billingAddress": "Adresa de Facturare", + "shippingAddress": "Adresa de Transport", + "description": "Descriere", + "sicCode": "Cod Sic", + "industry": "Industrie", + "type": "Tip", + "contactRole": "Rol" + }, + "links": { + "contacts": "Contacte", + "opportunities": "Oportunitati", + "cases": "Cazuri" + }, + "options": { + "type": { + "Customer": "Client", + "Investor": "Investitor", + "Partner": "Partener", + "Reseller": "Reseller" + }, + "industry": { + "Apparel": "Haine", + "Banking": "Banking", + "Computer Software": "Software Computer", + "Education": "Educatie", + "Electronics": "Electronice", + "Finance": "Finante", + "Insurance": "Asigurari" + } + }, + "labels": { + "Create Account": "Creare cont" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/ro_RO/Calendar.json b/application/Espo/Modules/Crm/Resources/i18n/ro_RO/Calendar.json index 4a3d4bbc30..f74ca24ff8 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/ro_RO/Calendar.json +++ b/application/Espo/Modules/Crm/Resources/i18n/ro_RO/Calendar.json @@ -1,13 +1,13 @@ { - "modes": { - "month": "Luna", - "week": "Saptamana", - "day": "Zi", - "agendaWeek": "Saptamana", - "agendaDay": "Zi" - }, - "labels": { - "Today": "Astazi", - "Create": "Creaza" - } + "modes": { + "month": "Luna", + "week": "Saptamana", + "day": "Zi", + "agendaWeek": "Saptamana", + "agendaDay": "Zi" + }, + "labels": { + "Today": "Astazi", + "Create": "Creaza" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/ro_RO/Call.json b/application/Espo/Modules/Crm/Resources/i18n/ro_RO/Call.json index e30d4fa865..ecfd7b181c 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/ro_RO/Call.json +++ b/application/Espo/Modules/Crm/Resources/i18n/ro_RO/Call.json @@ -1,39 +1,39 @@ { - "fields": { - "name": "Nume", - "parent": "Parinte", - "status": "Status", - "dateStart": "Data inceput", - "dateEnd": "Data terminare", - "direction": "Directie", - "duration": "Durata", - "description": "Descriere", - "users": "Utilizatori", - "contacts": "Contacte", - "leads": "Lead-uri" - }, - "links": { - }, - "options": { - "status": { - "Planned": "Planificat", - "Held": "Detinut", - "Not Held": "Nedetinut" - }, - "direction": { - "Outbound": "Iesire", - "Inbound": "Intrare" - } - }, - "labels": { - "Create Call": "Creare Apelare", - "Set Held": "Setare detinere", - "Set Not Held": "Setare nedetinere", - "Send Invitations": "Trimite invitatii" - }, - "presetFilters": { - "planned": "Planificat", - "held": "Detinut", - "todays": "Today's" - } + "fields": { + "name": "Nume", + "parent": "Parinte", + "status": "Status", + "dateStart": "Data inceput", + "dateEnd": "Data terminare", + "direction": "Directie", + "duration": "Durata", + "description": "Descriere", + "users": "Utilizatori", + "contacts": "Contacte", + "leads": "Lead-uri" + }, + "links": { + }, + "options": { + "status": { + "Planned": "Planificat", + "Held": "Detinut", + "Not Held": "Nedetinut" + }, + "direction": { + "Outbound": "Iesire", + "Inbound": "Intrare" + } + }, + "labels": { + "Create Call": "Creare Apelare", + "Set Held": "Setare detinere", + "Set Not Held": "Setare nedetinere", + "Send Invitations": "Trimite invitatii" + }, + "presetFilters": { + "planned": "Planificat", + "held": "Detinut", + "todays": "Today's" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/ro_RO/Case.json b/application/Espo/Modules/Crm/Resources/i18n/ro_RO/Case.json index a1211b4b8f..c473559e5b 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/ro_RO/Case.json +++ b/application/Espo/Modules/Crm/Resources/i18n/ro_RO/Case.json @@ -1,42 +1,42 @@ { - "fields": { - "name": "Nume", - "number": "Numar", - "status": "Status", - "account": "Cont", - "contact": "Contact", - "priority": "Prioritate", - "type": "Tip", - "description": "Descriere" - }, - "links": { - }, - "options": { - "status": { - "New": "Nou", - "Assigned": "Alocat", - "Pending": "In asteptare", - "Closed": "Inchis", - "Rejected": "Respins", - "Duplicate": "Duplicat" - }, - "priority" : { - "Low": "Scazut", - "Normal": "Normal", - "High": "Inalt", - "Urgent": "Urgent" - }, - "type": { - "Question": "Intrebare", - "Incident": "Incident", - "Problem": "Problema" - } - }, - "labels": { - "Create Case": "Creare Caz" - }, - "presetFilters": { - "open": "Deschide", - "closed": "Inchis" - } + "fields": { + "name": "Nume", + "number": "Numar", + "status": "Status", + "account": "Cont", + "contact": "Contact", + "priority": "Prioritate", + "type": "Tip", + "description": "Descriere" + }, + "links": { + }, + "options": { + "status": { + "New": "Nou", + "Assigned": "Alocat", + "Pending": "In asteptare", + "Closed": "Inchis", + "Rejected": "Respins", + "Duplicate": "Duplicat" + }, + "priority" : { + "Low": "Scazut", + "Normal": "Normal", + "High": "Inalt", + "Urgent": "Urgent" + }, + "type": { + "Question": "Intrebare", + "Incident": "Incident", + "Problem": "Problema" + } + }, + "labels": { + "Create Case": "Creare Caz" + }, + "presetFilters": { + "open": "Deschide", + "closed": "Inchis" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/ro_RO/Contact.json b/application/Espo/Modules/Crm/Resources/i18n/ro_RO/Contact.json index d85af57b9b..2efe08045c 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/ro_RO/Contact.json +++ b/application/Espo/Modules/Crm/Resources/i18n/ro_RO/Contact.json @@ -1,31 +1,31 @@ { - "fields": { - "name": "Nume", - "emailAddress": "Email", - "title": "Titlu", - "account": "Cont", - "accounts": "Conturi", - "phoneNumber": "Telefon", - "accountType": "Tip cont", - "doNotCall": "Nu sunati", - "address": "Adresa", - "opportunityRole": "Opportunity Role", - "accountRole": "Rol", - "description": "Descriere" - }, - "links": { - "opportunities": "Oportunitati", - "cases": "Cazuri" - }, - "labels": { - "Create Contact": "Creare Contact" - }, - "options": { - "opportunityRole": { - "": "--None--", - "Decision Maker": "Decision Maker", - "Evaluator": "Evaluator", - "Influencer": "Influencer" - } - } + "fields": { + "name": "Nume", + "emailAddress": "Email", + "title": "Titlu", + "account": "Cont", + "accounts": "Conturi", + "phoneNumber": "Telefon", + "accountType": "Tip cont", + "doNotCall": "Nu sunati", + "address": "Adresa", + "opportunityRole": "Opportunity Role", + "accountRole": "Rol", + "description": "Descriere" + }, + "links": { + "opportunities": "Oportunitati", + "cases": "Cazuri" + }, + "labels": { + "Create Contact": "Creare Contact" + }, + "options": { + "opportunityRole": { + "": "--None--", + "Decision Maker": "Decision Maker", + "Evaluator": "Evaluator", + "Influencer": "Influencer" + } + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/ro_RO/Global.json b/application/Espo/Modules/Crm/Resources/i18n/ro_RO/Global.json index f81448c4af..184b730026 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/ro_RO/Global.json +++ b/application/Espo/Modules/Crm/Resources/i18n/ro_RO/Global.json @@ -1,79 +1,79 @@ { - "scopeNames": { - "Account": "Cont", - "Contact": "Contact", - "Lead": "Lead", - "Target": "Tinta", - "Opportunity": "Oportunitate", - "Meeting": "Intalnire", - "Calendar": "Calendar", - "Call": "Apel", - "Task": "Activitate", - "Case": "Caz", - "InboundEmail": "Intrari Email" - }, - "scopeNamesPlural": { - "Account": "Conturi", - "Contact": "Contacte", - "Lead": "Lead-uri", - "Target": "Tinte", - "Opportunity": "Oportunitati", - "Meeting": "Intalniri", - "Calendar": "Calendar", - "Call": "Apeluri", - "Task": "Activitati", - "Case": "Cazuri", - "InboundEmail": "Email-uri intrate" - }, - "dashlets": { - "Leads": "Lead-urile mele", - "Opportunities": "Oportunitatile mele", - "Tasks": "Activitatile mele", - "Cases": "Cazurile mele", - "Calendar": "Calendar", - "OpportunitiesByStage": "Oportunitati in functie de stadiu", - "OpportunitiesByLeadSource": "Oportunitati in functie de Sursal Lead-ului", - "SalesByMonth": "Vanzari pe luna", - "SalesPipeline": "Flux Vanzari" - }, - "labels": { - "Create InboundEmail": "Creare Email intrare", - "Activities": "Activitati", - "History": "Istoric", - "Attendees": "Participanti", - "Schedule Meeting": "Programeaza Intalnire", - "Schedule Call": "Programeaza Apel", - "Compose Email": "Compune Email", - "Log Meeting": "Log Intalnire", - "Log Call": "Log Apel", - "Archive Email": "Arhiveaza Email", - "Create Task": "Creaza Activitate", - "Tasks": "Activitati" - }, - "fields": { - "billingAddressCity": "Oras", - "billingAddressCountry": "Tara", - "billingAddressPostalCode": "Code Postal ", - "billingAddressState": "Stat", - "billingAddressStreet": "Strada", - "addressCity": "Oras", - "addressStreet": "Strada", - "addressCountry": "Tara", - "addressState": "Stat", - "addressPostalCode": "Code Postal ", - "shippingAddressCity": "City (Shipping)", - "shippingAddressStreet": "Street (Shipping)", - "shippingAddressCountry": "Country (Shipping)", - "shippingAddressState": "State (Shipping)", - "shippingAddressPostalCode": "Postal Code (Shipping)" - }, - "links": { - "contacts": "Contacte", - "opportunities": "Oportunitati", - "leads": "Lead-uri", - "meetings": "Intalniri", - "calls": "Apeluri", - "tasks": "Activitati", - "emails": "Email-uri" - } + "scopeNames": { + "Account": "Cont", + "Contact": "Contact", + "Lead": "Lead", + "Target": "Tinta", + "Opportunity": "Oportunitate", + "Meeting": "Intalnire", + "Calendar": "Calendar", + "Call": "Apel", + "Task": "Activitate", + "Case": "Caz", + "InboundEmail": "Intrari Email" + }, + "scopeNamesPlural": { + "Account": "Conturi", + "Contact": "Contacte", + "Lead": "Lead-uri", + "Target": "Tinte", + "Opportunity": "Oportunitati", + "Meeting": "Intalniri", + "Calendar": "Calendar", + "Call": "Apeluri", + "Task": "Activitati", + "Case": "Cazuri", + "InboundEmail": "Email-uri intrate" + }, + "dashlets": { + "Leads": "Lead-urile mele", + "Opportunities": "Oportunitatile mele", + "Tasks": "Activitatile mele", + "Cases": "Cazurile mele", + "Calendar": "Calendar", + "OpportunitiesByStage": "Oportunitati in functie de stadiu", + "OpportunitiesByLeadSource": "Oportunitati in functie de Sursal Lead-ului", + "SalesByMonth": "Vanzari pe luna", + "SalesPipeline": "Flux Vanzari" + }, + "labels": { + "Create InboundEmail": "Creare Email intrare", + "Activities": "Activitati", + "History": "Istoric", + "Attendees": "Participanti", + "Schedule Meeting": "Programeaza Intalnire", + "Schedule Call": "Programeaza Apel", + "Compose Email": "Compune Email", + "Log Meeting": "Log Intalnire", + "Log Call": "Log Apel", + "Archive Email": "Arhiveaza Email", + "Create Task": "Creaza Activitate", + "Tasks": "Activitati" + }, + "fields": { + "billingAddressCity": "Oras", + "billingAddressCountry": "Tara", + "billingAddressPostalCode": "Code Postal ", + "billingAddressState": "Stat", + "billingAddressStreet": "Strada", + "addressCity": "Oras", + "addressStreet": "Strada", + "addressCountry": "Tara", + "addressState": "Stat", + "addressPostalCode": "Code Postal ", + "shippingAddressCity": "City (Shipping)", + "shippingAddressStreet": "Street (Shipping)", + "shippingAddressCountry": "Country (Shipping)", + "shippingAddressState": "State (Shipping)", + "shippingAddressPostalCode": "Postal Code (Shipping)" + }, + "links": { + "contacts": "Contacte", + "opportunities": "Oportunitati", + "leads": "Lead-uri", + "meetings": "Intalniri", + "calls": "Apeluri", + "tasks": "Activitati", + "emails": "Email-uri" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/ro_RO/InboundEmail.json b/application/Espo/Modules/Crm/Resources/i18n/ro_RO/InboundEmail.json index c4585fdf4c..62fb09e410 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/ro_RO/InboundEmail.json +++ b/application/Espo/Modules/Crm/Resources/i18n/ro_RO/InboundEmail.json @@ -1,43 +1,43 @@ { - "fields": { - "name": "Nume", - "team": "Echipa", - "status": "Status", - "assignToUser": "Atribuie utilizatorului", - "host": "Gazda", - "username": "Nume Utilizator", - "password": "Parola", - "port": "Port", - "monitoredFolders": "Directoare Monitorizate", - "trashFolder": "Gunoi", - "ssl": "SSL", - "createCase": "Creare Caz", - "reply": "Raspunde", - "caseDistribution": "Distribuire Caz", - "replyEmailTemplate": "Template Raspuns Email ", - "replyFromAddress": "Raspunde cu Adresa", - "replyFromName": "Raspunde cu Numele" - }, - "links": { - }, - "options": { - "status": { - "Active": "Activ", - "Inactive": "Inactiv" - }, - "caseDistribution": { - "Direct-Assignment": "Atribuire directa", - "Round-Robin": "Round-Robin", - "Least-Busy": "Cel putin, Ocupat" - } - }, - "labels": { - "Create InboundEmail": "Creare Email intrare", - "IMAP": "IMAP", - "Actions": "Actiuni", - "Main": "Principal" - }, - "messages": { - "couldNotConnectToImap": "Could neconectat la server-ul IMAP" - } + "fields": { + "name": "Nume", + "team": "Echipa", + "status": "Status", + "assignToUser": "Atribuie utilizatorului", + "host": "Gazda", + "username": "Nume Utilizator", + "password": "Parola", + "port": "Port", + "monitoredFolders": "Directoare Monitorizate", + "trashFolder": "Gunoi", + "ssl": "SSL", + "createCase": "Creare Caz", + "reply": "Raspunde", + "caseDistribution": "Distribuire Caz", + "replyEmailTemplate": "Template Raspuns Email ", + "replyFromAddress": "Raspunde cu Adresa", + "replyFromName": "Raspunde cu Numele" + }, + "links": { + }, + "options": { + "status": { + "Active": "Activ", + "Inactive": "Inactiv" + }, + "caseDistribution": { + "Direct-Assignment": "Atribuire directa", + "Round-Robin": "Round-Robin", + "Least-Busy": "Cel putin, Ocupat" + } + }, + "labels": { + "Create InboundEmail": "Creare Email intrare", + "IMAP": "IMAP", + "Actions": "Actiuni", + "Main": "Principal" + }, + "messages": { + "couldNotConnectToImap": "Could neconectat la server-ul IMAP" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/ro_RO/Lead.json b/application/Espo/Modules/Crm/Resources/i18n/ro_RO/Lead.json index 5ccb05d062..fb52fa87f9 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/ro_RO/Lead.json +++ b/application/Espo/Modules/Crm/Resources/i18n/ro_RO/Lead.json @@ -1,49 +1,49 @@ { - "labels": { - "Converted To": "Convertit la", - "Create Lead": "Creare Lead", - "Convert": "Converteste" - }, - "fields": { - "name": "Nume", - "emailAddress": "Email", - "title": "Titlu", - "website": "Site Web", - "phoneNumber": "Telefon", - "accountName": "Nume Cont", - "doNotCall": "Nu sunati", - "address": "Adresa", - "status": "Status", - "source": "Sursa", - "opportunityAmount": "Suma Oportunitate", - "description": "Descriere", - "createdAccount": "Cont", - "createdContact": "Contact", - "createdOpportunity": "Oportunitate" - }, - "links": { - }, - "options": { - "status": { - "New": "Nou", - "Assigned": "Alocat", - "In Process": "In Proces", - "Converted": "Convertit", - "Recycled": "Reciclat", - "Dead": "Inactiv" - }, - "source": { - "Call": "Apel", - "Email": "Email", - "Existing Customer": "Client Existent", - "Partner": "Partener", - "Public Relations": "Relatii Publice", - "Web Site": "Site Web", - "Campaign": "Campanie", - "Other": "Altele" - } - }, - "presetFilters": { - "active": "Activ" - } + "labels": { + "Converted To": "Convertit la", + "Create Lead": "Creare Lead", + "Convert": "Converteste" + }, + "fields": { + "name": "Nume", + "emailAddress": "Email", + "title": "Titlu", + "website": "Site Web", + "phoneNumber": "Telefon", + "accountName": "Nume Cont", + "doNotCall": "Nu sunati", + "address": "Adresa", + "status": "Status", + "source": "Sursa", + "opportunityAmount": "Suma Oportunitate", + "description": "Descriere", + "createdAccount": "Cont", + "createdContact": "Contact", + "createdOpportunity": "Oportunitate" + }, + "links": { + }, + "options": { + "status": { + "New": "Nou", + "Assigned": "Alocat", + "In Process": "In Proces", + "Converted": "Convertit", + "Recycled": "Reciclat", + "Dead": "Inactiv" + }, + "source": { + "Call": "Apel", + "Email": "Email", + "Existing Customer": "Client Existent", + "Partner": "Partener", + "Public Relations": "Relatii Publice", + "Web Site": "Site Web", + "Campaign": "Campanie", + "Other": "Altele" + } + }, + "presetFilters": { + "active": "Activ" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/ro_RO/Meeting.json b/application/Espo/Modules/Crm/Resources/i18n/ro_RO/Meeting.json index 905b7b0bf8..18d81cea14 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/ro_RO/Meeting.json +++ b/application/Espo/Modules/Crm/Resources/i18n/ro_RO/Meeting.json @@ -1,36 +1,36 @@ { - "fields": { - "name": "Nume", - "parent": "Parinte", - "status": "Status", - "dateStart": "Data inceput", - "dateEnd": "Data terminare", - "duration": "Durata", - "description": "Descriere", - "users": "Utilizatori", - "contacts": "Contacte", - "leads": "Lead-uri" - }, - "links": { - }, - "options": { - "status": { - "Planned": "Planificat", - "Held": "Detinut", - "Not Held": "Nedetinut" - } - }, - "labels": { - "Create Meeting": "Creare Intalnire", - "Set Held": "Setare detinere", - "Set Not Held": "Setare nedetinere", - "Send Invitations": "Trimite invitatii", - "Saved as Held": "Saved as Held", - "Saved as Not Held": "Saved as Not Held" - }, - "presetFilters": { - "planned": "Planificat", - "held": "Detinut", - "todays": "Today's" - } + "fields": { + "name": "Nume", + "parent": "Parinte", + "status": "Status", + "dateStart": "Data inceput", + "dateEnd": "Data terminare", + "duration": "Durata", + "description": "Descriere", + "users": "Utilizatori", + "contacts": "Contacte", + "leads": "Lead-uri" + }, + "links": { + }, + "options": { + "status": { + "Planned": "Planificat", + "Held": "Detinut", + "Not Held": "Nedetinut" + } + }, + "labels": { + "Create Meeting": "Creare Intalnire", + "Set Held": "Setare detinere", + "Set Not Held": "Setare nedetinere", + "Send Invitations": "Trimite invitatii", + "Saved as Held": "Saved as Held", + "Saved as Not Held": "Saved as Not Held" + }, + "presetFilters": { + "planned": "Planificat", + "held": "Detinut", + "todays": "Today's" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/ro_RO/Opportunity.json b/application/Espo/Modules/Crm/Resources/i18n/ro_RO/Opportunity.json index e53988201b..815c033392 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/ro_RO/Opportunity.json +++ b/application/Espo/Modules/Crm/Resources/i18n/ro_RO/Opportunity.json @@ -1,38 +1,38 @@ { - "fields": { - "name": "Nume", - "account": "Cont", - "stage": "Stadiu", - "amount": "Suma", - "probability": "Probabilitate, %", - "leadSource": "Sursa Lead", - "doNotCall": "Nu sunati", - "closeDate": "Data Inchiderii", - "contacts": "Contacte", - "description": "Descriere" - }, - "links": { - "contacts": "Contacte" - }, - "options": { - "stage": { - "Prospecting": "Prospectare", - "Qualification": "Calificari", - "Needs Analysis": "Necesita Analiza", - "Value Proposition": "Valoare Propunere", - "Id. Decision Makers": "Id. Factori de Decizie", - "Perception Analysis": "Analiza Perceptiei", - "Proposal/Price Quote": "Propunere/Oferta Pret", - "Negotiation/Review": "Negociere/Revizuire", - "Closed Won": "Inchide ca Castigat", - "Closed Lost": "Inchide ca Pierdut" - } - }, - "labels": { - "Create Opportunity": "Creare Oportunitate" - }, - "presetFilters": { - "open": "Deschide", - "won": "Won" - } + "fields": { + "name": "Nume", + "account": "Cont", + "stage": "Stadiu", + "amount": "Suma", + "probability": "Probabilitate, %", + "leadSource": "Sursa Lead", + "doNotCall": "Nu sunati", + "closeDate": "Data Inchiderii", + "contacts": "Contacte", + "description": "Descriere" + }, + "links": { + "contacts": "Contacte" + }, + "options": { + "stage": { + "Prospecting": "Prospectare", + "Qualification": "Calificari", + "Needs Analysis": "Necesita Analiza", + "Value Proposition": "Valoare Propunere", + "Id. Decision Makers": "Id. Factori de Decizie", + "Perception Analysis": "Analiza Perceptiei", + "Proposal/Price Quote": "Propunere/Oferta Pret", + "Negotiation/Review": "Negociere/Revizuire", + "Closed Won": "Inchide ca Castigat", + "Closed Lost": "Inchide ca Pierdut" + } + }, + "labels": { + "Create Opportunity": "Creare Oportunitate" + }, + "presetFilters": { + "open": "Deschide", + "won": "Won" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/ro_RO/Target.json b/application/Espo/Modules/Crm/Resources/i18n/ro_RO/Target.json index 00c50560ca..3965c134f2 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/ro_RO/Target.json +++ b/application/Espo/Modules/Crm/Resources/i18n/ro_RO/Target.json @@ -1,19 +1,19 @@ { - "fields": { - "name": "Nume", - "emailAddress": "Email", - "title": "Titlu", - "website": "Site Web", - "accountName": "Nume Cont", - "phoneNumber": "Telefon", - "doNotCall": "Nu sunati", - "address": "Adresa", - "description": "Descriere" - }, - "links": { - }, - "labels": { - "Create Target": "Creare Tinta", - "Convert to Lead": "Converteste la Lead" - } + "fields": { + "name": "Nume", + "emailAddress": "Email", + "title": "Titlu", + "website": "Site Web", + "accountName": "Nume Cont", + "phoneNumber": "Telefon", + "doNotCall": "Nu sunati", + "address": "Adresa", + "description": "Descriere" + }, + "links": { + }, + "labels": { + "Create Target": "Creare Tinta", + "Convert to Lead": "Converteste la Lead" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/ro_RO/Task.json b/application/Espo/Modules/Crm/Resources/i18n/ro_RO/Task.json index f59ec99fe8..d477bcf2c6 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/ro_RO/Task.json +++ b/application/Espo/Modules/Crm/Resources/i18n/ro_RO/Task.json @@ -1,37 +1,37 @@ { - "fields": { - "name": "Nume", - "parent": "Parinte", - "status": "Status", - "dateStart": "Data inceput", - "dateEnd": "Data scadenta", - "priority": "Prioritate", - "description": "Descriere", - "isOverdue": "Este Restant" - }, - "links": { - }, - "options": { - "status": { - "Not Started": "Ne inceput", - "Started": "Inceput", - "Completed": "Completat", - "Canceled": "Anulat" - }, - "priority" : { - "Low": "Scazut", - "Normal": "Normal", - "High": "Inalt", - "Urgent": "Urgent" - } - }, - "labels": { - "Create Task": "Creaza Activitate" - }, - "presetFilters": { - "active": "Activ", - "completed": "Completat", - "todays": "Today's", - "overdue": "Overdue" - } + "fields": { + "name": "Nume", + "parent": "Parinte", + "status": "Status", + "dateStart": "Data inceput", + "dateEnd": "Data scadenta", + "priority": "Prioritate", + "description": "Descriere", + "isOverdue": "Este Restant" + }, + "links": { + }, + "options": { + "status": { + "Not Started": "Ne inceput", + "Started": "Inceput", + "Completed": "Completat", + "Canceled": "Anulat" + }, + "priority" : { + "Low": "Scazut", + "Normal": "Normal", + "High": "Inalt", + "Urgent": "Urgent" + } + }, + "labels": { + "Create Task": "Creaza Activitate" + }, + "presetFilters": { + "active": "Activ", + "completed": "Completat", + "todays": "Today's", + "overdue": "Overdue" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/ru_RU/Account.json b/application/Espo/Modules/Crm/Resources/i18n/ru_RU/Account.json index f1005bd60f..a63a3669f9 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/ru_RU/Account.json +++ b/application/Espo/Modules/Crm/Resources/i18n/ru_RU/Account.json @@ -1,40 +1,42 @@ { - "fields": { - "name": "Имя", - "emailAddress": "Почта", - "website": "Интернет сайт", - "phoneNumber": "Телефонный номер", - "billingAddress": "Платежный адрес", - "shippingAddress": "Почтовый адрес", - "description": "Описание", - "sicCode": "SicCode", - "industry": "Промышленность", - "type": "Раздел", - "contactRole": "Роль" - }, - "links": { - "contacts": "Контакты", - "opportunities": "Возможности", - "cases": "Обращения" - }, - "options": { - "type": { - "Customer": "Заказчик", - "Investor": "Вкладчик", - "Partner": "Партнер", - "Reseller": "Посредник" - }, - "industry": { - "Apparel": "Одежда", - "Banking": "Банковское дело", - "Computer Software": "Программное обеспечение", - "Education": "Образование", - "Electronics": "Электроника", - "Finance": "Финансы", - "Insurance": "Страхование" - } - }, - "labels": { - "Create Account": "Создать новую организацию" - } + "fields": { + "name": "Name", + "emailAddress": "Email", + "website": "Интернет сайт", + "phoneNumber": "Phone", + "billingAddress": "Платежный адрес", + "shippingAddress": "Почтовый адрес", + "description": "Описание", + "sicCode": "SicCode", + "industry": "Промышленность", + "type": "Type", + "contactRole": "Роль" + }, + "links": { + "contacts": "Контакты", + "opportunities": "Сделки", + "cases": "Обращения", + "documents": "Documents" + }, + "options": { + "type": { + "Customer": "Заказчик", + "Investor": "Вкладчик", + "Partner": "Партнер", + "Reseller": "Посредник" + }, + "industry": { + "Apparel": "Одежда", + "Banking": "Банковское дело", + "Computer Software": "Программное обеспечение", + "Education": "Образование", + "Electronics": "Электроника", + "Finance": "Финансы", + "Insurance": "Страхование" + } + }, + "labels": { + "Create Account": "Создать контрагента", + "Copy Billing": "Copy Billing" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/ru_RU/Admin.json b/application/Espo/Modules/Crm/Resources/i18n/ru_RU/Admin.json new file mode 100644 index 0000000000..a970fabb2c --- /dev/null +++ b/application/Espo/Modules/Crm/Resources/i18n/ru_RU/Admin.json @@ -0,0 +1,5 @@ +{ + "layouts": { + "detailConvert": "Преобразовать потенциального клиента" + } +} diff --git a/application/Espo/Modules/Crm/Resources/i18n/ru_RU/Calendar.json b/application/Espo/Modules/Crm/Resources/i18n/ru_RU/Calendar.json index bc45c401b2..a10c764a10 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/ru_RU/Calendar.json +++ b/application/Espo/Modules/Crm/Resources/i18n/ru_RU/Calendar.json @@ -1,13 +1,13 @@ { - "modes": { - "month": "месяц", - "week": "неделя", - "day": "день", - "agendaWeek": "На неделю", - "agendaDay": "На день" - }, - "labels": { - "Today": "Сегодня", - "Create": "Создать" - } + "modes": { + "month": "месяц", + "week": "неделя", + "day": "день", + "agendaWeek": "неделя", + "agendaDay": "день" + }, + "labels": { + "Today": "Сегодня", + "Create": "Создать" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/ru_RU/Call.json b/application/Espo/Modules/Crm/Resources/i18n/ru_RU/Call.json index 2899867959..ef6d31fe02 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/ru_RU/Call.json +++ b/application/Espo/Modules/Crm/Resources/i18n/ru_RU/Call.json @@ -1,39 +1,44 @@ { - "fields": { - "name": "Тема", - "parent": "Источник", - "status": "Статус", - "dateStart": "Дата начала", - "dateEnd": "Дата окончания", - "direction": "Категория", - "duration": "Длительность", - "description": "Описание", - "users": "Пользователи", - "contacts": "Контакты", - "leads": "Лиды" - }, - "links": { - }, - "options": { - "status": { - "Planned": "Запланированный", - "Held": "Выполнен", - "Not Held": "Не состоялся" - }, - "direction": { - "Outbound": "Исходящий", - "Inbound": "Входящий" - } - }, - "labels": { - "Create Call": "Новый звонок", - "Set Held": "Был выполнен", - "Set Not Held": "Не состоялся", - "Send Invitations": "Отправить приглашения" - }, - "presetFilters": { - "planned": "Запланированные", - "held": "Отложенные", - "todays": "На сегодня" - } + "fields": { + "name": "Name", + "parent": "Источник", + "status": "статус", + "dateStart": "Дата начала", + "dateEnd": "Дата окончания", + "direction": "Категория", + "duration": "Duration", + "description": "Описание", + "users": "Users", + "contacts": "Контакты", + "leads": "Потенциальные клиенты" + }, + "links": { + }, + "options": { + "status": { + "Planned": "Запланированный", + "Held": "Выполнен", + "Not Held": "Не состоялся" + }, + "direction": { + "Outbound": "Исходящий", + "Inbound": "Входящий" + }, + "acceptanceStatus": { + "None": "Нет", + "Accepted": "Accepted", + "Declined": "Declined" + } + }, + "labels": { + "Create Call": "Новый звонок", + "Set Held": "Был выполнен", + "Set Not Held": "Set Not Held", + "Send Invitations": "Отправить приглашения" + }, + "presetFilters": { + "planned": "Запланированный", + "held": "Выполнен", + "todays": "На сегодня" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/ru_RU/Case.json b/application/Espo/Modules/Crm/Resources/i18n/ru_RU/Case.json index 65dd4c10b2..047e1d4319 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/ru_RU/Case.json +++ b/application/Espo/Modules/Crm/Resources/i18n/ru_RU/Case.json @@ -1,42 +1,42 @@ { - "fields": { - "name": "Имя", - "number": "Номер", - "status": "Статус", - "account": "Организация", - "contact": "Контакт", - "priority": "Приоритет", - "type": "Раздел", - "description": "Описание" - }, - "links": { - }, - "options": { - "status": { - "New": "Новый", - "Assigned": "На рассмотрении", - "Pending": "Текущее", - "Closed": "Закрыто", - "Rejected": "Отказано", - "Duplicate": "Копия" - }, - "priority" : { - "Low": "Низкий", - "Normal": "Нормальный", - "High": "Высокий", - "Urgent": "Срочно" - }, - "type": { - "Question": "Вопрос", - "Incident": "Происшествие", - "Problem": "Проблема" - } - }, - "labels": { - "Create Case": "Создать обращение" - }, - "presetFilters": { - "open": "Открыто", - "closed": "Закрыто" - } + "fields": { + "name": "Name", + "number": "Номер", + "status": "статус", + "account": "Контрагент", + "contact": "Контакт", + "priority": "Приоритет", + "type": "Type", + "description": "Описание" + }, + "links": { + }, + "options": { + "status": { + "New": "Новый", + "Assigned": "На рассмотрении", + "Pending": "Текущее", + "Closed": "Закрыто", + "Rejected": "Отказано", + "Duplicate": "Копия" + }, + "priority" : { + "Low": "Низкий", + "Normal": "Нормальный", + "High": "Высокий", + "Urgent": "Срочно" + }, + "type": { + "Question": "Вопрос", + "Incident": "Происшествие", + "Problem": "Проблема" + } + }, + "labels": { + "Create Case": "Создать обращение" + }, + "presetFilters": { + "open": "Открыть", + "closed": "Закрыто" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/ru_RU/Contact.json b/application/Espo/Modules/Crm/Resources/i18n/ru_RU/Contact.json index 97a164f51e..1dd106e2f1 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/ru_RU/Contact.json +++ b/application/Espo/Modules/Crm/Resources/i18n/ru_RU/Contact.json @@ -1,38 +1,31 @@ { - "fields": { - "name": "Полное имя", - "emailAddress": "E-mail", - "title": "Должность", - "account": "Организация", - "accounts": "Организации", - "phoneNumber": "Телефон", - "accountType": "Тип организации", - "doNotCall": "Не звонить", - "address": "Адрес", - "opportunityRole": "Роль в возможности", - "accountRole": "Роль", - "description": "Описание", - "owner":"Пригласивший" - }, - "links": { - "orders": "Заказы", - "cases": "Обращения" - }, - "labels": { - "Create Contact": "Создать контакт" - }, - "options": { - "opportunityRole": { - "": "--Нет--", - "Decision Maker": "Принимающий решение", - "Evaluator": "Оценщик", - "Influencer": "Консультант" - }, - "salutationName": { - "options": { - "Жен": "Жен. ", - "Муж": "Муж. " - } - } - } + "fields": { + "name": "Name", + "emailAddress": "Email", + "title": "Название", + "account": "Контрагент", + "accounts": "Контрагенты", + "phoneNumber": "Phone", + "accountType": "Тип контрагента", + "doNotCall": "Не звонить", + "address": "Address", + "opportunityRole": "Роль сделки", + "accountRole": "Роль", + "description": "Описание" + }, + "links": { + "opportunities": "Сделки", + "cases": "Обращения" + }, + "labels": { + "Create Contact": "Создать контакт" + }, + "options": { + "opportunityRole": { + "": "--Нет--", + "Decision Maker": "Принимающий решение", + "Evaluator": "Оценщик", + "Influencer": "Консультант" + } + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/ru_RU/Document.json b/application/Espo/Modules/Crm/Resources/i18n/ru_RU/Document.json new file mode 100644 index 0000000000..d2db3b4245 --- /dev/null +++ b/application/Espo/Modules/Crm/Resources/i18n/ru_RU/Document.json @@ -0,0 +1,32 @@ +{ + "labels": { + "Create Document": "Create Document", + "Details": "Описание" + }, + "fields": { + "name": "Name", + "status": "статус", + "file": "File", + "type": "Type", + "source": "Source", + "publishDate": "Publish Date", + "expirationDate": "Expiration Date", + "description": "Описание" + }, + "links": { + "accounts": "Контрагенты", + "opportunities": "Сделки" + }, + "options": { + "status": { + "Active": "Активный", + "Draft": "Черновик", + "Expired": "Expired", + "Canceled": "Отменена" + } + }, + "presetFilters": { + "active": "Активный", + "draft": "Черновик" + } +} diff --git a/application/Espo/Modules/Crm/Resources/i18n/ru_RU/Global.json b/application/Espo/Modules/Crm/Resources/i18n/ru_RU/Global.json index e49f85d3b3..02103f6db3 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/ru_RU/Global.json +++ b/application/Espo/Modules/Crm/Resources/i18n/ru_RU/Global.json @@ -1,81 +1,90 @@ { - "scopeNames": { - "Account": "Организация", - "Contact": "Контакт", - "Lead": "Лид", - "Target": "Цель", - "Opportunity": "Возможность", - "Meeting": "Встреча", - "Calendar": "Календарь", - "Call": "Вызов", - "Task": "Задача", - "Case": "Обращение", - "InboundEmail": "Входящая почта" - }, - "scopeNamesPlural": { - "Account": "Организации", - "Contact": "Контакты", - "Lead": "Лиды", - "Target": "Цели", - "Opportunity": "Возможности", - "Meeting": "Встречи", - "Calendar": "Календарь", - "Call": "Звонки", - "Task": "Задачи", - "Case": "Обращения", - "InboundEmail": "Входящие письма" - }, - "dashlets": { - "Leads": "Мои Лиды", - "Opportunities": "Мои возможности", - "Tasks": "Мои задачи", - "Cases": "Мои обращения", - "Calendar": "Календарь", - "Calls": "Мои звонки", - "Meetings": "Мои встречи", - "OpportunitiesByStage": "Возможности в ожидании", - "OpportunitiesByLeadSource": "Возможности в разработке", - "SalesByMonth": "Продажи по месяцам", - "SalesPipeline": "Источники продаж" - }, - "labels": { - "Create InboundEmail": "Создать входящую почту", - "Activities": "Мероприятия", - "History": "История", - "Attendees": "Участники", - "Schedule Meeting": "Запланировать встречу", - "Schedule Call": "Запланировать звонок", - "Compose Email": "Создать e-mail", - "Log Meeting": "Записать встречу", - "Log Call": "Записать звонок", - "Archive Email": "Архив e-mail", - "Create Task": "Создать задачу", - "Tasks": "Задачи" - }, - "fields": { - "billingAddressCity": "Город", - "billingAddressCountry": "Страна", - "billingAddressPostalCode": "Почтовый код", - "billingAddressState": "Регион", - "billingAddressStreet": "Улица", - "addressCity": "Город", - "addressStreet": "Улица", - "addressCountry": "Страна", - "addressState": "Регион", - "addressPostalCode": "Почтовый код", - "shippingAddressCity": "Город доставки", - "shippingAddressStreet": "Улица доставки", - "shippingAddressCountry": "Страна доставки", - "shippingAddressState": "Регион доставки", - "shippingAddressPostalCode": "Почтовый код доставки" - }, - "links": { - "contacts": "Контакты", - "opportunities": "Возможности", - "leads": "Лиды", - "meetings": "Встречи", - "calls": "Звонки", - "tasks": "Задачи", - "emails": "E-mail адреса" - } + "scopeNames": { + "Account": "Контрагент", + "Contact": "Контакт", + "Lead": "Потенциальный клиент", + "Target": "Цель", + "Opportunity": "Cделка", + "Meeting": "Встреча", + "Calendar": "Календарь", + "Call": "Вызов", + "Task": "Задача", + "Case": "Обращение", + "InboundEmail": "Входящая почта", + "Document": "Document" + }, + "scopeNamesPlural": { + "Account": "Контрагенты", + "Contact": "Контакты", + "Lead": "Потенциальные клиенты", + "Target": "Цели", + "Opportunity": "Сделки", + "Meeting": "Встречи", + "Calendar": "Календарь", + "Call": "Звонки", + "Task": "Задачи", + "Case": "Обращения", + "InboundEmail": "Inbound Emails", + "Document": "Documents" + }, + "dashlets": { + "Leads": "Мои потенциальные клиенты", + "Opportunities": "Мои сделки", + "Tasks": "Мои задачи", + "Cases": "Мои обращения", + "Calendar": "Календарь", + "Calls": "Мои звонки", + "Meetings": "Мои встречи", + "OpportunitiesByStage": "Сделки по стадии", + "OpportunitiesByLeadSource": "Сделки по источнику потенциального клиента", + "SalesByMonth": "Продажи по месяцам", + "SalesPipeline": "Источники продаж" + }, + "labels": { + "Create InboundEmail": "Создать входящую почту", + "Activities": "Мероприятия", + "History": "История", + "Attendees": "Участники", + "Schedule Meeting": "Запланировать встречу", + "Schedule Call": "Запланировать звонок", + "Compose Email": "Создать e-mail", + "Log Meeting": "Записать встречу", + "Log Call": "Записать звонок", + "Archive Email": "Отправить письмо в архив", + "Create Task": "Создать задачу", + "Tasks": "Задачи" + }, + "fields": { + "billingAddressCity": "Город", + "billingAddressCountry": "Страна", + "billingAddressPostalCode": "Почтовый индекс", + "billingAddressState": "Регион", + "billingAddressStreet": "Улица", + "addressCity": "Город", + "addressStreet": "Улица", + "addressCountry": "Страна", + "addressState": "Регион", + "addressPostalCode": "Почтовый индекс", + "shippingAddressCity": "Город доставки", + "shippingAddressStreet": "Улица доставки", + "shippingAddressCountry": "Страна доставки", + "shippingAddressState": "Регион доставки", + "shippingAddressPostalCode": "Почтовый код доставки" + }, + "links": { + "contacts": "Контакты", + "opportunities": "Сделки", + "leads": "Потенциальные клиенты", + "meetings": "Встречи", + "calls": "Звонки", + "tasks": "Задачи", + "emails": "Письма", + "accounts": "Контрагенты", + "cases": "Обращения", + "documents": "Documents", + "account": "Контрагент", + "opportunity": "Cделка", + "contact": "Контакт", + "parent": "Источник" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/ru_RU/InboundEmail.json b/application/Espo/Modules/Crm/Resources/i18n/ru_RU/InboundEmail.json index c101d97c6b..711d51080f 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/ru_RU/InboundEmail.json +++ b/application/Espo/Modules/Crm/Resources/i18n/ru_RU/InboundEmail.json @@ -1,52 +1,52 @@ { - "fields": { - "name": "Имя", - "team": "Команда", - "status": "Состояние", - "assignToUser": "Связаться с пользователем", - "host": "Хост", - "username": "Имя пользователя", - "password": "Пароль", - "port": "Порт", - "monitoredFolders": "Отслеживаемые разделы", - "trashFolder": "Корзина", - "ssl": "SSL", - "createCase": "Создать обращение", - "reply": "Ответ", - "caseDistribution": "Распределение обращений", - "replyEmailTemplate": "Ответить по образцу", - "replyFromAddress": "Ответить с адреса", - "replyToAddress": "Адрес для получения ответа", - "replyFromName": "Ответить от имени" - }, - "tooltips": { - "reply": "Уведомить отправителей, что их письма были получены.", - "createCase": "Автоматически создавать обращение из входящих писем.", - "replyToAddress": "Укажите адрес для этого ящика, чтобы ответы приходили в него.", - "caseDistribution": "Как обращения будут назначаться: на пользователя или среди группы.", - "assignToUser": "Пользователь, на которого письма и обращения будут назначаться.", - "team": "Группа, к которой будут относиться письма и обращения." - }, - "links": { - }, - "options": { - "status": { - "Active": "Активный", - "Inactive": "Неактивный" - }, - "caseDistribution": { - "Direct-Assignment": "Прямая задача", - "Round-Robin": "Циклическая", - "Least-Busy": "Наиболее свободный" - } - }, - "labels": { - "Create InboundEmail": "Создать входящее письмо", - "IMAP": "IMAP", - "Actions": "Действия", - "Main": "Главная" - }, - "messages": { - "couldNotConnectToImap": "Не получается подключиться к серверу IMAP" - } + "fields": { + "name": "Name", + "team": "Группа", + "status": "статус", + "assignToUser": "Связаться с пользователем", + "host": "Host", + "username": "Username", + "password": "Пароль", + "port": "Порт", + "monitoredFolders": "Отслеживаемые разделы", + "trashFolder": "Корзина", + "ssl": "SSL", + "createCase": "Создать обращение", + "reply": "Ответить", + "caseDistribution": "Распределение обращений", + "replyEmailTemplate": "Ответить по образцу", + "replyFromAddress": "Ответить с адреса", + "replyToAddress": "Адрес для получения ответа", + "replyFromName": "Ответить от имени" + }, + "tooltips": { + "reply": "Уведомить отправителей, что их письма были получены.", + "createCase": "Автоматически создавать обращение из входящих писем.", + "replyToAddress": "Укажите адрес для этого ящика, чтобы ответы приходили в него.", + "caseDistribution": "Как обращения будут назначаться: на пользователя или среди группы.", + "assignToUser": "Пользователь, на которого письма и обращения будут назначаться.", + "team": "Группа, к которой будут относиться письма и обращения." + }, + "links": { + }, + "options": { + "status": { + "Active": "Активный", + "Inactive": "Неактивный" + }, + "caseDistribution": { + "Direct-Assignment": "Прямая задача", + "Round-Robin": "Циклическая", + "Least-Busy": "Наиболее свободный" + } + }, + "labels": { + "Create InboundEmail": "Создать входящую почту", + "IMAP": "IMAP", + "Actions": "Действия", + "Main": "Main" + }, + "messages": { + "couldNotConnectToImap": "Не получается подключиться к серверу IMAP" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/ru_RU/Lead.json b/application/Espo/Modules/Crm/Resources/i18n/ru_RU/Lead.json index 1c1d244fb6..2346ef6b7b 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/ru_RU/Lead.json +++ b/application/Espo/Modules/Crm/Resources/i18n/ru_RU/Lead.json @@ -1,57 +1,50 @@ { - "labels": { - "Converted To": "Преобразован в", - "Create Lead": "Создать Лид", - "Convert": "Преобразовать" - }, - "fields": { - "name": "Полное имя", - "emailAddress": "E-mail", - "title": "Должность", - "website": "Сайт", - "phoneNumber": "Телефон", - "accountName": "Название организации", - "doNotCall": "Не звонить", - "address": "Адрес", - "status": "Статус", - "source": "Источник", - "opportunityAmount": "Возможный доход", - "opportunityAmountConverted": "Возможный доход (конвертирован)", - "description": "Описание", - "createdAccount": "Созданная организация", - "createdContact": "Созданный контакт", - "createdOpportunity": "Созданная возможность" - }, - "links": { - }, - "options": { - "status": { - "New": "Новый", - "Assigned": "Назначено", - "In Process": "В процессе", - "Converted": "Преобразовано", - "Recycled": "Восстановленный", - "Dead": "Мертв" - }, - "source": { - "Call": "Звонок", - "Email": "E-mail", - "Partner": "Партнеры", - "Other": "Другое", - "friend": "подруга/друг", - "relative": "родственник", - "1happy": "1 happy", - "autopay": "автопей", - "vk": "вконтакт", - "wife": "жена/муж", - "BA": "ба/аба", - "mother": "мама/дочь", - "radio": "сарафанное радио", - "talk": "мое общение", - "magic": "волшебным образом" - } - }, - "presetFilters": { - "active": "Только активные" - } + "labels": { + "Converted To": "Преобразован в", + "Create Lead": "Создать потенциального клиента", + "Convert": "Преобразовать" + }, + "fields": { + "name": "Name", + "emailAddress": "Email", + "title": "Название", + "website": "Интернет сайт", + "phoneNumber": "Phone", + "accountName": "Имя контрагента", + "doNotCall": "Не звонить", + "address": "Address", + "status": "статус", + "source": "Source", + "opportunityAmount": "Сумма сделки", + "opportunityAmountConverted": "Сумма сделки (конвертирован)", + "description": "Описание", + "createdAccount": "Контрагент", + "createdContact": "Контакт", + "createdOpportunity": "Cделка" + }, + "links": { + }, + "options": { + "status": { + "New": "Новый", + "Assigned": "На рассмотрении", + "In Process": "В процессе", + "Converted": "Преобразовано", + "Recycled": "Восстановленный", + "Dead": "Мертв" + }, + "source": { + "Call": "Вызов", + "Email": "Email", + "Existing Customer": "Existing Customer", + "Partner": "Партнер", + "Public Relations": "Public Relations", + "Web Site": "Web Site", + "Campaign": "Campaign", + "Other": "Дополнительно" + } + }, + "presetFilters": { + "active": "Активный" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/ru_RU/Meeting.json b/application/Espo/Modules/Crm/Resources/i18n/ru_RU/Meeting.json index 529f1987f9..4118c6091c 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/ru_RU/Meeting.json +++ b/application/Espo/Modules/Crm/Resources/i18n/ru_RU/Meeting.json @@ -1,36 +1,39 @@ { - "fields": { - "name": "Имя", - "parent": "Источник", - "status": "Статус", - "dateStart": "Дата начала", - "dateEnd": "Дата окончания", - "duration": "Продолжительность", - "description": "Описание", - "users": "Пользователи", - "contacts": "Контакты", - "leads": "Лиды" - }, - "links": { - }, - "options": { - "status": { - "Planned": "Запланирована", - "Held": "Проведена", - "Not Held": "Не состоялась" - } - }, - "labels": { - "Create Meeting": "Создать встречу", - "Set Held": "Была проведена", - "Set Not Held": "Не состоялась", - "Send Invitations": "Отправить приглашение", - "Saved as Held": "Сохранено как состоявшееся", - "Saved as Not Held": "Сохранено как несостоявшееся" - }, - "presetFilters": { - "planned": "Запланированные", - "held": "Проведенные", - "todays": "На сегодня" - } + "fields": { + "name": "Name", + "parent": "Источник", + "status": "статус", + "dateStart": "Дата начала", + "dateEnd": "Дата окончания", + "duration": "Duration", + "description": "Описание", + "users": "Users", + "contacts": "Контакты", + "leads": "Потенциальные клиенты" + }, + "links": { + }, + "options": { + "status": { + "Planned": "Запланированный", + "Held": "Выполнен", + "Not Held": "Не состоялся" + }, + "acceptanceStatus": { + "None": "Нет", + "Accepted": "Accepted", + "Declined": "Declined" + } + }, + "labels": { + "Create Meeting": "Создать встречу", + "Set Held": "Был выполнен", + "Set Not Held": "Set Not Held", + "Send Invitations": "Отправить приглашения" + }, + "presetFilters": { + "planned": "Запланированный", + "held": "Выполнен", + "todays": "На сегодня" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/ru_RU/Opportunity.json b/application/Espo/Modules/Crm/Resources/i18n/ru_RU/Opportunity.json index 2730d93c70..4cde368a8a 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/ru_RU/Opportunity.json +++ b/application/Espo/Modules/Crm/Resources/i18n/ru_RU/Opportunity.json @@ -1,39 +1,41 @@ { - "fields": { - "name": "Имя", - "account": "Организация", - "stage": "Стадия", - "amount": "Сумма", - "probability": "Вероятность успеха, %", - "leadSource": "Лид", - "doNotCall": "Не звонить", - "closeDate": "Дата закрытия", - "contacts": "Контакты", - "description": "Описание", - "amountConverted": "Сумма (сконвертирована)" - }, - "links": { - "contacts": "Контакты" - }, - "options": { - "stage": { - "Prospecting": "Привлечение клиента", - "Qualification": "Оценка возможности", - "Needs Analysis": "Требует анализа", - "Value Proposition": "Выбор предложения/оферты", - "Id. Decision Makers": "Определение ответственного лица", - "Perception Analysis": "Проведение анализа", - "Proposal/Price Quote": "Отправлено предложение/оферта", - "Negotiation/Review": "Согласование/рассмотрение", - "Closed Won": "Закрыто - Успех", - "Closed Lost": "Закрыто - Провал" - } - }, - "labels": { - "Create Opportunity": "Создать возможность" - }, - "presetFilters": { - "open": "Открытые", - "won": "Успешные" - } + "fields": { + "name": "Name", + "account": "Контрагент", + "stage": "Стадия", + "amount": "Сумма", + "probability": "Вероятность успеха, %", + "leadSource": "Источник потенциального клиента", + "doNotCall": "Не звонить", + "closeDate": "Дата закрытия", + "contacts": "Контакты", + "description": "Описание", + "amountConverted": "Сумма (сконвертирована)", + "amountWeightedConverted": "Amount Weighted" + }, + "links": { + "contacts": "Контакты", + "documents": "Documents" + }, + "options": { + "stage": { + "Prospecting": "Привлечение клиента", + "Qualification": "Оценка возможности", + "Needs Analysis": "Требует анализа", + "Value Proposition": "Выбор предложения/оферты", + "Id. Decision Makers": "Определение ответственного лица", + "Perception Analysis": "Проведение анализа", + "Proposal/Price Quote": "Отправлено предложение/оферта", + "Negotiation/Review": "Согласование/рассмотрение", + "Closed Won": "Закрыто - Успех", + "Closed Lost": "Закрыто - Провал" + } + }, + "labels": { + "Create Opportunity": "Создать сделку" + }, + "presetFilters": { + "open": "Открыть", + "won": "Успешные" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/ru_RU/Target.json b/application/Espo/Modules/Crm/Resources/i18n/ru_RU/Target.json index fed3c77433..ffb4d94f92 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/ru_RU/Target.json +++ b/application/Espo/Modules/Crm/Resources/i18n/ru_RU/Target.json @@ -1,19 +1,19 @@ { - "fields": { - "name": "Имя", - "emailAddress": "E-mail", - "title": "Название", - "website": "Сайт", - "accountName": "Название организации", - "phoneNumber": "Телефон", - "doNotCall": "Не звонить", - "address": "Адрес", - "description": "Описание" - }, - "links": { - }, - "labels": { - "Create Target": "Создать цель", - "Convert to Lead": "Преобразовать в Лид" - } + "fields": { + "name": "Name", + "emailAddress": "Email", + "title": "Название", + "website": "Интернет сайт", + "accountName": "Имя контрагента", + "phoneNumber": "Phone", + "doNotCall": "Не звонить", + "address": "Address", + "description": "Описание" + }, + "links": { + }, + "labels": { + "Create Target": "Создать цель", + "Convert to Lead": "Преобразовать в потенциального клиента" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/ru_RU/Task.json b/application/Espo/Modules/Crm/Resources/i18n/ru_RU/Task.json index ba4215ac4b..48c4a980c3 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/ru_RU/Task.json +++ b/application/Espo/Modules/Crm/Resources/i18n/ru_RU/Task.json @@ -1,37 +1,38 @@ { - "fields": { - "name": "Имя", - "parent": "Источник", - "status": "Статус", - "dateStart": "Дата начала", - "dateEnd": "Дата окончания", - "priority": "Приоритет", - "description": "Описание", - "isOverdue": "Просрочена" - }, - "links": { - }, - "options": { - "status": { - "Not Started": "Не началась", - "Started": "Началась", - "Completed": "Завершена", - "Canceled": "Отменена" - }, - "priority" : { - "Low": "Низкий", - "Normal": "Нормальный", - "High": "Высокий", - "Urgent": "Срочно" - } - }, - "labels": { - "Create Task": "Создать задачу" - }, - "presetFilters": { - "active": "Активные", - "completed": "Завершенные", - "todays": "На сегодня", - "overdue": "Просроченные" - } + "fields": { + "name": "Name", + "parent": "Источник", + "status": "статус", + "dateStart": "Дата начала", + "dateEnd": "Date Due", + "priority": "Приоритет", + "description": "Описание", + "isOverdue": "Просрочена" + }, + "links": { + }, + "options": { + "status": { + "Not Started": "Не началась", + "Started": "Началась", + "Completed": "Завершена", + "Canceled": "Отменена" + }, + "priority" : { + "Low": "Низкий", + "Normal": "Нормальный", + "High": "Высокий", + "Urgent": "Срочно" + } + }, + "labels": { + "Create Task": "Создать задачу", + "Complete": "Complete" + }, + "presetFilters": { + "actual": "Actual", + "completed": "Завершена", + "todays": "На сегодня", + "overdue": "Просроченные" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/tr_TR/Account.json b/application/Espo/Modules/Crm/Resources/i18n/tr_TR/Account.json index e437d2478e..0d501859f4 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/tr_TR/Account.json +++ b/application/Espo/Modules/Crm/Resources/i18n/tr_TR/Account.json @@ -1,40 +1,40 @@ { - "fields": { - "name": "İsim", - "emailAddress": "Eposta", - "website": "Website", - "phone": "Telefon", - "fax": "Faks", - "billingAddress": "Fatura Adresi", - "shippingAddress": "Teslimat Adresi", - "description": "açıklama", - "sicCode": "Firma Kodu", - "industry": "Sektör", - "type": "Tür" - }, - "links": { - "contacts": "Bağlantılar", - "opportunities": "Fırsatlar", - "cases": "Dosyalar" - }, - "options": { - "type": { - "Customer": "Müşteri", - "Investor": "Yatırımcı", - "Partner": "Ortak", - "Reseller": "Satıcı" - }, - "industry": { - "Apparel": "Konfeksiyon", - "Banking": "Bankacılık", - "Computer Software": "Bilgisayar Yazılımı", - "Education": "Eğitim", - "Electronics": "Elektronik", - "Finance": "Finans", - "Insurance": "Sigortacılık" - } - }, - "labels": { - "Create Account": "Hesap Oluştur" - } + "fields": { + "name": "İsim", + "emailAddress": "Eposta", + "website": "Website", + "phone": "Telefon", + "fax": "Faks", + "billingAddress": "Fatura Adresi", + "shippingAddress": "Teslimat Adresi", + "description": "açıklama", + "sicCode": "Firma Kodu", + "industry": "Sektör", + "type": "Tür" + }, + "links": { + "contacts": "Bağlantılar", + "opportunities": "Fırsatlar", + "cases": "Dosyalar" + }, + "options": { + "type": { + "Customer": "Müşteri", + "Investor": "Yatırımcı", + "Partner": "Ortak", + "Reseller": "Satıcı" + }, + "industry": { + "Apparel": "Konfeksiyon", + "Banking": "Bankacılık", + "Computer Software": "Bilgisayar Yazılımı", + "Education": "Eğitim", + "Electronics": "Elektronik", + "Finance": "Finans", + "Insurance": "Sigortacılık" + } + }, + "labels": { + "Create Account": "Hesap Oluştur" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/tr_TR/Calendar.json b/application/Espo/Modules/Crm/Resources/i18n/tr_TR/Calendar.json index b25bf11a8b..be79e53815 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/tr_TR/Calendar.json +++ b/application/Espo/Modules/Crm/Resources/i18n/tr_TR/Calendar.json @@ -1,13 +1,13 @@ { - "modes": { - "month": "Ay", - "week": "hafta", - "day": "Gün", - "agendaWeek": "hafta", - "agendaDay": "Gün" - }, - "labels": { - "Today": "Bugün", - "Create": "Oluştur" - } + "modes": { + "month": "Ay", + "week": "hafta", + "day": "Gün", + "agendaWeek": "hafta", + "agendaDay": "Gün" + }, + "labels": { + "Today": "Bugün", + "Create": "Oluştur" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/tr_TR/Call.json b/application/Espo/Modules/Crm/Resources/i18n/tr_TR/Call.json index 6d2162c0a6..9cbdfd430f 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/tr_TR/Call.json +++ b/application/Espo/Modules/Crm/Resources/i18n/tr_TR/Call.json @@ -1,34 +1,34 @@ { - "fields": { - "name": "İsim", - "parent": "Üst Seçenek", - "status": "Durum", - "dateStart": "Başlangıç Tarihi", - "dateEnd": "Bitiş Tarihi", - "direction": "Yönlendirme", - "duration": "Süre", - "description": "açıklama", - "users": "Kullanıcılar", - "contacts": "Bağlantılar", - "leads": "Müşteri Adayları" - }, - "links": { - }, - "options": { - "status": { - "Planned": "Planlanmış", - "Held": "Elde Tutulanlar", - "Not Held": "Elde Tutulmayanlar" - }, - "direction": { - "Outbound": "Giden", - "Inbound": "Gelen" - } - }, - "labels": { - "Create Call": "Arama Oluştur", - "Set Held": "SET HELDXXX", - "Set Not Held": "SET NOT HELD XXXX", - "Send Invitations": "Davetleri Gönder" - } + "fields": { + "name": "İsim", + "parent": "Üst Seçenek", + "status": "Durum", + "dateStart": "Başlangıç Tarihi", + "dateEnd": "Bitiş Tarihi", + "direction": "Yönlendirme", + "duration": "Süre", + "description": "açıklama", + "users": "Kullanıcılar", + "contacts": "Bağlantılar", + "leads": "Müşteri Adayları" + }, + "links": { + }, + "options": { + "status": { + "Planned": "Planlanmış", + "Held": "Elde Tutulanlar", + "Not Held": "Elde Tutulmayanlar" + }, + "direction": { + "Outbound": "Giden", + "Inbound": "Gelen" + } + }, + "labels": { + "Create Call": "Arama Oluştur", + "Set Held": "SET HELDXXX", + "Set Not Held": "SET NOT HELD XXXX", + "Send Invitations": "Davetleri Gönder" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/tr_TR/Case.json b/application/Espo/Modules/Crm/Resources/i18n/tr_TR/Case.json index 63a1995ef9..a64baabbae 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/tr_TR/Case.json +++ b/application/Espo/Modules/Crm/Resources/i18n/tr_TR/Case.json @@ -1,38 +1,38 @@ { - "fields": { - "name": "İsim", - "number": "Numara", - "status": "Durum", - "account": "Hesap", - "contact": "Bağlantı", - "priority": "Öncelik", - "type": "Tür", - "description": "açıklama" - }, - "links": { - }, - "options": { - "status": { - "New": "Yeni", - "Assigned": "Atanmış", - "Pending": "Beklemede", - "Closed": "Kapandı", - "Rejected": "Reddedildi", - "Duplicate": "Kopyala" - }, - "priority" : { - "Low": "Düşük", - "Normal": "Normal", - "High": "Yüksek", - "Urgent": "Acil" - }, - "type": { - "Question": "Soru", - "Incident": "Olay", - "Problem": "sorun" - } - }, - "labels": { - "Create Case": "Dosya Oluştur" - } + "fields": { + "name": "İsim", + "number": "Numara", + "status": "Durum", + "account": "Hesap", + "contact": "Bağlantı", + "priority": "Öncelik", + "type": "Tür", + "description": "açıklama" + }, + "links": { + }, + "options": { + "status": { + "New": "Yeni", + "Assigned": "Atanmış", + "Pending": "Beklemede", + "Closed": "Kapandı", + "Rejected": "Reddedildi", + "Duplicate": "Kopyala" + }, + "priority" : { + "Low": "Düşük", + "Normal": "Normal", + "High": "Yüksek", + "Urgent": "Acil" + }, + "type": { + "Question": "Soru", + "Incident": "Olay", + "Problem": "sorun" + } + }, + "labels": { + "Create Case": "Dosya Oluştur" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/tr_TR/Contact.json b/application/Espo/Modules/Crm/Resources/i18n/tr_TR/Contact.json index d4f74ebfdb..27c3f7c948 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/tr_TR/Contact.json +++ b/application/Espo/Modules/Crm/Resources/i18n/tr_TR/Contact.json @@ -1,22 +1,22 @@ { - "fields": { - "name": "İsim", - "emailAddress": "Eposta", - "title": "Başlık", - "account": "Hesap", - "phone": "Telefon", - "phoneOffice": "Phone (Office)", - "fax": "Faks", - "accountType": "Hesap Türü", - "doNotCall": "Arama Yapma", - "address": "Adres", - "description": "açıklama" - }, - "links": { - "opportunities": "Fırsatlar", - "cases": "Dosyalar" - }, - "labels": { - "Create Contact": "Bağlantı Oluştur" - } + "fields": { + "name": "İsim", + "emailAddress": "Eposta", + "title": "Başlık", + "account": "Hesap", + "phone": "Telefon", + "phoneOffice": "Phone (Office)", + "fax": "Faks", + "accountType": "Hesap Türü", + "doNotCall": "Arama Yapma", + "address": "Adres", + "description": "açıklama" + }, + "links": { + "opportunities": "Fırsatlar", + "cases": "Dosyalar" + }, + "labels": { + "Create Contact": "Bağlantı Oluştur" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/tr_TR/Global.json b/application/Espo/Modules/Crm/Resources/i18n/tr_TR/Global.json index 2d62f362d2..0573820b13 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/tr_TR/Global.json +++ b/application/Espo/Modules/Crm/Resources/i18n/tr_TR/Global.json @@ -1,79 +1,79 @@ { - "scopeNames": { - "Account": "Hesap", - "Contact": "Bağlantı", - "Lead": "Müşteri Adayı", - "Prospect": "Beklenti", - "Opportunity": "Fırsat", - "Meeting": "Toplantı", - "Calendar": "Takvim", - "Call": "Arama", - "Task": "Görev", - "Case": "Dosya", - "InboundEmail": "Gelen Eposta" - }, - "scopeNamesPlural": { - "Account": "Hesaplar", - "Contact": "Bağlantılar", - "Lead": "Müşteri Adayları", - "Prospect": "Beklentiler", - "Opportunity": "Fırsatlar", - "Meeting": "Toplantılar", - "Calendar": "Takvim", - "Call": "Aramalar", - "Task": "Görevler", - "Case": "Dosyalar", - "InboundEmail": "Gelen Epostalar" - }, - "dashlets": { - "Leads": "Müşteri Adaylarım", - "Opportunities": "Fırsatlarım", - "Tasks": "Görevleri", - "Cases": "Dosyalarım", - "Calendar": "Takvim", - "OpportunitiesByStage": "Aşamaya Göre Fırstalar", - "OpportunitiesByLeadSource": "Aday Müşterilere Göre Fırsatlar", - "SalesByMonth": "Aylık Satışlar", - "SalesPipeline": "Satış Öngörüleri" - }, - "labels": { - "Create InboundEmail": "Gelen Eposta Oluştur", - "Activities": "Aktiviteler", - "History": "Geçmiş", - "Attendees": "Katılımcılar", - "Schedule Meeting": "Toplantı Ayarla", - "Schedule Call": "Arama Ayarla", - "Compose Email": "Eposta Gönder", - "Log Meeting": "Günlük Toplantı", - "Log Call": "Günlük Arama", - "Archive Email": "Epostayı Arşivle", - "Create Task": "Görev Oluştur", - "Tasks": "Görevler" - }, - "fields": { - "billingAddressCity": "Şehir", - "billingAddressCountry": "Ülke", - "billingAddressPostalCode": "Posta Kodu", - "billingAddressState": "Semt", - "billingAddressStreet": "Sokak", - "addressCity": "Şehir", - "addressStreet": "Sokak", - "addressCountry": "Ülke", - "addressState": "Semt", - "addressPostalCode": "Posta Kodu", - "shippingAddressCity": "City (Shipping)", - "shippingAddressStreet": "Street (Shipping)", - "shippingAddressCountry": "Country (Shipping)", - "shippingAddressState": "State (Shipping)", - "shippingAddressPostalCode": "Postal Code (Shipping)" - }, - "links": { - "contacts": "Bağlantılar", - "opportunities": "Fırsatlar", - "leads": "Müşteri Adayları", - "meetings": "Toplantılar", - "calls": "Aramalar", - "tasks": "Görevler", - "emails": "Epostalar" - } + "scopeNames": { + "Account": "Hesap", + "Contact": "Bağlantı", + "Lead": "Müşteri Adayı", + "Prospect": "Beklenti", + "Opportunity": "Fırsat", + "Meeting": "Toplantı", + "Calendar": "Takvim", + "Call": "Arama", + "Task": "Görev", + "Case": "Dosya", + "InboundEmail": "Gelen Eposta" + }, + "scopeNamesPlural": { + "Account": "Hesaplar", + "Contact": "Bağlantılar", + "Lead": "Müşteri Adayları", + "Prospect": "Beklentiler", + "Opportunity": "Fırsatlar", + "Meeting": "Toplantılar", + "Calendar": "Takvim", + "Call": "Aramalar", + "Task": "Görevler", + "Case": "Dosyalar", + "InboundEmail": "Gelen Epostalar" + }, + "dashlets": { + "Leads": "Müşteri Adaylarım", + "Opportunities": "Fırsatlarım", + "Tasks": "Görevleri", + "Cases": "Dosyalarım", + "Calendar": "Takvim", + "OpportunitiesByStage": "Aşamaya Göre Fırstalar", + "OpportunitiesByLeadSource": "Aday Müşterilere Göre Fırsatlar", + "SalesByMonth": "Aylık Satışlar", + "SalesPipeline": "Satış Öngörüleri" + }, + "labels": { + "Create InboundEmail": "Gelen Eposta Oluştur", + "Activities": "Aktiviteler", + "History": "Geçmiş", + "Attendees": "Katılımcılar", + "Schedule Meeting": "Toplantı Ayarla", + "Schedule Call": "Arama Ayarla", + "Compose Email": "Eposta Gönder", + "Log Meeting": "Günlük Toplantı", + "Log Call": "Günlük Arama", + "Archive Email": "Epostayı Arşivle", + "Create Task": "Görev Oluştur", + "Tasks": "Görevler" + }, + "fields": { + "billingAddressCity": "Şehir", + "billingAddressCountry": "Ülke", + "billingAddressPostalCode": "Posta Kodu", + "billingAddressState": "Semt", + "billingAddressStreet": "Sokak", + "addressCity": "Şehir", + "addressStreet": "Sokak", + "addressCountry": "Ülke", + "addressState": "Semt", + "addressPostalCode": "Posta Kodu", + "shippingAddressCity": "City (Shipping)", + "shippingAddressStreet": "Street (Shipping)", + "shippingAddressCountry": "Country (Shipping)", + "shippingAddressState": "State (Shipping)", + "shippingAddressPostalCode": "Postal Code (Shipping)" + }, + "links": { + "contacts": "Bağlantılar", + "opportunities": "Fırsatlar", + "leads": "Müşteri Adayları", + "meetings": "Toplantılar", + "calls": "Aramalar", + "tasks": "Görevler", + "emails": "Epostalar" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/tr_TR/InboundEmail.json b/application/Espo/Modules/Crm/Resources/i18n/tr_TR/InboundEmail.json index 17f24377bf..7e716000bf 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/tr_TR/InboundEmail.json +++ b/application/Espo/Modules/Crm/Resources/i18n/tr_TR/InboundEmail.json @@ -1,43 +1,43 @@ { - "fields": { - "name": "İsim", - "team": "Takım", - "status": "Durum", - "assignToUser": "Kullanıcıya Ata", - "host": "Sunucu", - "username": "Kullanıcı Adı", - "password": "Şifre", - "port": "Bağlantı Noktası", - "monitoredFolders": "İzlenen Klasörler", - "trashFolder": "Çöp Kutusu", - "ssl": "SSL", - "createCase": "Dosya Oluştur", - "reply": "Cevapla", - "caseDistribution": "Dosya Dağılımı", - "replyEmailTemplate": "Cevaplama Eposta Şablonu", - "replyFromAddress": "Adresten Cevapla", - "replyFromName": "İsimden Cevapla" - }, - "links": { - }, - "options": { - "status": { - "Active": "Aktif", - "Inactive": "Pasif" - }, - "caseDistribution": { - "Direct-Assignment": "DIRECT-ASSIGNMENTXXXX", - "Round-Robin": "ROUND-ROBINXXXX", - "Least-Busy": "LEAST-BUSYXXXX" - } - }, - "labels": { - "Create InboundEmail": "Gelen Eposta Oluştur", - "IMAP": "IMAP", - "Actions": "Hareketler", - "Main": "Ana" - }, - "messages": { - "couldNotConnectToImap": "IMAP sunucusuna bağlanamadı" - } + "fields": { + "name": "İsim", + "team": "Takım", + "status": "Durum", + "assignToUser": "Kullanıcıya Ata", + "host": "Sunucu", + "username": "Kullanıcı Adı", + "password": "Şifre", + "port": "Bağlantı Noktası", + "monitoredFolders": "İzlenen Klasörler", + "trashFolder": "Çöp Kutusu", + "ssl": "SSL", + "createCase": "Dosya Oluştur", + "reply": "Cevapla", + "caseDistribution": "Dosya Dağılımı", + "replyEmailTemplate": "Cevaplama Eposta Şablonu", + "replyFromAddress": "Adresten Cevapla", + "replyFromName": "İsimden Cevapla" + }, + "links": { + }, + "options": { + "status": { + "Active": "Aktif", + "Inactive": "Pasif" + }, + "caseDistribution": { + "Direct-Assignment": "DIRECT-ASSIGNMENTXXXX", + "Round-Robin": "ROUND-ROBINXXXX", + "Least-Busy": "LEAST-BUSYXXXX" + } + }, + "labels": { + "Create InboundEmail": "Gelen Eposta Oluştur", + "IMAP": "IMAP", + "Actions": "Hareketler", + "Main": "Ana" + }, + "messages": { + "couldNotConnectToImap": "IMAP sunucusuna bağlanamadı" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/tr_TR/Lead.json b/application/Espo/Modules/Crm/Resources/i18n/tr_TR/Lead.json index 3eb986e150..45f5319bd6 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/tr_TR/Lead.json +++ b/application/Espo/Modules/Crm/Resources/i18n/tr_TR/Lead.json @@ -1,48 +1,48 @@ { - "labels": { - "Converted To": "Çevrildi", - "Create Lead": "Müşteri Adayı Oluştur", - "Convert": "Çevir" - }, - "fields": { - "name": "İsim", - "emailAddress": "Eposta", - "title": "Başlık", - "website": "Website", - "phone": "Telefon", - "phoneOffice": "Phone (Office)", - "fax": "Faks", - "accountName": "Hesap Adı", - "doNotCall": "Arama Yapma", - "address": "Adres", - "status": "Durum", - "source": "Kaynak", - "opportunityAmount": "Fırsat Tutarı", - "description": "açıklama", - "createdAccount": "Hesap", - "createdContact": "Bağlantı", - "createdOpportunity": "Fırsat" - }, - "links": { - }, - "options": { - "status": { - "New": "Yeni", - "Assigned": "Atanmış", - "In Process": "İşlemde", - "Converted": "Çevrildi", - "Recycled": "Geri Dönüştürüldü", - "Dead": "Ölü" - }, - "source": { - "Call": "Arama", - "Email": "Eposta", - "Existing Customer": "Varolan Müşteri", - "Partner": "Ortak", - "Public Relations": "Halkla İlişkiler", - "Web Site": "Web Site", - "Campaign": "Kampanya", - "Other": "Diğer" - } - } + "labels": { + "Converted To": "Çevrildi", + "Create Lead": "Müşteri Adayı Oluştur", + "Convert": "Çevir" + }, + "fields": { + "name": "İsim", + "emailAddress": "Eposta", + "title": "Başlık", + "website": "Website", + "phone": "Telefon", + "phoneOffice": "Phone (Office)", + "fax": "Faks", + "accountName": "Hesap Adı", + "doNotCall": "Arama Yapma", + "address": "Adres", + "status": "Durum", + "source": "Kaynak", + "opportunityAmount": "Fırsat Tutarı", + "description": "açıklama", + "createdAccount": "Hesap", + "createdContact": "Bağlantı", + "createdOpportunity": "Fırsat" + }, + "links": { + }, + "options": { + "status": { + "New": "Yeni", + "Assigned": "Atanmış", + "In Process": "İşlemde", + "Converted": "Çevrildi", + "Recycled": "Geri Dönüştürüldü", + "Dead": "Ölü" + }, + "source": { + "Call": "Arama", + "Email": "Eposta", + "Existing Customer": "Varolan Müşteri", + "Partner": "Ortak", + "Public Relations": "Halkla İlişkiler", + "Web Site": "Web Site", + "Campaign": "Kampanya", + "Other": "Diğer" + } + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/tr_TR/Meeting.json b/application/Espo/Modules/Crm/Resources/i18n/tr_TR/Meeting.json index f95d2cf5b7..26854880aa 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/tr_TR/Meeting.json +++ b/application/Espo/Modules/Crm/Resources/i18n/tr_TR/Meeting.json @@ -1,29 +1,29 @@ { - "fields": { - "name": "İsim", - "parent": "Üst Seçenek", - "status": "Durum", - "dateStart": "Başlangıç Tarihi", - "dateEnd": "Bitiş Tarihi", - "duration": "Süre", - "description": "açıklama", - "users": "Kullanıcılar", - "contacts": "Bağlantılar", - "leads": "Müşteri Adayları" - }, - "links": { - }, - "options": { - "status": { - "Planned": "Planlanmış", - "Held": "Elde Tutulanlar", - "Not Held": "Elde Tutulmayanlar" - } - }, - "labels": { - "Create Meeting": "Toplantı Oluştur ", - "Set Held": "SET HELDXXX", - "Set Not Held": "SET NOT HELD XXXX", - "Send Invitations": "Davetleri Gönder" - } + "fields": { + "name": "İsim", + "parent": "Üst Seçenek", + "status": "Durum", + "dateStart": "Başlangıç Tarihi", + "dateEnd": "Bitiş Tarihi", + "duration": "Süre", + "description": "açıklama", + "users": "Kullanıcılar", + "contacts": "Bağlantılar", + "leads": "Müşteri Adayları" + }, + "links": { + }, + "options": { + "status": { + "Planned": "Planlanmış", + "Held": "Elde Tutulanlar", + "Not Held": "Elde Tutulmayanlar" + } + }, + "labels": { + "Create Meeting": "Toplantı Oluştur ", + "Set Held": "SET HELDXXX", + "Set Not Held": "SET NOT HELD XXXX", + "Send Invitations": "Davetleri Gönder" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/tr_TR/Opportunity.json b/application/Espo/Modules/Crm/Resources/i18n/tr_TR/Opportunity.json index cda9a2e408..7661ed0f15 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/tr_TR/Opportunity.json +++ b/application/Espo/Modules/Crm/Resources/i18n/tr_TR/Opportunity.json @@ -1,43 +1,43 @@ { - "fields": { - "name": "İsim", - "account": "Hesap", - "stage": "Aşama", - "amount": "Tutar", - "probability": "Olasılık, %", - "leadSource": "Aday Müşteri Kaynağı", - "doNotCall": "Arama Yapma", - "closeDate": "Kapanış Tarii", - "description": "açıklama" - }, - "links": { - "contacts": "Bağlantılar" - }, - "options": { - "stage": { - "Prospecting": "Araştırma", - "Qualification": "Yeterlilik", - "Needs Analysis": "Analiz Yapılmalı", - "Value Proposition": "Değer Önerisi", - "Id. Decision Makers": "Id. Karar Vericiler", - "Perception Analysis": "Algı Analizi", - "Proposal/Price Quote": "Proposal/Price Quote", - "Negotiation/Review": "Görüşme/İnceleme", - "Closed Won": "Kapalı Kazanç", - "Closed Lost": "Kapalı Kayıp" - }, - "leadSource": { - "Call": "Arama", - "Email": "Eposta", - "Existing Customer": "Varolan Müşteri", - "Partner": "Ortak", - "Public Relations": "Halkla İlişkiler", - "Web Site": "Web Site", - "Campaign": "Kampanya", - "Other": "Diğer" - } - }, - "labels": { - "Create Opportunity": "Fırsat Oluştur" - } + "fields": { + "name": "İsim", + "account": "Hesap", + "stage": "Aşama", + "amount": "Tutar", + "probability": "Olasılık, %", + "leadSource": "Aday Müşteri Kaynağı", + "doNotCall": "Arama Yapma", + "closeDate": "Kapanış Tarii", + "description": "açıklama" + }, + "links": { + "contacts": "Bağlantılar" + }, + "options": { + "stage": { + "Prospecting": "Araştırma", + "Qualification": "Yeterlilik", + "Needs Analysis": "Analiz Yapılmalı", + "Value Proposition": "Değer Önerisi", + "Id. Decision Makers": "Id. Karar Vericiler", + "Perception Analysis": "Algı Analizi", + "Proposal/Price Quote": "Proposal/Price Quote", + "Negotiation/Review": "Görüşme/İnceleme", + "Closed Won": "Kapalı Kazanç", + "Closed Lost": "Kapalı Kayıp" + }, + "leadSource": { + "Call": "Arama", + "Email": "Eposta", + "Existing Customer": "Varolan Müşteri", + "Partner": "Ortak", + "Public Relations": "Halkla İlişkiler", + "Web Site": "Web Site", + "Campaign": "Kampanya", + "Other": "Diğer" + } + }, + "labels": { + "Create Opportunity": "Fırsat Oluştur" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/tr_TR/Prospect.json b/application/Espo/Modules/Crm/Resources/i18n/tr_TR/Prospect.json index 511b019a9b..3be928c1d8 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/tr_TR/Prospect.json +++ b/application/Espo/Modules/Crm/Resources/i18n/tr_TR/Prospect.json @@ -1,21 +1,21 @@ { - "fields": { - "name": "İsim", - "emailAddress": "Eposta", - "title": "Başlık", - "website": "Website", - "accountName": "Hesap Adı", - "phone": "Telefon", - "phoneOffice": "Phone (Office)", - "fax": "Faks", - "doNotCall": "Arama Yapma", - "address": "Adres", - "description": "açıklama" - }, - "links": { - }, - "labels": { - "Create Prospect": "Beklenti Oluştur", - "Convert to Lead": "Müşteri Adayına Dönüştür" - } + "fields": { + "name": "İsim", + "emailAddress": "Eposta", + "title": "Başlık", + "website": "Website", + "accountName": "Hesap Adı", + "phone": "Telefon", + "phoneOffice": "Phone (Office)", + "fax": "Faks", + "doNotCall": "Arama Yapma", + "address": "Adres", + "description": "açıklama" + }, + "links": { + }, + "labels": { + "Create Prospect": "Beklenti Oluştur", + "Convert to Lead": "Müşteri Adayına Dönüştür" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/tr_TR/Task.json b/application/Espo/Modules/Crm/Resources/i18n/tr_TR/Task.json index 1530a9f217..e0fd0ea3c0 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/tr_TR/Task.json +++ b/application/Espo/Modules/Crm/Resources/i18n/tr_TR/Task.json @@ -1,31 +1,31 @@ { - "fields": { - "name": "İsim", - "parent": "Üst Seçenek", - "status": "Durum", - "dateStart": "Başlangıç Tarihi", - "dateEnd": "Vade Tarihi", - "priority": "Öncelik", - "description": "açıklama", - "isOverdue": "Vadesi Geçmiş" - }, - "links": { - }, - "options": { - "status": { - "Not Started": "başlamadı", - "Started": "Başladı", - "Completed": "Tamamlandı", - "Canceled": "İptal edildi" - }, - "priority" : { - "Low": "Düşük", - "Normal": "Normal", - "High": "Yüksek", - "Urgent": "Acil" - } - }, - "labels": { - "Create Task": "Görev Oluştur" - } + "fields": { + "name": "İsim", + "parent": "Üst Seçenek", + "status": "Durum", + "dateStart": "Başlangıç Tarihi", + "dateEnd": "Vade Tarihi", + "priority": "Öncelik", + "description": "açıklama", + "isOverdue": "Vadesi Geçmiş" + }, + "links": { + }, + "options": { + "status": { + "Not Started": "başlamadı", + "Started": "Başladı", + "Completed": "Tamamlandı", + "Canceled": "İptal edildi" + }, + "priority" : { + "Low": "Düşük", + "Normal": "Normal", + "High": "Yüksek", + "Urgent": "Acil" + } + }, + "labels": { + "Create Task": "Görev Oluştur" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/vi_VN/Account.json b/application/Espo/Modules/Crm/Resources/i18n/vi_VN/Account.json index 89659d96f3..3302a2d07e 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/vi_VN/Account.json +++ b/application/Espo/Modules/Crm/Resources/i18n/vi_VN/Account.json @@ -1,40 +1,40 @@ { - "fields": { - "name": "Tên", - "emailAddress": "Email", - "website": "Website", - "phoneNumber": "Điện thoại", - "billingAddress": "Địa chủ thanh toán", - "shippingAddress": "Địa chỉ vận chuyển", - "description": "Mô tả", - "sicCode": "Mã Sic", - "industry": "Industry", - "type": "Loại", - "contactRole": "Vai trò" - }, - "links": { - "contacts": "Sổ liên lạc", - "opportunities": "Cơ hội", - "cases": "Trường hợp" - }, - "options": { - "type": { - "Customer": "Khách hàng", - "Investor": "Nhà đầu tư", - "Partner": "Đối tác", - "Reseller": "Đại lý" - }, - "industry": { - "Apparel": "May mặc", - "Banking": "Ngân hàng", - "Computer Software": "Phần mềm", - "Education": "Giáo dục", - "Electronics": "Điện máy", - "Finance": "Tín dụng", - "Insurance": "Bảo hiểm" - } - }, - "labels": { - "Create Account": "Tạo tài khoản" - } + "fields": { + "name": "Tên", + "emailAddress": "Email", + "website": "Website", + "phoneNumber": "Điện thoại", + "billingAddress": "Địa chủ thanh toán", + "shippingAddress": "Địa chỉ vận chuyển", + "description": "Mô tả", + "sicCode": "Mã Sic", + "industry": "Industry", + "type": "Loại", + "contactRole": "Vai trò" + }, + "links": { + "contacts": "Sổ liên lạc", + "opportunities": "Cơ hội", + "cases": "Trường hợp" + }, + "options": { + "type": { + "Customer": "Khách hàng", + "Investor": "Nhà đầu tư", + "Partner": "Đối tác", + "Reseller": "Đại lý" + }, + "industry": { + "Apparel": "May mặc", + "Banking": "Ngân hàng", + "Computer Software": "Phần mềm", + "Education": "Giáo dục", + "Electronics": "Điện máy", + "Finance": "Tín dụng", + "Insurance": "Bảo hiểm" + } + }, + "labels": { + "Create Account": "Tạo tài khoản" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/vi_VN/Calendar.json b/application/Espo/Modules/Crm/Resources/i18n/vi_VN/Calendar.json index 8a933a8ae8..0f13cf2d1a 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/vi_VN/Calendar.json +++ b/application/Espo/Modules/Crm/Resources/i18n/vi_VN/Calendar.json @@ -1,13 +1,13 @@ { - "modes": { - "month": "Tháng", - "week": "Tuần", - "day": "Ngày", - "agendaWeek": "Tuần", - "agendaDay": "Ngày" - }, - "labels": { - "Today": "Today", - "Create": "Tạo" - } + "modes": { + "month": "Tháng", + "week": "Tuần", + "day": "Ngày", + "agendaWeek": "Tuần", + "agendaDay": "Ngày" + }, + "labels": { + "Today": "Today", + "Create": "Tạo" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/vi_VN/Call.json b/application/Espo/Modules/Crm/Resources/i18n/vi_VN/Call.json index f9a01bddf3..7f62e0e452 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/vi_VN/Call.json +++ b/application/Espo/Modules/Crm/Resources/i18n/vi_VN/Call.json @@ -1,39 +1,39 @@ { - "fields": { - "name": "Tên", - "parent": "Chủ", - "status": "Trạng thái", - "dateStart": "Ngày bắt đầu", - "dateEnd": "Ngày kết thúc", - "direction": "Hướng", - "duration": "Thời gian", - "description": "Mô tả", - "users": "Người dùng", - "contacts": "Sổ liên lạc", - "leads": "Trưởng nhóm" - }, - "links": { - }, - "options": { - "status": { - "Planned": "Đã lên kế hoạch", - "Held": "Đã được tổ chức", - "Not Held": "Chưa được tổ chức" - }, - "direction": { - "Outbound": "Ra ngoài", - "Inbound": "Vào trong" - } - }, - "labels": { - "Create Call": "Tạo cuộc gọi", - "Set Held": "Tổ chức", - "Set Not Held": "Không tổ chức", - "Send Invitations": "Gửi giấy mời" - }, - "presetFilters": { - "planned": "Đã lên kế hoạch", - "held": "Đã được tổ chức", - "todays": "Hôm nay" - } + "fields": { + "name": "Tên", + "parent": "Chủ", + "status": "Trạng thái", + "dateStart": "Ngày bắt đầu", + "dateEnd": "Ngày kết thúc", + "direction": "Hướng", + "duration": "Thời gian", + "description": "Mô tả", + "users": "Người dùng", + "contacts": "Sổ liên lạc", + "leads": "Trưởng nhóm" + }, + "links": { + }, + "options": { + "status": { + "Planned": "Đã lên kế hoạch", + "Held": "Đã được tổ chức", + "Not Held": "Chưa được tổ chức" + }, + "direction": { + "Outbound": "Ra ngoài", + "Inbound": "Vào trong" + } + }, + "labels": { + "Create Call": "Tạo cuộc gọi", + "Set Held": "Tổ chức", + "Set Not Held": "Không tổ chức", + "Send Invitations": "Gửi giấy mời" + }, + "presetFilters": { + "planned": "Đã lên kế hoạch", + "held": "Đã được tổ chức", + "todays": "Hôm nay" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/vi_VN/Case.json b/application/Espo/Modules/Crm/Resources/i18n/vi_VN/Case.json index 26a6371ac7..13c91aa5c4 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/vi_VN/Case.json +++ b/application/Espo/Modules/Crm/Resources/i18n/vi_VN/Case.json @@ -1,42 +1,42 @@ { - "fields": { - "name": "Tên", - "number": "Số", - "status": "Trạng thái", - "account": "Tài khoản", - "contact": "Liên hệ", - "priority": "Ưu tiên", - "type": "Loại", - "description": "Mô tả" - }, - "links": { - }, - "options": { - "status": { - "New": "Mới", - "Assigned": "Chỉ định", - "Pending": "Đang chờ", - "Closed": "Đã đóng", - "Rejected": "Đã từ chối", - "Duplicate": "Trùng" - }, - "priority" : { - "Low": "Thấp", - "Normal": "Bình thường", - "High": "Cao", - "Urgent": "Gấp" - }, - "type": { - "Question": "Câu hỏi", - "Incident": "Sự cố", - "Problem": "Có vấn đề" - } - }, - "labels": { - "Create Case": "Tạo trường hợp" - }, - "presetFilters": { - "open": "Mở", - "closed": "Đã đóng" - } + "fields": { + "name": "Tên", + "number": "Số", + "status": "Trạng thái", + "account": "Tài khoản", + "contact": "Liên hệ", + "priority": "Ưu tiên", + "type": "Loại", + "description": "Mô tả" + }, + "links": { + }, + "options": { + "status": { + "New": "Mới", + "Assigned": "Chỉ định", + "Pending": "Đang chờ", + "Closed": "Đã đóng", + "Rejected": "Đã từ chối", + "Duplicate": "Trùng" + }, + "priority" : { + "Low": "Thấp", + "Normal": "Bình thường", + "High": "Cao", + "Urgent": "Gấp" + }, + "type": { + "Question": "Câu hỏi", + "Incident": "Sự cố", + "Problem": "Có vấn đề" + } + }, + "labels": { + "Create Case": "Tạo trường hợp" + }, + "presetFilters": { + "open": "Mở", + "closed": "Đã đóng" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/vi_VN/Contact.json b/application/Espo/Modules/Crm/Resources/i18n/vi_VN/Contact.json index 9a6f701dfd..4c2e68155f 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/vi_VN/Contact.json +++ b/application/Espo/Modules/Crm/Resources/i18n/vi_VN/Contact.json @@ -1,31 +1,31 @@ { - "fields": { - "name": "Tên", - "emailAddress": "Email", - "title": "Tiêu đề", - "account": "Tài khoản", - "accounts": "Tài khoản", - "phoneNumber": "Điện thoại", - "accountType": "Loại tài khoản", - "doNotCall": "Không gọi", - "address": "Địa chỉ", - "opportunityRole": "Vai trò cơ hội", - "accountRole": "Vai trò", - "description": "Mô tả" - }, - "links": { - "opportunities": "Cơ hội", - "cases": "Trường hợp" - }, - "labels": { - "Create Contact": "Tạo liên hệ" - }, - "options": { - "opportunityRole": { - "": "--Trống--", - "Decision Maker": "Tạo quyết định", - "Evaluator": "Đánh giá", - "Influencer": "Phụ thuộc" - } - } + "fields": { + "name": "Tên", + "emailAddress": "Email", + "title": "Tiêu đề", + "account": "Tài khoản", + "accounts": "Tài khoản", + "phoneNumber": "Điện thoại", + "accountType": "Loại tài khoản", + "doNotCall": "Không gọi", + "address": "Địa chỉ", + "opportunityRole": "Vai trò cơ hội", + "accountRole": "Vai trò", + "description": "Mô tả" + }, + "links": { + "opportunities": "Cơ hội", + "cases": "Trường hợp" + }, + "labels": { + "Create Contact": "Tạo liên hệ" + }, + "options": { + "opportunityRole": { + "": "--Trống--", + "Decision Maker": "Tạo quyết định", + "Evaluator": "Đánh giá", + "Influencer": "Phụ thuộc" + } + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/vi_VN/Global.json b/application/Espo/Modules/Crm/Resources/i18n/vi_VN/Global.json index e02d4ff90c..f9e1f2344c 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/vi_VN/Global.json +++ b/application/Espo/Modules/Crm/Resources/i18n/vi_VN/Global.json @@ -1,79 +1,79 @@ { - "scopeNames": { - "Account": "Tài khoản", - "Contact": "Liên hệ", - "Lead": "Chỉ dẫn", - "Target": "Mục tiêu", - "Opportunity": "Cơ hội", - "Meeting": "Buổi gặp", - "Calendar": "Lịch", - "Call": "Gọi", - "Task": "Nhiệm vụ", - "Case": "Trường hợp", - "InboundEmail": "Email tới" - }, - "scopeNamesPlural": { - "Account": "Tài khoản", - "Contact": "Sổ liên lạc", - "Lead": "Trưởng nhóm", - "Target": "Mục tiêu", - "Opportunity": "Cơ hội", - "Meeting": "Hẹn gặp", - "Calendar": "Lịch", - "Call": "Cuộc gọi", - "Task": "Nhiệm vụ", - "Case": "Trường hợp", - "InboundEmail": "Email đã nhận" - }, - "dashlets": { - "Leads": "Chỉ dẫn của tôi", - "Opportunities": "Cơ hội của tôi", - "Tasks": "Nhiệm vụ của tôi", - "Cases": "Công việc của tôi", - "Calendar": "Lịch", - "OpportunitiesByStage": "Chia mức cơ hội", - "OpportunitiesByLeadSource": "Phân chia cơ hội theo người chỉ dẫn", - "SalesByMonth": "Doanh thu hàng tháng", - "SalesPipeline": "Doanh thu đường ống" - }, - "labels": { - "Create InboundEmail": "Tạo email đến", - "Activities": "Hành động", - "History": "Lịch sử", - "Attendees": "Người dự", - "Schedule Meeting": "Lên lịch hẹn", - "Schedule Call": "Lên lịch gọi", - "Compose Email": "Tạo email", - "Log Meeting": "Log cuộc hẹn", - "Log Call": "Log cuộc gọi", - "Archive Email": "Email lưu trữ", - "Create Task": "Tạo nhiệm vụ", - "Tasks": "Nhiệm vụ" - }, - "fields": { - "billingAddressCity": "Quận - huyện", - "billingAddressCountry": "Quốc gia", - "billingAddressPostalCode": "Mã bưu điện", - "billingAddressState": "Thành phố", - "billingAddressStreet": "Đường", - "addressCity": "Quận - huyện", - "addressStreet": "Đường", - "addressCountry": "Quốc gia", - "addressState": "Thành phố", - "addressPostalCode": "Mã bưu điện", - "shippingAddressCity": "City (Shipping)", - "shippingAddressStreet": "Street (Shipping)", - "shippingAddressCountry": "Country (Shipping)", - "shippingAddressState": "State (Shipping)", - "shippingAddressPostalCode": "Postal Code (Shipping)" - }, - "links": { - "contacts": "Sổ liên lạc", - "opportunities": "Cơ hội", - "leads": "Trưởng nhóm", - "meetings": "Hẹn gặp", - "calls": "Cuộc gọi", - "tasks": "Nhiệm vụ", - "emails": "Địa chỉ email" - } + "scopeNames": { + "Account": "Tài khoản", + "Contact": "Liên hệ", + "Lead": "Chỉ dẫn", + "Target": "Mục tiêu", + "Opportunity": "Cơ hội", + "Meeting": "Buổi gặp", + "Calendar": "Lịch", + "Call": "Gọi", + "Task": "Nhiệm vụ", + "Case": "Trường hợp", + "InboundEmail": "Email tới" + }, + "scopeNamesPlural": { + "Account": "Tài khoản", + "Contact": "Sổ liên lạc", + "Lead": "Trưởng nhóm", + "Target": "Mục tiêu", + "Opportunity": "Cơ hội", + "Meeting": "Hẹn gặp", + "Calendar": "Lịch", + "Call": "Cuộc gọi", + "Task": "Nhiệm vụ", + "Case": "Trường hợp", + "InboundEmail": "Email đã nhận" + }, + "dashlets": { + "Leads": "Chỉ dẫn của tôi", + "Opportunities": "Cơ hội của tôi", + "Tasks": "Nhiệm vụ của tôi", + "Cases": "Công việc của tôi", + "Calendar": "Lịch", + "OpportunitiesByStage": "Chia mức cơ hội", + "OpportunitiesByLeadSource": "Phân chia cơ hội theo người chỉ dẫn", + "SalesByMonth": "Doanh thu hàng tháng", + "SalesPipeline": "Doanh thu đường ống" + }, + "labels": { + "Create InboundEmail": "Tạo email đến", + "Activities": "Hành động", + "History": "Lịch sử", + "Attendees": "Người dự", + "Schedule Meeting": "Lên lịch hẹn", + "Schedule Call": "Lên lịch gọi", + "Compose Email": "Tạo email", + "Log Meeting": "Log cuộc hẹn", + "Log Call": "Log cuộc gọi", + "Archive Email": "Email lưu trữ", + "Create Task": "Tạo nhiệm vụ", + "Tasks": "Nhiệm vụ" + }, + "fields": { + "billingAddressCity": "Quận - huyện", + "billingAddressCountry": "Quốc gia", + "billingAddressPostalCode": "Mã bưu điện", + "billingAddressState": "Thành phố", + "billingAddressStreet": "Đường", + "addressCity": "Quận - huyện", + "addressStreet": "Đường", + "addressCountry": "Quốc gia", + "addressState": "Thành phố", + "addressPostalCode": "Mã bưu điện", + "shippingAddressCity": "City (Shipping)", + "shippingAddressStreet": "Street (Shipping)", + "shippingAddressCountry": "Country (Shipping)", + "shippingAddressState": "State (Shipping)", + "shippingAddressPostalCode": "Postal Code (Shipping)" + }, + "links": { + "contacts": "Sổ liên lạc", + "opportunities": "Cơ hội", + "leads": "Trưởng nhóm", + "meetings": "Hẹn gặp", + "calls": "Cuộc gọi", + "tasks": "Nhiệm vụ", + "emails": "Địa chỉ email" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/vi_VN/InboundEmail.json b/application/Espo/Modules/Crm/Resources/i18n/vi_VN/InboundEmail.json index f4d225149b..da3d864bfe 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/vi_VN/InboundEmail.json +++ b/application/Espo/Modules/Crm/Resources/i18n/vi_VN/InboundEmail.json @@ -1,43 +1,43 @@ { - "fields": { - "name": "Tên", - "team": "Nhóm", - "status": "Trạng thái", - "assignToUser": "Chỉ định", - "host": "Máy chủ", - "username": "Tên đăng nhập", - "password": "Mật khẩu", - "port": "Cổng", - "monitoredFolders": "Thư mục được theo dõi", - "trashFolder": "Thùng rác", - "ssl": "SSL", - "createCase": "Tạo trường hợp", - "reply": "Trả lời", - "caseDistribution": "Trường hợp phân phối", - "replyEmailTemplate": "Mẫu email trả lời", - "replyFromAddress": "Địa chỉ email trả lời", - "replyFromName": "Tên người gửi" - }, - "links": { - }, - "options": { - "status": { - "Active": "Đang hoạt động", - "Inactive": "Chưa hoạt động" - }, - "caseDistribution": { - "Direct-Assignment": "Direct-Assignment", - "Round-Robin": "Round-Robin", - "Least-Busy": "Least-Busy" - } - }, - "labels": { - "Create InboundEmail": "Tạo email đến", - "IMAP": "IMAP", - "Actions": "Hoạt động", - "Main": "Chính" - }, - "messages": { - "couldNotConnectToImap": "Không thể kết nối với máy chủ IMAP" - } + "fields": { + "name": "Tên", + "team": "Nhóm", + "status": "Trạng thái", + "assignToUser": "Chỉ định", + "host": "Máy chủ", + "username": "Tên đăng nhập", + "password": "Mật khẩu", + "port": "Cổng", + "monitoredFolders": "Thư mục được theo dõi", + "trashFolder": "Thùng rác", + "ssl": "SSL", + "createCase": "Tạo trường hợp", + "reply": "Trả lời", + "caseDistribution": "Trường hợp phân phối", + "replyEmailTemplate": "Mẫu email trả lời", + "replyFromAddress": "Địa chỉ email trả lời", + "replyFromName": "Tên người gửi" + }, + "links": { + }, + "options": { + "status": { + "Active": "Đang hoạt động", + "Inactive": "Chưa hoạt động" + }, + "caseDistribution": { + "Direct-Assignment": "Direct-Assignment", + "Round-Robin": "Round-Robin", + "Least-Busy": "Least-Busy" + } + }, + "labels": { + "Create InboundEmail": "Tạo email đến", + "IMAP": "IMAP", + "Actions": "Hoạt động", + "Main": "Chính" + }, + "messages": { + "couldNotConnectToImap": "Không thể kết nối với máy chủ IMAP" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/vi_VN/Lead.json b/application/Espo/Modules/Crm/Resources/i18n/vi_VN/Lead.json index 99628058b9..52ccf6fd6e 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/vi_VN/Lead.json +++ b/application/Espo/Modules/Crm/Resources/i18n/vi_VN/Lead.json @@ -1,49 +1,49 @@ { - "labels": { - "Converted To": "Đã chuyển đổi sang", - "Create Lead": "Tạo chỉ dẫn", - "Convert": "Chuyển đổi" - }, - "fields": { - "name": "Tên", - "emailAddress": "Email", - "title": "Tiêu đề", - "website": "Website", - "phoneNumber": "Điện thoại", - "accountName": "Tên tài khoản", - "doNotCall": "Không gọi", - "address": "Địa chỉ", - "status": "Trạng thái", - "source": "Nguồn", - "opportunityAmount": "Trị giá", - "description": "Mô tả", - "createdAccount": "Tài khoản", - "createdContact": "Liên hệ", - "createdOpportunity": "Cơ hội" - }, - "links": { - }, - "options": { - "status": { - "New": "Mới", - "Assigned": "Chỉ định", - "In Process": "Đang tiến hành", - "Converted": "Đã chuyển đổi", - "Recycled": "Thùng rác", - "Dead": "Chết" - }, - "source": { - "Call": "Gọi", - "Email": "Email", - "Existing Customer": "Khách hàng hiện có", - "Partner": "Đối tác", - "Public Relations": "Khách hàng công khai", - "Web Site": "Web Site", - "Campaign": "Chiến dịch", - "Other": "Khác" - } - }, - "presetFilters": { - "active": "Đang hoạt động" - } + "labels": { + "Converted To": "Đã chuyển đổi sang", + "Create Lead": "Tạo chỉ dẫn", + "Convert": "Chuyển đổi" + }, + "fields": { + "name": "Tên", + "emailAddress": "Email", + "title": "Tiêu đề", + "website": "Website", + "phoneNumber": "Điện thoại", + "accountName": "Tên tài khoản", + "doNotCall": "Không gọi", + "address": "Địa chỉ", + "status": "Trạng thái", + "source": "Nguồn", + "opportunityAmount": "Trị giá", + "description": "Mô tả", + "createdAccount": "Tài khoản", + "createdContact": "Liên hệ", + "createdOpportunity": "Cơ hội" + }, + "links": { + }, + "options": { + "status": { + "New": "Mới", + "Assigned": "Chỉ định", + "In Process": "Đang tiến hành", + "Converted": "Đã chuyển đổi", + "Recycled": "Thùng rác", + "Dead": "Chết" + }, + "source": { + "Call": "Gọi", + "Email": "Email", + "Existing Customer": "Khách hàng hiện có", + "Partner": "Đối tác", + "Public Relations": "Khách hàng công khai", + "Web Site": "Web Site", + "Campaign": "Chiến dịch", + "Other": "Khác" + } + }, + "presetFilters": { + "active": "Đang hoạt động" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/vi_VN/Meeting.json b/application/Espo/Modules/Crm/Resources/i18n/vi_VN/Meeting.json index 5229a8f824..c1bb810c7a 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/vi_VN/Meeting.json +++ b/application/Espo/Modules/Crm/Resources/i18n/vi_VN/Meeting.json @@ -1,36 +1,36 @@ { - "fields": { - "name": "Tên", - "parent": "Chủ", - "status": "Trạng thái", - "dateStart": "Ngày bắt đầu", - "dateEnd": "Ngày kết thúc", - "duration": "Thời gian", - "description": "Mô tả", - "users": "Người dùng", - "contacts": "Sổ liên lạc", - "leads": "Trưởng nhóm" - }, - "links": { - }, - "options": { - "status": { - "Planned": "Đã lên kế hoạch", - "Held": "Đã được tổ chức", - "Not Held": "Chưa được tổ chức" - } - }, - "labels": { - "Create Meeting": "Tạo buổi hẹn", - "Set Held": "Tổ chức", - "Set Not Held": "Không tổ chức", - "Send Invitations": "Gửi giấy mời", - "Saved as Held": "Lưu là đã tổ chức", - "Saved as Not Held": "Lưu là chưa tổ chức" - }, - "presetFilters": { - "planned": "Đã lên kế hoạch", - "held": "Đã được tổ chức", - "todays": "Hôm nay" - } + "fields": { + "name": "Tên", + "parent": "Chủ", + "status": "Trạng thái", + "dateStart": "Ngày bắt đầu", + "dateEnd": "Ngày kết thúc", + "duration": "Thời gian", + "description": "Mô tả", + "users": "Người dùng", + "contacts": "Sổ liên lạc", + "leads": "Trưởng nhóm" + }, + "links": { + }, + "options": { + "status": { + "Planned": "Đã lên kế hoạch", + "Held": "Đã được tổ chức", + "Not Held": "Chưa được tổ chức" + } + }, + "labels": { + "Create Meeting": "Tạo buổi hẹn", + "Set Held": "Tổ chức", + "Set Not Held": "Không tổ chức", + "Send Invitations": "Gửi giấy mời", + "Saved as Held": "Lưu là đã tổ chức", + "Saved as Not Held": "Lưu là chưa tổ chức" + }, + "presetFilters": { + "planned": "Đã lên kế hoạch", + "held": "Đã được tổ chức", + "todays": "Hôm nay" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/vi_VN/Opportunity.json b/application/Espo/Modules/Crm/Resources/i18n/vi_VN/Opportunity.json index 30431bb217..6f9380ef01 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/vi_VN/Opportunity.json +++ b/application/Espo/Modules/Crm/Resources/i18n/vi_VN/Opportunity.json @@ -1,38 +1,38 @@ { - "fields": { - "name": "Tên", - "account": "Tài khoản", - "stage": "Mức", - "amount": "Tổng", - "probability": "Xác suất, %", - "leadSource": "Nguồn dẫn", - "doNotCall": "Không gọi", - "closeDate": "Ngày kết thúc", - "contacts": "Sổ liên lạc", - "description": "Mô tả" - }, - "links": { - "contacts": "Sổ liên lạc" - }, - "options": { - "stage": { - "Prospecting": "Khảo sát", - "Qualification": "Trình độ chuyên môn", - "Needs Analysis": "Phân tích nhu cầu", - "Value Proposition": "Đề xuất giá trị", - "Id. Decision Makers": "Id. Người tạo quyết định", - "Perception Analysis": "Phân tích khả năng", - "Proposal/Price Quote": "Giá đặt ra", - "Negotiation/Review": "Đàm phán / đánh giá", - "Closed Won": "Thắng thầu", - "Closed Lost": "Thua thầu" - } - }, - "labels": { - "Create Opportunity": "Tạo cơ hội" - }, - "presetFilters": { - "open": "Mở", - "won": "Thắng" - } + "fields": { + "name": "Tên", + "account": "Tài khoản", + "stage": "Mức", + "amount": "Tổng", + "probability": "Xác suất, %", + "leadSource": "Nguồn dẫn", + "doNotCall": "Không gọi", + "closeDate": "Ngày kết thúc", + "contacts": "Sổ liên lạc", + "description": "Mô tả" + }, + "links": { + "contacts": "Sổ liên lạc" + }, + "options": { + "stage": { + "Prospecting": "Khảo sát", + "Qualification": "Trình độ chuyên môn", + "Needs Analysis": "Phân tích nhu cầu", + "Value Proposition": "Đề xuất giá trị", + "Id. Decision Makers": "Id. Người tạo quyết định", + "Perception Analysis": "Phân tích khả năng", + "Proposal/Price Quote": "Giá đặt ra", + "Negotiation/Review": "Đàm phán / đánh giá", + "Closed Won": "Thắng thầu", + "Closed Lost": "Thua thầu" + } + }, + "labels": { + "Create Opportunity": "Tạo cơ hội" + }, + "presetFilters": { + "open": "Mở", + "won": "Thắng" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/vi_VN/Target.json b/application/Espo/Modules/Crm/Resources/i18n/vi_VN/Target.json index 97cd91cf7f..86a8cba83d 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/vi_VN/Target.json +++ b/application/Espo/Modules/Crm/Resources/i18n/vi_VN/Target.json @@ -1,19 +1,19 @@ { - "fields": { - "name": "Tên", - "emailAddress": "Email", - "title": "Tiêu đề", - "website": "Website", - "accountName": "Tên tài khoản", - "phoneNumber": "Điện thoại", - "doNotCall": "Không gọi", - "address": "Địa chỉ", - "description": "Mô tả" - }, - "links": { - }, - "labels": { - "Create Target": "Tạo mục tiêu", - "Convert to Lead": "Chuyển đổi thành chỉ dẫn" - } + "fields": { + "name": "Tên", + "emailAddress": "Email", + "title": "Tiêu đề", + "website": "Website", + "accountName": "Tên tài khoản", + "phoneNumber": "Điện thoại", + "doNotCall": "Không gọi", + "address": "Địa chỉ", + "description": "Mô tả" + }, + "links": { + }, + "labels": { + "Create Target": "Tạo mục tiêu", + "Convert to Lead": "Chuyển đổi thành chỉ dẫn" + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/vi_VN/Task.json b/application/Espo/Modules/Crm/Resources/i18n/vi_VN/Task.json index 0417c40e06..b888b642ab 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/vi_VN/Task.json +++ b/application/Espo/Modules/Crm/Resources/i18n/vi_VN/Task.json @@ -1,37 +1,37 @@ { - "fields": { - "name": "Tên", - "parent": "Chủ", - "status": "Trạng thái", - "dateStart": "Ngày bắt đầu", - "dateEnd": "Hạn", - "priority": "Ưu tiên", - "description": "Mô tả", - "isOverdue": "Đã quá hạn" - }, - "links": { - }, - "options": { - "status": { - "Not Started": "Chưa bắt đầu", - "Started": "Đã bắt đầu", - "Completed": "Hoàn thành", - "Canceled": "Hủy" - }, - "priority" : { - "Low": "Thấp", - "Normal": "Bình thường", - "High": "Cao", - "Urgent": "Gấp" - } - }, - "labels": { - "Create Task": "Tạo nhiệm vụ" - }, - "presetFilters": { - "active": "Đang hoạt động", - "completed": "Hoàn thành", - "todays": "Hôm nay", - "overdue": "Quá hạn" - } + "fields": { + "name": "Tên", + "parent": "Chủ", + "status": "Trạng thái", + "dateStart": "Ngày bắt đầu", + "dateEnd": "Hạn", + "priority": "Ưu tiên", + "description": "Mô tả", + "isOverdue": "Đã quá hạn" + }, + "links": { + }, + "options": { + "status": { + "Not Started": "Chưa bắt đầu", + "Started": "Đã bắt đầu", + "Completed": "Hoàn thành", + "Canceled": "Hủy" + }, + "priority" : { + "Low": "Thấp", + "Normal": "Bình thường", + "High": "Cao", + "Urgent": "Gấp" + } + }, + "labels": { + "Create Task": "Tạo nhiệm vụ" + }, + "presetFilters": { + "active": "Đang hoạt động", + "completed": "Hoàn thành", + "todays": "Hôm nay", + "overdue": "Quá hạn" + } } diff --git a/application/Espo/Modules/Crm/Resources/layouts/Account/detail.json b/application/Espo/Modules/Crm/Resources/layouts/Account/detail.json index ce52801f3d..4e76ff18e1 100644 --- a/application/Espo/Modules/Crm/Resources/layouts/Account/detail.json +++ b/application/Espo/Modules/Crm/Resources/layouts/Account/detail.json @@ -1,19 +1,19 @@ [ - { - "label":"Overview", - "rows": [ - [{"name":"name"},false], - [{"name":"emailAddress"},{"name":"phoneNumber"}], - [{"name":"website"},false], - [{"name":"billingAddress"},{"name":"shippingAddress"}], - [{"name":"description"},false] - ] - }, - { - "label":"Details", - "rows": [ - [{"name":"type"},{"name":"sicCode"}], - [{"name":"industry"},false] - ] - } + { + "label":"Overview", + "rows": [ + [{"name":"name"},false], + [{"name":"emailAddress"},{"name":"phoneNumber"}], + [{"name":"website"},false], + [{"name":"billingAddress"},{"name":"shippingAddress"}], + [{"name":"description", "fullWidth": true}] + ] + }, + { + "label":"Details", + "rows": [ + [{"name":"type"},{"name":"sicCode"}], + [{"name":"industry"},false] + ] + } ] diff --git a/application/Espo/Modules/Crm/Resources/layouts/Account/detailConvert.json b/application/Espo/Modules/Crm/Resources/layouts/Account/detailConvert.json index 23915f546a..e0d9fe873e 100644 --- a/application/Espo/Modules/Crm/Resources/layouts/Account/detailConvert.json +++ b/application/Espo/Modules/Crm/Resources/layouts/Account/detailConvert.json @@ -1,18 +1,18 @@ [ - { - "label":"Overview", - "rows":[ - [{"name":"name"},false], - [{"name":"website"},{"name":"phoneNumber"}], - [{"name":"emailAddress"},false], - [{"name":"billingAddress"},{"name":"shippingAddress"}], - [{"name":"description"},false] - ] - }, { - "label":"Details", - "rows":[ - [{"name":"type"},{"name":"sicCode"}], - [{"name":"industry"},false] - ] - } + { + "label":"Overview", + "rows":[ + [{"name":"name"},false], + [{"name":"website"},{"name":"phoneNumber"}], + [{"name":"emailAddress"},false], + [{"name":"billingAddress"},{"name":"shippingAddress"}], + [{"name":"description", "fullWidth": true}] + ] + }, { + "label":"Details", + "rows":[ + [{"name":"type"},{"name":"sicCode"}], + [{"name":"industry"},false] + ] + } ] diff --git a/application/Espo/Modules/Crm/Resources/layouts/Call/detail.json b/application/Espo/Modules/Crm/Resources/layouts/Call/detail.json index 0d2a22046e..0abf4871f0 100644 --- a/application/Espo/Modules/Crm/Resources/layouts/Call/detail.json +++ b/application/Espo/Modules/Crm/Resources/layouts/Call/detail.json @@ -1,13 +1,13 @@ [ - { - "label":"Overview", - "rows": [ - [ - {"name":"name"},{"name":"parent"}], - [{"name":"status"}, {"name":"direction"}], - [{"name":"dateStart"}], - [{"name":"duration"}], - [{"name":"description"},false] - ] - } + { + "label":"Overview", + "rows": [ + [ + {"name":"name"},{"name":"parent"}], + [{"name":"status"}, {"name":"direction"}], + [{"name":"dateStart"}], + [{"name":"duration"}], + [{"name":"description"},false] + ] + } ] diff --git a/application/Espo/Modules/Crm/Resources/layouts/Case/detail.json b/application/Espo/Modules/Crm/Resources/layouts/Case/detail.json index 5abf260bd7..d7eee59570 100644 --- a/application/Espo/Modules/Crm/Resources/layouts/Case/detail.json +++ b/application/Espo/Modules/Crm/Resources/layouts/Case/detail.json @@ -1 +1,12 @@ -[{"label":"Overview","rows":[[{"name":"name"},{"name":"number"}],[{"name":"status"},{"name":"account"}],[{"name":"priority"},{"name":"contact"}],[{"name":"type"},false],[{"name":"description"},false]]}] +[ + { + "label":"Overview", + "rows":[ + [{"name":"name"},{"name":"number"}], + [{"name":"status"},{"name":"account"}], + [{"name":"priority"},{"name":"contact"}], + [{"name":"type"},false], + [{"name":"description", "fullWidth": true}] + ] + } +] diff --git a/application/Espo/Modules/Crm/Resources/layouts/Case/list.json b/application/Espo/Modules/Crm/Resources/layouts/Case/list.json index 156a723ccd..fcc0c7d09f 100644 --- a/application/Espo/Modules/Crm/Resources/layouts/Case/list.json +++ b/application/Espo/Modules/Crm/Resources/layouts/Case/list.json @@ -1 +1,8 @@ -[{"name":"number","width":15},{"name":"name","width":30,"link":true},{"name":"status","width":15},{"name":"priority","width":15},{"name":"assignedUser","width":15}] \ No newline at end of file +[ + {"name":"number","width":12}, + {"name":"name","width":30,"link":true}, + {"name":"status"}, + {"name":"priority"}, + {"name":"account"}, + {"name":"assignedUser"} +] \ No newline at end of file diff --git a/application/Espo/Modules/Crm/Resources/layouts/Contact/detail.json b/application/Espo/Modules/Crm/Resources/layouts/Contact/detail.json index 24cf4f47f8..6b01f50da4 100644 --- a/application/Espo/Modules/Crm/Resources/layouts/Contact/detail.json +++ b/application/Espo/Modules/Crm/Resources/layouts/Contact/detail.json @@ -1,11 +1,11 @@ [ - { - "label":"Overview", - "rows":[ - [{"name":"name"},{"name":"accounts"}], - [{"name":"emailAddress"},{"name":"phoneNumber"}], - [{"name":"address"},{"name":"doNotCall"}], - [{"name":"description"},false] - ] - } + { + "label":"Overview", + "rows":[ + [{"name":"name"},{"name":"accounts"}], + [{"name":"emailAddress"},{"name":"phoneNumber"}], + [{"name":"address"},{"name":"doNotCall"}], + [{"name":"description", "fullWidth": true}] + ] + } ] diff --git a/application/Espo/Modules/Crm/Resources/layouts/Contact/detailConvert.json b/application/Espo/Modules/Crm/Resources/layouts/Contact/detailConvert.json index b49b6a9b94..65468430ee 100644 --- a/application/Espo/Modules/Crm/Resources/layouts/Contact/detailConvert.json +++ b/application/Espo/Modules/Crm/Resources/layouts/Contact/detailConvert.json @@ -1,12 +1,12 @@ [ - { - "label":"Overview", - "rows": [ - [{"name":"name"}], - [{"name":"emailAddress"},{"name":"phoneNumber"}], - [{"name":"title"}, {"name":"doNotCall"}], - [{"name":"address"}, false], - [{"name":"description"},false] - ] - } + { + "label":"Overview", + "rows": [ + [{"name":"name"}], + [{"name":"emailAddress"},{"name":"phoneNumber"}], + [{"name":"title"}, {"name":"doNotCall"}], + [{"name":"address"}, false], + [{"name":"description", "fullWidth": true}] + ] + } ] diff --git a/application/Espo/Modules/Crm/Resources/layouts/Contact/detailSmall.json b/application/Espo/Modules/Crm/Resources/layouts/Contact/detailSmall.json index 7ee66fb94d..68946d5abe 100644 --- a/application/Espo/Modules/Crm/Resources/layouts/Contact/detailSmall.json +++ b/application/Espo/Modules/Crm/Resources/layouts/Contact/detailSmall.json @@ -1,11 +1,11 @@ [ - { - "label": "", - "rows": [ - [{"name":"name"}], - [{"name":"accounts"}], - [{"name":"emailAddress"}], - [{"name":"phoneNumber"}] - ] - } + { + "label": "", + "rows": [ + [{"name":"name"}], + [{"name":"accounts"}], + [{"name":"emailAddress"}], + [{"name":"phoneNumber"}] + ] + } ] diff --git a/application/Espo/Modules/Crm/Resources/layouts/Contact/listForAccount.json b/application/Espo/Modules/Crm/Resources/layouts/Contact/listForAccount.json index fbc63da227..924e629737 100644 --- a/application/Espo/Modules/Crm/Resources/layouts/Contact/listForAccount.json +++ b/application/Espo/Modules/Crm/Resources/layouts/Contact/listForAccount.json @@ -1,6 +1,6 @@ [ - {"name":"name","width":32,"link":"true"}, - {"name":"accountRole", "notSortable": true}, - {"name":"emailAddress"}, - {"name":"phoneNumber"} + {"name":"name","width":32,"link":"true"}, + {"name":"accountRole", "notSortable": true}, + {"name":"emailAddress"}, + {"name":"phoneNumber"} ] diff --git a/application/Espo/Modules/Crm/Resources/layouts/Contact/listSmall.json b/application/Espo/Modules/Crm/Resources/layouts/Contact/listSmall.json index 8873704e66..8751974ebd 100644 --- a/application/Espo/Modules/Crm/Resources/layouts/Contact/listSmall.json +++ b/application/Espo/Modules/Crm/Resources/layouts/Contact/listSmall.json @@ -1,6 +1,6 @@ [ - {"name":"name","width":32,"link":"true"}, - {"name":"account"}, - {"name":"emailAddress"}, - {"name":"phoneNumber"} + {"name":"name","width":32,"link":"true"}, + {"name":"account"}, + {"name":"emailAddress"}, + {"name":"phoneNumber"} ] diff --git a/application/Espo/Modules/Crm/Resources/layouts/Document/detail.json b/application/Espo/Modules/Crm/Resources/layouts/Document/detail.json index f4fd3569ad..e561276349 100644 --- a/application/Espo/Modules/Crm/Resources/layouts/Document/detail.json +++ b/application/Espo/Modules/Crm/Resources/layouts/Document/detail.json @@ -1,17 +1,17 @@ [ - { - "label":false, - "rows":[ - [{"name":"file"}, {"name":"source"}], - [{"name":"name"}, {"name":"status"}], - [{"name":"type"}, false] - ] - }, - { - "label": "Details", - "rows": [ - [{"name":"publishDate"}, {"name":"expirationDate"}], - [{"name":"description"}, false] - ] - } + { + "label":false, + "rows":[ + [{"name":"file"}, {"name":"source"}], + [{"name":"name"}, {"name":"status"}], + [{"name":"type"}, false] + ] + }, + { + "label": "Details", + "rows": [ + [{"name":"publishDate"}, {"name":"expirationDate"}], + [{"name":"description", "fullWidth": true}] + ] + } ] diff --git a/application/Espo/Modules/Crm/Resources/layouts/Document/detailSmall.json b/application/Espo/Modules/Crm/Resources/layouts/Document/detailSmall.json index b066a21da2..6d8b82e016 100644 --- a/application/Espo/Modules/Crm/Resources/layouts/Document/detailSmall.json +++ b/application/Espo/Modules/Crm/Resources/layouts/Document/detailSmall.json @@ -1,12 +1,12 @@ [ - { - "label": false, - "rows": [ - [{"name":"source"}], - [{"name":"file"}], - [{"name":"name"}], - [{"name":"type"}], - [{"name":"status"}] - ] - } + { + "label": false, + "rows": [ + [{"name":"source"}], + [{"name":"file"}], + [{"name":"name"}], + [{"name":"type"}], + [{"name":"status"}] + ] + } ] diff --git a/application/Espo/Modules/Crm/Resources/layouts/Document/filters.json b/application/Espo/Modules/Crm/Resources/layouts/Document/filters.json index 9104416f02..09bee68fe6 100644 --- a/application/Espo/Modules/Crm/Resources/layouts/Document/filters.json +++ b/application/Espo/Modules/Crm/Resources/layouts/Document/filters.json @@ -1,6 +1,6 @@ [ - "type", - "status", - "publishDate", - "expirationDate" + "type", + "status", + "publishDate", + "expirationDate" ] diff --git a/application/Espo/Modules/Crm/Resources/layouts/Document/list.json b/application/Espo/Modules/Crm/Resources/layouts/Document/list.json index f90ca6dc4f..e318384ce3 100644 --- a/application/Espo/Modules/Crm/Resources/layouts/Document/list.json +++ b/application/Espo/Modules/Crm/Resources/layouts/Document/list.json @@ -1,7 +1,7 @@ [ - {"name":"name","width":25,"link":true}, - {"name":"file","width":25}, - {"name":"type"}, - {"name":"status"}, - {"name":"createdAt"} + {"name":"name","width":25,"link":true}, + {"name":"file","width":25}, + {"name":"type"}, + {"name":"status"}, + {"name":"createdAt"} ] diff --git a/application/Espo/Modules/Crm/Resources/layouts/Document/listSmall.json b/application/Espo/Modules/Crm/Resources/layouts/Document/listSmall.json index 7c4cea0402..08cdb7aec2 100644 --- a/application/Espo/Modules/Crm/Resources/layouts/Document/listSmall.json +++ b/application/Espo/Modules/Crm/Resources/layouts/Document/listSmall.json @@ -1,7 +1,7 @@ [ - {"name":"name","width":30,"link":true}, - {"name":"file","width":10, "view": "Crm:Document.Fields.FileShort","notSortable": true}, - {"name":"type"}, - {"name":"status"}, - {"name":"createdAt"} + {"name":"name","width":30,"link":true}, + {"name":"file","width":10, "view": "Crm:Document.Fields.FileShort","notSortable": true}, + {"name":"type"}, + {"name":"status"}, + {"name":"createdAt"} ] diff --git a/application/Espo/Modules/Crm/Resources/layouts/InboundEmail/detail.json b/application/Espo/Modules/Crm/Resources/layouts/InboundEmail/detail.json index 6b2be07cfb..7ca9730485 100644 --- a/application/Espo/Modules/Crm/Resources/layouts/InboundEmail/detail.json +++ b/application/Espo/Modules/Crm/Resources/layouts/InboundEmail/detail.json @@ -1,56 +1,56 @@ [ - { - "label":"Main", - "rows":[ - [ - {"name":"name"}, - {"name":"status"} - ], - [ - {"name":"team"} - - ], - [ - {"name":"assignToUser"} - ] - ] - }, - { - "label":"IMAP", - "rows":[ - [ - {"name":"host"},{"name":"ssl"} - ], - [ - {"name":"port"},{"name":"username"} - ], - [ - {"name":"monitoredFolders"},{"name":"password"} - ] - ] - }, - { - "label":"Actions", - "rows": [ - [ - {"name":"createCase"},{"name":"reply"} - ], - [ - {"name":"caseDistribution"}, - {"name":"replyEmailTemplate"} - ], - [ - false, - {"name":"replyToAddress"} - ], - [ - false, - {"name":"replyFromAddress"} - ], - [ - false, - {"name":"replyFromName"} - ] - ] - } + { + "label":"Main", + "rows":[ + [ + {"name":"name"}, + {"name":"status"} + ], + [ + {"name":"team"} + + ], + [ + {"name":"assignToUser"} + ] + ] + }, + { + "label":"IMAP", + "rows":[ + [ + {"name":"host"},{"name":"ssl"} + ], + [ + {"name":"port"},{"name":"username"} + ], + [ + {"name":"monitoredFolders"},{"name":"password"} + ] + ] + }, + { + "label":"Actions", + "rows": [ + [ + {"name":"createCase"},{"name":"reply"} + ], + [ + {"name":"caseDistribution"}, + {"name":"replyEmailTemplate"} + ], + [ + {"name":"targetUserPosition"}, + {"name":"replyToAddress"} + ], + [ + false, + {"name":"replyFromAddress"} + ], + [ + false, + {"name":"replyFromName"} + ] + ] + } ] diff --git a/application/Espo/Modules/Crm/Resources/layouts/Lead/detail.json b/application/Espo/Modules/Crm/Resources/layouts/Lead/detail.json index 58d0c96977..a5dfcbff79 100644 --- a/application/Espo/Modules/Crm/Resources/layouts/Lead/detail.json +++ b/application/Espo/Modules/Crm/Resources/layouts/Lead/detail.json @@ -1,17 +1,19 @@ [ - { - "label":"Overview", - "rows": [ - [{"name":"name"},{"name":"accountName"}], - [{"name":"emailAddress"},{"name":"phoneNumber"}], - [{"name":"title"},{"name":"doNotCall"}], - [{"name":"address"},{"name":"website"}], - [{"name":"description"},false]] - }, { - "label":"Details", - "rows": [ - [{"name":"status"},{"name":"source"}], - [{"name":"opportunityAmount"},false] - ] - } + { + "label":"Overview", + "rows": [ + [{"name":"name"},{"name":"accountName"}], + [{"name":"emailAddress"},{"name":"phoneNumber"}], + [{"name":"title"},{"name":"doNotCall"}], + [{"name":"address"},{"name":"website"}], + [{"name":"description", "fullWidth": true}] + ] + }, + { + "label":"Details", + "rows": [ + [{"name":"status"},{"name":"source"}], + [{"name":"opportunityAmount"},false] + ] + } ] diff --git a/application/Espo/Modules/Crm/Resources/layouts/Lead/detailSmall.json b/application/Espo/Modules/Crm/Resources/layouts/Lead/detailSmall.json index 8f122a9dd2..14c707edbe 100644 --- a/application/Espo/Modules/Crm/Resources/layouts/Lead/detailSmall.json +++ b/application/Espo/Modules/Crm/Resources/layouts/Lead/detailSmall.json @@ -1,19 +1,19 @@ [ - { - "label":"", - "rows":[ - [ - {"name":"name"} - ], - [ - {"name":"emailAddress"} - ], - [ - {"name":"phoneNumber"} - ], - [ - {"name":"status"} - ] - ] - } + { + "label":"", + "rows":[ + [ + {"name":"name"} + ], + [ + {"name":"emailAddress"} + ], + [ + {"name":"phoneNumber"} + ], + [ + {"name":"status"} + ] + ] + } ] diff --git a/application/Espo/Modules/Crm/Resources/layouts/Lead/filters.json b/application/Espo/Modules/Crm/Resources/layouts/Lead/filters.json index b24ec5b3ae..d7b544e659 100644 --- a/application/Espo/Modules/Crm/Resources/layouts/Lead/filters.json +++ b/application/Espo/Modules/Crm/Resources/layouts/Lead/filters.json @@ -1,7 +1,7 @@ [ - "status", - "source", - "opportunityAmountConverted", - "teams", - "address" + "status", + "source", + "opportunityAmountConverted", + "teams", + "address" ] diff --git a/application/Espo/Modules/Crm/Resources/layouts/Lead/listDashlet.json b/application/Espo/Modules/Crm/Resources/layouts/Lead/listDashlet.json index 81023fbc15..b7c7b7296b 100644 --- a/application/Espo/Modules/Crm/Resources/layouts/Lead/listDashlet.json +++ b/application/Espo/Modules/Crm/Resources/layouts/Lead/listDashlet.json @@ -1,5 +1,5 @@ [ - {"name":"name"}, - {"name":"emailAddress"}, - {"name":"city"} + {"name":"name"}, + {"name":"emailAddress"}, + {"name":"city"} ] diff --git a/application/Espo/Modules/Crm/Resources/layouts/Opportunity/detail.json b/application/Espo/Modules/Crm/Resources/layouts/Opportunity/detail.json index e900c534a3..edbffa92ec 100644 --- a/application/Espo/Modules/Crm/Resources/layouts/Opportunity/detail.json +++ b/application/Espo/Modules/Crm/Resources/layouts/Opportunity/detail.json @@ -1,12 +1,12 @@ [ - { - "label":"Overview", - "rows":[ - [{"name":"name"},{"name":"account"}], - [{"name":"stage"},{"name":"amount"}], - [{"name":"probability"},{"name":"leadSource"}], - [{"name":"contacts"},{"name":"closeDate"}], - [{"name":"description"},false] - ] - } + { + "label":"Overview", + "rows":[ + [{"name":"name"},{"name":"account"}], + [{"name":"stage"},{"name":"amount"}], + [{"name":"probability"},{"name":"leadSource"}], + [{"name":"contacts"},{"name":"closeDate"}], + [{"name":"description", "fullWidth": true}] + ] + } ] diff --git a/application/Espo/Modules/Crm/Resources/layouts/Opportunity/detailConvert.json b/application/Espo/Modules/Crm/Resources/layouts/Opportunity/detailConvert.json index 153e6641d6..d82bc87b36 100644 --- a/application/Espo/Modules/Crm/Resources/layouts/Opportunity/detailConvert.json +++ b/application/Espo/Modules/Crm/Resources/layouts/Opportunity/detailConvert.json @@ -1,12 +1,12 @@ [ - { - "label":"Overview", - "rows":[ - [{"name":"name"}], - [{"name":"stage"},{"name":"amount"}], - [{"name":"probability"}, false], - [{"name":"closeDate"},false], - [{"name":"description"},false] - ] - } + { + "label":"Overview", + "rows":[ + [{"name":"name"}], + [{"name":"stage"},{"name":"amount"}], + [{"name":"probability"}, false], + [{"name":"closeDate"},false], + [{"name":"description", "fullWidth": true}] + ] + } ] diff --git a/application/Espo/Modules/Crm/Resources/layouts/Opportunity/filters.json b/application/Espo/Modules/Crm/Resources/layouts/Opportunity/filters.json index 9784ff79d0..f7a6628473 100644 --- a/application/Espo/Modules/Crm/Resources/layouts/Opportunity/filters.json +++ b/application/Espo/Modules/Crm/Resources/layouts/Opportunity/filters.json @@ -1,10 +1,10 @@ [ - "teams", - "assignedUser", - "stage", - "probability", - "account", - "amountConverted", - "closeDate", - "leadSource" + "teams", + "assignedUser", + "stage", + "probability", + "account", + "amountConverted", + "closeDate", + "leadSource" ] diff --git a/application/Espo/Modules/Crm/Resources/metadata/app/jsLibs.json b/application/Espo/Modules/Crm/Resources/metadata/app/jsLibs.json index cc5a6f2fce..9e9bea9a05 100644 --- a/application/Espo/Modules/Crm/Resources/metadata/app/jsLibs.json +++ b/application/Espo/Modules/Crm/Resources/metadata/app/jsLibs.json @@ -1,7 +1,7 @@ { - "FullCalendar": { - "path": "client/modules/crm/lib/fullcalendar.min.js", - "exportsTo": "$", - "exportsAs": "fullCalendar" - } + "FullCalendar": { + "path": "client/modules/crm/lib/fullcalendar.min.js", + "exportsTo": "$", + "exportsAs": "fullCalendar" + } } diff --git a/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Call.json b/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Call.json index 7f32172640..92c669487a 100644 --- a/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Call.json +++ b/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Call.json @@ -1,81 +1,85 @@ { - "controller": "Controllers.Record", - "views":{ - "detail":"Crm:Call.Detail" - }, - "menu": { - "detail": { - "dropdown": [ - { - "label": "Duplicate", - "action": "duplicate", - "acl": "edit" - } - ] - } - }, - "sidePanels":{ - "detail":[ - { - "name":"attendees", - "label":"Attendees", - "view":"Record.Panels.Side", - "options":{ - "fields":[ - "users", - "contacts", - "leads" - ], - "mode":"detail" - } - } - ], - "edit":[ - { - "name":"attendees", - "label":"Attendees", - "view":"Record.Panels.Side", - "options":{ - "fields":[ - "users", - "contacts", - "leads" - ], - "mode":"edit" - } - } - ] - }, - "presetFilters": [ - { - "name":"planned", - "style": "primary", - "data": { - "status": { - "type": "in", - "value": ["Planned"] - } - } - }, - { - "name":"held", - "style": "success", - "data": { - "status": { - "type": "in", - "value": ["Held"] - } - } - }, - { - "name":"todays", - "data": { - "dateStart": { - "type": "today", - "dateTime": true - } - } - } - ], - "boolFilters": ["onlyMy"] + "controller": "Controllers.Record", + "views":{ + "detail":"Crm:Call.Detail", + "list": "Crm:Call.List" + }, + "recordViews":{ + "list":"Crm:Call.Record.List" + }, + "menu": { + "detail": { + "dropdown": [ + { + "label": "Duplicate", + "action": "duplicate", + "acl": "edit" + } + ] + } + }, + "sidePanels":{ + "detail":[ + { + "name":"attendees", + "label":"Attendees", + "view":"Record.Panels.Side", + "options":{ + "fields":[ + "users", + "contacts", + "leads" + ], + "mode":"detail" + } + } + ], + "edit":[ + { + "name":"attendees", + "label":"Attendees", + "view":"Record.Panels.Side", + "options":{ + "fields":[ + "users", + "contacts", + "leads" + ], + "mode":"edit" + } + } + ] + }, + "presetFilters": [ + { + "name":"planned", + "style": "primary", + "data": { + "status": { + "type": "in", + "value": ["Planned"] + } + } + }, + { + "name":"held", + "style": "success", + "data": { + "status": { + "type": "in", + "value": ["Held"] + } + } + }, + { + "name":"todays", + "data": { + "dateStart": { + "type": "today", + "dateTime": true + } + } + } + ], + "boolFilters": ["onlyMy"] } diff --git a/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Case.json b/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Case.json index 3bee9b8fe4..837fe3008a 100644 --- a/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Case.json +++ b/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Case.json @@ -45,5 +45,5 @@ } } ], - "boolFilters": ["onlyMy"] + "boolFilters": ["onlyMy"] } diff --git a/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Contact.json b/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Contact.json index d3d0214746..2e53aa5d20 100644 --- a/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Contact.json +++ b/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Contact.json @@ -22,5 +22,5 @@ } ] }, - "boolFilters": ["onlyMy"] + "boolFilters": ["onlyMy"] } diff --git a/application/Espo/Modules/Crm/Resources/metadata/clientDefs/InboundEmail.json b/application/Espo/Modules/Crm/Resources/metadata/clientDefs/InboundEmail.json index c984f52f3e..ebbf0bdb4a 100644 --- a/application/Espo/Modules/Crm/Resources/metadata/clientDefs/InboundEmail.json +++ b/application/Espo/Modules/Crm/Resources/metadata/clientDefs/InboundEmail.json @@ -1,48 +1,70 @@ { - "recordViews":{ - "detail":"Crm:InboundEmail.Record.Detail", - "edit":"Crm:InboundEmail.Record.Edit", - "list":"Crm:InboundEmail.Record.List" - }, - "formDependency": { - "createCase": { - "map": { - "true" : [ - { - "action": "show", - "fields": ["caseDistribution"] - } - ] - }, - "default": [ - { - "action": "hide", - "fields": ["caseDistribution"] - } - ] - }, - "reply": { - "map": { - "true" : [ - { - "action": "show", - "fields": ["replyEmailTemplate", "replyFromAddress", "replyFromName", "replyToAddress"] - }, { - "action": "setRequired", - "fields": ["replyEmailTemplate"] - } - ] - }, - "default": [ - { - "action": "hide", - "fields": ["replyEmailTemplate", "replyFromAddress", "replyFromName", "replyToAddress"] - }, { - "action": "setNotRequired", - "fields": ["replyEmailTemplate"] - } - ] - } - }, - "disableSearchPanel": true + "recordViews":{ + "detail":"Crm:InboundEmail.Record.Detail", + "edit":"Crm:InboundEmail.Record.Edit", + "list":"Crm:InboundEmail.Record.List" + }, + "formDependency": { + "createCase": { + "map": { + "true" : [ + { + "action": "show", + "fields": ["caseDistribution"] + } + ] + }, + "default": [ + { + "action": "hide", + "fields": ["caseDistribution"] + } + ] + }, + "caseDistribution": { + "map": { + "Round-Robin" : [ + { + "action": "show", + "fields": ["targetUserPosition"] + } + ], + "Least-Busy" : [ + { + "action": "show", + "fields": ["targetUserPosition"] + } + ] + }, + "default": [ + { + "action": "hide", + "fields": ["targetUserPosition"] + } + ] + }, + "reply": { + "map": { + "true" : [ + { + "action": "show", + "fields": ["replyEmailTemplate", "replyFromAddress", "replyFromName", "replyToAddress"] + }, { + "action": "setRequired", + "fields": ["replyEmailTemplate"] + } + ] + }, + "default": [ + { + "action": "hide", + "fields": ["replyEmailTemplate", "replyFromAddress", "replyFromName", "replyToAddress"] + }, { + "action": "setNotRequired", + "fields": ["replyEmailTemplate"] + } + ] + } + }, + "disableSearchPanel": true } diff --git a/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Lead.json b/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Lead.json index 4e278a6bb8..43cb5bb27e 100644 --- a/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Lead.json +++ b/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Lead.json @@ -37,5 +37,5 @@ } } ], - "boolFilters": ["onlyMy"] + "boolFilters": ["onlyMy"] } diff --git a/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Meeting.json b/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Meeting.json index 91700d6e53..e525c2eac4 100644 --- a/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Meeting.json +++ b/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Meeting.json @@ -1,81 +1,81 @@ { - "controller": "Controllers.Record", - "views":{ - "detail":"Crm:Meeting.Detail" - }, - "menu": { - "detail": { - "dropdown": [ - { - "label": "Duplicate", - "action": "duplicate", - "acl": "edit" - } - ] - } - }, - "sidePanels":{ - "detail":[ - { - "name":"attendees", - "label":"Attendees", - "view":"Record.Panels.Side", - "options":{ - "fields":[ - "users", - "contacts", - "leads" - ], - "mode":"detail" - } - } - ], - "edit":[ - { - "name":"attendees", - "label":"Attendees", - "view":"Record.Panels.Side", - "options":{ - "fields":[ - "users", - "contacts", - "leads" - ], - "mode":"edit" - } - } - ] - }, - "presetFilters": [ - { - "name":"planned", - "style": "primary", - "data": { - "status": { - "type": "in", - "value": ["Planned"] - } - } - }, - { - "name":"held", - "style": "success", - "data": { - "status": { - "type": "in", - "value": ["Held"] - } - } - }, - { - "name":"todays", - "data": { - "dateStart": { - "type": "today", - "dateTime": true - } - } - } - ], - "boolFilters": ["onlyMy"] + "controller": "Controllers.Record", + "views":{ + "detail":"Crm:Meeting.Detail" + }, + "menu": { + "detail": { + "dropdown": [ + { + "label": "Duplicate", + "action": "duplicate", + "acl": "edit" + } + ] + } + }, + "sidePanels":{ + "detail":[ + { + "name":"attendees", + "label":"Attendees", + "view":"Record.Panels.Side", + "options":{ + "fields":[ + "users", + "contacts", + "leads" + ], + "mode":"detail" + } + } + ], + "edit":[ + { + "name":"attendees", + "label":"Attendees", + "view":"Record.Panels.Side", + "options":{ + "fields":[ + "users", + "contacts", + "leads" + ], + "mode":"edit" + } + } + ] + }, + "presetFilters": [ + { + "name":"planned", + "style": "primary", + "data": { + "status": { + "type": "in", + "value": ["Planned"] + } + } + }, + { + "name":"held", + "style": "success", + "data": { + "status": { + "type": "in", + "value": ["Held"] + } + } + }, + { + "name":"todays", + "data": { + "dateStart": { + "type": "today", + "dateTime": true + } + } + } + ], + "boolFilters": ["onlyMy"] } diff --git a/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Opportunity.json b/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Opportunity.json index 56f3f7518d..45a950d0ed 100644 --- a/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Opportunity.json +++ b/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Opportunity.json @@ -44,5 +44,5 @@ } } ], - "boolFilters": ["onlyMy"] + "boolFilters": ["onlyMy"] } diff --git a/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Target.json b/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Target.json index f92518ec90..84b6263567 100644 --- a/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Target.json +++ b/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Target.json @@ -14,5 +14,5 @@ ] } }, - "boolFilters": ["onlyMy"] + "boolFilters": ["onlyMy"] } diff --git a/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Task.json b/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Task.json index 0287432797..45a0882694 100644 --- a/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Task.json +++ b/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Task.json @@ -1,5 +1,12 @@ { "controller": "Controllers.Record", + "recordViews":{ + "list":"Crm:Task.Record.List" + }, + "views": { + "list": "Crm:Task.List", + "detail": "Crm:Task.Detail" + }, "presetFilters": [ { "name":"actual", diff --git a/application/Espo/Modules/Crm/Resources/metadata/entityDefs/Account.json b/application/Espo/Modules/Crm/Resources/metadata/entityDefs/Account.json index 12abe918cf..0fd4e4a863 100644 --- a/application/Espo/Modules/Crm/Resources/metadata/entityDefs/Account.json +++ b/application/Espo/Modules/Crm/Resources/metadata/entityDefs/Account.json @@ -28,9 +28,9 @@ "maxLength": 40 }, "contactRole": { - "type": "varchar", - "notStorable": true, - "disabled": true + "type": "varchar", + "notStorable": true, + "disabled": true }, "billingAddress": { "type": "address" @@ -160,7 +160,7 @@ } }, "collection": { - "sortBy": "name", - "asc": true + "sortBy": "name", + "asc": true } } diff --git a/application/Espo/Modules/Crm/Resources/metadata/entityDefs/Call.json b/application/Espo/Modules/Crm/Resources/metadata/entityDefs/Call.json index 5dd171bcb6..cdc0bd33da 100644 --- a/application/Espo/Modules/Crm/Resources/metadata/entityDefs/Call.json +++ b/application/Espo/Modules/Crm/Resources/metadata/entityDefs/Call.json @@ -10,8 +10,7 @@ "default": "Planned", "view": "Fields.EnumStyled", "style": { - "Held": "success", - "Not Held": "danger" + "Held": "success" } }, "dateStart": { @@ -47,17 +46,17 @@ "disabled": true }, "acceptanceStatus": { - "type": "enum", - "notStorable": true, - "disabled": true, - "options": ["None", "Accepted", "Declined"] + "type": "enum", + "notStorable": true, + "disabled": true, + "options": ["None", "Accepted", "Declined"] }, "users": { "type": "linkMultiple", "disabled": true, "view": "Crm:Meeting.Fields.Attendees", "columns": { - "status": "acceptanceStatus" + "status": "acceptanceStatus" } }, "contacts": { @@ -65,7 +64,7 @@ "disabled": true, "view": "Crm:Meeting.Fields.Contacts", "columns": { - "status": "acceptanceStatus" + "status": "acceptanceStatus" } }, "leads": { @@ -73,7 +72,7 @@ "disabled": true, "view": "Crm:Meeting.Fields.Attendees", "columns": { - "status": "acceptanceStatus" + "status": "acceptanceStatus" } }, "createdAt": { @@ -127,11 +126,11 @@ "entity": "User", "foreign": "calls", "additionalColumns": { - "status": { - "type": "varchar", - "len": "36", - "default": "None" - } + "status": { + "type": "varchar", + "len": "36", + "default": "None" + } } }, "contacts": { @@ -139,11 +138,11 @@ "entity": "Contact", "foreign": "calls", "additionalColumns": { - "status": { - "type": "varchar", - "len": "36", - "default": "None" - } + "status": { + "type": "varchar", + "len": "36", + "default": "None" + } } }, "leads": { @@ -151,11 +150,11 @@ "entity": "Lead", "foreign": "calls", "additionalColumns": { - "status": { - "type": "varchar", - "len": "36", - "default": "None" - } + "status": { + "type": "varchar", + "len": "36", + "default": "None" + } } }, "parent": { @@ -165,7 +164,7 @@ } }, "collection": { - "sortBy": "dateStart", - "asc": false + "sortBy": "dateStart", + "asc": false } } diff --git a/application/Espo/Modules/Crm/Resources/metadata/entityDefs/Case.json b/application/Espo/Modules/Crm/Resources/metadata/entityDefs/Case.json index 6e638986cd..70a6298ff7 100644 --- a/application/Espo/Modules/Crm/Resources/metadata/entityDefs/Case.json +++ b/application/Espo/Modules/Crm/Resources/metadata/entityDefs/Case.json @@ -13,9 +13,9 @@ "default": "New", "view": "Fields.EnumStyled", "style": { - "Closed": "success", - "Duplicate": "danger", - "Rejected": "danger" + "Closed": "success", + "Duplicate": "danger", + "Rejected": "danger" } }, "priority": { @@ -36,7 +36,8 @@ "type": "link" }, "contact": { - "type": "link" + "type": "link", + "view": "Crm:Case.Fields.Contact" }, "createdAt": { "type": "datetime", @@ -112,8 +113,8 @@ } }, "collection": { - "sortBy": "number", - "asc": false, - "boolFilters": ["onlyMy"] + "sortBy": "number", + "asc": false, + "boolFilters": ["onlyMy"] } } diff --git a/application/Espo/Modules/Crm/Resources/metadata/entityDefs/Contact.json b/application/Espo/Modules/Crm/Resources/metadata/entityDefs/Contact.json index c91558d098..fa0ea1e820 100644 --- a/application/Espo/Modules/Crm/Resources/metadata/entityDefs/Contact.json +++ b/application/Espo/Modules/Crm/Resources/metadata/entityDefs/Contact.json @@ -20,8 +20,9 @@ }, "accountId": { "where": { - "=": "contact.id IN (SELECT contact_id FROM account_contact WHERE deleted = 0 AND account_id = {value})" - } + "=": "contact.id IN (SELECT contact_id FROM account_contact WHERE deleted = 0 AND account_id = {value})" + }, + "disabled": true }, "title": { "type": "varchar", @@ -30,8 +31,8 @@ "select": "accountContact.role", "orderBy": "accountContact.role {direction}", "where": { - "LIKE": "contact.id IN (SELECT contact_id FROM account_contact WHERE deleted = 0 AND role LIKE {value})", - "=": "contact.id IN (SELECT contact_id FROM account_contact WHERE deleted = 0 AND role = {value})" + "LIKE": "contact.id IN (SELECT contact_id FROM account_contact WHERE deleted = 0 AND role LIKE {value})", + "=": "contact.id IN (SELECT contact_id FROM account_contact WHERE deleted = 0 AND role = {value})" } }, "description": { @@ -75,13 +76,13 @@ "type": "linkMultiple", "view": "Crm:Contact.Fields.Accounts", "columns": { - "role": "contactRole" + "role": "contactRole" } }, "accountRole": { - "type": "varchar", - "notStorable": true, - "disabled": true + "type": "varchar", + "notStorable": true, + "disabled": true }, "accountType": { "type": "foreign", @@ -89,15 +90,15 @@ "field": "type" }, "opportunityRole": { - "type": "enum", - "notStorable": true, - "disabled": true, - "options": ["", "Decision Maker", "Evaluator", "Influencer"] + "type": "enum", + "notStorable": true, + "disabled": true, + "options": ["", "Decision Maker", "Evaluator", "Influencer"] }, "acceptanceStatus": { - "type": "varchar", - "notStorable": true, - "disabled": true + "type": "varchar", + "notStorable": true, + "disabled": true }, "createdAt": { "type": "datetime", @@ -149,12 +150,12 @@ "type": "hasMany", "entity": "Account", "foreign": "contacts", - "additionalColumns": { - "role": { - "type": "varchar", - "len": 50 - } - } + "additionalColumns": { + "role": { + "type": "varchar", + "len": 50 + } + } }, "opportunities": { "type": "hasMany", @@ -187,7 +188,7 @@ } }, "collection": { - "sortBy": "name", - "asc": true + "sortBy": "name", + "asc": true } } diff --git a/application/Espo/Modules/Crm/Resources/metadata/entityDefs/Document.json b/application/Espo/Modules/Crm/Resources/metadata/entityDefs/Document.json index dbc8707490..cfc7aaa423 100644 --- a/application/Espo/Modules/Crm/Resources/metadata/entityDefs/Document.json +++ b/application/Espo/Modules/Crm/Resources/metadata/entityDefs/Document.json @@ -14,14 +14,14 @@ "options": ["Active", "Draft", "Expired", "Canceled"], "view": "Fields.EnumStyled", "style": { - "Canceled": "danger", - "Expired": "danger" + "Canceled": "danger", + "Expired": "danger" } }, "source": { - "type": "enum", - "options": ["Espo"], - "default": "Espo" + "type": "enum", + "options": ["Espo"], + "default": "Espo" }, "type": { "type": "enum", @@ -64,16 +64,16 @@ } }, "links": { - "accounts": { + "accounts": { "type": "hasMany", "entity": "Account", "foreign": "documents" - }, - "opportunities": { + }, + "opportunities": { "type": "hasMany", "entity": "Opportunity", "foreign": "documents" - }, + }, "createdBy": { "type": "belongsTo", "entity": "User" @@ -93,7 +93,7 @@ } }, "collection": { - "sortBy": "createdAt", - "asc": false + "sortBy": "createdAt", + "asc": false } } diff --git a/application/Espo/Modules/Crm/Resources/metadata/entityDefs/InboundEmail.json b/application/Espo/Modules/Crm/Resources/metadata/entityDefs/InboundEmail.json index 4ed9bc3e08..33fdbb9a08 100644 --- a/application/Espo/Modules/Crm/Resources/metadata/entityDefs/InboundEmail.json +++ b/application/Espo/Modules/Crm/Resources/metadata/entityDefs/InboundEmail.json @@ -34,7 +34,7 @@ "view": "Crm:InboundEmail.Fields.Folders" }, "fetchData": { - "type": "text", + "type": "text", "readOnly": true }, "assignToUser": { @@ -55,6 +55,10 @@ "default": "Direct-Assignment", "tooltip": true }, + "targetUserPosition": { + "type": "enum", + "view": "Crm:InboundEmail.Fields.TargetUserPosition" + }, "reply": { "type": "bool", "tooltip": true @@ -112,7 +116,7 @@ } }, "collection": { - "sortBy": "name", - "asc": true + "sortBy": "name", + "asc": true } } diff --git a/application/Espo/Modules/Crm/Resources/metadata/entityDefs/Lead.json b/application/Espo/Modules/Crm/Resources/metadata/entityDefs/Lead.json index 46750859cc..676aa8d490 100644 --- a/application/Espo/Modules/Crm/Resources/metadata/entityDefs/Lead.json +++ b/application/Espo/Modules/Crm/Resources/metadata/entityDefs/Lead.json @@ -28,9 +28,9 @@ "default": "New", "view": "Fields.EnumStyled", "style": { - "Converted": "success", - "Recycled": "danger", - "Dead": "danger" + "Converted": "success", + "Recycled": "danger", + "Dead": "danger" } }, "source": { @@ -106,9 +106,9 @@ "required": true }, "acceptanceStatus": { - "type": "varchar", - "notStorable": true, - "disabled": true + "type": "varchar", + "notStorable": true, + "disabled": true }, "teams": { "type": "linkMultiple" @@ -197,7 +197,7 @@ } }, "collection": { - "sortBy": "createdAt", - "asc": false + "sortBy": "createdAt", + "asc": false } } diff --git a/application/Espo/Modules/Crm/Resources/metadata/entityDefs/Meeting.json b/application/Espo/Modules/Crm/Resources/metadata/entityDefs/Meeting.json index 89a75baf00..36c2fbe20e 100644 --- a/application/Espo/Modules/Crm/Resources/metadata/entityDefs/Meeting.json +++ b/application/Espo/Modules/Crm/Resources/metadata/entityDefs/Meeting.json @@ -10,8 +10,7 @@ "default": "Planned", "view": "Fields.EnumStyled", "style": { - "Held": "success", - "Not Held": "danger" + "Held": "success" } }, "dateStart": { @@ -28,7 +27,7 @@ "type": "duration", "start": "dateStart", "end": "dateEnd", - "options": [0, 900, 1800, 3600, 7200, 10800, 86400], + "options": [900, 1800, 3600, 7200, 10800, 86400], "default": 3600 }, "description": { @@ -42,17 +41,17 @@ "disabled": true }, "acceptanceStatus": { - "type": "enum", - "notStorable": true, - "disabled": true, - "options": ["None", "Accepted", "Declined"] + "type": "enum", + "notStorable": true, + "disabled": true, + "options": ["None", "Accepted", "Declined"] }, "users": { "type": "linkMultiple", "view": "Crm:Meeting.Fields.Attendees", "disabled": true, "columns": { - "status": "acceptanceStatus" + "status": "acceptanceStatus" } }, "contacts": { @@ -60,7 +59,7 @@ "disabled": true, "view": "Crm:Meeting.Fields.Contacts", "columns": { - "status": "acceptanceStatus" + "status": "acceptanceStatus" } }, "leads": { @@ -68,7 +67,7 @@ "view": "Crm:Meeting.Fields.Attendees", "disabled": true, "columns": { - "status": "acceptanceStatus" + "status": "acceptanceStatus" } }, "createdAt": { @@ -122,11 +121,11 @@ "entity": "User", "foreign": "meetings", "additionalColumns": { - "status": { - "type": "varchar", - "len": "36", - "default": "None" - } + "status": { + "type": "varchar", + "len": "36", + "default": "None" + } } }, "contacts": { @@ -134,11 +133,11 @@ "entity": "Contact", "foreign": "meetings", "additionalColumns": { - "status": { - "type": "varchar", - "len": "36", - "default": "None" - } + "status": { + "type": "varchar", + "len": "36", + "default": "None" + } } }, "leads": { @@ -146,11 +145,11 @@ "entity": "Lead", "foreign": "meetings", "additionalColumns": { - "status": { - "type": "varchar", - "len": "36", - "default": "None" - } + "status": { + "type": "varchar", + "len": "36", + "default": "None" + } } }, "parent": { @@ -160,7 +159,7 @@ } }, "collection": { - "sortBy": "dateStart", - "asc": false + "sortBy": "dateStart", + "asc": false } } diff --git a/application/Espo/Modules/Crm/Resources/metadata/entityDefs/Opportunity.json b/application/Espo/Modules/Crm/Resources/metadata/entityDefs/Opportunity.json index ec966bc7fd..a48243568e 100644 --- a/application/Espo/Modules/Crm/Resources/metadata/entityDefs/Opportunity.json +++ b/application/Espo/Modules/Crm/Resources/metadata/entityDefs/Opportunity.json @@ -19,12 +19,12 @@ "notStorable": true, "select": "opportunity.amount * amount_currency_alias.rate * opportunity.probability / 100", "where": { - "=": "(opportunity.amount * amount_currency_alias.rate * opportunity.probability / 100) = {value}", - "<": "(opportunity.amount * amount_currency_alias.rate * opportunity.probability / 100) < {value}", - ">": "(opportunity.amount * amount_currency_alias.rate * opportunity.probability / 100) > {value}", - "<=": "(opportunity.amount * amount_currency_alias.rate * opportunity.probability / 100) <= {value}", - ">=": "(opportunity.amount * amount_currency_alias.rate * opportunity.probability / 100) >= {value}", - "<>": "(opportunity.amount * amount_currency_alias.rate * opportunity.probability / 100) <> {value}" + "=": "(opportunity.amount * amount_currency_alias.rate * opportunity.probability / 100) = {value}", + "<": "(opportunity.amount * amount_currency_alias.rate * opportunity.probability / 100) < {value}", + ">": "(opportunity.amount * amount_currency_alias.rate * opportunity.probability / 100) > {value}", + "<=": "(opportunity.amount * amount_currency_alias.rate * opportunity.probability / 100) <= {value}", + ">=": "(opportunity.amount * amount_currency_alias.rate * opportunity.probability / 100) >= {value}", + "<>": "(opportunity.amount * amount_currency_alias.rate * opportunity.probability / 100) <> {value}" }, "orderBy": "amountWeightedConverted {direction}", "view": "Fields.CurrencyConverted" @@ -37,7 +37,7 @@ "type": "linkMultiple", "view": "Crm:Opportunity.Fields.Contacts", "columns": { - "role": "opportunityRole" + "role": "opportunityRole" } }, "stage": { @@ -115,12 +115,12 @@ "type": "hasMany", "entity": "Contact", "foreign": "opportunities", - "additionalColumns": { - "role": { - "type": "varchar", - "len": 50 - } - } + "additionalColumns": { + "role": { + "type": "varchar", + "len": 50 + } + } }, "meetings": { "type": "hasChildren", @@ -149,7 +149,19 @@ } }, "collection": { - "sortBy": "createdAt", - "asc": false + "sortBy": "createdAt", + "asc": false + }, + "probabilityMap": { + "Prospecting": 10, + "Qualification": 10, + "Needs Analysis": 20, + "Value Proposition": 50, + "Id. Decision Makers": 60, + "Perception Analysis": 70, + "Proposal/Price Quote": 75, + "Negotiation/Review": 90, + "Closed Won": 100, + "Closed Lost": 0 } } diff --git a/application/Espo/Modules/Crm/Resources/metadata/entityDefs/Target.json b/application/Espo/Modules/Crm/Resources/metadata/entityDefs/Target.json index c1cd05f74f..597d60e6f0 100644 --- a/application/Espo/Modules/Crm/Resources/metadata/entityDefs/Target.json +++ b/application/Espo/Modules/Crm/Resources/metadata/entityDefs/Target.json @@ -107,7 +107,7 @@ } }, "collection": { - "sortBy": "createdAt", - "asc": false + "sortBy": "createdAt", + "asc": false } } diff --git a/application/Espo/Modules/Crm/Resources/metadata/entityDefs/Task.json b/application/Espo/Modules/Crm/Resources/metadata/entityDefs/Task.json index e51cb7f187..79ef49061c 100644 --- a/application/Espo/Modules/Crm/Resources/metadata/entityDefs/Task.json +++ b/application/Espo/Modules/Crm/Resources/metadata/entityDefs/Task.json @@ -9,7 +9,7 @@ "options": ["Not Started", "Started", "Completed", "Canceled"], "view": "Fields.EnumStyled", "style": { - "Completed": "success" + "Completed": "success" } }, "priority": { @@ -27,10 +27,10 @@ "view": "Crm:Task.Fields.DateEnd" }, "isOverdue": { - "type": "bool", - "readOnly": true, - "notStorable": true, - "view": "Crm:Task.Fields.IsOverdue" + "type": "bool", + "readOnly": true, + "notStorable": true, + "view": "Crm:Task.Fields.IsOverdue" }, "description": { "type": "text" @@ -87,7 +87,7 @@ } }, "collection": { - "sortBy": "createdAt", - "asc": false + "sortBy": "createdAt", + "asc": false } } diff --git a/application/Espo/Modules/Crm/Resources/metadata/scopes/Account.json b/application/Espo/Modules/Crm/Resources/metadata/scopes/Account.json index 30dcc61e7d..3308931398 100644 --- a/application/Espo/Modules/Crm/Resources/metadata/scopes/Account.json +++ b/application/Espo/Modules/Crm/Resources/metadata/scopes/Account.json @@ -1,10 +1,10 @@ { - "entity": true, - "layouts": true, - "tab": true, - "acl": true, - "module": "Crm", - "customizable": true, - "stream": true, - "importable": true + "entity": true, + "layouts": true, + "tab": true, + "acl": true, + "module": "Crm", + "customizable": true, + "stream": true, + "importable": true } diff --git a/application/Espo/Modules/Crm/Resources/metadata/scopes/Activities.json b/application/Espo/Modules/Crm/Resources/metadata/scopes/Activities.json index 36527bd8d9..d22d5e93df 100644 --- a/application/Espo/Modules/Crm/Resources/metadata/scopes/Activities.json +++ b/application/Espo/Modules/Crm/Resources/metadata/scopes/Activities.json @@ -1,8 +1,8 @@ { - "entity": false, - "layouts": false, - "tab": false, - "acl": false, - "module": "Crm", - "customizable": false + "entity": false, + "layouts": false, + "tab": false, + "acl": false, + "module": "Crm", + "customizable": false } diff --git a/application/Espo/Modules/Crm/Resources/metadata/scopes/Calendar.json b/application/Espo/Modules/Crm/Resources/metadata/scopes/Calendar.json index 51a3dcec23..abd0e157f8 100644 --- a/application/Espo/Modules/Crm/Resources/metadata/scopes/Calendar.json +++ b/application/Espo/Modules/Crm/Resources/metadata/scopes/Calendar.json @@ -1 +1,6 @@ -{"entity":false,"tab":true,"acl":false,"module":"Crm"} +{ + "entity": false, + "tab": true, + "acl": "boolean", + "module": "Crm" +} diff --git a/application/Espo/Modules/Crm/Resources/metadata/scopes/Call.json b/application/Espo/Modules/Crm/Resources/metadata/scopes/Call.json index 2b9cff0207..a8e7a855da 100644 --- a/application/Espo/Modules/Crm/Resources/metadata/scopes/Call.json +++ b/application/Espo/Modules/Crm/Resources/metadata/scopes/Call.json @@ -1,9 +1,9 @@ { - "entity": true, - "layouts": true, - "tab": true, - "acl": true, - "module": "Crm", - "customizable": true, - "importable": true + "entity": true, + "layouts": true, + "tab": true, + "acl": true, + "module": "Crm", + "customizable": true, + "importable": true } diff --git a/application/Espo/Modules/Crm/Resources/metadata/scopes/Case.json b/application/Espo/Modules/Crm/Resources/metadata/scopes/Case.json index 30dcc61e7d..3308931398 100644 --- a/application/Espo/Modules/Crm/Resources/metadata/scopes/Case.json +++ b/application/Espo/Modules/Crm/Resources/metadata/scopes/Case.json @@ -1,10 +1,10 @@ { - "entity": true, - "layouts": true, - "tab": true, - "acl": true, - "module": "Crm", - "customizable": true, - "stream": true, - "importable": true + "entity": true, + "layouts": true, + "tab": true, + "acl": true, + "module": "Crm", + "customizable": true, + "stream": true, + "importable": true } diff --git a/application/Espo/Modules/Crm/Resources/metadata/scopes/Contact.json b/application/Espo/Modules/Crm/Resources/metadata/scopes/Contact.json index 30f6f8dcd2..072e7b3d7a 100644 --- a/application/Espo/Modules/Crm/Resources/metadata/scopes/Contact.json +++ b/application/Espo/Modules/Crm/Resources/metadata/scopes/Contact.json @@ -1,5 +1,5 @@ {"entity":true,"layouts":true,"tab":true,"acl":true,"module":"Crm", - "customizable": true, - "stream": true, - "importable": true + "customizable": true, + "stream": true, + "importable": true } diff --git a/application/Espo/Modules/Crm/Resources/metadata/scopes/Document.json b/application/Espo/Modules/Crm/Resources/metadata/scopes/Document.json index 4bb51bf381..a96a75db25 100644 --- a/application/Espo/Modules/Crm/Resources/metadata/scopes/Document.json +++ b/application/Espo/Modules/Crm/Resources/metadata/scopes/Document.json @@ -1,9 +1,9 @@ { - "entity": true, - "layouts": false, - "tab": true, - "acl": true, - "module": "Crm", - "customizable": false, - "importable": false + "entity": true, + "layouts": false, + "tab": true, + "acl": true, + "module": "Crm", + "customizable": false, + "importable": false } diff --git a/application/Espo/Modules/Crm/Resources/metadata/scopes/InboundEmail.json b/application/Espo/Modules/Crm/Resources/metadata/scopes/InboundEmail.json index 7174685f4c..da59fcc7a4 100644 --- a/application/Espo/Modules/Crm/Resources/metadata/scopes/InboundEmail.json +++ b/application/Espo/Modules/Crm/Resources/metadata/scopes/InboundEmail.json @@ -1,7 +1,7 @@ { - "entity": true, - "layouts": false, - "tab": false, - "acl": false, - "module": "Crm" + "entity": true, + "layouts": false, + "tab": false, + "acl": false, + "module": "Crm" } diff --git a/application/Espo/Modules/Crm/Resources/metadata/scopes/Lead.json b/application/Espo/Modules/Crm/Resources/metadata/scopes/Lead.json index 30dcc61e7d..3308931398 100644 --- a/application/Espo/Modules/Crm/Resources/metadata/scopes/Lead.json +++ b/application/Espo/Modules/Crm/Resources/metadata/scopes/Lead.json @@ -1,10 +1,10 @@ { - "entity": true, - "layouts": true, - "tab": true, - "acl": true, - "module": "Crm", - "customizable": true, - "stream": true, - "importable": true + "entity": true, + "layouts": true, + "tab": true, + "acl": true, + "module": "Crm", + "customizable": true, + "stream": true, + "importable": true } diff --git a/application/Espo/Modules/Crm/Resources/metadata/scopes/Meeting.json b/application/Espo/Modules/Crm/Resources/metadata/scopes/Meeting.json index 2b9cff0207..a8e7a855da 100644 --- a/application/Espo/Modules/Crm/Resources/metadata/scopes/Meeting.json +++ b/application/Espo/Modules/Crm/Resources/metadata/scopes/Meeting.json @@ -1,9 +1,9 @@ { - "entity": true, - "layouts": true, - "tab": true, - "acl": true, - "module": "Crm", - "customizable": true, - "importable": true + "entity": true, + "layouts": true, + "tab": true, + "acl": true, + "module": "Crm", + "customizable": true, + "importable": true } diff --git a/application/Espo/Modules/Crm/Resources/metadata/scopes/Opportunity.json b/application/Espo/Modules/Crm/Resources/metadata/scopes/Opportunity.json index 30dcc61e7d..3308931398 100644 --- a/application/Espo/Modules/Crm/Resources/metadata/scopes/Opportunity.json +++ b/application/Espo/Modules/Crm/Resources/metadata/scopes/Opportunity.json @@ -1,10 +1,10 @@ { - "entity": true, - "layouts": true, - "tab": true, - "acl": true, - "module": "Crm", - "customizable": true, - "stream": true, - "importable": true + "entity": true, + "layouts": true, + "tab": true, + "acl": true, + "module": "Crm", + "customizable": true, + "stream": true, + "importable": true } diff --git a/application/Espo/Modules/Crm/Resources/metadata/scopes/Target.json b/application/Espo/Modules/Crm/Resources/metadata/scopes/Target.json index 2e95ea947b..bcacda91d0 100644 --- a/application/Espo/Modules/Crm/Resources/metadata/scopes/Target.json +++ b/application/Espo/Modules/Crm/Resources/metadata/scopes/Target.json @@ -1,9 +1,9 @@ { - "entity": false, - "layouts": false, - "tab": false, - "acl": false, - "module": "Crm", - "customizable": false, - "importable": false + "entity": false, + "layouts": false, + "tab": false, + "acl": false, + "module": "Crm", + "customizable": false, + "importable": false } diff --git a/application/Espo/Modules/Crm/Resources/metadata/scopes/Task.json b/application/Espo/Modules/Crm/Resources/metadata/scopes/Task.json index 2b9cff0207..a8e7a855da 100644 --- a/application/Espo/Modules/Crm/Resources/metadata/scopes/Task.json +++ b/application/Espo/Modules/Crm/Resources/metadata/scopes/Task.json @@ -1,9 +1,9 @@ { - "entity": true, - "layouts": true, - "tab": true, - "acl": true, - "module": "Crm", - "customizable": true, - "importable": true + "entity": true, + "layouts": true, + "tab": true, + "acl": true, + "module": "Crm", + "customizable": true, + "importable": true } diff --git a/application/Espo/Modules/Crm/Resources/routes.json b/application/Espo/Modules/Crm/Resources/routes.json index ba81ad58b8..5cf0133fe8 100644 --- a/application/Espo/Modules/Crm/Resources/routes.json +++ b/application/Espo/Modules/Crm/Resources/routes.json @@ -1,22 +1,22 @@ [ { - "route":"/Activities/:scope/:id/:name", + "route":"/Activities/:scope/:id/:name", "method":"get", "params":{ "controller":"Activities", - "action":"list", - "scope":":scope", - "id":":id", - "name":":name" + "action":"list", + "scope":":scope", + "id":":id", + "name":":name" } }, { - "route":"/Activities", + "route":"/Activities", "method":"get", "params":{ "controller":"Activities", - "action":"listCalendarEvents" + "action":"listCalendarEvents" } } ] diff --git a/application/Espo/Modules/Crm/Resources/templates/InvitationBody.tpl b/application/Espo/Modules/Crm/Resources/templates/InvitationBody.en_US.tpl similarity index 100% rename from application/Espo/Modules/Crm/Resources/templates/InvitationBody.tpl rename to application/Espo/Modules/Crm/Resources/templates/InvitationBody.en_US.tpl diff --git a/application/Espo/Modules/Crm/Resources/templates/InvitationSubject.tpl b/application/Espo/Modules/Crm/Resources/templates/InvitationSubject.en_US.tpl similarity index 100% rename from application/Espo/Modules/Crm/Resources/templates/InvitationSubject.tpl rename to application/Espo/Modules/Crm/Resources/templates/InvitationSubject.en_US.tpl diff --git a/application/Espo/Modules/Crm/SelectManagers/Call.php b/application/Espo/Modules/Crm/SelectManagers/Call.php index 1836490d66..63936b3f29 100644 --- a/application/Espo/Modules/Crm/SelectManagers/Call.php +++ b/application/Espo/Modules/Crm/SelectManagers/Call.php @@ -24,14 +24,14 @@ namespace Espo\Modules\Crm\SelectManagers; class Call extends \Espo\Core\SelectManagers\Base { - - protected function getBoolFilterWhereOnlyMy() - { - return array( - 'type' => 'linkedWith', - 'field' => 'users', - 'value' => array($this->user->id) - ); - } + + protected function getBoolFilterWhereOnlyMy() + { + return array( + 'type' => 'linkedWith', + 'field' => 'users', + 'value' => array($this->user->id) + ); + } } diff --git a/application/Espo/Modules/Crm/SelectManagers/Meeting.php b/application/Espo/Modules/Crm/SelectManagers/Meeting.php index aedc764636..9911218f43 100644 --- a/application/Espo/Modules/Crm/SelectManagers/Meeting.php +++ b/application/Espo/Modules/Crm/SelectManagers/Meeting.php @@ -24,14 +24,14 @@ namespace Espo\Modules\Crm\SelectManagers; class Meeting extends \Espo\Core\SelectManagers\Base { - - protected function getBoolFilterWhereOnlyMy() - { - return array( - 'type' => 'linkedWith', - 'field' => 'users', - 'value' => array($this->user->id) - ); - } + + protected function getBoolFilterWhereOnlyMy() + { + return array( + 'type' => 'linkedWith', + 'field' => 'users', + 'value' => array($this->user->id) + ); + } } diff --git a/application/Espo/Modules/Crm/SelectManagers/Task.php b/application/Espo/Modules/Crm/SelectManagers/Task.php index 791da4a29a..5c0fb296f9 100644 --- a/application/Espo/Modules/Crm/SelectManagers/Task.php +++ b/application/Espo/Modules/Crm/SelectManagers/Task.php @@ -24,23 +24,23 @@ namespace Espo\Modules\Crm\SelectManagers; class Task extends \Espo\Core\SelectManagers\Base { - - protected function getBoolFilterWhereActive() - { - return array( - 'type' => 'notIn', - 'field' => 'status', - 'value' => array('Completed', 'Canceled') - ); - } - - protected function getBoolFilterWhereInactive() - { - return array( - 'type' => 'in', - 'field' => 'status', - 'value' => array('Completed', 'Canceled') - ); - } + + protected function getBoolFilterWhereActive() + { + return array( + 'type' => 'notIn', + 'field' => 'status', + 'value' => array('Completed', 'Canceled') + ); + } + + protected function getBoolFilterWhereInactive() + { + return array( + 'type' => 'in', + 'field' => 'status', + 'value' => array('Completed', 'Canceled') + ); + } } diff --git a/application/Espo/Modules/Crm/Services/Account.php b/application/Espo/Modules/Crm/Services/Account.php index b6ba4b77f5..e2b9f0968f 100644 --- a/application/Espo/Modules/Crm/Services/Account.php +++ b/application/Espo/Modules/Crm/Services/Account.php @@ -25,20 +25,20 @@ namespace Espo\Modules\Crm\Services; use \Espo\ORM\Entity; class Account extends \Espo\Services\Record -{ - protected $linkSelectParams = array( - 'contacts' => array( - 'additionalColumns' => array( - 'role' => 'accountRole' - ) - ) - ); - - protected function getDuplicateWhereClause(Entity $entity) - { - return array( - 'name' => $entity->get('name') - ); - } +{ + protected $linkSelectParams = array( + 'contacts' => array( + 'additionalColumns' => array( + 'role' => 'accountRole' + ) + ) + ); + + protected function getDuplicateWhereClause(Entity $entity) + { + return array( + 'name' => $entity->get('name') + ); + } } diff --git a/application/Espo/Modules/Crm/Services/Activities.php b/application/Espo/Modules/Crm/Services/Activities.php index 7ac901fd43..aef76bad0f 100644 --- a/application/Espo/Modules/Crm/Services/Activities.php +++ b/application/Espo/Modules/Crm/Services/Activities.php @@ -27,394 +27,414 @@ use \PDO; class Activities extends \Espo\Core\Services\Base { - protected $dependencies = array( - 'entityManager', - 'user', - 'metadata', - 'acl' - ); - - protected function getPDO() - { - return $this->getEntityManager()->getPDO(); - } + protected $dependencies = array( + 'entityManager', + 'user', + 'metadata', + 'acl' + ); + + protected function getPDO() + { + return $this->getEntityManager()->getPDO(); + } - protected function getEntityManager() - { - return $this->injections['entityManager']; - } + protected function getEntityManager() + { + return $this->injections['entityManager']; + } - protected function getUser() - { - return $this->injections['user']; - } - - protected function getAcl() - { - return $this->injections['acl']; - } - - protected function getMetadata() - { - return $this->injections['metadata']; - } - - protected function isPerson($scope) - { - return in_array($scope, array('Contact', 'Lead', 'User')); - } - - protected function getMeetingQuery($scope, $id, $op = 'IN', $notIn = array()) - { - $baseSql = " - SELECT meeting.id AS 'id', meeting.name AS 'name', meeting.date_start AS 'dateStart', meeting.date_end AS 'dateEnd', 'Meeting' AS '_scope', - meeting.assigned_user_id AS assignedUserId, TRIM(CONCAT(user.first_name, ' ', user.last_name)) AS assignedUserName, - meeting.parent_type AS 'parentType', meeting.parent_id AS 'parentId', meeting.status AS status, meeting.created_at AS createdAt - FROM `meeting` - LEFT JOIN `user` ON user.id = meeting.assigned_user_id - "; - - $sql = $baseSql; - $sql .= " - WHERE - meeting.deleted = 0 AND - "; - if ($scope == 'Account') { - $sql .= " - (meeting.parent_type = ".$this->getPDO()->quote($scope)." AND meeting.parent_id = ".$this->getPDO()->quote($id)." - OR - meeting.account_id = ".$this->getPDO()->quote($id).") - "; - } else { - $sql .= " - (meeting.parent_type = ".$this->getPDO()->quote($scope)." AND meeting.parent_id = ".$this->getPDO()->quote($id).") - "; - } - - if (!empty($notIn)) { - $sql .= " - AND meeting.status {$op} ('". implode("', '", $notIn) . "') - "; - } - - if ($this->isPerson($scope)) { - $sql = $sql . " - UNION - " . $baseSql; - - switch ($scope) { - case 'Contact': - $joinTable = 'contact_meeting'; - $key = 'contact_id'; - break; - case 'Lead': - $joinTable = 'lead_meeting'; - $key = 'lead_id'; - break; - case 'User': - $joinTable = 'meeting_user'; - $key = 'user_id'; - break; - } - $sql .= " - JOIN `{$joinTable}` ON - meeting.id = {$joinTable}.meeting_id AND - {$joinTable}.deleted = 0 AND - {$joinTable}.{$key} = ".$this->getPDO()->quote($id)." - "; - $sql .= " - WHERE - (meeting.parent_type <> ".$this->getPDO()->quote($scope)." OR meeting.parent_id <> ".$this->getPDO()->quote($id).") AND - meeting.deleted = 0 - "; - if (!empty($notIn)) { - $sql .= " - AND meeting.status {$op} ('". implode("', '", $notIn) . "') - "; - } - - } + protected function getUser() + { + return $this->injections['user']; + } + + protected function getAcl() + { + return $this->injections['acl']; + } + + protected function getMetadata() + { + return $this->injections['metadata']; + } + + protected function isPerson($scope) + { + return in_array($scope, array('Contact', 'Lead', 'User')); + } + + protected function getMeetingQuery($scope, $id, $op = 'IN', $notIn = array()) + { + $baseSql = " + SELECT meeting.id AS 'id', meeting.name AS 'name', meeting.date_start AS 'dateStart', meeting.date_end AS 'dateEnd', 'Meeting' AS '_scope', + meeting.assigned_user_id AS assignedUserId, TRIM(CONCAT(user.first_name, ' ', user.last_name)) AS assignedUserName, + meeting.parent_type AS 'parentType', meeting.parent_id AS 'parentId', meeting.status AS status, meeting.created_at AS createdAt + FROM `meeting` + LEFT JOIN `user` ON user.id = meeting.assigned_user_id + "; + + $sql = $baseSql; + $sql .= " + WHERE + meeting.deleted = 0 AND + "; + if ($scope == 'Account') { + $sql .= " + (meeting.parent_type = ".$this->getPDO()->quote($scope)." AND meeting.parent_id = ".$this->getPDO()->quote($id)." + OR + meeting.account_id = ".$this->getPDO()->quote($id).") + "; + } else { + $sql .= " + (meeting.parent_type = ".$this->getPDO()->quote($scope)." AND meeting.parent_id = ".$this->getPDO()->quote($id).") + "; + } + + if (!empty($notIn)) { + $sql .= " + AND meeting.status {$op} ('". implode("', '", $notIn) . "') + "; + } + + if ($this->isPerson($scope)) { + $sql = $sql . " + UNION + " . $baseSql; + + switch ($scope) { + case 'Contact': + $joinTable = 'contact_meeting'; + $key = 'contact_id'; + break; + case 'Lead': + $joinTable = 'lead_meeting'; + $key = 'lead_id'; + break; + case 'User': + $joinTable = 'meeting_user'; + $key = 'user_id'; + break; + } + $sql .= " + JOIN `{$joinTable}` ON + meeting.id = {$joinTable}.meeting_id AND + {$joinTable}.deleted = 0 AND + {$joinTable}.{$key} = ".$this->getPDO()->quote($id)." + "; + $sql .= " + WHERE + ( + meeting.parent_type <> ".$this->getPDO()->quote($scope)." OR + meeting.parent_id <> ".$this->getPDO()->quote($id)." OR + meeting.parent_type IS NULL OR + meeting.parent_id IS NULL + ) AND + meeting.deleted = 0 + "; + if (!empty($notIn)) { + $sql .= " + AND meeting.status {$op} ('". implode("', '", $notIn) . "') + "; + } + + } - return $sql; - } - - protected function getCallQuery($scope, $id, $op = 'IN', $notIn = array()) - { - $baseSql = " - SELECT call.id AS 'id', call.name AS 'name', call.date_start AS 'dateStart', call.date_end AS 'dateEnd', 'Call' AS '_scope', - call.assigned_user_id AS assignedUserId, TRIM(CONCAT(user.first_name, ' ', user.last_name)) AS assignedUserName, - call.parent_type AS 'parentType', call.parent_id AS 'parentId', call.status AS status, call.created_at AS createdAt - FROM `call` - LEFT JOIN `user` ON user.id = call.assigned_user_id - "; - - $sql = $baseSql; - $sql .= " - WHERE - call.deleted = 0 AND - "; - if ($scope == 'Account') { - $sql .= " - (call.parent_type = ".$this->getPDO()->quote($scope)." AND call.parent_id = ".$this->getPDO()->quote($id)." - OR - call.account_id = ".$this->getPDO()->quote($id).") - "; - } else { - $sql .= " - (call.parent_type = ".$this->getPDO()->quote($scope)." AND call.parent_id = ".$this->getPDO()->quote($id).") - "; - } - - if (!empty($notIn)) { - $sql .= " - AND call.status {$op} ('". implode("', '", $notIn) . "') - "; - } - - if ($this->isPerson($scope)) { - $sql = $sql . " - UNION - " . $baseSql; - - switch ($scope) { - case 'Contact': - $joinTable = 'call_contact'; - $key = 'contact_id'; - break; - case 'Lead': - $joinTable = 'call_lead'; - $key = 'lead_id'; - break; - case 'User': - $joinTable = 'call_user'; - $key = 'user_id'; - break; - } - $sql .= " - JOIN `{$joinTable}` ON - call.id = {$joinTable}.call_id AND - {$joinTable}.deleted = 0 AND - {$joinTable}.{$key} = ".$this->getPDO()->quote($id)." - "; - $sql .= " - WHERE - (call.parent_type <> ".$this->getPDO()->quote($scope)." OR call.parent_id <> ".$this->getPDO()->quote($id).") AND - call.deleted = 0 - "; - if (!empty($notIn)) { - $sql .= " - AND call.status {$op} ('". implode("', '", $notIn) . "') - "; - } - - } + return $sql; + } + + protected function getCallQuery($scope, $id, $op = 'IN', $notIn = array()) + { + $baseSql = " + SELECT call.id AS 'id', call.name AS 'name', call.date_start AS 'dateStart', call.date_end AS 'dateEnd', 'Call' AS '_scope', + call.assigned_user_id AS assignedUserId, TRIM(CONCAT(user.first_name, ' ', user.last_name)) AS assignedUserName, + call.parent_type AS 'parentType', call.parent_id AS 'parentId', call.status AS status, call.created_at AS createdAt + FROM `call` + LEFT JOIN `user` ON user.id = call.assigned_user_id + "; + + $sql = $baseSql; + $sql .= " + WHERE + call.deleted = 0 AND + "; + if ($scope == 'Account') { + $sql .= " + (call.parent_type = ".$this->getPDO()->quote($scope)." AND call.parent_id = ".$this->getPDO()->quote($id)." + OR + call.account_id = ".$this->getPDO()->quote($id).") + "; + } else { + $sql .= " + (call.parent_type = ".$this->getPDO()->quote($scope)." AND call.parent_id = ".$this->getPDO()->quote($id).") + "; + } + + if (!empty($notIn)) { + $sql .= " + AND call.status {$op} ('". implode("', '", $notIn) . "') + "; + } + + if ($this->isPerson($scope)) { + $sql = $sql . " + UNION + " . $baseSql; + + switch ($scope) { + case 'Contact': + $joinTable = 'call_contact'; + $key = 'contact_id'; + break; + case 'Lead': + $joinTable = 'call_lead'; + $key = 'lead_id'; + break; + case 'User': + $joinTable = 'call_user'; + $key = 'user_id'; + break; + } + $sql .= " + JOIN `{$joinTable}` ON + call.id = {$joinTable}.call_id AND + {$joinTable}.deleted = 0 AND + {$joinTable}.{$key} = ".$this->getPDO()->quote($id)." + "; + $sql .= " + WHERE + ( + call.parent_type <> ".$this->getPDO()->quote($scope)." OR + call.parent_id <> ".$this->getPDO()->quote($id)." OR + call.parent_type IS NULL OR + call.parent_id IS NULL + ) AND + call.deleted = 0 + "; + if (!empty($notIn)) { + $sql .= " + AND call.status {$op} ('". implode("', '", $notIn) . "') + "; + } + + } - return $sql; - } - - protected function getEmailQuery($scope, $id, $op = 'IN', $notIn = array()) - { - $baseSql = " - SELECT DISTINCT - email.id AS 'id', email.name AS 'name', email.date_sent AS 'dateStart', '' AS 'dateEnd', 'Email' AS '_scope', - email.assigned_user_id AS assignedUserId, TRIM(CONCAT(user.first_name, ' ', user.last_name)) AS assignedUserName, - email.parent_type AS 'parentType', email.parent_id AS 'parentId', email.status AS status, email.created_at AS createdAt - FROM `email` - LEFT JOIN `user` ON user.id = email.assigned_user_id - "; - - $sql = $baseSql; - $sql .= " - WHERE - email.deleted = 0 AND - "; - if ($scope == 'Account') { - $sql .= " - (email.parent_type = ".$this->getPDO()->quote($scope)." AND email.parent_id = ".$this->getPDO()->quote($id)." - OR - email.account_id = ".$this->getPDO()->quote($id).") - "; - } else { - $sql .= " - (email.parent_type = ".$this->getPDO()->quote($scope)." AND email.parent_id = ".$this->getPDO()->quote($id).") - "; - } - - if (!empty($notIn)) { - $sql .= " - AND email.status {$op} ('". implode("', '", $notIn) . "') - "; - } - - if ($this->isPerson($scope)) { - $sql = $sql . " - UNION - " . $baseSql; - $sql .= " - LEFT JOIN entity_email_address AS entity_email_address_2 ON - entity_email_address_2.email_address_id = email.from_email_address_id AND - entity_email_address_2.entity_type = " . $this->getPDO()->quote($scope) . " AND - entity_email_address_2.deleted = 0 - - LEFT JOIN email_email_address ON - email_email_address.email_id = email.id AND - email_email_address.deleted = 0 - LEFT JOIN entity_email_address AS entity_email_address_1 ON - entity_email_address_1.email_address_id = email_email_address.email_address_id AND - - entity_email_address_1.entity_type = " . $this->getPDO()->quote($scope) . " AND - entity_email_address_1.deleted = 0 - "; - $sql .= " - WHERE - email.deleted = 0 AND - (email.parent_type <> ".$this->getPDO()->quote($scope)." OR email.parent_id <> ".$this->getPDO()->quote($id).") AND - (entity_email_address_1.entity_id = ".$this->getPDO()->quote($id)." OR entity_email_address_2.entity_id = ".$this->getPDO()->quote($id).") - "; - if (!empty($notIn)) { - $sql .= " - AND email.status {$op} ('". implode("', '", $notIn) . "') - "; - } - } - - return $sql; - } - - protected function getResult($parts, $scope, $id, $params) - { - $pdo = $this->getEntityManager()->getPDO(); - - $onlyScope = false; - if (!empty($params['scope'])) { - $onlyScope = $params['scope']; - } - - if (!$onlyScope) { - $qu = implode(" UNION ", $parts); - } else { - $qu = $parts[$onlyScope]; - } - - $countQu = "SELECT COUNT(*) AS 'count' FROM ({$qu}) AS c"; - $sth = $pdo->prepare($countQu); - $sth->execute(); - - $row = $sth->fetch(PDO::FETCH_ASSOC); - $totalCount = $row['count']; - - $qu .= " - ORDER BY dateStart DESC, createdAt DESC - "; - - if (!empty($params['maxSize'])) { - $qu .= " - LIMIT :offset, :maxSize - "; - } + return $sql; + } + + protected function getEmailQuery($scope, $id, $op = 'IN', $notIn = array()) + { + $baseSql = " + SELECT DISTINCT + email.id AS 'id', email.name AS 'name', email.date_sent AS 'dateStart', '' AS 'dateEnd', 'Email' AS '_scope', + email.assigned_user_id AS assignedUserId, TRIM(CONCAT(user.first_name, ' ', user.last_name)) AS assignedUserName, + email.parent_type AS 'parentType', email.parent_id AS 'parentId', email.status AS status, email.created_at AS createdAt + FROM `email` + LEFT JOIN `user` ON user.id = email.assigned_user_id + "; + + $sql = $baseSql; + $sql .= " + WHERE + email.deleted = 0 AND + "; + if ($scope == 'Account') { + $sql .= " + (email.parent_type = ".$this->getPDO()->quote($scope)." AND email.parent_id = ".$this->getPDO()->quote($id)." + OR + email.account_id = ".$this->getPDO()->quote($id).") + "; + } else { + $sql .= " + (email.parent_type = ".$this->getPDO()->quote($scope)." AND email.parent_id = ".$this->getPDO()->quote($id).") + "; + } + + if (!empty($notIn)) { + $sql .= " + AND email.status {$op} ('". implode("', '", $notIn) . "') + "; + } + + if ($this->isPerson($scope)) { + $sql = $sql . " + UNION + " . $baseSql; + $sql .= " + LEFT JOIN entity_email_address AS entity_email_address_2 ON + entity_email_address_2.email_address_id = email.from_email_address_id AND + entity_email_address_2.entity_type = " . $this->getPDO()->quote($scope) . " AND + entity_email_address_2.deleted = 0 + + LEFT JOIN email_email_address ON + email_email_address.email_id = email.id AND + email_email_address.deleted = 0 + LEFT JOIN entity_email_address AS entity_email_address_1 ON + entity_email_address_1.email_address_id = email_email_address.email_address_id AND + + entity_email_address_1.entity_type = " . $this->getPDO()->quote($scope) . " AND + entity_email_address_1.deleted = 0 + "; + $sql .= " + WHERE + email.deleted = 0 AND + ( + email.parent_type <> ".$this->getPDO()->quote($scope)." OR + email.parent_id <> ".$this->getPDO()->quote($id)." OR + email.parent_type IS NULL OR + email.parent_id IS NULL + ) AND + (entity_email_address_1.entity_id = ".$this->getPDO()->quote($id)." OR entity_email_address_2.entity_id = ".$this->getPDO()->quote($id).") + "; + if (!empty($notIn)) { + $sql .= " + AND email.status {$op} ('". implode("', '", $notIn) . "') + "; + } + } + + return $sql; + } + + protected function getResult($parts, $scope, $id, $params) + { + $pdo = $this->getEntityManager()->getPDO(); + + $onlyScope = false; + if (!empty($params['scope'])) { + $onlyScope = $params['scope']; + } + + if (!$onlyScope) { + $qu = implode(" UNION ", $parts); + } else { + $qu = $parts[$onlyScope]; + } + + $countQu = "SELECT COUNT(*) AS 'count' FROM ({$qu}) AS c"; + $sth = $pdo->prepare($countQu); + $sth->execute(); + + $row = $sth->fetch(PDO::FETCH_ASSOC); + $totalCount = $row['count']; + + $qu .= " + ORDER BY dateStart DESC, createdAt DESC + "; + + if (!empty($params['maxSize'])) { + $qu .= " + LIMIT :offset, :maxSize + "; + } - + - $sth = $pdo->prepare($qu); - - if (!empty($params['maxSize'])) { - $offset = 0; - if (!empty($params['offset'])) { - $offset = $params['offset']; - } - - $sth->bindParam(':offset', $offset, PDO::PARAM_INT); - $sth->bindParam(':maxSize', $params['maxSize'], PDO::PARAM_INT); - } - - $sth->execute(); - - $rows = $sth->fetchAll(PDO::FETCH_ASSOC); - - $list = array(); - foreach ($rows as $row) { - $list[] = $row; - } - - return array( - 'list' => $rows, - 'total' => $totalCount - ); - } - - public function getActivities($scope, $id, $params = array()) - { - $parts = array( - 'Meeting' => $this->getMeetingQuery($scope, $id, 'NOT IN', array('Held', 'Not Held')), - 'Call' => $this->getCallQuery($scope, $id, 'NOT IN', array('Held', 'Not Held')), - ); - return $this->getResult($parts, $scope, $id, $params); - } - - public function getHistory($scope, $id, $params) - { - $parts = array( - 'Meeting' => $this->getMeetingQuery($scope, $id, 'IN', array('Held')), - 'Call' => $this->getCallQuery($scope, $id, 'IN', array('Held')), - 'Email' => $this->getEmailQuery($scope, $id, 'IN', array('Archived', 'Sent')), - ); - $result = $this->getResult($parts, $scope, $id, $params); - - foreach ($result['list'] as &$item) { - if ($item['_scope'] == 'Email') { - $item['dateSent'] = $item['dateStart']; - } - } - - return $result; - } - - public function getEvents($userId, $from, $to) - { - $pdo = $this->getPDO(); - - $sql = " - SELECT 'Meeting' AS scope, meeting.id AS id, meeting.name AS name, meeting.date_start AS dateStart, meeting.date_end AS dateEnd, meeting.status AS status - FROM `meeting` - JOIN meeting_user ON meeting_user.meeting_id = meeting.id AND meeting_user.deleted = 0 - WHERE - meeting.deleted = 0 AND - meeting.date_start >= ".$pdo->quote($from)." AND - meeting.date_start < ".$pdo->quote($to)." AND - meeting_user.user_id =".$pdo->quote($userId)." - UNION - SELECT 'Call' AS scope, call.id AS id, call.name AS name, call.date_start AS dateStart, call.date_end AS dateEnd, call.status AS status - FROM `call` - JOIN call_user ON call_user.call_id = call.id AND call_user.deleted = 0 - WHERE - call.deleted = 0 AND - call.date_start >= ".$pdo->quote($from)." AND - call.date_start < ".$pdo->quote($to)." AND - call_user.user_id = ".$pdo->quote($userId)." - UNION - SELECT 'Task' AS scope, task.id AS id, task.name AS name, task.date_start AS dateStart, task.date_end AS dateEnd, task.status AS status - FROM `task` - WHERE - task.deleted = 0 AND - ( - ( - task.date_start >= ".$pdo->quote($from)." AND - task.date_start < ".$pdo->quote($to)." - ) OR ( - (task.date_start IS NULL OR task.date_start = '') AND - task.date_end >= ".$pdo->quote($from)." AND - task.date_end < ".$pdo->quote($to)." - ) - ) AND - task.assigned_user_id = ".$pdo->quote($userId)." - "; + $sth = $pdo->prepare($qu); + + if (!empty($params['maxSize'])) { + $offset = 0; + if (!empty($params['offset'])) { + $offset = $params['offset']; + } + + $sth->bindParam(':offset', $offset, PDO::PARAM_INT); + $sth->bindParam(':maxSize', $params['maxSize'], PDO::PARAM_INT); + } + + $sth->execute(); + + $rows = $sth->fetchAll(PDO::FETCH_ASSOC); + + $list = array(); + foreach ($rows as $row) { + $list[] = $row; + } + + return array( + 'list' => $rows, + 'total' => $totalCount + ); + } + + public function getActivities($scope, $id, $params = array()) + { + $fetchAll = empty($params['scope']); + + $parts = array( + 'Meeting' => ($fetchAll || $params['scope'] == 'Meeting') ? $this->getMeetingQuery($scope, $id, 'NOT IN', array('Held', 'Not Held')) : array(), + 'Call' => ($fetchAll || $params['scope'] == 'Call') ? $this->getCallQuery($scope, $id, 'NOT IN', array('Held', 'Not Held')) : array(), + ); + return $this->getResult($parts, $scope, $id, $params); + } + + public function getHistory($scope, $id, $params) + { + + $fetchAll = empty($params['scope']); - - $sth = $pdo->prepare($sql); - $sth->execute(); - $rows = $sth->fetchAll(PDO::FETCH_ASSOC); - - return $rows; - } + $parts = array( + 'Meeting' => ($fetchAll || $params['scope'] == 'Meeting') ? $this->getMeetingQuery($scope, $id, 'IN', array('Held')) : array(), + 'Call' => ($fetchAll || $params['scope'] == 'Call') ? $this->getCallQuery($scope, $id, 'IN', array('Held')) : array(), + 'Email' => ($fetchAll || $params['scope'] == 'Email') ? $this->getEmailQuery($scope, $id, 'IN', array('Archived', 'Sent')) : array(), + ); + $result = $this->getResult($parts, $scope, $id, $params); + + foreach ($result['list'] as &$item) { + if ($item['_scope'] == 'Email') { + $item['dateSent'] = $item['dateStart']; + } + } + + return $result; + } + + public function getEvents($userId, $from, $to) + { + $pdo = $this->getPDO(); + + $sql = " + SELECT 'Meeting' AS scope, meeting.id AS id, meeting.name AS name, meeting.date_start AS dateStart, meeting.date_end AS dateEnd, meeting.status AS status + FROM `meeting` + JOIN meeting_user ON meeting_user.meeting_id = meeting.id AND meeting_user.deleted = 0 + WHERE + meeting.deleted = 0 AND + meeting.date_start >= ".$pdo->quote($from)." AND + meeting.date_start < ".$pdo->quote($to)." AND + meeting_user.user_id =".$pdo->quote($userId)." + UNION + SELECT 'Call' AS scope, call.id AS id, call.name AS name, call.date_start AS dateStart, call.date_end AS dateEnd, call.status AS status + FROM `call` + JOIN call_user ON call_user.call_id = call.id AND call_user.deleted = 0 + WHERE + call.deleted = 0 AND + call.date_start >= ".$pdo->quote($from)." AND + call.date_start < ".$pdo->quote($to)." AND + call_user.user_id = ".$pdo->quote($userId)." + UNION + SELECT 'Task' AS scope, task.id AS id, task.name AS name, task.date_start AS dateStart, task.date_end AS dateEnd, task.status AS status + FROM `task` + WHERE + task.deleted = 0 AND + ( + ( + task.date_start >= ".$pdo->quote($from)." AND + task.date_start < ".$pdo->quote($to)." + ) OR ( + (task.date_start IS NULL OR task.date_start = '') AND + task.date_end >= ".$pdo->quote($from)." AND + task.date_end < ".$pdo->quote($to)." + ) + ) AND + task.assigned_user_id = ".$pdo->quote($userId)." + "; + + + $sth = $pdo->prepare($sql); + $sth->execute(); + $rows = $sth->fetchAll(PDO::FETCH_ASSOC); + + return $rows; + } } diff --git a/application/Espo/Modules/Crm/Services/Contact.php b/application/Espo/Modules/Crm/Services/Contact.php index 37668c1d5e..8570a5670f 100644 --- a/application/Espo/Modules/Crm/Services/Contact.php +++ b/application/Espo/Modules/Crm/Services/Contact.php @@ -26,19 +26,19 @@ use \Espo\ORM\Entity; class Contact extends \Espo\Services\Record { - protected function getDuplicateWhereClause(Entity $entity) - { - return array( - 'OR' => array( - array( - 'firstName' => $entity->get('firstName'), - 'lastName' => $entity->get('lastName'), - ), - array( - 'emailAddress' => $entity->get('emailAddress'), - ), - ), - ); - } + protected function getDuplicateWhereClause(Entity $entity) + { + return array( + 'OR' => array( + array( + 'firstName' => $entity->get('firstName'), + 'lastName' => $entity->get('lastName'), + ), + array( + 'emailAddress' => $entity->get('emailAddress'), + ), + ), + ); + } } diff --git a/application/Espo/Modules/Crm/Services/InboundEmail.php b/application/Espo/Modules/Crm/Services/InboundEmail.php index ba0decf886..1a718cedc7 100644 --- a/application/Espo/Modules/Crm/Services/InboundEmail.php +++ b/application/Espo/Modules/Crm/Services/InboundEmail.php @@ -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; @@ -28,386 +28,407 @@ use \Espo\Core\Exceptions\Error; use \Espo\Core\Exceptions\Forbidden; class InboundEmail extends \Espo\Services\Record -{ - protected $internalFields = array('password'); - - const PORTION_LIMIT = 20; - - public function createEntity($data) - { - $entity = parent::createEntity($data); - return $entity; - } - - public function getEntity($id = null) - { - $entity = parent::getEntity($id); - return $entity; - } - - public function updateEntity($id, $data) - { - $entity = parent::updateEntity($id, $data); - return $entity; - } - - public function findEntities($params) - { - $result = parent::findEntities($params); - - return $result; - } - - protected function init() - { - $this->dependencies[] = 'fileManager'; - $this->dependencies[] = 'mailSender'; - } - - protected function getFileManager() - { - return $this->injections['fileManager']; - } - - protected function getMailSender() - { - return $this->injections['mailSender']; - } - - public function getFolders($params) - { - $password = $params['password']; - - if (!empty($params['id'])) { - $entity = $this->getEntityManager()->getEntity('InboundEmail', $params['id']); - if ($entity) { - $password = $entity->get('password'); - } - } - - $imapParams = array( - 'host' => $params['host'], - 'port' => $params['port'], - 'user' => $params['username'], - 'password' => $password, - ); - - if (!empty($params['ssl'])) { - $imapParams['ssl'] = 'SSL'; - } - - $foldersArr = array(); - - $storage = new \Zend\Mail\Storage\Imap($imapParams); - - $folders = new \RecursiveIteratorIterator($storage->getFolders(), \RecursiveIteratorIterator::SELF_FIRST); - foreach ($folders as $name => $folder) { - $foldersArr[] = $folder->getGlobalName(); - } - return $foldersArr; - } - - 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'), - 'user' => $inboundEmail->get('username'), - 'password' => $inboundEmail->get('password'), - ); - - if ($inboundEmail->get('ssl')) { - $imapParams['ssl'] = 'SSL'; - } - - $storage = new \Espo\Core\Mail\Storage\Imap($imapParams); - - $monitoredFolders = $inboundEmail->get('monitoredFolders'); - if (empty($monitoredFolders)) { - $monitoredFolders = 'INBOX'; - } - - $monitoredFoldersArr = explode(',', $monitoredFolders); - foreach ($monitoredFoldersArr as $folder) { - $folder = trim($folder); - $storage->selectFolder($folder); - - $lastUID = 0; - $lastDate = 0; - if (!empty($fetchData['lastUID'][$folder])) { - $lastUID = $fetchData['lastUID'][$folder]; - } - if (!empty($fetchData['lastDate'][$folder])) { - $lastDate = $fetchData['lastDate'][$folder]; - } +{ + protected $internalFields = array('password'); - $ids = $storage->getIdsFromUID($lastUID); - - if ((count($ids) == 1) && !empty($lastUID)) { - if ($storage->getUniqueId($ids[0]) == $lastUID) { - continue; - } - } - - $k = 0; - foreach ($ids as $i => $id) { - if ($k == count($ids) - 1) { - $lastUID = $storage->getUniqueId($id); - } - - if ($maxSize) { - if ($storage->getSize($id) > $maxSize * 1024 * 1024) { - continue; - } - } - - $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++; - } - - $fetchData['lastUID'][$folder] = $lastUID; - $fetchData['lastDate'][$folder] = $lastDate; - - $inboundEmail->set('fetchData', json_encode($fetchData)); - $this->getEntityManager()->saveEntity($inboundEmail); - } - - 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) - { - $roundRobin = new \Espo\Modules\Crm\Business\CaseDistribution\RoundRobin($this->getEntityManager()); - $user = $roundRobin->getUser($team); - if ($user) { - $case->set('assignedUserId', $user->id); - } - } - - protected function assignLeastBusy($case, $team) - { - $leastBusy = new \Espo\Modules\Crm\Business\CaseDistribution\LeastBusy($this->getEntityManager()); - $user = $leastBusy->getUser($team); - if ($user) { - $case->set('assignedUserId', $user->id); - } - } - - protected function emailToCase(\Espo\Entities\Email $email, array $params = array()) - { - $case = $this->getEntityManager()->getEntity('Case'); - $case->populateDefaults(); - $case->set('name', $email->get('name')); - - $userId = $this->getUser()->id; - if (!empty($params['userId'])) { - $userId = $params['userId']; - } - $case->set('assignedUserId', $userId); - - $teamId = false; - if (!empty($params['teamId'])) { - $teamId = $params['teamId']; - } - if ($teamId) { - $case->set('teamsIds', array($teamId)); - } - - $caseDistribution = 'Direct-Assignment'; - if (!empty($params['caseDistribution'])) { - $caseDistribution = $params['caseDistribution']; - } - - $case->set('status', 'Assigned'); - - switch ($caseDistribution) { - case 'Round-Robin': - if ($teamId) { - $team = $this->getEntityManager()->getEntity('Team', $teamId); - if ($team) { - $this->assignRoundRobin($case, $team); - } - } - break; - case 'Least-Busy': - if ($teamId) { - $team = $this->getEntityManager()->getEntity('Team', $teamId); - if ($team) { - $this->assignLeastBusy($case, $team); - } - } - break; - } - - $email->set('assignedUserId', $case->get('assignedUserId')); - - $contact = $this->getEntityManager()->getRepository('Contact')->where(array( - 'EmailAddress.id' => $email->get('fromEmailAddressId') - ))->findOne(); - if ($contact) { - $case->set('contactId', $contact->id); - if ($contact->get('accountId')) { - $case->set('accountId', $contact->get('accountId')); - } - } - - $this->getEntityManager()->saveEntity($case); - - $email->set('parentType', 'Case'); - $email->set('parentId', $case->id); - $this->getEntityManager()->saveEntity($email); - - $case = $this->getEntityManager()->getEntity('Case', $case->id); - - return $case; - } - - protected function autoReply($inboundEmail, $email, $case = null, $user = null) - { - try { - $replyEmailTemplateId = $inboundEmail->get('replyEmailTemplateId'); - if ($replyEmailTemplateId) { - $entityHash = array(); - if ($case) { - $entityHash['Case'] = $case; - if ($case->get('contactId')) { - $contact = $this->getEntityManager()->getEntity('Contact', $case->get('contactId')); - } - } - if (empty($contact)) { - $contact = $this->getEntityManager()->getEntity('Contact'); - $contact->set('name', $email->get('fromName')); - } - - - $entityHash['Person'] = $contact; - $entityHash['Contact'] = $contact; - - if ($user) { - $entityHash['User'] = $user; - } - - $emailTemplateService = $this->getServiceFactory()->create('EmailTemplate'); - - $replyData = $emailTemplateService->parse($replyEmailTemplateId, array('entityHash' => $entityHash), true); - - $subject = $replyData['subject']; - if ($case) { - $subject = '[#' . $case->get('number'). '] ' . $subject; - } - - $reply = $this->getEntityManager()->getEntity('Email'); - $reply->set('to', $email->get('from')); - $reply->set('subject', $subject); - $reply->set('body', $replyData['body']); - $reply->set('isHtml', $replyData['isHtml']); - $reply->set('attachmentsIds', $replyData['attachmentsIds']); - - $this->getEntityManager()->saveEntity($reply); - - $sender = $this->getMailSender()->useGlobal(); - $senderParams = array(); - if ($inboundEmail->get('replyFromAddress')) { - $senderParams['fromAddress'] = $inboundEmail->get('replyFromAddress'); - } - if ($inboundEmail->get('replyFromName')) { - $senderParams['fromName'] = $inboundEmail->get('replyFromName'); - } - if ($inboundEmail->get('replyToAddress')) { - $senderParams['replyToAddress'] = $inboundEmail->get('replyToAddress'); - } - $sender->send($reply, $senderParams); - - foreach ($reply->get('attachments') as $attachment) { - $this->getEntityManager()->removeEntity($attachment); - } - - $this->getEntityManager()->removeEntity($reply); - - return true; - } - - } catch (\Exception $e) {} - } + const PORTION_LIMIT = 20; + + public function createEntity($data) + { + $entity = parent::createEntity($data); + return $entity; + } + + public function getEntity($id = null) + { + $entity = parent::getEntity($id); + return $entity; + } + + public function updateEntity($id, $data) + { + $entity = parent::updateEntity($id, $data); + return $entity; + } + + public function findEntities($params) + { + $result = parent::findEntities($params); + + return $result; + } + + protected function init() + { + $this->dependencies[] = 'fileManager'; + $this->dependencies[] = 'mailSender'; + $this->dependencies[] = 'crypt'; + } + + protected function getFileManager() + { + return $this->injections['fileManager']; + } + + protected function getMailSender() + { + return $this->injections['mailSender']; + } + + protected function getCrypt() + { + return $this->injections['crypt']; + } + + protected function handleInput(&$data) + { + parent::handleInput($data); + if (array_key_exists('password', $data)) { + $data['password'] = $this->getCrypt()->encrypt($data['password']); + } + } + + public function getFolders($params) + { + $password = $params['password']; + + if (!empty($params['id'])) { + $entity = $this->getEntityManager()->getEntity('InboundEmail', $params['id']); + if ($entity) { + $password = $this->getCrypt()->decrypt($entity->get('password')); + } + } + + $imapParams = array( + 'host' => $params['host'], + 'port' => $params['port'], + 'user' => $params['username'], + 'password' => $password, + ); + + if (!empty($params['ssl'])) { + $imapParams['ssl'] = 'SSL'; + } + + $foldersArr = array(); + + $storage = new \Zend\Mail\Storage\Imap($imapParams); + + $folders = new \RecursiveIteratorIterator($storage->getFolders(), \RecursiveIteratorIterator::SELF_FIRST); + foreach ($folders as $name => $folder) { + $foldersArr[] = $folder->getGlobalName(); + } + return $foldersArr; + } + + 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'), + 'user' => $inboundEmail->get('username'), + 'password' => $this->getCrypt()->decrypt($inboundEmail->get('password')), + ); + + if ($inboundEmail->get('ssl')) { + $imapParams['ssl'] = 'SSL'; + } + + $storage = new \Espo\Core\Mail\Storage\Imap($imapParams); + + $monitoredFolders = $inboundEmail->get('monitoredFolders'); + if (empty($monitoredFolders)) { + $monitoredFolders = 'INBOX'; + } + + $monitoredFoldersArr = explode(',', $monitoredFolders); + foreach ($monitoredFoldersArr as $folder) { + $folder = trim($folder); + $storage->selectFolder($folder); + + $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); + + if ((count($ids) == 1) && !empty($lastUID)) { + if ($storage->getUniqueId($ids[0]) == $lastUID) { + continue; + } + } + + $k = 0; + foreach ($ids as $i => $id) { + if ($k == count($ids) - 1) { + $lastUID = $storage->getUniqueId($id); + } + + if ($maxSize) { + if ($storage->getSize($id) > $maxSize * 1024 * 1024) { + continue; + } + } + + $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++; + } + + $fetchData['lastUID'][$folder] = $lastUID; + $fetchData['lastDate'][$folder] = $lastDate; + + $inboundEmail->set('fetchData', json_encode($fetchData)); + $this->getEntityManager()->saveEntity($inboundEmail); + } + + 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'), + 'targetUserPosition' => $inboundEmail->get('targetUserPosition') + ); + $case = $this->emailToCase($email, $params); + $user = $this->getEntityManager()->getEntity('User', $case->get('assignedUserId')); + $this->getServiceFactory()->create('Stream')->noteEmailReceived($case, $email, true); + if ($inboundEmail->get('reply')) { + $this->autoReply($inboundEmail, $email, $case, $user); + } + } + } + + protected function assignRoundRobin($case, $team, $targetUserPosition) + { + $roundRobin = new \Espo\Modules\Crm\Business\CaseDistribution\RoundRobin($this->getEntityManager()); + $user = $roundRobin->getUser($team, $targetUserPosition); + if ($user) { + $case->set('assignedUserId', $user->id); + } + } + + protected function assignLeastBusy($case, $team, $targetUserPosition) + { + $leastBusy = new \Espo\Modules\Crm\Business\CaseDistribution\LeastBusy($this->getEntityManager()); + $user = $leastBusy->getUser($team, $targetUserPosition); + if ($user) { + $case->set('assignedUserId', $user->id); + } + } + + protected function emailToCase(\Espo\Entities\Email $email, array $params = array()) + { + $case = $this->getEntityManager()->getEntity('Case'); + $case->populateDefaults(); + $case->set('name', $email->get('name')); + + $userId = $this->getUser()->id; + if (!empty($params['userId'])) { + $userId = $params['userId']; + } + $case->set('assignedUserId', $userId); + + $teamId = false; + if (!empty($params['teamId'])) { + $teamId = $params['teamId']; + } + if ($teamId) { + $case->set('teamsIds', array($teamId)); + } + + $caseDistribution = 'Direct-Assignment'; + if (!empty($params['caseDistribution'])) { + $caseDistribution = $params['caseDistribution']; + } + + $targetUserPosition = null; + if (!empty($params['targetUserPosition'])) { + $targetUserPosition = $params['targetUserPosition']; + } + + $case->set('status', 'Assigned'); + + switch ($caseDistribution) { + case 'Round-Robin': + if ($teamId) { + $team = $this->getEntityManager()->getEntity('Team', $teamId); + if ($team) { + $this->assignRoundRobin($case, $team, $targetUserPosition); + } + } + break; + case 'Least-Busy': + if ($teamId) { + $team = $this->getEntityManager()->getEntity('Team', $teamId); + if ($team) { + $this->assignLeastBusy($case, $team, $targetUserPosition); + } + } + break; + } + + $email->set('assignedUserId', $case->get('assignedUserId')); + + $contact = $this->getEntityManager()->getRepository('Contact')->where(array( + 'EmailAddress.id' => $email->get('fromEmailAddressId') + ))->findOne(); + if ($contact) { + $case->set('contactId', $contact->id); + if ($contact->get('accountId')) { + $case->set('accountId', $contact->get('accountId')); + } + } + + $this->getEntityManager()->saveEntity($case); + + $email->set('parentType', 'Case'); + $email->set('parentId', $case->id); + $this->getEntityManager()->saveEntity($email); + + $case = $this->getEntityManager()->getEntity('Case', $case->id); + + return $case; + } + + protected function autoReply($inboundEmail, $email, $case = null, $user = null) + { + try { + $replyEmailTemplateId = $inboundEmail->get('replyEmailTemplateId'); + if ($replyEmailTemplateId) { + $entityHash = array(); + if ($case) { + $entityHash['Case'] = $case; + if ($case->get('contactId')) { + $contact = $this->getEntityManager()->getEntity('Contact', $case->get('contactId')); + } + } + if (empty($contact)) { + $contact = $this->getEntityManager()->getEntity('Contact'); + $contact->set('name', $email->get('fromName')); + } + + + $entityHash['Person'] = $contact; + $entityHash['Contact'] = $contact; + + if ($user) { + $entityHash['User'] = $user; + } + + $emailTemplateService = $this->getServiceFactory()->create('EmailTemplate'); + + $replyData = $emailTemplateService->parse($replyEmailTemplateId, array('entityHash' => $entityHash), true); + + $subject = $replyData['subject']; + if ($case) { + $subject = '[#' . $case->get('number'). '] ' . $subject; + } + + $reply = $this->getEntityManager()->getEntity('Email'); + $reply->set('to', $email->get('from')); + $reply->set('subject', $subject); + $reply->set('body', $replyData['body']); + $reply->set('isHtml', $replyData['isHtml']); + $reply->set('attachmentsIds', $replyData['attachmentsIds']); + + $this->getEntityManager()->saveEntity($reply); + + $sender = $this->getMailSender()->useGlobal(); + $senderParams = array(); + if ($inboundEmail->get('replyFromAddress')) { + $senderParams['fromAddress'] = $inboundEmail->get('replyFromAddress'); + } + if ($inboundEmail->get('replyFromName')) { + $senderParams['fromName'] = $inboundEmail->get('replyFromName'); + } + if ($inboundEmail->get('replyToAddress')) { + $senderParams['replyToAddress'] = $inboundEmail->get('replyToAddress'); + } + $sender->send($reply, $senderParams); + + foreach ($reply->get('attachments') as $attachment) { + $this->getEntityManager()->removeEntity($attachment); + } + + $this->getEntityManager()->removeEntity($reply); + + return true; + } + + } catch (\Exception $e) {} + } } diff --git a/application/Espo/Modules/Crm/Services/Lead.php b/application/Espo/Modules/Crm/Services/Lead.php index 2128af3cbd..386b21a5ad 100644 --- a/application/Espo/Modules/Crm/Services/Lead.php +++ b/application/Espo/Modules/Crm/Services/Lead.php @@ -28,99 +28,99 @@ use \Espo\Core\Exceptions\Forbidden; use \Espo\ORM\Entity; class Lead extends \Espo\Services\Record -{ - protected function getDuplicateWhereClause(Entity $entity) - { - return array( - 'OR' => array( - array( - 'firstName' => $entity->get('firstName'), - 'lastName' => $entity->get('lastName'), - ), - array( - 'emailAddress' => $entity->get('emailAddress'), - ), - ), - ); - } - - public function convert($id, $recordsData) - { - $lead = $this->getEntity($id); - - if (!$this->getAcl()->check($lead, 'edit')) { - throw new Forbidden(); - } +{ + protected function getDuplicateWhereClause(Entity $entity) + { + return array( + 'OR' => array( + array( + 'firstName' => $entity->get('firstName'), + 'lastName' => $entity->get('lastName'), + ), + array( + 'emailAddress' => $entity->get('emailAddress'), + ), + ), + ); + } + + public function convert($id, $recordsData) + { + $lead = $this->getEntity($id); + + if (!$this->getAcl()->check($lead, 'edit')) { + throw new Forbidden(); + } - $entityManager = $this->getEntityManager(); + $entityManager = $this->getEntityManager(); - if (!empty($recordsData->Account)) { - $account = $entityManager->getEntity('Account'); - $account->set(get_object_vars($recordsData->Account)); - $entityManager->saveEntity($account); - $lead->set('createdAccountId', $account->id); - } - if (!empty($recordsData->Opportunity)) { - $opportunity = $entityManager->getEntity('Opportunity'); - $opportunity->set(get_object_vars($recordsData->Opportunity)); - if (isset($account)) { - $opportunity->set('accountId', $account->id); - } - $entityManager->saveEntity($opportunity); - $lead->set('createdOpportunityId', $opportunity->id); - } - if (!empty($recordsData->Contact)) { - $contact = $entityManager->getEntity('Contact'); - $contact->set(get_object_vars($recordsData->Contact)); - if (isset($account)) { - $contact->set('accountId', $account->id); - } - $entityManager->saveEntity($contact); - if (isset($opportunity)) { - $entityManager->getRepository('Contact')->relate($contact, 'opportunities', $opportunity); - } - $lead->set('createdContactId', $contact->id); - } + if (!empty($recordsData->Account)) { + $account = $entityManager->getEntity('Account'); + $account->set(get_object_vars($recordsData->Account)); + $entityManager->saveEntity($account); + $lead->set('createdAccountId', $account->id); + } + if (!empty($recordsData->Opportunity)) { + $opportunity = $entityManager->getEntity('Opportunity'); + $opportunity->set(get_object_vars($recordsData->Opportunity)); + if (isset($account)) { + $opportunity->set('accountId', $account->id); + } + $entityManager->saveEntity($opportunity); + $lead->set('createdOpportunityId', $opportunity->id); + } + if (!empty($recordsData->Contact)) { + $contact = $entityManager->getEntity('Contact'); + $contact->set(get_object_vars($recordsData->Contact)); + if (isset($account)) { + $contact->set('accountId', $account->id); + } + $entityManager->saveEntity($contact); + if (isset($opportunity)) { + $entityManager->getRepository('Contact')->relate($contact, 'opportunities', $opportunity); + } + $lead->set('createdContactId', $contact->id); + } - $lead->set('status', 'Converted'); - $entityManager->saveEntity($lead); - - if ($meetings = $lead->get('meetings')) { - foreach ($meetings as $meeting) { - if (!empty($contact)) { - $entityManager->getRepository('Meeting')->relate($meeting, 'contacts', $contact); - } - - if (!empty($opportunity)) { - $meeting->set('parentId', $opportunity->id); - $meeting->set('parentType', 'Opportunity'); - $entityManager->saveEntity($meeting); - } else if (!empty($account)) { - $meeting->set('parentId', $account->id); - $meeting->set('parentType', 'Account'); - $entityManager->saveEntity($meeting); - } - } - } - if ($calls = $lead->get('calls')) { - foreach ($calls as $call) { - if (!empty($contact)) { - $entityManager->getRepository('Call')->relate($call, 'contacts', $contact); - } - if (!empty($opportunity)) { - $call->set('parentId', $opportunity->id); - $call->set('parentType', 'Opportunity'); - $entityManager->saveEntity($call); - } else if (!empty($account)) { - $call->set('parentId', $account->id); - $call->set('parentType', 'Account'); - $entityManager->saveEntity($call); - } - } - } + $lead->set('status', 'Converted'); + $entityManager->saveEntity($lead); + + if ($meetings = $lead->get('meetings')) { + foreach ($meetings as $meeting) { + if (!empty($contact)) { + $entityManager->getRepository('Meeting')->relate($meeting, 'contacts', $contact); + } + + if (!empty($opportunity)) { + $meeting->set('parentId', $opportunity->id); + $meeting->set('parentType', 'Opportunity'); + $entityManager->saveEntity($meeting); + } else if (!empty($account)) { + $meeting->set('parentId', $account->id); + $meeting->set('parentType', 'Account'); + $entityManager->saveEntity($meeting); + } + } + } + if ($calls = $lead->get('calls')) { + foreach ($calls as $call) { + if (!empty($contact)) { + $entityManager->getRepository('Call')->relate($call, 'contacts', $contact); + } + if (!empty($opportunity)) { + $call->set('parentId', $opportunity->id); + $call->set('parentType', 'Opportunity'); + $entityManager->saveEntity($call); + } else if (!empty($account)) { + $call->set('parentId', $account->id); + $call->set('parentType', 'Account'); + $entityManager->saveEntity($call); + } + } + } - return $lead; - } + return $lead; + } } diff --git a/application/Espo/Modules/Crm/Services/Meeting.php b/application/Espo/Modules/Crm/Services/Meeting.php index f0ce9899ad..d35b0074e1 100644 --- a/application/Espo/Modules/Crm/Services/Meeting.php +++ b/application/Espo/Modules/Crm/Services/Meeting.php @@ -30,80 +30,94 @@ use \Espo\Core\Exceptions\Forbidden; class Meeting extends \Espo\Services\Record { - protected function init() - { - $this->dependencies[] = 'mailSender'; - $this->dependencies[] = 'preferences'; - $this->dependencies[] = 'language'; - $this->dependencies[] = 'dateTime'; - } + protected function init() + { + $this->dependencies[] = 'mailSender'; + $this->dependencies[] = 'preferences'; + $this->dependencies[] = 'language'; + $this->dependencies[] = 'dateTime'; + $this->dependencies[] = 'crypt'; + } - protected function getMailSender() - { - return $this->injections['mailSender']; - } + protected function getMailSender() + { + return $this->injections['mailSender']; + } - protected function getPreferences() - { - return $this->injections['preferences']; - } + protected function getPreferences() + { + return $this->injections['preferences']; + } - protected function getLanguage() - { - return $this->injections['language']; - } + protected function getCrypt() + { + return $this->injections['crypt']; + } - protected function getDateTime() - { - return $this->injections['dateTime']; - } - - protected function getInvitationManager() - { - return new Invitations($this->getEntityManager(), $this->getMailSender(), $this->getConfig(), $this->getDateTime(), $this->getLanguage()); - } + protected function getLanguage() + { + return $this->injections['language']; + } - public function sendInvitations(Entity $entity) - { - $invitationManager = $this->getInvitationManager(); - - $users = $entity->get('users'); - foreach ($users as $user) { - $invitationManager->sendInvitation($entity, $user, 'users'); - } + protected function getDateTime() + { + return $this->injections['dateTime']; + } + + protected function getInvitationManager() + { + $smtpParams = $this->getPreferences()->getSmtpParams(); + if ($smtpParams) { + if (array_key_exists('password', $smtpParams)) { + $smtpParams['password'] = $this->getCrypt()->decrypt($smtpParams['password']); + } + $smtpParams['fromAddress'] = $this->getUser()->get('emailAddress'); + $smtpParams['fromName'] = $this->getUser()->get('name'); + } + return new Invitations($this->getEntityManager(), $smtpParams, $this->getMailSender(), $this->getConfig(), $this->getDateTime(), $this->getLanguage()); + } - $contacts = $entity->get('contacts'); - foreach ($contacts as $contact) { - $invitationManager->sendInvitation($entity, $contact, 'contacts'); - } + public function sendInvitations(Entity $entity) + { + $invitationManager = $this->getInvitationManager(); + + $users = $entity->get('users'); + foreach ($users as $user) { + $invitationManager->sendInvitation($entity, $user, 'users'); + } - $leads = $entity->get('leads'); - foreach ($leads as $lead) { - $invitationManager->sendInvitation($entity, $lead, 'leads'); - } + $contacts = $entity->get('contacts'); + foreach ($contacts as $contact) { + $invitationManager->sendInvitation($entity, $contact, 'contacts'); + } - return true; - } + $leads = $entity->get('leads'); + foreach ($leads as $lead) { + $invitationManager->sendInvitation($entity, $lead, 'leads'); + } - protected function storeEntity(Entity $entity) - { - $assignedUserId = $entity->get('assignedUserId'); - if ($assignedUserId && $entity->has('usersIds')) { - $usersIds = $entity->get('usersIds'); - if (!is_array($usersIds)) { - $usersIds = array(); - } - if (!in_array($assignedUserId, $usersIds)) { - $usersIds[] = $assignedUserId; - $entity->set('usersIds', $usersIds); - $hash = $entity->get('usersNames'); - if ($hash instanceof \stdClass) { - $hash->assignedUserId = $entity->get('assignedUserName'); - $entity->set('usersNames', $hash); - } - } - } - return parent::storeEntity($entity); - } + return true; + } + + protected function storeEntity(Entity $entity) + { + $assignedUserId = $entity->get('assignedUserId'); + if ($assignedUserId && $entity->has('usersIds')) { + $usersIds = $entity->get('usersIds'); + if (!is_array($usersIds)) { + $usersIds = array(); + } + if (!in_array($assignedUserId, $usersIds)) { + $usersIds[] = $assignedUserId; + $entity->set('usersIds', $usersIds); + $hash = $entity->get('usersNames'); + if ($hash instanceof \stdClass) { + $hash->assignedUserId = $entity->get('assignedUserName'); + $entity->set('usersNames', $hash); + } + } + } + return parent::storeEntity($entity); + } } diff --git a/application/Espo/Modules/Crm/Services/Opportunity.php b/application/Espo/Modules/Crm/Services/Opportunity.php index 73af9e08b3..b7e1f827d8 100644 --- a/application/Espo/Modules/Crm/Services/Opportunity.php +++ b/application/Espo/Modules/Crm/Services/Opportunity.php @@ -29,130 +29,130 @@ use \Espo\Core\Exceptions\Forbidden; class Opportunity extends \Espo\Services\Record { - public function reportSalesPipeline($dateFrom, $dateTo) - { - $pdo = $this->getEntityManager()->getPDO(); + public function reportSalesPipeline($dateFrom, $dateTo) + { + $pdo = $this->getEntityManager()->getPDO(); - $options = $this->getMetadata()->get('entityDefs.Opportunity.fields.stage.options'); + $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)."') - "; + $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(); + $sth = $pdo->prepare($sql); + $sth->execute(); - $rows = $sth->fetchAll(\PDO::FETCH_ASSOC); + $rows = $sth->fetchAll(\PDO::FETCH_ASSOC); - $result = array(); - foreach ($rows as $row) { - $result[$row['stage']] = floatval($row['amount']); - } + $result = array(); + foreach ($rows as $row) { + $result[$row['stage']] = floatval($row['amount']); + } - return $result; - } + return $result; + } - public function reportByLeadSource($dateFrom, $dateTo) - { - $pdo = $this->getEntityManager()->getPDO(); + 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 - "; + $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(); + $sth = $pdo->prepare($sql); + $sth->execute(); - $rows = $sth->fetchAll(\PDO::FETCH_ASSOC); + $rows = $sth->fetchAll(\PDO::FETCH_ASSOC); - $result = array(); - foreach ($rows as $row) { - $result[$row['leadSource']] = floatval($row['amount']); - } + $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` - 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 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; - } + 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` + 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 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; + } } diff --git a/application/Espo/Modules/Crm/Services/Target.php b/application/Espo/Modules/Crm/Services/Target.php index 1c61110783..7885333c3b 100644 --- a/application/Espo/Modules/Crm/Services/Target.php +++ b/application/Espo/Modules/Crm/Services/Target.php @@ -27,34 +27,34 @@ use \Espo\Core\Exceptions\Forbidden; use \Espo\ORM\Entity; class Target extends \Espo\Services\Record -{ - protected function getDuplicateWhereClause(Entity $entity) - { - return array( - 'firstName' => $entity->get('firstName'), - 'lastName' => $entity->get('lastName'), - ); - } - - public function convert($id) - { - $entityManager = $this->getEntityManager(); - $target = $this->getEntity($id); - - if (!$this->getAcl()->check($target, 'delete')) { - throw new Forbidden(); - } - if (!$this->getAcl()->check('Lead', 'read')) { - throw new Forbidden(); - } - - $lead = $entityManager->getEntity('Lead'); - $lead->set($target->toArray()); - - $entityManager->removeEntity($target); - $entityManager->saveEntity($lead); +{ + protected function getDuplicateWhereClause(Entity $entity) + { + return array( + 'firstName' => $entity->get('firstName'), + 'lastName' => $entity->get('lastName'), + ); + } + + public function convert($id) + { + $entityManager = $this->getEntityManager(); + $target = $this->getEntity($id); + + if (!$this->getAcl()->check($target, 'delete')) { + throw new Forbidden(); + } + if (!$this->getAcl()->check('Lead', 'read')) { + throw new Forbidden(); + } + + $lead = $entityManager->getEntity('Lead'); + $lead->set($target->toArray()); + + $entityManager->removeEntity($target); + $entityManager->saveEntity($lead); - return $lead; - } + return $lead; + } } diff --git a/application/Espo/ORM/DB/IMapper.php b/application/Espo/ORM/DB/IMapper.php index 5c9f64ecb5..4a17ea5a7a 100644 --- a/application/Espo/ORM/DB/IMapper.php +++ b/application/Espo/ORM/DB/IMapper.php @@ -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\ORM\DB; @@ -27,160 +27,160 @@ use Espo\ORM\Classes\EntityFactory; interface IMapper { - /** - * Selects bean by id. - * - * @param IEntity $entity - * @param string $id Id of the needed bean - * @return IEntity $entity - */ - function selectById(IEntity $entity, $id); - - /** - * Selects list of beans according to given parameters. - * - * @param IEntity $entity - * @param array $params Parameters (whereClause, offset, limit, orderBy, order, customWhere, joins, distinct) - * @return array Array of beans - */ - function select(IEntity $entity, $params); + /** + * Selects bean by id. + * + * @param IEntity $entity + * @param string $id Id of the needed bean + * @return IEntity $entity + */ + function selectById(IEntity $entity, $id); - /** - * Invokes aggregate function and returns a value. - * - * @param IEntity $entity - * @param array $params Parameters (whereClause, joins, distinct, customWhere, customJoin) - * @param string $aggregation Aggregate function (COUNT, MAX, MIN, SUM, AVG) - * @param string $aggregationBy Field to aggregate - * @param bool $deleted True to consider records marked as deleted either. - * @return mixed Result of the aggregation - */ - function aggregate(IEntity $entity, $params, $aggregation, $aggregationBy, $deleted); - - /** - * Returns count of records according to given parameters. - * - * @param IEntity $entity - * @param array $params Parameters (ordering, and limitig are not used) - * @return int Count of record - */ - function count(IEntity $entity, $params); - - /** - * Returns max value of the field in the select according to given parameters. - * - * @param IEntity $entity - * @param array $params Parameters - * @param string $field Needed field. - * @param bool $deleted True to consider records marked as deleted either. - * @return mixed Max value - */ - function max(IEntity $entity, $params, $field, $deleted); - - /** - * Returns min value of the field in the select according to given parameters. - * - * @param IEntity $entity - * @param array $params Parameters - * @param string $field Needed field. - * @param bool $deleted True to consider records marked as deleted either. - * @return mixed Min value - */ - function min(IEntity $entity, $params, $field, $deleted); - - /** - * Returns sum value of the field in the select according to given parameters. - * - * @param IEntity $entity - * @param array $params Parameters - * @param string $field Needed field. - * @param bool $deleted True to consider records marked as deleted either. - * @return mixed Sum value - */ - function sum(IEntity $entity, $params); - - /** - * Selects related bean or list of beans. - * - * @param IEntity $entity - * @param string $relName Relation name - * @param array $params (whereClause, offset, limit, orderBy, order, customWhere) - * @param bool $totalCount used by DB::countRelated to make this method return total count - * @return array List of beans or total count if $totalCount was passed as true - */ - function selectRelated(IEntity $entity, $relName, $params, $totalCount); - - /** - * Returns count of related records according to given parameters. - * - * @param IEntity $entity - * @param string $relName Relation name - * @param array $params (whereClause, customWhere) - * @return int Count of records - */ - function countRelated(IEntity $entity, $relName, $params); - - /** - * Links the bean with another one. - * - * @param IEntity $entity - * @param string $relName Relation name - * @param string $id Id of the foreign record. - * @return bool True if success - */ - function addRelation(IEntity $entity, $relName, $id); - - /** - * Removes relation of bean with certain record. - * - * @param IEntity $entity - * @param string $relName Relation name - * @param string $id Id of the foreign record. - * @return bool True if success - */ - function removeRelation(IEntity $entity, $relName, $id); - - /** - * Removes all relations of bean of specified relation name. - * - * @param IEntity $entity - * @param string $relName Relation name - * @return bool True if success - */ - function removeAllRelations(IEntity $entity, $relName); - - /** - * Insert the bean into db. - * - * @param IEntity $entity - * @return bool True if success - */ - function insert(IEntity $entity); - - /** - * Updates the bean in db. - * - * @param IEntity $entity - * @return bool True if success - */ - function update(IEntity $entity); - - - /** - * Deletes the bean. - * (Marks as deleted) - * - * @param IEntity $entity - * @return bool True if success - */ - function delete(IEntity $entity); - - /** - * Sets class name of a model collection that will be returned by operations such as select. - * - * @param string $collectionClass Class name of a model collection. - */ - function setCollectionClass($collectionClass); + /** + * Selects list of beans according to given parameters. + * + * @param IEntity $entity + * @param array $params Parameters (whereClause, offset, limit, orderBy, order, customWhere, joins, distinct) + * @return array Array of beans + */ + function select(IEntity $entity, $params); + + /** + * Invokes aggregate function and returns a value. + * + * @param IEntity $entity + * @param array $params Parameters (whereClause, joins, distinct, customWhere, customJoin) + * @param string $aggregation Aggregate function (COUNT, MAX, MIN, SUM, AVG) + * @param string $aggregationBy Field to aggregate + * @param bool $deleted True to consider records marked as deleted either. + * @return mixed Result of the aggregation + */ + function aggregate(IEntity $entity, $params, $aggregation, $aggregationBy, $deleted); + + /** + * Returns count of records according to given parameters. + * + * @param IEntity $entity + * @param array $params Parameters (ordering, and limitig are not used) + * @return int Count of record + */ + function count(IEntity $entity, $params); + + /** + * Returns max value of the field in the select according to given parameters. + * + * @param IEntity $entity + * @param array $params Parameters + * @param string $field Needed field. + * @param bool $deleted True to consider records marked as deleted either. + * @return mixed Max value + */ + function max(IEntity $entity, $params, $field, $deleted); + + /** + * Returns min value of the field in the select according to given parameters. + * + * @param IEntity $entity + * @param array $params Parameters + * @param string $field Needed field. + * @param bool $deleted True to consider records marked as deleted either. + * @return mixed Min value + */ + function min(IEntity $entity, $params, $field, $deleted); + + /** + * Returns sum value of the field in the select according to given parameters. + * + * @param IEntity $entity + * @param array $params Parameters + * @param string $field Needed field. + * @param bool $deleted True to consider records marked as deleted either. + * @return mixed Sum value + */ + function sum(IEntity $entity, $params); + + /** + * Selects related bean or list of beans. + * + * @param IEntity $entity + * @param string $relName Relation name + * @param array $params (whereClause, offset, limit, orderBy, order, customWhere) + * @param bool $totalCount used by DB::countRelated to make this method return total count + * @return array List of beans or total count if $totalCount was passed as true + */ + function selectRelated(IEntity $entity, $relName, $params, $totalCount); + + /** + * Returns count of related records according to given parameters. + * + * @param IEntity $entity + * @param string $relName Relation name + * @param array $params (whereClause, customWhere) + * @return int Count of records + */ + function countRelated(IEntity $entity, $relName, $params); + + /** + * Links the bean with another one. + * + * @param IEntity $entity + * @param string $relName Relation name + * @param string $id Id of the foreign record. + * @return bool True if success + */ + function addRelation(IEntity $entity, $relName, $id); + + /** + * Removes relation of bean with certain record. + * + * @param IEntity $entity + * @param string $relName Relation name + * @param string $id Id of the foreign record. + * @return bool True if success + */ + function removeRelation(IEntity $entity, $relName, $id); + + /** + * Removes all relations of bean of specified relation name. + * + * @param IEntity $entity + * @param string $relName Relation name + * @return bool True if success + */ + function removeAllRelations(IEntity $entity, $relName); + + /** + * Insert the bean into db. + * + * @param IEntity $entity + * @return bool True if success + */ + function insert(IEntity $entity); + + /** + * Updates the bean in db. + * + * @param IEntity $entity + * @return bool True if success + */ + function update(IEntity $entity); + + + /** + * Deletes the bean. + * (Marks as deleted) + * + * @param IEntity $entity + * @return bool True if success + */ + function delete(IEntity $entity); + + /** + * Sets class name of a model collection that will be returned by operations such as select. + * + * @param string $collectionClass Class name of a model collection. + */ + function setCollectionClass($collectionClass); } diff --git a/application/Espo/ORM/DB/Mapper.php b/application/Espo/ORM/DB/Mapper.php index a052918ae9..17c94202e3 100644 --- a/application/Espo/ORM/DB/Mapper.php +++ b/application/Espo/ORM/DB/Mapper.php @@ -34,768 +34,780 @@ use PDO; */ abstract class Mapper implements IMapper { - public $pdo; - - protected $entityFactroy; - - protected $query; - - protected $fieldsMapCache = array(); - protected $aliasesCache = array(); - - protected $returnCollection = true; - - protected $collectionClass = "\\Espo\\ORM\\EntityCollection"; - - protected static $sqlOperators = array( - 'OR', - 'AND', - ); - - protected static $comparisonOperators = array( - '!=' => '<>', - '*' => 'LIKE', - '>=' => '>=', - '<=' => '<=', - '>' => '>', - '<' => '<', - '=' => '=', - ); - - protected static $selectParamList = array( - 'offset', - 'limit', - 'order', - 'orderBy', - 'customWhere', - 'customJoin', - 'joins', - 'leftJoins', - 'distinct', - 'joinConditions', - ); - - public function __construct(PDO $pdo, \Espo\ORM\EntityFactory $entityFactory, Query $query) { - $this->pdo = $pdo; - $this->query = $query; - $this->entityFactory = $entityFactory; - } - - public function selectById(IEntity $entity, $id, $params = array()) - { - if (!array_key_exists('whereClause', $params)) { - $params['whereClause'] = array(); - } - - $params['whereClause']['id'] = $id; - $params['whereClause']['deleted'] = 0; - - $sql = $this->query->createSelectQuery($entity->getEntityName(), $params); - - $ps = $this->pdo->query($sql); - - if ($ps) { - foreach ($ps as $row) { - $entity = $this->fromRow($entity, $row); - return true; - } - } - return false; - } - - public function count(IEntity $entity, $params = array()) - { - return $this->aggregate($entity, $params, 'COUNT', 'id'); - } - - public function max(IEntity $entity, $params = array(), $field, $deleted = false) - { - return $this->aggregate($entity, $params, 'MAX', $field, true); - } - - public function min(IEntity $entity, $params = array(), $field, $deleted = false) - { - return $this->aggregate($entity, $params, 'MIN', $field, true); - } - - public function sum(IEntity $entity, $params = array()) - { - return $this->aggregate($entity, $params, 'SUM', 'id'); - } - - public function select(IEntity $entity, $params = array()) - { - $sql = $this->query->createSelectQuery($entity->getEntityName(), $params); - - $dataArr = array(); - $ps = $this->pdo->query($sql); - if ($ps) { - $dataArr = $ps->fetchAll(); - } - - if ($this->returnCollection) { - $collectionClass = $this->collectionClass; - $entityArr = new $collectionClass($dataArr, $entity->getEntityName(), $this->entityFactory); - return $entityArr; - } else { - return $dataArr; - } - } - - public function aggregate(IEntity $entity, $params = array(), $aggregation, $aggregationBy, $deleted = false) - { - if (empty($aggregation) || !isset($entity->fields[$aggregationBy])) { - return false; - } - - $params['aggregation'] = $aggregation; - $params['aggregationBy'] = $aggregationBy; - - $sql = $this->query->createSelectQuery($entity->getEntityName(), $params, $deleted); - - $ps = $this->pdo->query($sql); - - if ($ps) { - foreach ($ps as $row) { - return $row['AggregateValue']; - } - } - return false; - } - - public function selectRelated(IEntity $entity, $relationName, $params = array(), $totalCount = false) - { - $relOpt = $entity->relations[$relationName]; - - if (!isset($relOpt['entity']) || !isset($relOpt['type'])) { - throw new \LogicException("Not appropriate defenition for relationship {$relationName} in " . $entity->getEntityName() . " entity"); - } - - $relEntityName = (!empty($relOpt['class'])) ? $relOpt['class'] : $relOpt['entity']; - $relEntity = $this->entityFactory->create($relEntityName); - - if (!$relEntity) { - return null; - } - - if ($totalCount) { - $params['aggregation'] = 'COUNT'; - $params['aggregationBy'] = 'id'; - } - - - if (empty($params['whereClause'])) { - $params['whereClause'] = array(); - } - - $relType = $relOpt['type']; - - $keySet = $this->query->getKeys($entity, $relationName); - - $key = $keySet['key']; - $foreignKey = $keySet['foreignKey']; - - switch ($relType) { - - case IEntity::BELONGS_TO: - $params['whereClause'][$foreignKey] = $entity->get($key); - $params['offset'] = 0; - $params['limit'] = 1; - - $sql = $this->query->createSelectQuery($relEntity->getEntityName(), $params); - - $ps = $this->pdo->query($sql); - - if ($ps) { - foreach ($ps as $row) { - if (!$totalCount) { - $relEntity = $this->fromRow($relEntity, $row); - return $relEntity; - } else { - return $row['AggregateValue']; - } - } - } - break; - - case IEntity::HAS_MANY: - case IEntity::HAS_CHILDREN: - - $params['whereClause'][$foreignKey] = $entity->get($key); - - if ($relType == IEntity::HAS_CHILDREN) { - $foreignType = $keySet['foreignType']; - $params['whereClause'][$foreignType] = $entity->getEntityName(); - } - - $dataArr = array(); - - $sql = $this->query->createSelectQuery($relEntity->getEntityName(), $params); - - $ps = $this->pdo->query($sql); - if ($ps) { - if (!$totalCount) { - $dataArr = $ps->fetchAll(); - - } else { - foreach ($ps as $row) { - return $row['AggregateValue']; - } - } - } - if ($this->returnCollection) { - $collectionClass = $this->collectionClass; - return new $collectionClass($dataArr, $relEntity->getEntityName(), $this->entityFactory); - } else { - return $dataArr; - } - break; - - case IEntity::MANY_MANY: - - $MMJoinPart = $this->getMMJoin($entity, $relationName, $keySet); - - if (empty($params['customJoin'])) { - $params['customJoin'] = ''; - } else { - $params['customJoin'] .= ' '; - } - $params['customJoin'] .= $MMJoinPart; - - - $params['relationName'] = $relOpt['relationName']; - - // TODO total - - - $sql = $this->query->createSelectQuery($relEntity->getEntityName(), $params); - - $dataArr = array(); - - - $ps = $this->pdo->query($sql); - if ($ps) { - if (!$totalCount) { - $dataArr = $ps->fetchAll(); - - } else { - foreach ($ps as $row) { - return $row['AggregateValue']; - } - } - } - if ($this->returnCollection) { - $collectionClass = $this->collectionClass; - return new $collectionClass($dataArr, $relEntity->getEntityName(), $this->entityFactory); - } else { - return $dataArr; - } - break; - } - - return false; - } - - - public function countRelated(IEntity $entity, $relationName, $params = array()) - { - return $this->selectRelated($entity, $relationName, $params, true); - } - - public function relate(IEntity $entityFrom, $relationName, IEntity $entityTo, $data = null) - { - $this->addRelation($entityFrom, $relationName, null, $entityTo, $data); - } - - public function unrelate(IEntity $entityFrom, $relationName, IEntity $entityTo) - { - $this->removeRelation($entityFrom, $relationName, null, false, $entityTo); - } - - public function updateRelation(IEntity $entity, $relationName, $id = null, array $columnData) - { - if (empty($id) || empty($relationName)) { - return false; - } - - $relOpt = $entity->relations[$relationName]; - $keySet = $this->query->getKeys($entity, $relationName); - - $relType = $relOpt['type']; - - - switch ($relType) { - case IEntity::MANY_MANY: - $relTable = $this->toDb($relOpt['relationName']); - $key = $keySet['key']; - $foreignKey = $keySet['foreignKey']; - $nearKey = $keySet['nearKey']; - $distantKey = $keySet['distantKey']; - - $setArr = array(); - foreach ($columnData as $column => $value) { - $setArr[] = $this->toDb($column) . " = " . $this->pdo->quote($value); - } - if (empty($setArr)) { - return true; - } - $setPart = implode(', ', $setArr); - - $wherePart = - $this->toDb($nearKey) . " = " . $this->pdo->quote($entity->id) . " - AND " . $this->toDb($distantKey) . " = " . $this->pdo->quote($id) . " AND deleted = 0 - "; - - if (!empty($relOpt['conditions']) && is_array($relOpt['conditions'])) { - foreach ($relOpt['conditions'] as $f => $v) { - $wherePart .= " AND " . $this->toDb($f) . " = " . $this->pdo->quote($v); - } - } - - $sql = $this->composeUpdateQuery($relTable, $setPart, $wherePart); - - if ($this->pdo->query($sql)) { - return true; - } - } - } - - public function addRelation(IEntity $entity, $relationName, $id = null, $relEntity = null, $data = null) - { - if (!is_null($relEntity)) { - $id = $relEntity->id; - } - - if (empty($id) || empty($relationName)) { - return false; - } - - $relOpt = $entity->relations[$relationName]; - - if (!isset($relOpt['entity']) || !isset($relOpt['type'])) { - throw new \LogicException("Not appropriate defenition for relationship {$relationName} in " . $entity->getEntityName() . " entity"); - } - - $relType = $relOpt['type']; - - $className = (!empty($relOpt['class'])) ? $relOpt['class'] : $relOpt['entity']; - - if (is_null($relEntity)) { - $relEntity = $this->entityFactory->create($className); - if (!$relEntity) { - return null; - } - $relEntity->id = $id; - } - - $keySet = $this->query->getKeys($entity, $relationName); - - switch ($relType) { - case IEntity::BELONGS_TO: - case IEntity::HAS_ONE: - return false; - break; - - case IEntity::HAS_CHILDREN: - case IEntity::HAS_MANY: - $key = $keySet['key']; - $foreignKey = $keySet['foreignKey']; - - if ($this->count($relEntity, array('whereClause' => array('id' => $id))) > 0) { - - $setPart = $this->toDb($foreignKey) . " = " . $this->pdo->quote($entity->get($key)); - - if ($relType == IEntity::HAS_CHILDREN) { - $foreignType = $keySet['foreignType']; - $setPart .= ", " . $this->toDb($foreignType) . " = " . $this->pdo->quote($entity->getEntityName()); - } - - $wherePart = $this->query->getWhere($relEntity, array('id' => $id, 'deleted' => 0)); - $sql = $this->composeUpdateQuery($this->toDb($relEntity->getEntityName()), $setPart, $wherePart); - - if ($this->pdo->query($sql)) { - return true; - } - } else { - return false; - } - break; - - case IEntity::MANY_MANY: - $key = $keySet['key']; - $foreignKey = $keySet['foreignKey']; - $nearKey = $keySet['nearKey']; - $distantKey = $keySet['distantKey']; - - if ($this->count($relEntity, array('whereClause' => array('id' => $id))) > 0) { - $relTable = $this->toDb($relOpt['relationName']); - - $wherePart = - $this->toDb($nearKey) . " = " . $this->pdo->quote($entity->id) . " ". - "AND " . $this->toDb($distantKey) . " = " . $this->pdo->quote($relEntity->id); - if (!empty($relOpt['conditions']) && is_array($relOpt['conditions'])) { - foreach ($relOpt['conditions'] as $f => $v) { - $wherePart .= " AND " . $this->toDb($f) . " = " . $this->pdo->quote($v); - } - } - - $sql = $this->query->composeSelectQuery($relTable, '*', '', $wherePart); - - $ps = $this->pdo->query($sql); - - if ($ps->rowCount() == 0) { - $fieldsPart = $this->toDb($nearKey) . ", " . $this->toDb($distantKey); - $valuesPart = $this->pdo->quote($entity->id) . ", " . $this->pdo->quote($relEntity->id); - - if (!empty($relOpt['conditions']) && is_array($relOpt['conditions'])) { - foreach ($relOpt['conditions'] as $f => $v) { - $fieldsPart .= ", " . $this->toDb($f); - $valuesPart .= ", " . $this->pdo->quote($v); - } - } - - if (!empty($data) && is_array($data)) { - foreach ($data as $column => $columnValue) { - $fieldsPart .= ", " . $this->toDb($column); - $valuesPart .= ", " . $this->pdo->quote($columnValue); - } - } - - $sql = $this->composeInsertQuery($relTable, $fieldsPart, $valuesPart); - - if ($this->pdo->query($sql)) { - return true; - } - } else { - $setPart = 'deleted = 0'; - - if (!empty($data) && is_array($data)) { - $setArr = array(); - foreach ($data as $column => $value) { - $setArr[] = $this->toDb($column) . " = " . $this->pdo->quote($value); - } - $setPart .= ', ' . implode(', ', $setArr); - } - - $wherePart = - $this->toDb($nearKey) . " = " . $this->pdo->quote($entity->id) . " - AND " . $this->toDb($distantKey) . " = " . $this->pdo->quote($relEntity->id) . " - "; - - if (!empty($relOpt['conditions']) && is_array($relOpt['conditions'])) { - foreach ($relOpt['conditions'] as $f => $v) { - $wherePart .= " AND " . $this->toDb($f) . " = " . $this->pdo->quote($v); - } - } - - $sql = $this->composeUpdateQuery($relTable, $setPart, $wherePart); - if ($this->pdo->query($sql)) { - return true; - } - } - } else { - return false; - } - break; - } - } - - public function removeRelation(IEntity $entity, $relationName, $id = null, $all = false, IEntity $relEntity = null) - { - if (!is_null($relEntity)) { - $id = $relEntity->id; - } - - if (empty($id) && empty($all) || empty($relationName)) { - return false; - } - - $relOpt = $entity->relations[$relationName]; - - if (!isset($relOpt['entity']) || !isset($relOpt['type'])) { - throw new \LogicException("Not appropriate defenition for relationship {$relationName} in " . $entity->getEntityName() . " entity"); - } - - $relType = $relOpt['type']; - - $className = (!empty($relOpt['class'])) ? $relOpt['class'] : $relOpt['entity']; - - if (is_null($relEntity)) { - $relEntity = $this->entityFactory->create($className); - if (!$relEntity) { - return null; - } - $relEntity->id = $id; - } - - $keySet = $this->query->getKeys($entity, $relationName); - - switch ($relType) { - - case IEntity::BELONGS_TO: - /*$foreignKey = $keySet['foreignKey']; - $relEntity->$foreignKey = null; - $this-> - break;*/ - - case IEntity::HAS_ONE: - return false; - - - case IEntity::HAS_MANY: - case IEntity::HAS_CHILDREN: - $key = $keySet['key']; - $foreignKey = $keySet['foreignKey']; - - $setPart = $this->toDb($foreignKey) . " = " . "NULL"; - - $whereClause = array('deleted' => 0); - if (empty($all)) { - $whereClause['id'] = $id; - } else { - $whereClause[$foreignKey] = $entity->id; - } - - if ($relType == IEntity::HAS_CHILDREN) { - $foreignType = $keySet['foreignType']; - $whereClause[$foreignType] = $entity->getEntityName(); - } - - $wherePart = $this->query->getWhere($relEntity, $whereClause); - $sql = $this->composeUpdateQuery($this->toDb($relEntity->getEntityName()), $setPart, $wherePart); - if ($this->pdo->query($sql)) { - return true; - } - break; - - case IEntity::MANY_MANY: - $key = $keySet['key']; - $foreignKey = $keySet['foreignKey']; - $nearKey = $keySet['nearKey']; - $distantKey = $keySet['distantKey']; - - $relTable = $this->toDb($relOpt['relationName']); - - $setPart = 'deleted = 1'; - $wherePart = $this->toDb($nearKey) . " = " . $this->pdo->quote($entity->id); - - - if (empty($all)) { - $wherePart .= " AND " . $this->toDb($distantKey) . " = " . $this->pdo->quote($id) . ""; - } - - if (!empty($relOpt['conditions']) && is_array($relOpt['conditions'])) { - foreach ($relOpt['conditions'] as $f => $v) { - $wherePart .= " AND " . $this->toDb($f) . " = " . $this->pdo->quote($v); - } - } - - $sql = $this->composeUpdateQuery($relTable, $setPart, $wherePart); - - if ($this->pdo->query($sql)) { - return true; - } - break; - } - } - - public function removeAllRelations(IEntity $entity, $relationName) - { - $this->removeRelation($entity, $relationName, null, true); - } - - protected function quote($value) - { - if (is_null($value)) { - return 'NULL'; - } else { - return $this->pdo->quote($value); - } - } - - public function insert(IEntity $entity) - { - $dataArr = $this->toArray($entity); - - $fieldArr = array(); - $valArr = array(); - foreach ($dataArr as $field => $value) { - $fieldArr[] = $this->toDb($field); - - $type = $entity->fields[$field]['type']; - - $value = $this->prepareValueForInsert($type, $value); - - $valArr[] = $this->quote($value); - } - $fieldsPart = "`" . implode("`, `", $fieldArr) . "`"; - $valuesPart = implode(", ", $valArr); - - $sql = $this->composeInsertQuery($this->toDb($entity->getEntityName()), $fieldsPart, $valuesPart); - - if ($this->pdo->query($sql)) { - return $entity->id; - } - - return false; - } - - public function update(IEntity $entity) - { - $dataArr = $this->toArray($entity); - - $setArr = array(); - foreach ($dataArr as $field => $value) { - if ($field == 'id') { - continue; - } - $type = $entity->fields[$field]['type']; - - if ($type == IEntity::FOREIGN) { - continue; - } - - if ($entity->getFetched($field) === $value && $type != IEntity::JSON_ARRAY && $type != IEntity::JSON_OBJECT) { - continue; - } - - $value = $this->prepareValueForInsert($type, $value); - - $setArr[] = "`" . $this->toDb($field) . "` = " . $this->quote($value); - } - if (count($setArr) == 0) { - return $entity->id; - } - - $setPart = implode(', ', $setArr); - $wherePart = $this->query->getWhere($entity, array('id' => $entity->id, 'deleted' => 0)); - - $sql = $this->composeUpdateQuery($this->toDb($entity->getEntityName()), $setPart, $wherePart); - - if ($this->pdo->query($sql)) { - return $entity->id; - } - - return false; - } - - protected function prepareValueForInsert($type, $value) { - if ($type == IEntity::JSON_ARRAY && is_array($value)) { - $value = json_encode($value); - } else if ($type == IEntity::JSON_OBJECT && (is_array($value) || $value instanceof \stdClass)) { - $value = json_encode($value); - } - - if (is_bool($value)) { - $value = (int) $value; - } - return $value; - } - - public function deleteFromDb($entityName, $id) - { - if (!empty($entityName) && !empty($id)) { - $table = $this->toDb($entityName); - $sql = "DELETE FROM `{$table}` WHERE id = " . $this->quote($id); - if ($this->pdo->query($sql)) { - return true; - } - } - } - - public function delete(IEntity $entity) - { - $entity->set('deleted', true); - return $this->update($entity); - } - - protected function toArray(IEntity $entity, $onlyStorable = true) - { - $arr = array(); - foreach ($entity->fields as $field => $fieldDefs) { - if ($entity->has($field)) { - if ($onlyStorable) { - if (!empty($fieldDefs['notStorable']) || isset($fieldDefs['source']) && $fieldDefs['source'] != 'db') - continue; - if ($fieldDefs['type'] == IEntity::FOREIGN) - continue; - } - $arr[$field] = $entity->get($field); - } - } - return $arr; - } - - protected function fromRow(IEntity $entity, $data) - { - $entity->set($data); - return $entity; - } - - protected function getMMJoin(IEntity $entity, $relationName, $keySet = false) - { - $relOpt = $entity->relations[$relationName]; - - if (empty($keySet)) { - $keySet = $this->query->getKeys($entity, $relationName); - } - - $key = $keySet['key']; - $foreignKey = $keySet['foreignKey']; - $nearKey = $keySet['nearKey']; - $distantKey = $keySet['distantKey']; - - $relTable = $this->toDb($relOpt['relationName']); - $distantTable = $this->toDb($relOpt['entity']); - - $join = - "JOIN `{$relTable}` ON {$distantTable}." . $this->toDb($foreignKey) . " = {$relTable}." . $this->toDb($distantKey) - . " AND " - . "{$relTable}." . $this->toDb($nearKey) . " = " . $this->pdo->quote($entity->get($key)) - . " AND " - . "{$relTable}.deleted = " . $this->pdo->quote(0) . ""; - - if (!empty($relOpt['conditions']) && is_array($relOpt['conditions'])) { - foreach ($relOpt['conditions'] as $f => $v) { - $join .= " AND {$relTable}." . $this->toDb($f) . " = " . $this->pdo->quote($v); - } - } - - return $join; - } - - - protected function composeInsertQuery($table, $fields, $values) - { - $sql = "INSERT INTO `{$table}`"; - $sql .= " ({$fields})"; - if (!is_array($values)) { - $sql .= " VALUES ({$values})"; - } else { - $sql .= " VALUES (" . implode("), (", $values) . ")"; - } - - return $sql; - } - - protected function composeUpdateQuery($table, $set, $where) - { - $sql = "UPDATE `{$table}` SET {$set} WHERE {$where}"; - - return $sql; - } - - abstract protected function toDb($field); - - public function setReturnCollection($returnCollection) - { - $this->returnCollection = $returnCollection; - } - - public function setCollectionClass($collectionClass) - { - $this->collectionClass = $collectionClass; - } + public $pdo; + + protected $entityFactroy; + + protected $query; + + protected $fieldsMapCache = array(); + protected $aliasesCache = array(); + + protected $returnCollection = true; + + protected $collectionClass = "\\Espo\\ORM\\EntityCollection"; + + protected static $sqlOperators = array( + 'OR', + 'AND', + ); + + protected static $comparisonOperators = array( + '!=' => '<>', + '*' => 'LIKE', + '>=' => '>=', + '<=' => '<=', + '>' => '>', + '<' => '<', + '=' => '=', + ); + + protected static $selectParamList = array( + 'offset', + 'limit', + 'order', + 'orderBy', + 'customWhere', + 'customJoin', + 'joins', + 'leftJoins', + 'distinct', + 'joinConditions', + 'additionalColumnsConditions' + ); + + public function __construct(PDO $pdo, \Espo\ORM\EntityFactory $entityFactory, Query $query) { + $this->pdo = $pdo; + $this->query = $query; + $this->entityFactory = $entityFactory; + } + + public function selectById(IEntity $entity, $id, $params = array()) + { + if (!array_key_exists('whereClause', $params)) { + $params['whereClause'] = array(); + } + + $params['whereClause']['id'] = $id; + $params['whereClause']['deleted'] = 0; + + $sql = $this->query->createSelectQuery($entity->getEntityName(), $params); + + $ps = $this->pdo->query($sql); + + if ($ps) { + foreach ($ps as $row) { + $entity = $this->fromRow($entity, $row); + return true; + } + } + return false; + } + + public function count(IEntity $entity, $params = array()) + { + return $this->aggregate($entity, $params, 'COUNT', 'id'); + } + + public function max(IEntity $entity, $params = array(), $field, $deleted = false) + { + return $this->aggregate($entity, $params, 'MAX', $field, true); + } + + public function min(IEntity $entity, $params = array(), $field, $deleted = false) + { + return $this->aggregate($entity, $params, 'MIN', $field, true); + } + + public function sum(IEntity $entity, $params = array()) + { + return $this->aggregate($entity, $params, 'SUM', 'id'); + } + + public function select(IEntity $entity, $params = array()) + { + $sql = $this->query->createSelectQuery($entity->getEntityName(), $params); + + $dataArr = array(); + $ps = $this->pdo->query($sql); + if ($ps) { + $dataArr = $ps->fetchAll(); + } + + if ($this->returnCollection) { + $collectionClass = $this->collectionClass; + $entityArr = new $collectionClass($dataArr, $entity->getEntityName(), $this->entityFactory); + return $entityArr; + } else { + return $dataArr; + } + } + + public function aggregate(IEntity $entity, $params = array(), $aggregation, $aggregationBy, $deleted = false) + { + if (empty($aggregation) || !isset($entity->fields[$aggregationBy])) { + return false; + } + + $params['aggregation'] = $aggregation; + $params['aggregationBy'] = $aggregationBy; + + $sql = $this->query->createSelectQuery($entity->getEntityName(), $params, $deleted); + + $ps = $this->pdo->query($sql); + + if ($ps) { + foreach ($ps as $row) { + return $row['AggregateValue']; + } + } + return false; + } + + public function selectRelated(IEntity $entity, $relationName, $params = array(), $totalCount = false) + { + $relOpt = $entity->relations[$relationName]; + + if (!isset($relOpt['entity']) || !isset($relOpt['type'])) { + throw new \LogicException("Not appropriate defenition for relationship {$relationName} in " . $entity->getEntityName() . " entity"); + } + + $relEntityName = (!empty($relOpt['class'])) ? $relOpt['class'] : $relOpt['entity']; + $relEntity = $this->entityFactory->create($relEntityName); + + if (!$relEntity) { + return null; + } + + if ($totalCount) { + $params['aggregation'] = 'COUNT'; + $params['aggregationBy'] = 'id'; + } + + + if (empty($params['whereClause'])) { + $params['whereClause'] = array(); + } + + $relType = $relOpt['type']; + + $keySet = $this->query->getKeys($entity, $relationName); + + $key = $keySet['key']; + $foreignKey = $keySet['foreignKey']; + + switch ($relType) { + + case IEntity::BELONGS_TO: + $params['whereClause'][$foreignKey] = $entity->get($key); + $params['offset'] = 0; + $params['limit'] = 1; + + $sql = $this->query->createSelectQuery($relEntity->getEntityName(), $params); + + $ps = $this->pdo->query($sql); + + if ($ps) { + foreach ($ps as $row) { + if (!$totalCount) { + $relEntity = $this->fromRow($relEntity, $row); + return $relEntity; + } else { + return $row['AggregateValue']; + } + } + } + break; + + case IEntity::HAS_MANY: + case IEntity::HAS_CHILDREN: + + $params['whereClause'][$foreignKey] = $entity->get($key); + + if ($relType == IEntity::HAS_CHILDREN) { + $foreignType = $keySet['foreignType']; + $params['whereClause'][$foreignType] = $entity->getEntityName(); + } + + $dataArr = array(); + + $sql = $this->query->createSelectQuery($relEntity->getEntityName(), $params); + + $ps = $this->pdo->query($sql); + if ($ps) { + if (!$totalCount) { + $dataArr = $ps->fetchAll(); + + } else { + foreach ($ps as $row) { + return $row['AggregateValue']; + } + } + } + if ($this->returnCollection) { + $collectionClass = $this->collectionClass; + return new $collectionClass($dataArr, $relEntity->getEntityName(), $this->entityFactory); + } else { + return $dataArr; + } + break; + + case IEntity::MANY_MANY: + + $additionalColumnsConditions = null; + if (!empty($params['additionalColumnsConditions'])) { + $additionalColumnsConditions = $params['additionalColumnsConditions']; + } + + $MMJoinPart = $this->getMMJoin($entity, $relationName, $keySet, $additionalColumnsConditions); + + if (empty($params['customJoin'])) { + $params['customJoin'] = ''; + } else { + $params['customJoin'] .= ' '; + } + $params['customJoin'] .= $MMJoinPart; + + + $params['relationName'] = $relOpt['relationName']; + + // TODO total + + + $sql = $this->query->createSelectQuery($relEntity->getEntityName(), $params); + + $dataArr = array(); + + + $ps = $this->pdo->query($sql); + if ($ps) { + if (!$totalCount) { + $dataArr = $ps->fetchAll(); + + } else { + foreach ($ps as $row) { + return $row['AggregateValue']; + } + } + } + if ($this->returnCollection) { + $collectionClass = $this->collectionClass; + return new $collectionClass($dataArr, $relEntity->getEntityName(), $this->entityFactory); + } else { + return $dataArr; + } + break; + } + + return false; + } + + + public function countRelated(IEntity $entity, $relationName, $params = array()) + { + return $this->selectRelated($entity, $relationName, $params, true); + } + + public function relate(IEntity $entityFrom, $relationName, IEntity $entityTo, $data = null) + { + $this->addRelation($entityFrom, $relationName, null, $entityTo, $data); + } + + public function unrelate(IEntity $entityFrom, $relationName, IEntity $entityTo) + { + $this->removeRelation($entityFrom, $relationName, null, false, $entityTo); + } + + public function updateRelation(IEntity $entity, $relationName, $id = null, array $columnData) + { + if (empty($id) || empty($relationName)) { + return false; + } + + $relOpt = $entity->relations[$relationName]; + $keySet = $this->query->getKeys($entity, $relationName); + + $relType = $relOpt['type']; + + + switch ($relType) { + case IEntity::MANY_MANY: + $relTable = $this->toDb($relOpt['relationName']); + $key = $keySet['key']; + $foreignKey = $keySet['foreignKey']; + $nearKey = $keySet['nearKey']; + $distantKey = $keySet['distantKey']; + + $setArr = array(); + foreach ($columnData as $column => $value) { + $setArr[] = $this->toDb($column) . " = " . $this->pdo->quote($value); + } + if (empty($setArr)) { + return true; + } + $setPart = implode(', ', $setArr); + + $wherePart = + $this->toDb($nearKey) . " = " . $this->pdo->quote($entity->id) . " + AND " . $this->toDb($distantKey) . " = " . $this->pdo->quote($id) . " AND deleted = 0 + "; + + if (!empty($relOpt['conditions']) && is_array($relOpt['conditions'])) { + foreach ($relOpt['conditions'] as $f => $v) { + $wherePart .= " AND " . $this->toDb($f) . " = " . $this->pdo->quote($v); + } + } + + $sql = $this->composeUpdateQuery($relTable, $setPart, $wherePart); + + if ($this->pdo->query($sql)) { + return true; + } + } + } + + public function addRelation(IEntity $entity, $relationName, $id = null, $relEntity = null, $data = null) + { + if (!is_null($relEntity)) { + $id = $relEntity->id; + } + + if (empty($id) || empty($relationName)) { + return false; + } + + $relOpt = $entity->relations[$relationName]; + + if (!isset($relOpt['entity']) || !isset($relOpt['type'])) { + throw new \LogicException("Not appropriate defenition for relationship {$relationName} in " . $entity->getEntityName() . " entity"); + } + + $relType = $relOpt['type']; + + $className = (!empty($relOpt['class'])) ? $relOpt['class'] : $relOpt['entity']; + + if (is_null($relEntity)) { + $relEntity = $this->entityFactory->create($className); + if (!$relEntity) { + return null; + } + $relEntity->id = $id; + } + + $keySet = $this->query->getKeys($entity, $relationName); + + switch ($relType) { + case IEntity::BELONGS_TO: + case IEntity::HAS_ONE: + return false; + break; + + case IEntity::HAS_CHILDREN: + case IEntity::HAS_MANY: + $key = $keySet['key']; + $foreignKey = $keySet['foreignKey']; + + if ($this->count($relEntity, array('whereClause' => array('id' => $id))) > 0) { + + $setPart = $this->toDb($foreignKey) . " = " . $this->pdo->quote($entity->get($key)); + + if ($relType == IEntity::HAS_CHILDREN) { + $foreignType = $keySet['foreignType']; + $setPart .= ", " . $this->toDb($foreignType) . " = " . $this->pdo->quote($entity->getEntityName()); + } + + $wherePart = $this->query->getWhere($relEntity, array('id' => $id, 'deleted' => 0)); + $sql = $this->composeUpdateQuery($this->toDb($relEntity->getEntityName()), $setPart, $wherePart); + + if ($this->pdo->query($sql)) { + return true; + } + } else { + return false; + } + break; + + case IEntity::MANY_MANY: + $key = $keySet['key']; + $foreignKey = $keySet['foreignKey']; + $nearKey = $keySet['nearKey']; + $distantKey = $keySet['distantKey']; + + if ($this->count($relEntity, array('whereClause' => array('id' => $id))) > 0) { + $relTable = $this->toDb($relOpt['relationName']); + + $wherePart = + $this->toDb($nearKey) . " = " . $this->pdo->quote($entity->id) . " ". + "AND " . $this->toDb($distantKey) . " = " . $this->pdo->quote($relEntity->id); + if (!empty($relOpt['conditions']) && is_array($relOpt['conditions'])) { + foreach ($relOpt['conditions'] as $f => $v) { + $wherePart .= " AND " . $this->toDb($f) . " = " . $this->pdo->quote($v); + } + } + + $sql = $this->query->composeSelectQuery($relTable, '*', '', $wherePart); + + $ps = $this->pdo->query($sql); + + if ($ps->rowCount() == 0) { + $fieldsPart = $this->toDb($nearKey) . ", " . $this->toDb($distantKey); + $valuesPart = $this->pdo->quote($entity->id) . ", " . $this->pdo->quote($relEntity->id); + + if (!empty($relOpt['conditions']) && is_array($relOpt['conditions'])) { + foreach ($relOpt['conditions'] as $f => $v) { + $fieldsPart .= ", " . $this->toDb($f); + $valuesPart .= ", " . $this->pdo->quote($v); + } + } + + if (!empty($data) && is_array($data)) { + foreach ($data as $column => $columnValue) { + $fieldsPart .= ", " . $this->toDb($column); + $valuesPart .= ", " . $this->pdo->quote($columnValue); + } + } + + $sql = $this->composeInsertQuery($relTable, $fieldsPart, $valuesPart); + + if ($this->pdo->query($sql)) { + return true; + } + } else { + $setPart = 'deleted = 0'; + + if (!empty($data) && is_array($data)) { + $setArr = array(); + foreach ($data as $column => $value) { + $setArr[] = $this->toDb($column) . " = " . $this->pdo->quote($value); + } + $setPart .= ', ' . implode(', ', $setArr); + } + + $wherePart = + $this->toDb($nearKey) . " = " . $this->pdo->quote($entity->id) . " + AND " . $this->toDb($distantKey) . " = " . $this->pdo->quote($relEntity->id) . " + "; + + if (!empty($relOpt['conditions']) && is_array($relOpt['conditions'])) { + foreach ($relOpt['conditions'] as $f => $v) { + $wherePart .= " AND " . $this->toDb($f) . " = " . $this->pdo->quote($v); + } + } + + $sql = $this->composeUpdateQuery($relTable, $setPart, $wherePart); + if ($this->pdo->query($sql)) { + return true; + } + } + } else { + return false; + } + break; + } + } + + public function removeRelation(IEntity $entity, $relationName, $id = null, $all = false, IEntity $relEntity = null) + { + if (!is_null($relEntity)) { + $id = $relEntity->id; + } + + if (empty($id) && empty($all) || empty($relationName)) { + return false; + } + + $relOpt = $entity->relations[$relationName]; + + if (!isset($relOpt['entity']) || !isset($relOpt['type'])) { + throw new \LogicException("Not appropriate defenition for relationship {$relationName} in " . $entity->getEntityName() . " entity"); + } + + $relType = $relOpt['type']; + + $className = (!empty($relOpt['class'])) ? $relOpt['class'] : $relOpt['entity']; + + if (is_null($relEntity)) { + $relEntity = $this->entityFactory->create($className); + if (!$relEntity) { + return null; + } + $relEntity->id = $id; + } + + $keySet = $this->query->getKeys($entity, $relationName); + + switch ($relType) { + + case IEntity::BELONGS_TO: + /*$foreignKey = $keySet['foreignKey']; + $relEntity->$foreignKey = null; + $this-> + break;*/ + + case IEntity::HAS_ONE: + return false; + + + case IEntity::HAS_MANY: + case IEntity::HAS_CHILDREN: + $key = $keySet['key']; + $foreignKey = $keySet['foreignKey']; + + $setPart = $this->toDb($foreignKey) . " = " . "NULL"; + + $whereClause = array('deleted' => 0); + if (empty($all)) { + $whereClause['id'] = $id; + } else { + $whereClause[$foreignKey] = $entity->id; + } + + if ($relType == IEntity::HAS_CHILDREN) { + $foreignType = $keySet['foreignType']; + $whereClause[$foreignType] = $entity->getEntityName(); + } + + $wherePart = $this->query->getWhere($relEntity, $whereClause); + $sql = $this->composeUpdateQuery($this->toDb($relEntity->getEntityName()), $setPart, $wherePart); + if ($this->pdo->query($sql)) { + return true; + } + break; + + case IEntity::MANY_MANY: + $key = $keySet['key']; + $foreignKey = $keySet['foreignKey']; + $nearKey = $keySet['nearKey']; + $distantKey = $keySet['distantKey']; + + $relTable = $this->toDb($relOpt['relationName']); + + $setPart = 'deleted = 1'; + $wherePart = $this->toDb($nearKey) . " = " . $this->pdo->quote($entity->id); + + + if (empty($all)) { + $wherePart .= " AND " . $this->toDb($distantKey) . " = " . $this->pdo->quote($id) . ""; + } + + if (!empty($relOpt['conditions']) && is_array($relOpt['conditions'])) { + foreach ($relOpt['conditions'] as $f => $v) { + $wherePart .= " AND " . $this->toDb($f) . " = " . $this->pdo->quote($v); + } + } + + $sql = $this->composeUpdateQuery($relTable, $setPart, $wherePart); + + if ($this->pdo->query($sql)) { + return true; + } + break; + } + } + + public function removeAllRelations(IEntity $entity, $relationName) + { + $this->removeRelation($entity, $relationName, null, true); + } + + protected function quote($value) + { + if (is_null($value)) { + return 'NULL'; + } else { + return $this->pdo->quote($value); + } + } + + public function insert(IEntity $entity) + { + $dataArr = $this->toArray($entity); + + $fieldArr = array(); + $valArr = array(); + foreach ($dataArr as $field => $value) { + $fieldArr[] = $this->toDb($field); + + $type = $entity->fields[$field]['type']; + + $value = $this->prepareValueForInsert($type, $value); + + $valArr[] = $this->quote($value); + } + $fieldsPart = "`" . implode("`, `", $fieldArr) . "`"; + $valuesPart = implode(", ", $valArr); + + $sql = $this->composeInsertQuery($this->toDb($entity->getEntityName()), $fieldsPart, $valuesPart); + + if ($this->pdo->query($sql)) { + return $entity->id; + } + + return false; + } + + public function update(IEntity $entity) + { + $dataArr = $this->toArray($entity); + + $setArr = array(); + foreach ($dataArr as $field => $value) { + if ($field == 'id') { + continue; + } + $type = $entity->fields[$field]['type']; + + if ($type == IEntity::FOREIGN) { + continue; + } + + if ($entity->getFetched($field) === $value && $type != IEntity::JSON_ARRAY && $type != IEntity::JSON_OBJECT) { + continue; + } + + $value = $this->prepareValueForInsert($type, $value); + + $setArr[] = "`" . $this->toDb($field) . "` = " . $this->quote($value); + } + if (count($setArr) == 0) { + return $entity->id; + } + + $setPart = implode(', ', $setArr); + $wherePart = $this->query->getWhere($entity, array('id' => $entity->id, 'deleted' => 0)); + + $sql = $this->composeUpdateQuery($this->toDb($entity->getEntityName()), $setPart, $wherePart); + + if ($this->pdo->query($sql)) { + return $entity->id; + } + + return false; + } + + protected function prepareValueForInsert($type, $value) { + if ($type == IEntity::JSON_ARRAY && is_array($value)) { + $value = json_encode($value); + } else if ($type == IEntity::JSON_OBJECT && (is_array($value) || $value instanceof \stdClass)) { + $value = json_encode($value); + } + + if (is_bool($value)) { + $value = (int) $value; + } + return $value; + } + + public function deleteFromDb($entityName, $id) + { + if (!empty($entityName) && !empty($id)) { + $table = $this->toDb($entityName); + $sql = "DELETE FROM `{$table}` WHERE id = " . $this->quote($id); + if ($this->pdo->query($sql)) { + return true; + } + } + } + + public function delete(IEntity $entity) + { + $entity->set('deleted', true); + return $this->update($entity); + } + + protected function toArray(IEntity $entity, $onlyStorable = true) + { + $arr = array(); + foreach ($entity->fields as $field => $fieldDefs) { + if ($entity->has($field)) { + if ($onlyStorable) { + if (!empty($fieldDefs['notStorable']) || isset($fieldDefs['source']) && $fieldDefs['source'] != 'db') + continue; + if ($fieldDefs['type'] == IEntity::FOREIGN) + continue; + } + $arr[$field] = $entity->get($field); + } + } + return $arr; + } + + protected function fromRow(IEntity $entity, $data) + { + $entity->set($data); + return $entity; + } + + protected function getMMJoin(IEntity $entity, $relationName, $keySet = false, $conditions = array()) + { + $relOpt = $entity->relations[$relationName]; + + if (empty($keySet)) { + $keySet = $this->query->getKeys($entity, $relationName); + } + + $key = $keySet['key']; + $foreignKey = $keySet['foreignKey']; + $nearKey = $keySet['nearKey']; + $distantKey = $keySet['distantKey']; + + $relTable = $this->toDb($relOpt['relationName']); + $distantTable = $this->toDb($relOpt['entity']); + + $join = + "JOIN `{$relTable}` ON {$distantTable}." . $this->toDb($foreignKey) . " = {$relTable}." . $this->toDb($distantKey) + . " AND " + . "{$relTable}." . $this->toDb($nearKey) . " = " . $this->pdo->quote($entity->get($key)) + . " AND " + . "{$relTable}.deleted = " . $this->pdo->quote(0) . ""; + + if (!empty($relOpt['conditions']) && is_array($relOpt['conditions'])) { + foreach ($relOpt['conditions'] as $f => $v) { + $join .= " AND {$relTable}." . $this->toDb($f) . " = " . $this->pdo->quote($v); + } + } + + if (!empty($conditions) && is_array($conditions)) { + foreach ($conditions as $f => $v) { + $join .= " AND {$relTable}." . $this->toDb($f) . " = " . $this->pdo->quote($v); + } + } + + return $join; + } + + + protected function composeInsertQuery($table, $fields, $values) + { + $sql = "INSERT INTO `{$table}`"; + $sql .= " ({$fields})"; + if (!is_array($values)) { + $sql .= " VALUES ({$values})"; + } else { + $sql .= " VALUES (" . implode("), (", $values) . ")"; + } + + return $sql; + } + + protected function composeUpdateQuery($table, $set, $where) + { + $sql = "UPDATE `{$table}` SET {$set} WHERE {$where}"; + + return $sql; + } + + abstract protected function toDb($field); + + public function setReturnCollection($returnCollection) + { + $this->returnCollection = $returnCollection; + } + + public function setCollectionClass($collectionClass) + { + $this->collectionClass = $collectionClass; + } } diff --git a/application/Espo/ORM/DB/MysqlMapper.php b/application/Espo/ORM/DB/MysqlMapper.php index 76688d7c63..34a0624eae 100644 --- a/application/Espo/ORM/DB/MysqlMapper.php +++ b/application/Espo/ORM/DB/MysqlMapper.php @@ -33,10 +33,10 @@ use PDO; */ class MysqlMapper extends Mapper { - protected function toDb($field) - { - return $this->query->toDb($field); - } + protected function toDb($field) + { + return $this->query->toDb($field); + } } diff --git a/application/Espo/ORM/DB/Query.php b/application/Espo/ORM/DB/Query.php index 4898ee2689..fb17ed9808 100644 --- a/application/Espo/ORM/DB/Query.php +++ b/application/Espo/ORM/DB/Query.php @@ -28,781 +28,787 @@ use Espo\ORM\EntityFactory; use PDO; class Query -{ - protected static $selectParamList = array( - 'select', - 'whereClause', - 'offset', - 'limit', - 'order', - 'orderBy', - 'customWhere', - 'customJoin', - 'joins', - 'leftJoins', - 'distinct', - 'joinConditions', - 'aggregation', - 'aggregationBy', - 'groupBy' - ); - - protected static $sqlOperators = array( - 'OR', - 'AND', - ); - - protected static $comparisonOperators = array( - '!=' => '<>', - '*' => 'LIKE', - '>=' => '>=', - '<=' => '<=', - '>' => '>', - '<' => '<', - '=' => '=', - ); - - protected $entityFactory; - - protected $pdo; - - protected $fieldsMapCache = array(); - - protected $aliasesCache = array(); - - protected $seedCache = array(); - - public function __construct(PDO $pdo, EntityFactory $entityFactory) - { - $this->entityFactory = $entityFactory; - $this->pdo = $pdo; - } - - protected function getSeed($entityName) - { - if (empty($this->seedCache[$entityName])) { - $this->seedCache[$entityName] = $this->entityFactory->create($entityName); - } - return $this->seedCache[$entityName]; - } - - public function createSelectQuery($entityName, array $params = array(), $deleted = false) - { - $entity = $this->getSeed($entityName); - - foreach (self::$selectParamList as $k) { - $params[$k] = array_key_exists($k, $params) ? $params[$k] : null; - } - - $whereClause = $params['whereClause']; - if (empty($whereClause)) { - $whereClause = array(); - } - - if (!$deleted) { - $whereClause = $whereClause + array('deleted' => 0); - } - - if (empty($params['aggregation'])) { - $selectPart = $this->getSelect($entity, $params['select'], $params['distinct']); - $orderPart = $this->getOrder($entity, $params['orderBy'], $params['order']); - - if (!empty($params['additionalColumns']) && is_array($params['additionalColumns']) && !empty($params['relationName'])) { - foreach ($params['additionalColumns'] as $column => $field) { - $selectPart .= ", `" . $this->toDb($params['relationName']) . "`." . $this->toDb($column) . " AS `{$field}`"; - } - } - - } else { - $aggDist = false; - if ($params['distinct'] && $params['aggregation'] == 'COUNT') { - $aggDist = true; - } - $selectPart = $this->getAggregationSelect($entity, $params['aggregation'], $params['aggregationBy'], $aggDist); - } - - if (empty($params['joins'])) { - $params['joins'] = array(); - } - if (empty($params['leftJoins'])) { - $params['leftJoins'] = array(); - } - - $joinsPart = $this->getBelongsToJoins($entity, $params['select'], $params['joins'] + $params['leftJoins']); - - $wherePart = $this->getWhere($entity, $whereClause); - - if (!empty($params['customWhere'])) { - $wherePart .= ' ' . $params['customWhere']; - } - - if (!empty($params['customJoin'])) { - if (!empty($joinsPart)) { - $joinsPart .= ' '; - } - $joinsPart .= '' . $params['customJoin'] . ''; - } - - if (!empty($params['joins']) && is_array($params['joins'])) { - $joinsRelated = $this->getJoins($entity, $params['joins'], false, $params['joinConditions']); - if (!empty($joinsRelated)) { - if (!empty($joinsPart)) { - $joinsPart .= ' '; - } - $joinsPart .= $joinsRelated; - } - } - - if (!empty($params['leftJoins']) && is_array($params['leftJoins'])) { - $joinsRelated = $this->getJoins($entity, $params['leftJoins'], true, $params['joinConditions']); - if (!empty($joinsRelated)) { - if (!empty($joinsPart)) { - $joinsPart .= ' '; - } - $joinsPart .= $joinsRelated; - } - } - - $groupByPart = null; - if (!empty($params['groupBy']) && is_array($params['groupBy'])) { - $arr = array(); - foreach ($params['groupBy'] as $field) { - $arr[] = $this->convertComplexExpression($entity, $field, $entity->getEntityName()); - } - $groupByPart = implode(', ', $arr); - } - - if (empty($params['aggregation'])) { - return $this->composeSelectQuery($this->toDb($entity->getEntityName()), $selectPart, $joinsPart, $wherePart, $orderPart, $params['offset'], $params['limit'], $params['distinct'], null, $groupByPart); - } else { - return $this->composeSelectQuery($this->toDb($entity->getEntityName()), $selectPart, $joinsPart, $wherePart, null, null, null, false, $params['aggregation']); - } - } - - protected function getFunctionPart($function, $part, $entityName, $distinct = false) - { - switch ($function) { - case 'MONTH': - return "DATE_FORMAT({$part}, '%Y-%m')"; - case 'DAY': - return "DATE_FORMAT({$part}, '%Y-%m-%d')"; - } - if ($distinct) { - $idPart = $this->toDb($entityName) . ".id"; - switch ($function) { - case 'SUM': - case 'COUNT': - return $function . "({$part}) * COUNT(DISTINCT {$idPart}) / COUNT({$idPart})"; - } - } - return $function . '(' . $part . ')'; - } - - - protected function convertComplexExpression($entity, $field, $entityName = null, $distinct = false) - { - $function = null; - $relName = null; - - if (strpos($field, ':')) { - list($function, $field) = explode(':', $field); - } - if (strpos($field, '.')) { - list($relName, $field) = explode('.', $field); - } - - $part = $this->toDb($field); - if ($relName) { - $part = $this->toDb($relName) . '.' . $part; - } else { - if (!empty($entity->fields[$field]['select'])) { - $part = $entity->fields[$field]['select']; - } else { - if ($entityName) { - $part = $this->toDb($entityName) . '.' . $part; - } - } - } - if ($function) { - $part = $this->getFunctionPart(strtoupper($function), $part, $entityName, $distinct); - } - return $part; - } - - protected function getSelect(IEntity $entity, $fields = null, $distinct = false) - { - $select = ""; - $arr = array(); - $specifiedList = is_array($fields) ? true : false; - - if (empty($fields)) { - $fieldList = array_keys($entity->fields); - } else { - $fieldList = $fields; - } - - foreach ($fieldList as $field) { - if (array_key_exists($field, $entity->fields)) { - $fieldDefs = $entity->fields[$field]; - } else { - $part = $this->convertComplexExpression($entity, $field, $entity->getEntityName(), $distinct); - $arr[] = $part . ' AS `' . $field . '`'; - continue; - } - - if (!empty($fieldDefs['select'])) { - $fieldPath = $fieldDefs['select']; - } else { - if (!empty($fieldDefs['notStorable'])) { - continue; - } - $fieldPath = $this->getFieldPath($entity, $field); - } - - $arr[] = $fieldPath . ' AS `' . $field . '`'; - } - - $select = implode(', ', $arr); - - return $select; - } - - protected function getBelongsToJoin(IEntity $entity, $relationName, $r = null) - { - if (empty($r)) { - $r = $entity->relations[$relationName]; - } - - $keySet = $this->getKeys($entity, $relationName); - $key = $keySet['key']; - $foreignKey = $keySet['foreignKey']; - - $alias = $this->getAlias($entity, $relationName); - - if ($alias) { - return "JOIN `" . $this->toDb($r['entity']) . "` AS `" . $alias . "` ON ". - $this->toDb($entity->getEntityName()) . "." . $this->toDb($key) . " = " . $alias . "." . $this->toDb($foreignKey); - } - } - - protected function getBelongsToJoins(IEntity $entity, $select = null, $skipList = array()) - { - $joinsArr = array(); - - $fieldDefs = $entity->fields; - - $relationsToJoin = array(); - if (is_array($select)) { - foreach ($select as $field) { - if (!empty($fieldDefs[$field]) && $fieldDefs[$field]['type'] == 'foreign' && !empty($fieldDefs[$field]['relation'])) { - $relationsToJoin[] = $fieldDefs[$field]['relation']; - } - } - } - - foreach ($entity->relations as $relationName => $r) { - if ($r['type'] == IEntity::BELONGS_TO) { - if (in_array($relationName, $skipList)) { - continue; - } - - if (!empty($select)) { - if (!in_array($relationName, $relationsToJoin)) { - continue; - } - } - - $join = $this->getBelongsToJoin($entity, $relationName, $r); - if ($join) { - $joinsArr[] = 'LEFT ' . $join; - } - } - } - - return implode(' ', $joinsArr); - } - - protected function getOrderPart(IEntity $entity, $orderBy = null, $order = null) { - - if (!is_null($orderBy)) { - if (is_array($orderBy)) { - $arr = array(); - - foreach ($orderBy as $item) { - if (is_array($item)) { - $orderByInternal = $item[0]; - $orderInternal = null; - if (!empty($item[1])) { - $orderInternal = $item[1]; - } - $arr[] = $this->getOrderPart($entity, $orderByInternal, $orderInternal); - } - } - return implode(", ", $arr); - } - - if (strpos($orderBy, 'LIST:') === 0) { - list($l, $field, $list) = explode(':', $orderBy); - $fieldPath = $this->getFieldPathForOrderBy($entity, $field); - return "FIELD(" . $fieldPath . ", '" . implode("', '", explode(",", $list)) . "')"; - } - - if (!is_null($order)) { - $order = strtoupper($order); - if (!in_array($order, array('ASC', 'DESC'))) { - $order = 'ASC'; - } - } else { - $order = 'ASC'; - } - - if (is_integer($orderBy)) { - return "{$orderBy} " . $order; - } - - if (!empty($entity->fields[$orderBy])) { - $fieldDefs = $entity->fields[$orderBy]; - } - if (!empty($fieldDefs) && !empty($fieldDefs['orderBy'])) { - $orderPart = str_replace('{direction}', $order, $fieldDefs['orderBy']); - return "{$orderPart}"; - } else { - $fieldPath = $this->getFieldPathForOrderBy($entity, $orderBy); - - return "{$fieldPath} " . $order; - } - } - } - - protected function getOrder(IEntity $entity, $orderBy = null, $order = null) - { - $orderPart = $this->getOrderPart($entity, $orderBy, $order); - if ($orderPart) { - return "ORDER BY " . $orderPart; - } - - } - - protected function getFieldPathForOrderBy($entity, $orderBy) - { - if (strpos($orderBy, '.') !== false) { - list($alias, $field) = explode('.', $orderBy); - $fieldPath = $this->toDb($alias) . '.' . $this->toDb($field); - } else { - $fieldPath = $this->getFieldPath($entity, $orderBy); - } - return $fieldPath; - } - - protected function getAggregationSelect(IEntity $entity, $aggregation, $aggregationBy, $distinct = false) - { - if (!isset($entity->fields[$aggregationBy])) { - return false; - } - - $aggregation = strtoupper($aggregation); - - $distinctPart = ''; - if ($distinct) { - $distinctPart = 'DISTINCT '; - } - - $selectPart = "{$aggregation}({$distinctPart}" . $this->toDb($entity->getEntityName()) . "." . $this->toDb($aggregationBy) . ") AS AggregateValue"; - return $selectPart; - } - - public function toDb($field) - { - if (array_key_exists($field, $this->fieldsMapCache)) { - return $this->fieldsMapCache[$field]; - - } else { - $field[0] = strtolower($field[0]); - $dbField = preg_replace_callback('/([A-Z])/', array($this, 'toDbConversion'), $field); - - $this->fieldsMapCache[$field] = $dbField; - return $dbField; - } - } - - protected function toDbConversion($matches) - { - return "_" . strtolower($matches[1]); - } - - protected function getAlias(IEntity $entity, $relationName) - { - if (!isset($this->aliasesCache[$entity->getEntityName()])) { - $this->aliasesCache[$entity->getEntityName()] = $this->getTableAliases($entity); - } - - if (isset($this->aliasesCache[$entity->getEntityName()][$relationName])) { - return $this->aliasesCache[$entity->getEntityName()][$relationName]; - } else { - return false; - } - } - - protected function getTableAliases(IEntity $entity) - { - $aliases = array(); - $c = 0; - - $occuranceHash = array(); - - foreach ($entity->relations as $name => $r) { - if ($r['type'] == IEntity::BELONGS_TO) { - $table = $this->toDb($r['entity']); - - - if (!array_key_exists($name, $aliases)) { - if (array_key_exists($name, $occuranceHash)) { - $occuranceHash[$name]++; - } else { - $occuranceHash[$name] = 0; - } - $suffix = ''; - if ($occuranceHash[$name] > 0) { - $suffix .= '_' . $occuranceHash[$name]; - } - - $aliases[$name] = $this->toDb($name) . $suffix; - } - } - } - - return $aliases; - } - - protected function getFieldPath(IEntity $entity, $field) - { - if (isset($entity->fields[$field])) { - $f = $entity->fields[$field]; - - if (isset($f['source'])) { - if ($f['source'] != 'db') { - return false; - } - } - - if (!empty($f['notStorable'])) { - return false; - } - - $fieldPath = ''; - - switch($f['type']) { - case 'foreign': - if (isset($f['relation'])) { - $relationName = $f['relation']; - - $foreigh = $f['foreign']; - - if (is_array($foreigh)) { - foreach ($foreigh as $i => $value) { - if ($value == ' ') { - $foreigh[$i] = '\' \''; - } else { - $foreigh[$i] = $this->getAlias($entity, $relationName) . '.' . $this->toDb($value); - } - } - $fieldPath = 'TRIM(CONCAT(' . implode(', ', $foreigh). '))'; - } else { - $fieldPath = $this->getAlias($entity, $relationName) . '.' . $this->toDb($foreigh); - } - } - break; - default: - $fieldPath = $this->toDb($entity->getEntityName()) . '.' . $this->toDb($field) ; - } - - return $fieldPath; - } - - return false; - } - - public function getWhere(IEntity $entity, $whereClause, $sqlOp = 'AND') - { - $whereParts = array(); - - foreach ($whereClause as $field => $value) { - - if (is_int($field)) { - $field = 'AND'; - } - - if (!in_array($field, self::$sqlOperators)) { - - $inRelated = false; - - if (strpos($field, '.') !== false) { - list($entityName, $field) = array_map('trim', explode('.', $field)); - $entityName = preg_replace('/[^A-Za-z0-9_]+/', '', $entityName); - $field = preg_replace('/[^A-Za-z0-9_]+/', '', $field); - $inRelated = true; - } - - $operator = '='; - - if (!preg_match('/^[a-z0-9]+$/i', $field)) { - foreach (self::$comparisonOperators as $op => $opDb) { - if (strpos($field, $op) !== false) { - $field = trim(str_replace($op, '', $field)); - $operator = $opDb; - break; - } - } - } - - if (!$inRelated) { - - if (!isset($entity->fields[$field])) { - continue; - } - - $fieldDefs = $entity->fields[$field]; - - if (!empty($fieldDefs['where']) && !empty($fieldDefs['where'][$operator])) { - $whereParts[] = str_replace('{value}', $this->pdo->quote($value), $fieldDefs['where'][$operator]); - } else { - if ($fieldDefs['type'] == IEntity::FOREIGN) { - $leftPart = ''; - if (isset($fieldDefs['relation'])) { - $relationName = $fieldDefs['relation']; - if (isset($entity->relations[$relationName])) { - - $alias = $this->getAlias($entity, $relationName); - if ($alias) { - $leftPart = $alias . '.' . $this->toDb($fieldDefs['foreign']); - } - } - } - } else { - $leftPart = $this->toDb($entity->getEntityName()) . '.' . $this->toDb($field); - } - } - } else { - $leftPart = $this->toDb($entityName) . '.' . $this->toDb($field); - } - - if (!empty($leftPart)) { - if (!is_array($value)) { - $whereParts[] = $leftPart . " " . $operator . " " . $this->pdo->quote($value); - - } else { - $valArr = $value; - foreach ($valArr as $k => $v) { - $valArr[$k] = $this->pdo->quote($valArr[$k]); - } - $oppose = ''; - if ($operator == '<>') { - $oppose = 'NOT'; - } - if (!empty($valArr)) { - $whereParts[] = $leftPart . " {$oppose} IN " . "(" . implode(',', $valArr) . ")"; - } - } - } - } else { - $whereParts[] = "(" . $this->getWhere($entity, $value, $field) . ")"; - } - } - return implode(" " . $sqlOp . " ", $whereParts); - } - - protected function getJoins(IEntity $entity, array $joins, $left = false, $joinConditions = array()) - { - $joinsArr = array(); - foreach ($joins as $relationName) { - $conditions = array(); - if (!empty($joinConditions[$relationName])) { - $conditions = $joinConditions[$relationName]; - } - if ($joinRelated = $this->getJoinRelated($entity, $relationName, $left, $conditions)) { - $joinsArr[] = $joinRelated; - } - } - return implode(' ', $joinsArr); - } - - protected function getJoinRelated(IEntity $entity, $relationName, $left = false, $conditions = array()) - { - $relOpt = $entity->relations[$relationName]; - $keySet = $this->getKeys($entity, $relationName); - - $pre = ($left) ? 'LEFT ' : ''; - - if ($relOpt['type'] == IEntity::MANY_MANY) { - - $key = $keySet['key']; - $foreignKey = $keySet['foreignKey']; - $nearKey = $keySet['nearKey']; - $distantKey = $keySet['distantKey']; - - $relTable = $this->toDb($relOpt['relationName']); - $distantTable = $this->toDb($relOpt['entity']); - - $join = - "{$pre}JOIN `{$relTable}` ON {$this->toDb($entity->getEntityName())}." . $this->toDb($key) . " = {$relTable}." . $this->toDb($nearKey) - . " AND " - . "{$relTable}.deleted = " . $this->pdo->quote(0); - - if (!empty($relOpt['conditions']) && is_array($relOpt['conditions'])) { - $conditions = array_merge($conditions, $relOpt['conditions']); - } - foreach ($conditions as $f => $v) { - $join .= " AND {$relTable}." . $this->toDb($f) . " = " . $this->pdo->quote($v); - } - - $join .= " {$pre}JOIN `{$distantTable}` ON {$distantTable}." . $this->toDb($foreignKey) . " = {$relTable}." . $this->toDb($distantKey) - . " AND " - . "{$distantTable}.deleted = " . $this->pdo->quote(0) . ""; - - return $join; - } - - if ($relOpt['type'] == IEntity::HAS_MANY) { - - $foreignKey = $keySet['foreignKey']; - $distantTable = $this->toDb($relOpt['entity']); - - // TODO conditions - - $join = - "{$pre}JOIN `{$distantTable}` ON {$this->toDb($entity->getEntityName())}." . $this->toDb('id') . " = {$distantTable}." . $this->toDb($foreignKey) - . " AND " - . "{$distantTable}.deleted = " . $this->pdo->quote(0) . ""; - - return $join; - } - - if ($relOpt['type'] == IEntity::BELONGS_TO) { - return $pre . $this->getBelongsToJoin($entity, $relationName); - } - - return false; - } - - public function composeSelectQuery($table, $select, $joins = '', $where = '', $order = '', $offset = null, $limit = null, $distinct = null, $aggregation = false, $groupBy = null) - { - $sql = "SELECT"; - - /*if (!empty($distinct)) { - $sql .= " DISTINCT"; - }*/ - - $sql .= " {$select} FROM `{$table}`"; - - if (!empty($joins)) { - $sql .= " {$joins}"; - } - - if (!empty($where)) { - $sql .= " WHERE {$where}"; - } - - if (!empty($groupBy)) { - $sql .= " GROUP BY {$groupBy}"; - } else { - if (!empty($distinct)) { - $sql .= " GROUP BY `{$table}`.id"; - } - } - - if (!empty($order)) { - $sql .= " {$order}"; - } - - if (is_null($offset) && !is_null($limit)) { - $offset = 0; - } - - if (!is_null($offset) && !is_null($limit)) { - $offset = intval($offset); - $limit = intval($limit); - $sql .= " LIMIT {$offset}, {$limit}"; - } - - return $sql; - } - - public function getKeys(IEntity $entity, $relationName) - { - $relOpt = $entity->relations[$relationName]; - $relType = $relOpt['type']; - - switch ($relType) { - - case IEntity::BELONGS_TO: - $key = $this->toDb($entity->getEntityName()) . 'Id'; - if (isset($relOpt['key'])) { - $key = $relOpt['key']; - } - $foreignKey = 'id'; - if(isset($relOpt['foreignKey'])){ - $foreignKey = $relOpt['foreignKey']; - } - return array( - 'key' => $key, - 'foreignKey' => $foreignKey, - ); - - case IEntity::HAS_MANY: - $key = 'id'; - if (isset($relOpt['key'])){ - $key = $relOpt['key']; - } - $foreignKey = $this->toDb($entity->getEntityName()) . 'Id'; - if (isset($relOpt['foreignKey'])) { - $foreignKey = $relOpt['foreignKey']; - } - return array( - 'key' => $key, - 'foreignKey' => $foreignKey, - ); - case IEntity::HAS_CHILDREN: - $key = 'id'; - if (isset($relOpt['key'])){ - $key = $relOpt['key']; - } - $foreignKey = 'parentId'; - if (isset($relOpt['foreignKey'])) { - $foreignKey = $relOpt['foreignKey']; - } - $foreignType = 'parentType'; - if (isset($relOpt['foreignType'])) { - $foreignType = $relOpt['foreignType']; - } - return array( - 'key' => $key, - 'foreignKey' => $foreignKey, - 'foreignType' => $foreignType, - ); - - case IEntity::MANY_MANY: - $key = 'id'; - if(isset($relOpt['key'])){ - $key = $relOpt['key']; - } - $foreignKey = 'id'; - if(isset($relOpt['foreignKey'])){ - $foreignKey = $relOpt['foreignKey']; - } - $nearKey = $this->toDb($entity->getEntityName()) . 'Id'; - $distantKey = $this->toDb($relOpt['entity']) . 'Id'; - if (isset($relOpt['midKeys']) && is_array($relOpt['midKeys'])){ - $nearKey = $relOpt['midKeys'][0]; - $distantKey = $relOpt['midKeys'][1]; - } - return array( - 'key' => $key, - 'foreignKey' => $foreignKey, - 'nearKey' => $nearKey, - 'distantKey' => $distantKey, - ); - } - } - +{ + protected static $selectParamList = array( + 'select', + 'whereClause', + 'offset', + 'limit', + 'order', + 'orderBy', + 'customWhere', + 'customJoin', + 'joins', + 'leftJoins', + 'distinct', + 'joinConditions', + 'aggregation', + 'aggregationBy', + 'groupBy' + ); + + protected static $sqlOperators = array( + 'OR', + 'AND', + ); + + protected static $comparisonOperators = array( + '!=' => '<>', + '*' => 'LIKE', + '>=' => '>=', + '<=' => '<=', + '>' => '>', + '<' => '<', + '=' => '=', + ); + + protected $entityFactory; + + protected $pdo; + + protected $fieldsMapCache = array(); + + protected $aliasesCache = array(); + + protected $seedCache = array(); + + public function __construct(PDO $pdo, EntityFactory $entityFactory) + { + $this->entityFactory = $entityFactory; + $this->pdo = $pdo; + } + + protected function getSeed($entityName) + { + if (empty($this->seedCache[$entityName])) { + $this->seedCache[$entityName] = $this->entityFactory->create($entityName); + } + return $this->seedCache[$entityName]; + } + + public function createSelectQuery($entityName, array $params = array(), $deleted = false) + { + $entity = $this->getSeed($entityName); + + foreach (self::$selectParamList as $k) { + $params[$k] = array_key_exists($k, $params) ? $params[$k] : null; + } + + $whereClause = $params['whereClause']; + if (empty($whereClause)) { + $whereClause = array(); + } + + if (!$deleted) { + $whereClause = $whereClause + array('deleted' => 0); + } + + if (empty($params['aggregation'])) { + $selectPart = $this->getSelect($entity, $params['select'], $params['distinct']); + $orderPart = $this->getOrder($entity, $params['orderBy'], $params['order']); + + if (!empty($params['additionalColumns']) && is_array($params['additionalColumns']) && !empty($params['relationName'])) { + foreach ($params['additionalColumns'] as $column => $field) { + $selectPart .= ", `" . $this->toDb($params['relationName']) . "`." . $this->toDb($column) . " AS `{$field}`"; + } + } + + } else { + $aggDist = false; + if ($params['distinct'] && $params['aggregation'] == 'COUNT') { + $aggDist = true; + } + $selectPart = $this->getAggregationSelect($entity, $params['aggregation'], $params['aggregationBy'], $aggDist); + } + + if (empty($params['joins'])) { + $params['joins'] = array(); + } + if (empty($params['leftJoins'])) { + $params['leftJoins'] = array(); + } + + $joinsPart = $this->getBelongsToJoins($entity, $params['select'], $params['joins'] + $params['leftJoins']); + + $wherePart = $this->getWhere($entity, $whereClause); + + if (!empty($params['customWhere'])) { + $wherePart .= ' ' . $params['customWhere']; + } + + if (!empty($params['customJoin'])) { + if (!empty($joinsPart)) { + $joinsPart .= ' '; + } + $joinsPart .= '' . $params['customJoin'] . ''; + } + + if (!empty($params['joins']) && is_array($params['joins'])) { + $joinsRelated = $this->getJoins($entity, $params['joins'], false, $params['joinConditions']); + if (!empty($joinsRelated)) { + if (!empty($joinsPart)) { + $joinsPart .= ' '; + } + $joinsPart .= $joinsRelated; + } + } + + if (!empty($params['leftJoins']) && is_array($params['leftJoins'])) { + $joinsRelated = $this->getJoins($entity, $params['leftJoins'], true, $params['joinConditions']); + if (!empty($joinsRelated)) { + if (!empty($joinsPart)) { + $joinsPart .= ' '; + } + $joinsPart .= $joinsRelated; + } + } + + $groupByPart = null; + if (!empty($params['groupBy']) && is_array($params['groupBy'])) { + $arr = array(); + foreach ($params['groupBy'] as $field) { + $arr[] = $this->convertComplexExpression($entity, $field, $entity->getEntityName()); + } + $groupByPart = implode(', ', $arr); + } + + if (empty($params['aggregation'])) { + return $this->composeSelectQuery($this->toDb($entity->getEntityName()), $selectPart, $joinsPart, $wherePart, $orderPart, $params['offset'], $params['limit'], $params['distinct'], null, $groupByPart); + } else { + return $this->composeSelectQuery($this->toDb($entity->getEntityName()), $selectPart, $joinsPart, $wherePart, null, null, null, false, $params['aggregation']); + } + } + + protected function getFunctionPart($function, $part, $entityName, $distinct = false) + { + switch ($function) { + case 'MONTH': + return "DATE_FORMAT({$part}, '%Y-%m')"; + case 'DAY': + return "DATE_FORMAT({$part}, '%Y-%m-%d')"; + } + if ($distinct) { + $idPart = $this->toDb($entityName) . ".id"; + switch ($function) { + case 'SUM': + case 'COUNT': + return $function . "({$part}) * COUNT(DISTINCT {$idPart}) / COUNT({$idPart})"; + } + } + return $function . '(' . $part . ')'; + } + + + protected function convertComplexExpression($entity, $field, $entityName = null, $distinct = false) + { + $function = null; + $relName = null; + + if (strpos($field, ':')) { + list($function, $field) = explode(':', $field); + } + if (strpos($field, '.')) { + list($relName, $field) = explode('.', $field); + } + + if (!empty($function)) { + $function = preg_replace('/[^A-Za-z0-9_]+/', '', $function); + } + if (!empty($relName)) { + $relName = preg_replace('/[^A-Za-z0-9_]+/', '', $relName); + } + if (!empty($field)) { + $field = preg_replace('/[^A-Za-z0-9_]+/', '', $field); + } + + $part = $this->toDb($field); + if ($relName) { + $part = $this->toDb($relName) . '.' . $part; + } else { + if (!empty($entity->fields[$field]['select'])) { + $part = $entity->fields[$field]['select']; + } else { + if ($entityName) { + $part = $this->toDb($entityName) . '.' . $part; + } + } + } + if ($function) { + $part = $this->getFunctionPart(strtoupper($function), $part, $entityName, $distinct); + } + return $part; + } + + protected function getSelect(IEntity $entity, $fields = null, $distinct = false) + { + $select = ""; + $arr = array(); + $specifiedList = is_array($fields) ? true : false; + + if (empty($fields)) { + $fieldList = array_keys($entity->fields); + } else { + $fieldList = $fields; + } + + foreach ($fieldList as $field) { + if (array_key_exists($field, $entity->fields)) { + $fieldDefs = $entity->fields[$field]; + } else { + $part = $this->convertComplexExpression($entity, $field, $entity->getEntityName(), $distinct); + $arr[] = $part . ' AS `' . $field . '`'; + continue; + } + + if (!empty($fieldDefs['select'])) { + $fieldPath = $fieldDefs['select']; + } else { + if (!empty($fieldDefs['notStorable'])) { + continue; + } + $fieldPath = $this->getFieldPath($entity, $field); + } + + $arr[] = $fieldPath . ' AS `' . $field . '`'; + } + + $select = implode(', ', $arr); + + return $select; + } + + protected function getBelongsToJoin(IEntity $entity, $relationName, $r = null) + { + if (empty($r)) { + $r = $entity->relations[$relationName]; + } + + $keySet = $this->getKeys($entity, $relationName); + $key = $keySet['key']; + $foreignKey = $keySet['foreignKey']; + + $alias = $this->getAlias($entity, $relationName); + + if ($alias) { + return "JOIN `" . $this->toDb($r['entity']) . "` AS `" . $alias . "` ON ". + $this->toDb($entity->getEntityName()) . "." . $this->toDb($key) . " = " . $alias . "." . $this->toDb($foreignKey); + } + } + + protected function getBelongsToJoins(IEntity $entity, $select = null, $skipList = array()) + { + $joinsArr = array(); + + $fieldDefs = $entity->fields; + + $relationsToJoin = array(); + if (is_array($select)) { + foreach ($select as $field) { + if (!empty($fieldDefs[$field]) && $fieldDefs[$field]['type'] == 'foreign' && !empty($fieldDefs[$field]['relation'])) { + $relationsToJoin[] = $fieldDefs[$field]['relation']; + } + } + } + + foreach ($entity->relations as $relationName => $r) { + if ($r['type'] == IEntity::BELONGS_TO) { + if (in_array($relationName, $skipList)) { + continue; + } + + if (!empty($select)) { + if (!in_array($relationName, $relationsToJoin)) { + continue; + } + } + + $join = $this->getBelongsToJoin($entity, $relationName, $r); + if ($join) { + $joinsArr[] = 'LEFT ' . $join; + } + } + } + + return implode(' ', $joinsArr); + } + + protected function getOrderPart(IEntity $entity, $orderBy = null, $order = null) { + + if (!is_null($orderBy)) { + if (is_array($orderBy)) { + $arr = array(); + + foreach ($orderBy as $item) { + if (is_array($item)) { + $orderByInternal = $item[0]; + $orderInternal = null; + if (!empty($item[1])) { + $orderInternal = $item[1]; + } + $arr[] = $this->getOrderPart($entity, $orderByInternal, $orderInternal); + } + } + return implode(", ", $arr); + } + + if (strpos($orderBy, 'LIST:') === 0) { + list($l, $field, $list) = explode(':', $orderBy); + $fieldPath = $this->getFieldPathForOrderBy($entity, $field); + return "FIELD(" . $fieldPath . ", '" . implode("', '", explode(",", $list)) . "')"; + } + + if (!is_null($order)) { + $order = strtoupper($order); + if (!in_array($order, array('ASC', 'DESC'))) { + $order = 'ASC'; + } + } else { + $order = 'ASC'; + } + + if (is_integer($orderBy)) { + return "{$orderBy} " . $order; + } + + if (!empty($entity->fields[$orderBy])) { + $fieldDefs = $entity->fields[$orderBy]; + } + if (!empty($fieldDefs) && !empty($fieldDefs['orderBy'])) { + $orderPart = str_replace('{direction}', $order, $fieldDefs['orderBy']); + return "{$orderPart}"; + } else { + $fieldPath = $this->getFieldPathForOrderBy($entity, $orderBy); + + return "{$fieldPath} " . $order; + } + } + } + + protected function getOrder(IEntity $entity, $orderBy = null, $order = null) + { + $orderPart = $this->getOrderPart($entity, $orderBy, $order); + if ($orderPart) { + return "ORDER BY " . $orderPart; + } + + } + + protected function getFieldPathForOrderBy($entity, $orderBy) + { + if (strpos($orderBy, '.') !== false) { + list($alias, $field) = explode('.', $orderBy); + $fieldPath = $this->toDb($alias) . '.' . $this->toDb($field); + } else { + $fieldPath = $this->getFieldPath($entity, $orderBy); + } + return $fieldPath; + } + + protected function getAggregationSelect(IEntity $entity, $aggregation, $aggregationBy, $distinct = false) + { + if (!isset($entity->fields[$aggregationBy])) { + return false; + } + + $aggregation = strtoupper($aggregation); + + $distinctPart = ''; + if ($distinct) { + $distinctPart = 'DISTINCT '; + } + + $selectPart = "{$aggregation}({$distinctPart}" . $this->toDb($entity->getEntityName()) . "." . $this->toDb($aggregationBy) . ") AS AggregateValue"; + return $selectPart; + } + + public function toDb($field) + { + if (array_key_exists($field, $this->fieldsMapCache)) { + return $this->fieldsMapCache[$field]; + + } else { + $field[0] = strtolower($field[0]); + $dbField = preg_replace_callback('/([A-Z])/', array($this, 'toDbConversion'), $field); + + $this->fieldsMapCache[$field] = $dbField; + return $dbField; + } + } + + protected function toDbConversion($matches) + { + return "_" . strtolower($matches[1]); + } + + protected function getAlias(IEntity $entity, $relationName) + { + if (!isset($this->aliasesCache[$entity->getEntityName()])) { + $this->aliasesCache[$entity->getEntityName()] = $this->getTableAliases($entity); + } + + if (isset($this->aliasesCache[$entity->getEntityName()][$relationName])) { + return $this->aliasesCache[$entity->getEntityName()][$relationName]; + } else { + return false; + } + } + + protected function getTableAliases(IEntity $entity) + { + $aliases = array(); + $c = 0; + + $occuranceHash = array(); + + foreach ($entity->relations as $name => $r) { + if ($r['type'] == IEntity::BELONGS_TO) { + $table = $this->toDb($r['entity']); + + + if (!array_key_exists($name, $aliases)) { + if (array_key_exists($name, $occuranceHash)) { + $occuranceHash[$name]++; + } else { + $occuranceHash[$name] = 0; + } + $suffix = ''; + if ($occuranceHash[$name] > 0) { + $suffix .= '_' . $occuranceHash[$name]; + } + + $aliases[$name] = $this->toDb($name) . $suffix; + } + } + } + + return $aliases; + } + + protected function getFieldPath(IEntity $entity, $field) + { + if (isset($entity->fields[$field])) { + $f = $entity->fields[$field]; + + if (isset($f['source'])) { + if ($f['source'] != 'db') { + return false; + } + } + + if (!empty($f['notStorable'])) { + return false; + } + + $fieldPath = ''; + + switch($f['type']) { + case 'foreign': + if (isset($f['relation'])) { + $relationName = $f['relation']; + + $foreigh = $f['foreign']; + + if (is_array($foreigh)) { + foreach ($foreigh as $i => $value) { + if ($value == ' ') { + $foreigh[$i] = '\' \''; + } else { + $foreigh[$i] = $this->getAlias($entity, $relationName) . '.' . $this->toDb($value); + } + } + $fieldPath = 'TRIM(CONCAT(' . implode(', ', $foreigh). '))'; + } else { + $fieldPath = $this->getAlias($entity, $relationName) . '.' . $this->toDb($foreigh); + } + } + break; + default: + $fieldPath = $this->toDb($entity->getEntityName()) . '.' . $this->toDb($field) ; + } + + return $fieldPath; + } + + return false; + } + + public function getWhere(IEntity $entity, $whereClause, $sqlOp = 'AND') + { + $whereParts = array(); + + foreach ($whereClause as $field => $value) { + + if (is_int($field)) { + $field = 'AND'; + } + + if (!in_array($field, self::$sqlOperators)) { + $isComplex = false; + + $operator = '='; + + if (!preg_match('/^[a-z0-9]+$/i', $field)) { + foreach (self::$comparisonOperators as $op => $opDb) { + if (strpos($field, $op) !== false) { + $field = trim(str_replace($op, '', $field)); + $operator = $opDb; + break; + } + } + } + + if (strpos($field, '.') !== false || strpos($field, ':') !== false) { + $leftPart = $this->convertComplexExpression($entity, $field); + $isComplex = true; + } + + + if (empty($isComplex)) { + + if (!isset($entity->fields[$field])) { + continue; + } + + $fieldDefs = $entity->fields[$field]; + + if (!empty($fieldDefs['where']) && !empty($fieldDefs['where'][$operator])) { + $whereParts[] = str_replace('{value}', $this->pdo->quote($value), $fieldDefs['where'][$operator]); + } else { + if ($fieldDefs['type'] == IEntity::FOREIGN) { + $leftPart = ''; + if (isset($fieldDefs['relation'])) { + $relationName = $fieldDefs['relation']; + if (isset($entity->relations[$relationName])) { + + $alias = $this->getAlias($entity, $relationName); + if ($alias) { + $leftPart = $alias . '.' . $this->toDb($fieldDefs['foreign']); + } + } + } + } else { + $leftPart = $this->toDb($entity->getEntityName()) . '.' . $this->toDb($field); + } + } + } + + if (!empty($leftPart)) { + if (!is_array($value)) { + $whereParts[] = $leftPart . " " . $operator . " " . $this->pdo->quote($value); + + } else { + $valArr = $value; + foreach ($valArr as $k => $v) { + $valArr[$k] = $this->pdo->quote($valArr[$k]); + } + $oppose = ''; + if ($operator == '<>') { + $oppose = 'NOT'; + } + if (!empty($valArr)) { + $whereParts[] = $leftPart . " {$oppose} IN " . "(" . implode(',', $valArr) . ")"; + } + } + } + } else { + $whereParts[] = "(" . $this->getWhere($entity, $value, $field) . ")"; + } + } + return implode(" " . $sqlOp . " ", $whereParts); + } + + protected function getJoins(IEntity $entity, array $joins, $left = false, $joinConditions = array()) + { + $joinsArr = array(); + foreach ($joins as $relationName) { + $conditions = array(); + if (!empty($joinConditions[$relationName])) { + $conditions = $joinConditions[$relationName]; + } + if ($joinRelated = $this->getJoinRelated($entity, $relationName, $left, $conditions)) { + $joinsArr[] = $joinRelated; + } + } + return implode(' ', $joinsArr); + } + + protected function getJoinRelated(IEntity $entity, $relationName, $left = false, $conditions = array()) + { + $relOpt = $entity->relations[$relationName]; + $keySet = $this->getKeys($entity, $relationName); + + $pre = ($left) ? 'LEFT ' : ''; + + if ($relOpt['type'] == IEntity::MANY_MANY) { + + $key = $keySet['key']; + $foreignKey = $keySet['foreignKey']; + $nearKey = $keySet['nearKey']; + $distantKey = $keySet['distantKey']; + + $relTable = $this->toDb($relOpt['relationName']); + $distantTable = $this->toDb($relOpt['entity']); + + $join = + "{$pre}JOIN `{$relTable}` ON {$this->toDb($entity->getEntityName())}." . $this->toDb($key) . " = {$relTable}." . $this->toDb($nearKey) + . " AND " + . "{$relTable}.deleted = " . $this->pdo->quote(0); + + if (!empty($relOpt['conditions']) && is_array($relOpt['conditions'])) { + $conditions = array_merge($conditions, $relOpt['conditions']); + } + foreach ($conditions as $f => $v) { + $join .= " AND {$relTable}." . $this->toDb($f) . " = " . $this->pdo->quote($v); + } + + $join .= " {$pre}JOIN `{$distantTable}` ON {$distantTable}." . $this->toDb($foreignKey) . " = {$relTable}." . $this->toDb($distantKey) + . " AND " + . "{$distantTable}.deleted = " . $this->pdo->quote(0) . ""; + + return $join; + } + + if ($relOpt['type'] == IEntity::HAS_MANY) { + + $foreignKey = $keySet['foreignKey']; + $distantTable = $this->toDb($relOpt['entity']); + + // TODO conditions + + $join = + "{$pre}JOIN `{$distantTable}` ON {$this->toDb($entity->getEntityName())}." . $this->toDb('id') . " = {$distantTable}." . $this->toDb($foreignKey) + . " AND " + . "{$distantTable}.deleted = " . $this->pdo->quote(0) . ""; + + return $join; + } + + if ($relOpt['type'] == IEntity::BELONGS_TO) { + return $pre . $this->getBelongsToJoin($entity, $relationName); + } + + return false; + } + + public function composeSelectQuery($table, $select, $joins = '', $where = '', $order = '', $offset = null, $limit = null, $distinct = null, $aggregation = false, $groupBy = null) + { + $sql = "SELECT"; + + /*if (!empty($distinct)) { + $sql .= " DISTINCT"; + }*/ + + $sql .= " {$select} FROM `{$table}`"; + + if (!empty($joins)) { + $sql .= " {$joins}"; + } + + if (!empty($where)) { + $sql .= " WHERE {$where}"; + } + + if (!empty($groupBy)) { + $sql .= " GROUP BY {$groupBy}"; + } else { + if (!empty($distinct)) { + $sql .= " GROUP BY `{$table}`.id"; + } + } + + if (!empty($order)) { + $sql .= " {$order}"; + } + + if (is_null($offset) && !is_null($limit)) { + $offset = 0; + } + + if (!is_null($offset) && !is_null($limit)) { + $offset = intval($offset); + $limit = intval($limit); + $sql .= " LIMIT {$offset}, {$limit}"; + } + + return $sql; + } + + public function getKeys(IEntity $entity, $relationName) + { + $relOpt = $entity->relations[$relationName]; + $relType = $relOpt['type']; + + switch ($relType) { + + case IEntity::BELONGS_TO: + $key = $this->toDb($entity->getEntityName()) . 'Id'; + if (isset($relOpt['key'])) { + $key = $relOpt['key']; + } + $foreignKey = 'id'; + if(isset($relOpt['foreignKey'])){ + $foreignKey = $relOpt['foreignKey']; + } + return array( + 'key' => $key, + 'foreignKey' => $foreignKey, + ); + + case IEntity::HAS_MANY: + $key = 'id'; + if (isset($relOpt['key'])){ + $key = $relOpt['key']; + } + $foreignKey = $this->toDb($entity->getEntityName()) . 'Id'; + if (isset($relOpt['foreignKey'])) { + $foreignKey = $relOpt['foreignKey']; + } + return array( + 'key' => $key, + 'foreignKey' => $foreignKey, + ); + case IEntity::HAS_CHILDREN: + $key = 'id'; + if (isset($relOpt['key'])){ + $key = $relOpt['key']; + } + $foreignKey = 'parentId'; + if (isset($relOpt['foreignKey'])) { + $foreignKey = $relOpt['foreignKey']; + } + $foreignType = 'parentType'; + if (isset($relOpt['foreignType'])) { + $foreignType = $relOpt['foreignType']; + } + return array( + 'key' => $key, + 'foreignKey' => $foreignKey, + 'foreignType' => $foreignType, + ); + + case IEntity::MANY_MANY: + $key = 'id'; + if(isset($relOpt['key'])){ + $key = $relOpt['key']; + } + $foreignKey = 'id'; + if(isset($relOpt['foreignKey'])){ + $foreignKey = $relOpt['foreignKey']; + } + $nearKey = $this->toDb($entity->getEntityName()) . 'Id'; + $distantKey = $this->toDb($relOpt['entity']) . 'Id'; + if (isset($relOpt['midKeys']) && is_array($relOpt['midKeys'])){ + $nearKey = $relOpt['midKeys'][0]; + $distantKey = $relOpt['midKeys'][1]; + } + return array( + 'key' => $key, + 'foreignKey' => $foreignKey, + 'nearKey' => $nearKey, + 'distantKey' => $distantKey, + ); + } + } + } diff --git a/application/Espo/ORM/Entity.php b/application/Espo/ORM/Entity.php index 748b24ab2c..a6214b0d8c 100644 --- a/application/Espo/ORM/Entity.php +++ b/application/Espo/ORM/Entity.php @@ -18,293 +18,298 @@ * * 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\ORM; abstract class Entity implements IEntity { - public $id = null; - - private $isNew = false; + public $id = null; - /** - * Entity name. - * @var string - */ - protected $entityName; - - /** - * @var array Defenition of fields. - * @todo make protected - */ - public $fields = array(); - - /** - * @var array Defenition of relations. - * @todo make protected - */ - public $relations = array(); - - /** - * @var array Field-Value pairs. - */ - protected $valuesContainer = array(); - - /** - * @var array Field-Value pairs of initial values (fetched from DB). - */ - protected $fetchedValuesContainer = array(); - - /** - * @var EntityManager Entity Manager. - */ - protected $entityManager; - - protected $isFetched = false; - - public function __construct($defs = array(), EntityManager $entityManager = null) - { - if (empty($this->entityName)) { - $classNames = explode('\\', get_class($this)); - $this->entityName = end($classNames); - } - - $this->entityManager = $entityManager; - - if (!empty($defs['fields'])) { - $this->fields = $defs['fields']; - } - - if (!empty($defs['relations'])) { - $this->relations = $defs['relations']; - } - } - - public function clear($name = null) - { - if (is_null($name)) { - $this->reset(); - } - unset($this->valuesContainer[$name]); - } - - public function reset() - { - $this->valuesContainer = array(); - } - - protected function _setValue($name, $value) - { - $this->valuesContainer[$name] = $value; - } - - public function set($p1, $p2 = null) - { - if (is_array($p1)) { - if ($p2 === null) { - $p2 = false; - } - $this->populateFromArray($p1, $p2); - } else { - $name = $p1; - $value = $p2; - if ($name == 'id') { - $this->id = $value; - } - if ($this->hasField($name)) { - $method = 'set' . ucfirst($name); - if (method_exists($this, $method)) { - $this->$method($value); - } else { - $this->valuesContainer[$name] = $value; - } - } - } - } - - public function get($name, $params = array()) - { - if ($name == 'id') { - return $this->id; - } - $method = 'get' . ucfirst($name); - if (method_exists($this, $method)) { - return $this->$method(); - } - - if (isset($this->valuesContainer[$name])) { - return $this->valuesContainer[$name]; - } - - if (!empty($this->relations[$name])) { - $value = $this->entityManager->getRepository($this->entityName)->findRelated($this, $name, $params); - return $value; - } - - return null; - } - - public function has($name) - { - if ($name == 'id') { - return isset($this->id); - } - if (array_key_exists($name, $this->valuesContainer)) { - return true; - } - return false; - } - - public function populateFromArray(array $arr, $onlyAccessible = true, $reset = false) - { - if ($reset) { - $this->reset(); - } - - foreach ($this->fields as $field => $fieldDefs) { - if (array_key_exists($field, $arr)) { - if ($field == 'id') { - $this->id = $arr[$field]; - continue; - } - if ($onlyAccessible) { - if (isset($fieldDefs['notAccessible']) && $fieldDefs['notAccessible'] == true) { - continue; - } - } - - $value = $arr[$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; - case self::JSON_OBJECT: - $value = is_string($value) ? json_decode($value) : $value; - if (!($value instanceof \stdClass) && !is_array($value)) { - $value = null; - } - break; - default: - break; - } - } - - $method = 'set' . ucfirst($field); - if (method_exists($this, $method)) { - $this->$method($value); - } else { - $this->valuesContainer[$field] = $value; - } - } - } - } - - public function isNew() - { - return $this->isNew; - } - - public function setIsNew($isNew) - { - $this->isNew = $isNew; - } - - public function getEntityName() - { - return $this->entityName; - } - - public function hasField($fieldName) - { - return isset($this->fields[$fieldName]); - } - - public function hasRelation($relationName) - { - return isset($this->relations[$relationName]); - } - - 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); - } + private $isNew = false; - } - return $arr; - } - - public function getFields() - { - return $this->fields; - } - - public function getRelations() - { - return $this->relations; - } - - public function isFetched() - { - return $this->isFetched; - } - - public function isFieldChanged($fieldName) - { - return $this->has($fieldName) && ($this->get($fieldName) != $this->getFetched($fieldName)); - } - - public function getFetched($fieldName) - { - if (isset($this->fetchedValuesContainer[$fieldName])) { - return $this->fetchedValuesContainer[$fieldName]; - } - return null; - } - - public function resetFetchedValues() - { - $this->fetchedValuesContainer = array(); - } - - public function setAsFetched() - { - $this->isFetched = true; - $this->fetchedValuesContainer = $this->valuesContainer; - } - - public function populateDefaults() - { - foreach ($this->fields as $field => $defs) { - if (array_key_exists('default', $defs)) { - $this->valuesContainer[$field] = $defs['default']; - } - } - } + /** + * Entity name. + * @var string + */ + protected $entityName; + + /** + * @var array Defenition of fields. + * @todo make protected + */ + public $fields = array(); + + /** + * @var array Defenition of relations. + * @todo make protected + */ + public $relations = array(); + + /** + * @var array Field-Value pairs. + */ + protected $valuesContainer = array(); + + /** + * @var array Field-Value pairs of initial values (fetched from DB). + */ + protected $fetchedValuesContainer = array(); + + /** + * @var EntityManager Entity Manager. + */ + protected $entityManager; + + protected $isFetched = false; + + public function __construct($defs = array(), EntityManager $entityManager = null) + { + if (empty($this->entityName)) { + $classNames = explode('\\', get_class($this)); + $this->entityName = end($classNames); + } + + $this->entityManager = $entityManager; + + if (!empty($defs['fields'])) { + $this->fields = $defs['fields']; + } + + if (!empty($defs['relations'])) { + $this->relations = $defs['relations']; + } + } + + public function clear($name = null) + { + if (is_null($name)) { + $this->reset(); + } + unset($this->valuesContainer[$name]); + } + + public function reset() + { + $this->valuesContainer = array(); + } + + protected function setValue($name, $value) + { + $this->valuesContainer[$name] = $value; + } + + public function set($p1, $p2 = null) + { + if (is_array($p1)) { + if ($p2 === null) { + $p2 = false; + } + $this->populateFromArray($p1, $p2); + } else { + $name = $p1; + $value = $p2; + if ($name == 'id') { + $this->id = $value; + } + if ($this->hasField($name)) { + $method = '_set' . ucfirst($name); + if (method_exists($this, $method)) { + $this->$method($value); + } else { + $this->valuesContainer[$name] = $value; + } + } + } + } + + public function get($name, $params = array()) + { + if ($name == 'id') { + return $this->id; + } + $method = '_get' . ucfirst($name); + if (method_exists($this, $method)) { + return $this->$method(); + } + + if (isset($this->valuesContainer[$name])) { + return $this->valuesContainer[$name]; + } + + if (!empty($this->relations[$name])) { + $value = $this->entityManager->getRepository($this->entityName)->findRelated($this, $name, $params); + return $value; + } + + return null; + } + + public function has($name) + { + if ($name == 'id') { + return isset($this->id); + } + if (array_key_exists($name, $this->valuesContainer)) { + return true; + } + return false; + } + + public function populateFromArray(array $arr, $onlyAccessible = true, $reset = false) + { + if ($reset) { + $this->reset(); + } + + foreach ($this->fields as $field => $fieldDefs) { + if (array_key_exists($field, $arr)) { + if ($field == 'id') { + $this->id = $arr[$field]; + continue; + } + if ($onlyAccessible) { + if (isset($fieldDefs['notAccessible']) && $fieldDefs['notAccessible'] == true) { + continue; + } + } + + $value = $arr[$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; + case self::JSON_OBJECT: + $value = is_string($value) ? json_decode($value) : $value; + if (!($value instanceof \stdClass) && !is_array($value)) { + $value = null; + } + break; + default: + break; + } + } + + $method = '_set' . ucfirst($field); + if (method_exists($this, $method)) { + $this->$method($value); + } else { + $this->valuesContainer[$field] = $value; + } + } + } + } + + public function isNew() + { + return $this->isNew; + } + + public function setIsNew($isNew) + { + $this->isNew = $isNew; + } + + public function getEntityName() + { + return $this->entityName; + } + + public function hasField($fieldName) + { + return isset($this->fields[$fieldName]); + } + + public function hasRelation($relationName) + { + return isset($this->relations[$relationName]); + } + + 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); + } + + } + return $arr; + } + + public function getFields() + { + return $this->fields; + } + + public function getRelations() + { + return $this->relations; + } + + public function isFetched() + { + return $this->isFetched; + } + + public function isFieldChanged($fieldName) + { + return $this->has($fieldName) && ($this->get($fieldName) != $this->getFetched($fieldName)); + } + + public function getFetched($fieldName) + { + if (isset($this->fetchedValuesContainer[$fieldName])) { + return $this->fetchedValuesContainer[$fieldName]; + } + return null; + } + + public function resetFetchedValues() + { + $this->fetchedValuesContainer = array(); + } + + public function updateFetchedValues() + { + $this->fetchedValuesContainer = $this->valuesContainer; + } + + public function setAsFetched() + { + $this->isFetched = true; + $this->fetchedValuesContainer = $this->valuesContainer; + } + + public function populateDefaults() + { + foreach ($this->fields as $field => $defs) { + if (array_key_exists('default', $defs)) { + $this->valuesContainer[$field] = $defs['default']; + } + } + } } diff --git a/application/Espo/ORM/EntityCollection.php b/application/Espo/ORM/EntityCollection.php index f89aaa76fc..21a4cf6907 100644 --- a/application/Espo/ORM/EntityCollection.php +++ b/application/Espo/ORM/EntityCollection.php @@ -18,207 +18,207 @@ * * 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\ORM; class EntityCollection implements \Iterator, \Countable, \ArrayAccess, \SeekableIterator { - private $entityFactory = null; - - private $entityName; - - private $position = 0; - - protected $container = array(); - - public function __construct($data = array(), $entityName, EntityFactory $entityFactory = null) - { - $this->container = $data; - $this->entityName = $entityName; - $this->entityFactory = $entityFactory; - } - - public function rewind() - { - $this->position = 0; + private $entityFactory = null; - while (!$this->valid() && $this->position < count($this->container)) { - $this->position ++; - } - } - - public function current() - { - return $this->getEntityByOffset($this->position); - } - - public function key() - { - return $this->position; - } - - public function next() - { - do { - $this->position ++; - $next = false; - if (!$this->valid() && $this->position < count($this->container)) { - $next = true; - } - } while ($next); - } - - public function valid() - { - return isset($this->container[$this->position]); - } - - public function offsetExists($offset) - { - return isset($this->container[$offset]); - } - - public function offsetGet($offset) - { - if (!isset($this->container[$offset])) { - return null; - } - return $this->getEntityByOffset($offset); - } - - public function offsetSet($offset, $value) - { - if (!($value instanceof Entity)) { - throw new \InvalidArgumentException('Only Entity is allowed to be added to EntityCollection.'); - } - - if (is_null($offset)) { - $this->container[] = $value; - } else { - $this->container[$offset] = $value; - } - } + private $entityName; - public function offsetUnset($offset) - { - unset($this->container[$offset]); - } + private $position = 0; - public function count() - { - return count($this->container); - } - - public function seek($offset) - { - $this->position = $offset; - if (!$this->valid()) { - throw new \OutOfBoundsException("Invalid seek offset ($offset)."); - } - } + protected $container = array(); - public function append(Entity $entity) - { - $this->container[] = $entity; - } - - private function getEntityByOffset($offset) - { - $value = $this->container[$offset]; + public function __construct($data = array(), $entityName, EntityFactory $entityFactory = null) + { + $this->container = $data; + $this->entityName = $entityName; + $this->entityFactory = $entityFactory; + } - if ($value instanceof Entity) { - return $value; - } else if (is_array($value)) { - $this->container[$offset] = $this->buildEntityFromArray($value); - } else { - return null; - } - - return $this->container[$offset]; - } - - protected function buildEntityFromArray(array $dataArray) - { - $entity = $this->entityFactory->create($this->entityName); - if ($entity) { - $entity->set($dataArray); - $entity->setAsFetched(); - return $entity; - } - } + public function rewind() + { + $this->position = 0; - public function getEntityName() - { - return $this->entityName; - } + while (!$this->valid() && $this->position < count($this->container)) { + $this->position ++; + } + } - public function getInnerContainer() - { - return $this->container; - } - - public function merge(EntityCollection $collection) - { - $newData = $this->container; - $incomingData = $collection->getInnerContainer(); - - foreach ($incomingData as $v) { - if (!$this->contains($v)) { - $this->container[] = $v; - } - } - } - - public function contains($value) - { - if ($this->indexOf($value) !== false) { - return true; - } - return false; - } - - public function indexOf($value) - { - $index = 0; - if (is_array($value)) { - foreach ($this->container as $v) { - if (is_array($v)) { - if ($value['id'] == $v['id']) { - return $index; - } - } else if ($v instanceof Entity) { - if ($value['id'] == $v->id) { - return $index; - } - } - $index ++; - } - } else if ($value instanceof Entity) { - foreach ($this->container as $v) { - if (is_array($v)) { - if ($value->id == $v['id']) { - return $index; - } - } else if ($v instanceof Entity) { - if ($value === $v) { - return $index; - } - } - $index ++; - } - } - return false; - } - - public function toArray() - { - $arr = array(); - foreach ($this as $entity) { - $arr[] = $entity->toArray(); - } - return $arr; - } + public function current() + { + return $this->getEntityByOffset($this->position); + } + + public function key() + { + return $this->position; + } + + public function next() + { + do { + $this->position ++; + $next = false; + if (!$this->valid() && $this->position < count($this->container)) { + $next = true; + } + } while ($next); + } + + public function valid() + { + return isset($this->container[$this->position]); + } + + public function offsetExists($offset) + { + return isset($this->container[$offset]); + } + + public function offsetGet($offset) + { + if (!isset($this->container[$offset])) { + return null; + } + return $this->getEntityByOffset($offset); + } + + public function offsetSet($offset, $value) + { + if (!($value instanceof Entity)) { + throw new \InvalidArgumentException('Only Entity is allowed to be added to EntityCollection.'); + } + + if (is_null($offset)) { + $this->container[] = $value; + } else { + $this->container[$offset] = $value; + } + } + + public function offsetUnset($offset) + { + unset($this->container[$offset]); + } + + public function count() + { + return count($this->container); + } + + public function seek($offset) + { + $this->position = $offset; + if (!$this->valid()) { + throw new \OutOfBoundsException("Invalid seek offset ($offset)."); + } + } + + public function append(Entity $entity) + { + $this->container[] = $entity; + } + + private function getEntityByOffset($offset) + { + $value = $this->container[$offset]; + + if ($value instanceof Entity) { + return $value; + } else if (is_array($value)) { + $this->container[$offset] = $this->buildEntityFromArray($value); + } else { + return null; + } + + return $this->container[$offset]; + } + + protected function buildEntityFromArray(array $dataArray) + { + $entity = $this->entityFactory->create($this->entityName); + if ($entity) { + $entity->set($dataArray); + $entity->setAsFetched(); + return $entity; + } + } + + public function getEntityName() + { + return $this->entityName; + } + + public function getInnerContainer() + { + return $this->container; + } + + public function merge(EntityCollection $collection) + { + $newData = $this->container; + $incomingData = $collection->getInnerContainer(); + + foreach ($incomingData as $v) { + if (!$this->contains($v)) { + $this->container[] = $v; + } + } + } + + public function contains($value) + { + if ($this->indexOf($value) !== false) { + return true; + } + return false; + } + + public function indexOf($value) + { + $index = 0; + if (is_array($value)) { + foreach ($this->container as $v) { + if (is_array($v)) { + if ($value['id'] == $v['id']) { + return $index; + } + } else if ($v instanceof Entity) { + if ($value['id'] == $v->id) { + return $index; + } + } + $index ++; + } + } else if ($value instanceof Entity) { + foreach ($this->container as $v) { + if (is_array($v)) { + if ($value->id == $v['id']) { + return $index; + } + } else if ($v instanceof Entity) { + if ($value === $v) { + return $index; + } + } + $index ++; + } + } + return false; + } + + public function toArray() + { + $arr = array(); + foreach ($this as $entity) { + $arr[] = $entity->toArray(); + } + return $arr; + } } diff --git a/application/Espo/ORM/EntityFactory.php b/application/Espo/ORM/EntityFactory.php index d02bb5182d..da72e67ac0 100644 --- a/application/Espo/ORM/EntityFactory.php +++ b/application/Espo/ORM/EntityFactory.php @@ -18,31 +18,31 @@ * * 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\ORM; class EntityFactory -{ - protected $metadata; - - protected $entityManager; - - public function __construct(EntityManager $entityManager, Metadata $metadata) - { - $this->entityManager = $entityManager; - $this->metadata = $metadata; - } - public function create($name) - { - $className = $this->entityManager->normalizeEntityName($name); - $defs = $this->metadata->get($name); - if (!class_exists($className)) { - return null; - } - $entity = new $className($defs, $this->entityManager); - return $entity; - } +{ + protected $metadata; + + protected $entityManager; + + public function __construct(EntityManager $entityManager, Metadata $metadata) + { + $this->entityManager = $entityManager; + $this->metadata = $metadata; + } + public function create($name) + { + $className = $this->entityManager->normalizeEntityName($name); + $defs = $this->metadata->get($name); + if (!class_exists($className)) { + return null; + } + $entity = new $className($defs, $this->entityManager); + return $entity; + } } diff --git a/application/Espo/ORM/EntityManager.php b/application/Espo/ORM/EntityManager.php index 6adcb8cd1f..310b57aeba 100644 --- a/application/Espo/ORM/EntityManager.php +++ b/application/Espo/ORM/EntityManager.php @@ -25,137 +25,137 @@ namespace Espo\ORM; class EntityManager { - protected $pdo; + protected $pdo; - protected $entityFactory; + protected $entityFactory; - protected $repositoryFactory; + protected $repositoryFactory; - protected $mappers = array(); + protected $mappers = array(); - protected $metadata; + protected $metadata; - protected $repositoryHash = array(); + protected $repositoryHash = array(); - protected $params = array(); - - protected $query; + protected $params = array(); - public function __construct($params) - { - $this->params = $params; + protected $query; - $this->metadata = new Metadata(); + public function __construct($params) + { + $this->params = $params; - if (!empty($params['metadata'])) { - $this->setMetadata($params['metadata']); - } + $this->metadata = new Metadata(); - $entityFactoryClassName = '\\Espo\\ORM\\EntityFactory'; - if (!empty($params['entityFactoryClassName'])) { - $entityFactoryClassName = $params['entityFactoryClassName']; - } - $this->entityFactory = new $entityFactoryClassName($this, $this->metadata); + if (!empty($params['metadata'])) { + $this->setMetadata($params['metadata']); + } - $repositoryFactoryClassName = '\\Espo\\ORM\\RepositoryFactory'; - if (!empty($params['repositoryFactoryClassName'])) { - $repositoryFactoryClassName = $params['repositoryFactoryClassName']; - } - $this->repositoryFactory = new $repositoryFactoryClassName($this, $this->entityFactory); + $entityFactoryClassName = '\\Espo\\ORM\\EntityFactory'; + if (!empty($params['entityFactoryClassName'])) { + $entityFactoryClassName = $params['entityFactoryClassName']; + } + $this->entityFactory = new $entityFactoryClassName($this, $this->metadata); - $this->init(); - } - - public function getQuery() - { - if (empty($this->query)) { - $this->query = new DB\Query($this->getPDO(), $this->entityFactory); - } - return $this->query; - } + $repositoryFactoryClassName = '\\Espo\\ORM\\RepositoryFactory'; + if (!empty($params['repositoryFactoryClassName'])) { + $repositoryFactoryClassName = $params['repositoryFactoryClassName']; + } + $this->repositoryFactory = new $repositoryFactoryClassName($this, $this->entityFactory); - public function getMapper($className) - { - if (empty($this->mappers[$className])) { - // TODO use factory - - $this->mappers[$className] = new $className($this->getPDO(), $this->entityFactory, $this->getQuery()); - } - return $this->mappers[$className]; - } + $this->init(); + } - protected function initPDO() - { - $params = $this->params; + public function getQuery() + { + if (empty($this->query)) { + $this->query = new DB\Query($this->getPDO(), $this->entityFactory); + } + return $this->query; + } - $port = empty($params['port']) ? '' : 'port=' . $params['port'] . ';'; + public function getMapper($className) + { + if (empty($this->mappers[$className])) { + // TODO use factory - $this->pdo = new \PDO('mysql:host='.$params['host'].';'.$port.'dbname=' . $params['dbname'] . ';charset=utf8', $params['user'], $params['password']); - $this->pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); - } + $this->mappers[$className] = new $className($this->getPDO(), $this->entityFactory, $this->getQuery()); + } + return $this->mappers[$className]; + } - public function getEntity($name, $id = null) - { - return $this->getRepository($name)->get($id); - } + protected function initPDO() + { + $params = $this->params; - public function saveEntity(Entity $entity) - { - $entityName = $entity->getEntityName(); - return $this->getRepository($entityName)->save($entity); - } + $port = empty($params['port']) ? '' : 'port=' . $params['port'] . ';'; - public function removeEntity(Entity $entity) - { - $entityName = $entity->getEntityName(); - return $this->getRepository($entityName)->remove($entity); - } + $this->pdo = new \PDO('mysql:host='.$params['host'].';'.$port.'dbname=' . $params['dbname'] . ';charset=utf8', $params['user'], $params['password']); + $this->pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); + } - public function getRepository($name) - { - if (empty($this->repositoryHash[$name])) { - $this->repositoryHash[$name] = $this->repositoryFactory->create($name); - } - return $this->repositoryHash[$name]; - } + public function getEntity($name, $id = null) + { + return $this->getRepository($name)->get($id); + } - public function setMetadata(array $data) - { - $this->metadata->setData($data); - } + public function saveEntity(Entity $entity) + { + $entityName = $entity->getEntityName(); + return $this->getRepository($entityName)->save($entity); + } - public function getMetadata() - { - return $this->metadata; - } + public function removeEntity(Entity $entity) + { + $entityName = $entity->getEntityName(); + return $this->getRepository($entityName)->remove($entity); + } - public function getPDO() - { - if (empty($this->pdo)) { - $this->initPDO(); - } - return $this->pdo; - } + public function getRepository($name) + { + if (empty($this->repositoryHash[$name])) { + $this->repositoryHash[$name] = $this->repositoryFactory->create($name); + } + return $this->repositoryHash[$name]; + } - public function normalizeRepositoryName($name) - { - return $name; - } + public function setMetadata(array $data) + { + $this->metadata->setData($data); + } - public function normalizeEntityName($name) - { - return $name; - } + public function getMetadata() + { + return $this->metadata; + } - public function createCollection($entityName, $data = array()) - { - $seed = $this->getEntity($entityName); - $collection = new EntityCollection($data, $seed, $this->entityFactory); - return $collection; - } + public function getPDO() + { + if (empty($this->pdo)) { + $this->initPDO(); + } + return $this->pdo; + } - protected function init() - { - } + public function normalizeRepositoryName($name) + { + return $name; + } + + public function normalizeEntityName($name) + { + return $name; + } + + public function createCollection($entityName, $data = array()) + { + $seed = $this->getEntity($entityName); + $collection = new EntityCollection($data, $seed, $this->entityFactory); + return $collection; + } + + protected function init() + { + } } diff --git a/application/Espo/ORM/IEntity.php b/application/Espo/ORM/IEntity.php index cb81fe712e..b6403b01c3 100644 --- a/application/Espo/ORM/IEntity.php +++ b/application/Espo/ORM/IEntity.php @@ -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\ORM; @@ -27,59 +27,59 @@ namespace Espo\ORM; */ interface IEntity { - const ID = 'id'; - const VARCHAR = 'varchar'; - const INT = 'int'; - const FLOAT = 'float'; - const TEXT = 'text'; - const BOOL = 'bool'; - const FOREIGN_ID = 'foreignId'; - const FOREIGN = 'foreign'; - const FOREIGN_TYPE = 'foreignType'; - const DATE = 'date'; - const DATETIME = 'datetime'; - const JSON_ARRAY = 'jsonArray'; - const JSON_OBJECT = 'jsonObject'; - - const MANY_MANY = 'manyMany'; - const HAS_MANY = 'hasMany'; - const BELONGS_TO = 'belongsTo'; - const HAS_ONE = 'hasOne'; - const BELONGS_TO_PARENT = 'belongsToParent'; - const HAS_CHILDREN = 'hasChildren'; - - /** - * Push values from the array. - * E.g. insert values into the bean from a request data. - * @param array $arr Array of field - value pairs - */ - function populateFromArray(array $arr); - - /** - * Resets all fields in the current model. - */ - function reset(); - - /** - * Set field. - */ - function set($name, $value); - - /** - * Get field. - */ - function get($name); - - /** - * Check field is set. - */ - function has($name); - - /** - * Clear field. - */ - function clear($name); - + const ID = 'id'; + const VARCHAR = 'varchar'; + const INT = 'int'; + const FLOAT = 'float'; + const TEXT = 'text'; + const BOOL = 'bool'; + const FOREIGN_ID = 'foreignId'; + const FOREIGN = 'foreign'; + const FOREIGN_TYPE = 'foreignType'; + const DATE = 'date'; + const DATETIME = 'datetime'; + const JSON_ARRAY = 'jsonArray'; + const JSON_OBJECT = 'jsonObject'; + + const MANY_MANY = 'manyMany'; + const HAS_MANY = 'hasMany'; + const BELONGS_TO = 'belongsTo'; + const HAS_ONE = 'hasOne'; + const BELONGS_TO_PARENT = 'belongsToParent'; + const HAS_CHILDREN = 'hasChildren'; + + /** + * Push values from the array. + * E.g. insert values into the bean from a request data. + * @param array $arr Array of field - value pairs + */ + function populateFromArray(array $arr); + + /** + * Resets all fields in the current model. + */ + function reset(); + + /** + * Set field. + */ + function set($name, $value); + + /** + * Get field. + */ + function get($name); + + /** + * Check field is set. + */ + function has($name); + + /** + * Clear field. + */ + function clear($name); + } diff --git a/application/Espo/ORM/Metadata.php b/application/Espo/ORM/Metadata.php index 02eb63b6bc..222e7390bf 100644 --- a/application/Espo/ORM/Metadata.php +++ b/application/Espo/ORM/Metadata.php @@ -18,23 +18,23 @@ * * 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\ORM; class Metadata { - protected $data = array(); - - public function setData($data) - { - $this->data = $data; - } - - public function get($entityName) - { - return $this->data[$entityName]; - } + protected $data = array(); + + public function setData($data) + { + $this->data = $data; + } + + public function get($entityName) + { + return $this->data[$entityName]; + } } diff --git a/application/Espo/ORM/Repositories/RDB.php b/application/Espo/ORM/Repositories/RDB.php index ef3afc36f7..63c642d0c2 100644 --- a/application/Espo/ORM/Repositories/RDB.php +++ b/application/Espo/ORM/Repositories/RDB.php @@ -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\ORM\Repositories; @@ -31,349 +31,353 @@ use \Espo\ORM\IEntity; class RDB extends \Espo\ORM\Repository { - - public static $mapperClassName = '\\Espo\\ORM\\DB\\MysqlMapper'; - - /** - * @var Object Mapper. - */ - protected $mapper; - - /** - * @var array Where clause array. To be used in further find operation. - */ - protected $whereClause = array(); - /** - * @var array Parameters to be used in further find operations. - */ - protected $listParams = array(); - - public function __construct($entityName, EntityManager $entityManager, EntityFactory $entityFactory) - { - $this->entityName = $entityName; - $this->entityFactory = $entityFactory; - $this->seed = $this->entityFactory->create($entityName); - $this->entityClassName = get_class($this->seed); - $this->entityManager = $entityManager; - } - - protected function getMapper() - { - if (empty($this->mapper)) { - $this->mapper = $this->getEntityManager()->getMapper(self::$mapperClassName); - } - return $this->mapper; - } - - public function handleSelectParams(&$params) - { - } - - protected function getEntityFactory() - { - return $this->entityFactory; - } - - protected function getEntityManager() - { - return $this->entityManager; - } - - public function reset() - { - $this->whereClause = array(); - $this->listParams = array(); - } - - protected function getNewEntity() - { - $entity = $this->entityFactory->create($this->entityName); - if ($entity) { - $entity->setIsNew(true); - $entity->populateDefaults(); - return $entity; - } - } - - protected function getEntityById($id) - { - $params = array(); - $this->handleSelectParams($params); - - $entity = $this->entityFactory->create($this->entityName); - if ($entity) { - if ($this->getMapper()->selectById($entity, $id, $params)) { - $entity->setAsFetched(); - return $entity; - } - } - return null; - } - - public function get($id = null) - { - if (empty($id)) { - return $this->getNewEntity(); - } - return $this->getEntityById($id); - } - - protected function beforeSave(Entity $entity) - { - } - - protected function afterSave(Entity $entity) - { - } - - public function save(Entity $entity) - { - $this->beforeSave($entity); - if ($entity->isNew()) { - $result = $this->getMapper()->insert($entity); - if ($result) { - $entity->setIsNew(false); - } - } else { - $result = $this->getMapper()->update($entity); - } - if ($result) { - $this->afterSave($entity); - } - return $result; - } - - protected function beforeRemove(Entity $entity) - { - } - - protected function afterRemove(Entity $entity) - { - } - - public function remove(Entity $entity) - { - $this->beforeRemove($entity); - $result = $this->getMapper()->delete($entity); - if ($result) { - $this->afterRemove($entity); - } - return $result; - } - - public function deleteFromDb($id) - { - return $this->getMapper()->deleteFromDb($this->entityName, $id); - } + public static $mapperClassName = '\\Espo\\ORM\\DB\\MysqlMapper'; - public function find(array $params = array()) - { - $this->handleSelectParams($params); - $params = $this->getSelectParams($params); + /** + * @var Object Mapper. + */ + protected $mapper; - $dataArr = $this->getMapper()->select($this->seed, $params); - - $collection = new EntityCollection($dataArr, $this->entityName, $this->entityFactory); - $this->reset(); - - return $collection; - } - - public function findOne(array $params = array()) - { - $collection = $this->limit(0, 1)->find($params); - if (count($collection)) { - return $collection[0]; - } - return null; - } - - public function findRelated(Entity $entity, $relationName, array $params = array()) - { - $entityName = $entity->relations[$relationName]['entity']; - $this->getEntityManager()->getRepository($entityName)->handleSelectParams($params); - - $result = $this->getMapper()->selectRelated($entity, $relationName, $params); + /** + * @var array Where clause array. To be used in further find operation. + */ + protected $whereClause = array(); - if (is_array($result)) { - $collection = new EntityCollection($result, $entityName, $this->entityFactory); - return $collection; - } else { - return $result; - } - - } - - public function countRelated(Entity $entity, $relationName, array $params = array()) - { - $entityName = $entity->relations[$relationName]['entity']; - $this->getEntityManager()->getRepository($entityName)->handleSelectParams($params); - - return $this->getMapper()->countRelated($entity, $relationName, $params); - } - - public function relate(Entity $entity, $relationName, $foreign, $data) - { - if ($data instanceof \stdClass) { - $data = get_object_vars($data); - } - if ($foreign instanceof Entity) { - return $this->getMapper()->relate($entity, $relationName, $foreign, $data); - } - if (is_string($foreign)) { - return $this->getMapper()->addRelation($entity, $relationName, $foreign, null, $data); - } - return false; - } - - public function unrelate(Entity $entity, $relationName, $foreign) - { - if ($foreign instanceof Entity) { - return $this->getMapper()->unrelate($entity, $relationName, $foreign); - } - if (is_string($foreign)) { - return $this->getMapper()->removeRelation($entity, $relationName, $foreign); - } - if ($foreign === true) { - return $this->getMapper()->removeAllRelations($entity, $relationName); - } - return false; - } - - public function updateRelation(Entity $entity, $relationName, $foreign, $data) - { - if ($data instanceof \stdClass) { - $data = get_object_vars($data); - } - if ($foreign instanceof Entity) { - $id = $foreign->id; - } else { - $id = $foreign; - } - if (is_string($foreign)) { - return $this->getMapper()->updateRelation($entity, $relationName, $id, $data); - } - return false; - } - - - public function getAll() - { - $this->reset(); - return $this->find(); - } - - public function count(array $params = array()) - { - $this->handleSelectParams($params); - - $params = $this->getSelectParams($params); - return $this->getMapper()->count($this->seed, $params); - } - - public function max($field) - { - $params = $this->getSelectParams(); - return $this->getMapper()->max($this->seed, $params, $field); - } - - public function min($field) - { - $params = $this->getSelectParams(); - return $this->getMapper()->min($this->seed, $params, $field); - } - - public function sum($field) - { - $params = $this->getSelectParams(); - return $this->getMapper()->sum($this->seed, $params, $field); - } + /** + * @var array Parameters to be used in further find operations. + */ + protected $listParams = array(); - // @TODO use abstract class for list params - // @TODO join conditions - public function join() - { - $args = func_get_args(); - - if (empty($this->listParams['joins'])) { - $this->listParams['joins'] = array(); - } - - foreach ($args as &$param) { - if (is_array($param)) { - foreach ($param as $k => $v) { - $this->listParams['joins'][] = $v; - } - } else { - $this->listParams['joins'][] = $param; - } - } - - return $this; - } - - public function distinct() - { - $this->listParams['distinct'] = true; - return $this; - } - - public function where($param1 = array(), $param2 = null) - { - if (is_array($param1)) { - $this->whereClause = $param1 + $this->whereClause; - - } else { - if (!is_null($param2)) { - $this->whereClause[$param1] = $param2; - } - } - - return $this; - } - - public function order($field = 'id', $direction = "ASC") - { - $this->listParams['orderBy'] = $field; - $this->listParams['order'] = $direction; - - return $this; - } - - public function limit($offset, $limit) - { - $this->listParams['offset'] = $offset; - $this->listParams['limit'] = $limit; - - return $this; - } - - public function setListParams(array $params = array()) - { - $this->listParams = $params; - } - - public function getListParams() - { - return $this->listParams; - } - - protected function getSelectParams(array $params = array()) - { - if (isset($params['whereClause'])) { - $params['whereClause'] = $params['whereClause'] + $this->whereClause; - } else { - $params['whereClause'] = $this->whereClause; - } - $params = $params + $this->listParams; - - return $params; - } - - protected function getPDO() - { - return $this->getEntityManager()->getPDO(); - } + public function __construct($entityName, EntityManager $entityManager, EntityFactory $entityFactory) + { + $this->entityName = $entityName; + $this->entityFactory = $entityFactory; + $this->seed = $this->entityFactory->create($entityName); + $this->entityClassName = get_class($this->seed); + $this->entityManager = $entityManager; + } + + protected function getMapper() + { + if (empty($this->mapper)) { + $this->mapper = $this->getEntityManager()->getMapper(self::$mapperClassName); + } + return $this->mapper; + } + + public function handleSelectParams(&$params) + { + } + + protected function getEntityFactory() + { + return $this->entityFactory; + } + + protected function getEntityManager() + { + return $this->entityManager; + } + + public function reset() + { + $this->whereClause = array(); + $this->listParams = array(); + } + + protected function getNewEntity() + { + $entity = $this->entityFactory->create($this->entityName); + if ($entity) { + $entity->setIsNew(true); + $entity->populateDefaults(); + return $entity; + } + } + + protected function getEntityById($id) + { + $params = array(); + $this->handleSelectParams($params); + + $entity = $this->entityFactory->create($this->entityName); + if ($entity) { + if ($this->getMapper()->selectById($entity, $id, $params)) { + $entity->setAsFetched(); + return $entity; + } + } + return null; + } + + public function get($id = null) + { + if (empty($id)) { + return $this->getNewEntity(); + } + return $this->getEntityById($id); + } + + protected function beforeSave(Entity $entity) + { + } + + protected function afterSave(Entity $entity) + { + } + + public function save(Entity $entity) + { + $this->beforeSave($entity); + if ($entity->isNew()) { + $result = $this->getMapper()->insert($entity); + } else { + $result = $this->getMapper()->update($entity); + } + if ($result) { + $this->afterSave($entity); + if ($entity->isNew()) { + $entity->setIsNew(false); + } else { + if ($entity->isFetched()) { + $entity->updateFetchedValues(); + } + } + } + return $result; + } + + protected function beforeRemove(Entity $entity) + { + } + + protected function afterRemove(Entity $entity) + { + } + + public function remove(Entity $entity) + { + $this->beforeRemove($entity); + $result = $this->getMapper()->delete($entity); + if ($result) { + $this->afterRemove($entity); + } + return $result; + } + + public function deleteFromDb($id) + { + return $this->getMapper()->deleteFromDb($this->entityName, $id); + } + + public function find(array $params = array()) + { + $this->handleSelectParams($params); + $params = $this->getSelectParams($params); + + $dataArr = $this->getMapper()->select($this->seed, $params); + + $collection = new EntityCollection($dataArr, $this->entityName, $this->entityFactory); + $this->reset(); + + return $collection; + } + + public function findOne(array $params = array()) + { + $collection = $this->limit(0, 1)->find($params); + if (count($collection)) { + return $collection[0]; + } + return null; + } + + public function findRelated(Entity $entity, $relationName, array $params = array()) + { + $entityName = $entity->relations[$relationName]['entity']; + $this->getEntityManager()->getRepository($entityName)->handleSelectParams($params); + + $result = $this->getMapper()->selectRelated($entity, $relationName, $params); + + if (is_array($result)) { + $collection = new EntityCollection($result, $entityName, $this->entityFactory); + return $collection; + } else { + return $result; + } + + } + + public function countRelated(Entity $entity, $relationName, array $params = array()) + { + $entityName = $entity->relations[$relationName]['entity']; + $this->getEntityManager()->getRepository($entityName)->handleSelectParams($params); + + return $this->getMapper()->countRelated($entity, $relationName, $params); + } + + public function relate(Entity $entity, $relationName, $foreign, $data) + { + if ($data instanceof \stdClass) { + $data = get_object_vars($data); + } + if ($foreign instanceof Entity) { + return $this->getMapper()->relate($entity, $relationName, $foreign, $data); + } + if (is_string($foreign)) { + return $this->getMapper()->addRelation($entity, $relationName, $foreign, null, $data); + } + return false; + } + + public function unrelate(Entity $entity, $relationName, $foreign) + { + if ($foreign instanceof Entity) { + return $this->getMapper()->unrelate($entity, $relationName, $foreign); + } + if (is_string($foreign)) { + return $this->getMapper()->removeRelation($entity, $relationName, $foreign); + } + if ($foreign === true) { + return $this->getMapper()->removeAllRelations($entity, $relationName); + } + return false; + } + + public function updateRelation(Entity $entity, $relationName, $foreign, $data) + { + if ($data instanceof \stdClass) { + $data = get_object_vars($data); + } + if ($foreign instanceof Entity) { + $id = $foreign->id; + } else { + $id = $foreign; + } + if (is_string($foreign)) { + return $this->getMapper()->updateRelation($entity, $relationName, $id, $data); + } + return false; + } + + + public function getAll() + { + $this->reset(); + return $this->find(); + } + + public function count(array $params = array()) + { + $this->handleSelectParams($params); + + $params = $this->getSelectParams($params); + return $this->getMapper()->count($this->seed, $params); + } + + public function max($field) + { + $params = $this->getSelectParams(); + return $this->getMapper()->max($this->seed, $params, $field); + } + + public function min($field) + { + $params = $this->getSelectParams(); + return $this->getMapper()->min($this->seed, $params, $field); + } + + public function sum($field) + { + $params = $this->getSelectParams(); + return $this->getMapper()->sum($this->seed, $params, $field); + } + + // @TODO use abstract class for list params + // @TODO join conditions + public function join() + { + $args = func_get_args(); + + if (empty($this->listParams['joins'])) { + $this->listParams['joins'] = array(); + } + + foreach ($args as &$param) { + if (is_array($param)) { + foreach ($param as $k => $v) { + $this->listParams['joins'][] = $v; + } + } else { + $this->listParams['joins'][] = $param; + } + } + + return $this; + } + + public function distinct() + { + $this->listParams['distinct'] = true; + return $this; + } + + public function where($param1 = array(), $param2 = null) + { + if (is_array($param1)) { + $this->whereClause = $param1 + $this->whereClause; + + } else { + if (!is_null($param2)) { + $this->whereClause[$param1] = $param2; + } + } + + return $this; + } + + public function order($field = 'id', $direction = "ASC") + { + $this->listParams['orderBy'] = $field; + $this->listParams['order'] = $direction; + + return $this; + } + + public function limit($offset, $limit) + { + $this->listParams['offset'] = $offset; + $this->listParams['limit'] = $limit; + + return $this; + } + + public function setListParams(array $params = array()) + { + $this->listParams = $params; + } + + public function getListParams() + { + return $this->listParams; + } + + protected function getSelectParams(array $params = array()) + { + if (isset($params['whereClause'])) { + $params['whereClause'] = $params['whereClause'] + $this->whereClause; + } else { + $params['whereClause'] = $this->whereClause; + } + $params = $params + $this->listParams; + + return $params; + } + + protected function getPDO() + { + return $this->getEntityManager()->getPDO(); + } } diff --git a/application/Espo/ORM/Repository.php b/application/Espo/ORM/Repository.php index 9b9ee0d4ca..504f5c2aee 100644 --- a/application/Espo/ORM/Repository.php +++ b/application/Espo/ORM/Repository.php @@ -18,69 +18,69 @@ * * 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\ORM; abstract class Repository -{ - /** - * @var EntityFactory EntityFactory object. - */ - protected $entityFactory; - - /** - * @var EntityManager EntityManager object. - */ - protected $entityManager; - - - /** - * @var iModel Seed entity. - */ - protected $seed; - - /** - * @var string Class Name of aggregate root. - */ - protected $entityClassName; - - /** - * @var string Model Name of aggregate root. - */ - protected $entityName; - - public function __construct($entityName, EntityManager $entityManager, EntityFactory $entityFactory) - { - $this->entityName = $entityName; - $this->entityFactory = $entityFactory; - $this->seed = $this->entityFactory->create($entityName); - $this->entityClassName = get_class($this->seed); - $this->entityManager = $entityManager; - } - - protected function getEntityFactory() - { - return $this->entityFactory; - } - - protected function getEntityManager() - { - return $this->entityManager; - } - - abstract public function get($id = null); - - abstract public function save(Entity $entity); - - abstract public function remove(Entity $entity); +{ + /** + * @var EntityFactory EntityFactory object. + */ + protected $entityFactory; - abstract public function find(array $params); - - abstract public function findOne(array $params); + /** + * @var EntityManager EntityManager object. + */ + protected $entityManager; - abstract public function getAll(); - - abstract public function count(array $params); + + /** + * @var iModel Seed entity. + */ + protected $seed; + + /** + * @var string Class Name of aggregate root. + */ + protected $entityClassName; + + /** + * @var string Model Name of aggregate root. + */ + protected $entityName; + + public function __construct($entityName, EntityManager $entityManager, EntityFactory $entityFactory) + { + $this->entityName = $entityName; + $this->entityFactory = $entityFactory; + $this->seed = $this->entityFactory->create($entityName); + $this->entityClassName = get_class($this->seed); + $this->entityManager = $entityManager; + } + + protected function getEntityFactory() + { + return $this->entityFactory; + } + + protected function getEntityManager() + { + return $this->entityManager; + } + + abstract public function get($id = null); + + abstract public function save(Entity $entity); + + abstract public function remove(Entity $entity); + + abstract public function find(array $params); + + abstract public function findOne(array $params); + + abstract public function getAll(); + + abstract public function count(array $params); } diff --git a/application/Espo/ORM/RepositoryFactory.php b/application/Espo/ORM/RepositoryFactory.php index 13b7c1fdcb..c4350c2c90 100644 --- a/application/Espo/ORM/RepositoryFactory.php +++ b/application/Espo/ORM/RepositoryFactory.php @@ -18,44 +18,44 @@ * * 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\ORM; class RepositoryFactory { - protected $entityFactroy; - - protected $entityManager; - - protected $defaultRepositoryClassName = '\\Espo\\ORM\\Repository'; + protected $entityFactroy; - public function __construct(EntityManager $entityManager, EntityFactory $entityFactroy) - { - $this->entityManager = $entityManager; - $this->entityFactroy = $entityFactroy; - } - - public function create($name) - { - $className = $this->entityManager->normalizeRepositoryName($name); - - if (!class_exists($className)) { - $className = $this->defaultRepositoryClassName; - } - - $repository = new $className($name, $this->entityManager, $this->entityFactroy); - return $repository; - } - - protected function normalizeName($name) - { - return $name; - } - - public function setDefaultRepositoryClassName($defaultRepositoryClassName) - { - $this->defaultRepositoryClassName = $defaultRepositoryClassName; - } + protected $entityManager; + + protected $defaultRepositoryClassName = '\\Espo\\ORM\\Repository'; + + public function __construct(EntityManager $entityManager, EntityFactory $entityFactroy) + { + $this->entityManager = $entityManager; + $this->entityFactroy = $entityFactroy; + } + + public function create($name) + { + $className = $this->entityManager->normalizeRepositoryName($name); + + if (!class_exists($className)) { + $className = $this->defaultRepositoryClassName; + } + + $repository = new $className($name, $this->entityManager, $this->entityFactroy); + return $repository; + } + + protected function normalizeName($name) + { + return $name; + } + + public function setDefaultRepositoryClassName($defaultRepositoryClassName) + { + $this->defaultRepositoryClassName = $defaultRepositoryClassName; + } } diff --git a/application/Espo/Repositories/Attachment.php b/application/Espo/Repositories/Attachment.php index d141af85c0..6e408b60fb 100644 --- a/application/Espo/Repositories/Attachment.php +++ b/application/Espo/Repositories/Attachment.php @@ -26,35 +26,35 @@ use Espo\ORM\Entity; class Attachment extends \Espo\Core\ORM\Repositories\RDB { - protected $dependencies = array( - 'fileManager', - ); - - protected function getFileManager() - { - return $this->getInjection('fileManager'); - } - - public function save(Entity $entity) - { - $isNew = $entity->isNew(); - $result = parent::save($entity); - - if ($isNew) { - if (!empty($entity->id) && $entity->has('contents')) { - $contents = $entity->get('contents'); - $this->getFileManager()->putContents('data/upload/' . $entity->id, $contents); - } - } - - return $result; - } - - protected function afterRemove(Entity $entity) - { - parent::afterRemove($entity); - $this->getFileManager()->removeFile('data/upload/' . $entity->id); - } + protected $dependencies = array( + 'fileManager', + ); + + protected function getFileManager() + { + return $this->getInjection('fileManager'); + } + + public function save(Entity $entity) + { + $isNew = $entity->isNew(); + $result = parent::save($entity); + + if ($isNew) { + if (!empty($entity->id) && $entity->has('contents')) { + $contents = $entity->get('contents'); + $this->getFileManager()->putContents('data/upload/' . $entity->id, $contents); + } + } + + return $result; + } + + protected function afterRemove(Entity $entity) + { + parent::afterRemove($entity); + $this->getFileManager()->removeFile('data/upload/' . $entity->id); + } } diff --git a/application/Espo/Repositories/Email.php b/application/Espo/Repositories/Email.php index 03d97b593a..2317b36361 100644 --- a/application/Espo/Repositories/Email.php +++ b/application/Espo/Repositories/Email.php @@ -25,69 +25,69 @@ namespace Espo\Repositories; use Espo\ORM\Entity; class Email extends \Espo\Core\ORM\Repositories\RDB -{ - protected function prepareAddressess(Entity $entity, $type) - { - $eaRepositoty = $this->getEntityManager()->getRepository('EmailAddress'); - - $address = $entity->get($type); - $ids = array(); - if (!empty($address) || !filter_var($address, FILTER_VALIDATE_EMAIL)) { - $arr = array_map(function ($e) { - return trim($e); - }, explode(';', $address)); - - $ids = $eaRepositoty->getIds($arr); - } - $entity->set($type . 'EmailAddressesIds', $ids); - } - - protected function beforeSave(Entity $entity) - { - $eaRepositoty = $this->getEntityManager()->getRepository('EmailAddress'); - - $from = trim($entity->get('from')); - if (!empty($from)) { - $ids = $eaRepositoty->getIds(array($from)); - if (!empty($ids)) { - $entity->set('fromEmailAddressId', $ids[0]); - } - } else { - $entity->set('fromEmailAddressId', null); - } - - $this->prepareAddressess($entity, 'to'); - $this->prepareAddressess($entity, 'cc'); - $this->prepareAddressess($entity, 'bcc'); - - parent::beforeSave($entity); - - $parentId = $entity->get('parentId'); - $parentType = $entity->get('parentType'); - if (!empty($parentId) || !empty($parentType)) { - $parent = $this->getEntityManager()->getEntity($parentType, $parentId); - if (!empty($parent)) { - if ($parent->getEntityName() == 'Account') { - $accountId = $parent->id; - } else if ($parent->has('accountId')) { - $accountId = $parent->get('accountId'); - } - if (!empty($accountId)) { - $entity->set('accountId', $accountId); - } - } - } else { - // TODO find account by from address - } - } - - protected function beforeRemove(Entity $entity) - { - parent::beforeRemove($entity); - $attachments = $entity->get('attachments'); - foreach ($attachments as $attachment) { - $this->getEntityManager()->removeEntity($attachment); - } - } +{ + protected function prepareAddressess(Entity $entity, $type) + { + $eaRepositoty = $this->getEntityManager()->getRepository('EmailAddress'); + + $address = $entity->get($type); + $ids = array(); + if (!empty($address) || !filter_var($address, FILTER_VALIDATE_EMAIL)) { + $arr = array_map(function ($e) { + return trim($e); + }, explode(';', $address)); + + $ids = $eaRepositoty->getIds($arr); + } + $entity->set($type . 'EmailAddressesIds', $ids); + } + + protected function beforeSave(Entity $entity) + { + $eaRepositoty = $this->getEntityManager()->getRepository('EmailAddress'); + + $from = trim($entity->get('from')); + if (!empty($from)) { + $ids = $eaRepositoty->getIds(array($from)); + if (!empty($ids)) { + $entity->set('fromEmailAddressId', $ids[0]); + } + } else { + $entity->set('fromEmailAddressId', null); + } + + $this->prepareAddressess($entity, 'to'); + $this->prepareAddressess($entity, 'cc'); + $this->prepareAddressess($entity, 'bcc'); + + parent::beforeSave($entity); + + $parentId = $entity->get('parentId'); + $parentType = $entity->get('parentType'); + if (!empty($parentId) || !empty($parentType)) { + $parent = $this->getEntityManager()->getEntity($parentType, $parentId); + if (!empty($parent)) { + if ($parent->getEntityName() == 'Account') { + $accountId = $parent->id; + } else if ($parent->has('accountId')) { + $accountId = $parent->get('accountId'); + } + if (!empty($accountId)) { + $entity->set('accountId', $accountId); + } + } + } else { + // TODO find account by from address + } + } + + protected function beforeRemove(Entity $entity) + { + parent::beforeRemove($entity); + $attachments = $entity->get('attachments'); + foreach ($attachments as $attachment) { + $this->getEntityManager()->removeEntity($attachment); + } + } } diff --git a/application/Espo/Repositories/EmailAddress.php b/application/Espo/Repositories/EmailAddress.php index 837b290a5a..088bb9e0a8 100644 --- a/application/Espo/Repositories/EmailAddress.php +++ b/application/Espo/Repositories/EmailAddress.php @@ -26,312 +26,312 @@ use Espo\ORM\Entity; class EmailAddress extends \Espo\Core\ORM\Repositories\RDB { - public function getIds($arr = array()) - { - $ids = array(); - if (!empty($arr)) { - $a = array_map(function ($item) { - return strtolower($item); - }, $arr); - $eas = $this->where(array( - 'lower' => array_map(function ($item) { - return strtolower($item); - }, $arr) - ))->find(); - $ids = array(); - $exist = array(); - foreach ($eas as $ea) { - $ids[] = $ea->id; - $exist[] = $ea->get('lower'); - } - foreach ($arr as $address) { - if (empty($address) || !filter_var($address, FILTER_VALIDATE_EMAIL)) { - continue; - } - if (!in_array(strtolower($address), $exist)) { - $ea = $this->get(); - $ea->set('name', $address); - $this->save($ea); - $ids[] = $ea->id; - } - } - } - return $ids; - } - - public function getEmailAddressData(Entity $entity) - { - $data = array(); - - $pdo = $this->getEntityManager()->getPDO(); - $sql = " - SELECT email_address.name, email_address.invalid, email_address.opt_out AS optOut, entity_email_address.primary - FROM entity_email_address - JOIN email_address ON email_address.id = entity_email_address.email_address_id AND email_address.deleted = 0 - WHERE - entity_email_address.entity_id = ".$pdo->quote($entity->id)." AND - entity_email_address.entity_type = ".$pdo->quote($entity->getEntityName())." AND - entity_email_address.deleted = 0 - ORDER BY entity_email_address.primary DESC - "; - $sth = $pdo->prepare($sql); - $sth->execute(); - if ($rows = $sth->fetchAll()) { - foreach ($rows as $row) { - $obj = new \StdClass(); - $obj->emailAddress = $row['name']; - $obj->primary = ($row['primary'] == '1') ? true : false; - $obj->optOut = ($row['optOut'] == '1') ? true : false; - $obj->invalid = ($row['invalid'] == '1') ? true : false; - $data[] = $obj; - } - } - - return $data; - } - - public function getByAddress($address) - { - 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') - "; + public function getIds($arr = array()) + { + $ids = array(); + if (!empty($arr)) { + $a = array_map(function ($item) { + return strtolower($item); + }, $arr); + $eas = $this->where(array( + 'lower' => array_map(function ($item) { + return strtolower($item); + }, $arr) + ))->find(); + $ids = array(); + $exist = array(); + foreach ($eas as $ea) { + $ids[] = $ea->id; + $exist[] = $ea->get('lower'); + } + foreach ($arr as $address) { + if (empty($address) || !filter_var($address, FILTER_VALIDATE_EMAIL)) { + continue; + } + if (!in_array(strtolower($address), $exist)) { + $ea = $this->get(); + $ea->set('name', $address); + $this->save($ea); + $ids[] = $ea->id; + } + } + } + return $ids; + } + + public function getEmailAddressData(Entity $entity) + { + $data = array(); + + $pdo = $this->getEntityManager()->getPDO(); + $sql = " + SELECT email_address.name, email_address.invalid, email_address.opt_out AS optOut, entity_email_address.primary + FROM entity_email_address + JOIN email_address ON email_address.id = entity_email_address.email_address_id AND email_address.deleted = 0 + WHERE + entity_email_address.entity_id = ".$pdo->quote($entity->id)." AND + entity_email_address.entity_type = ".$pdo->quote($entity->getEntityName())." AND + entity_email_address.deleted = 0 + ORDER BY entity_email_address.primary DESC + "; + $sth = $pdo->prepare($sql); + $sth->execute(); + if ($rows = $sth->fetchAll()) { + foreach ($rows as $row) { + $obj = new \StdClass(); + $obj->emailAddress = $row['name']; + $obj->primary = ($row['primary'] == '1') ? true : false; + $obj->optOut = ($row['optOut'] == '1') ? true : false; + $obj->invalid = ($row['invalid'] == '1') ? true : false; + $data[] = $obj; + } + } + + return $data; + } + + public function getByAddress($address) + { + 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')); - $emailAddressData = null; - - if ($entity->has('emailAddressData')) { - $emailAddressData = $entity->get('emailAddressData'); - } - - $pdo = $this->getEntityManager()->getPDO(); - - if ($emailAddressData !== null && is_array($emailAddressData)) { - $previousEmailAddressData = array(); - if (!$entity->isNew()) { - $previousEmailAddressData = $this->getEmailAddressData($entity); - } - - $hash = array(); - foreach ($emailAddressData as $row) { - $key = $row->emailAddress; - if (!empty($key)) { - $hash[$key] = array( - 'primary' => $row->primary ? true : false, - 'optOut' => $row->optOut ? true : false, - 'invalid' => $row->invalid ? true : false, - ); - } - } - - $hashPrev = array(); - foreach ($previousEmailAddressData as $row) { - $key = $row->emailAddress; - if (!empty($key)) { - $hashPrev[$key] = array( - 'primary' => $row->primary ? true : false, - 'optOut' => $row->optOut ? true : false, - 'invalid' => $row->invalid ? true : false, - ); - } - } - - $primary = false; - $toCreate = array(); - $toUpdate = array(); - $toRemove = array(); + $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')); + $emailAddressData = null; + + if ($entity->has('emailAddressData')) { + $emailAddressData = $entity->get('emailAddressData'); + } + + $pdo = $this->getEntityManager()->getPDO(); + + if ($emailAddressData !== null && is_array($emailAddressData)) { + $previousEmailAddressData = array(); + if (!$entity->isNew()) { + $previousEmailAddressData = $this->getEmailAddressData($entity); + } + + $hash = array(); + foreach ($emailAddressData as $row) { + $key = $row->emailAddress; + if (!empty($key)) { + $hash[$key] = array( + 'primary' => $row->primary ? true : false, + 'optOut' => $row->optOut ? true : false, + 'invalid' => $row->invalid ? true : false, + ); + } + } + + $hashPrev = array(); + foreach ($previousEmailAddressData as $row) { + $key = $row->emailAddress; + if (!empty($key)) { + $hashPrev[$key] = array( + 'primary' => $row->primary ? true : false, + 'optOut' => $row->optOut ? true : false, + 'invalid' => $row->invalid ? true : false, + ); + } + } + + $primary = false; + $toCreate = array(); + $toUpdate = array(); + $toRemove = array(); - - foreach ($hash as $key => $data) { - $new = true; - $changed = false; - - if ($hash[$key]['primary']) { - $primary = $key; - } - - if (array_key_exists($key, $hashPrev)) { - $new = false; - $changed = $hash[$key]['optOut'] != $hashPrev[$key]['optOut'] || $hash[$key]['invalid'] != $hashPrev[$key]['invalid']; - if ($hash[$key]['primary']) { - if ($hash[$key]['primary'] == $hashPrev[$key]['primary']) { - $primary = false; - } - } - } - - if ($new) { - $toCreate[] = $key; - } - if ($changed) { - $toUpdate[] = $key; - } - } - - foreach ($hashPrev as $key => $data) { - if (!array_key_exists($key, $hash)) { - $toRemove[] = $key; - } - } - - foreach ($toRemove as $address) { - $emailAddress = $this->getByAddress($address); - if ($emailAddress) { - $query = " - UPDATE entity_email_address - SET `deleted` = 1, `primary` = 0 - WHERE - entity_id = ".$pdo->quote($entity->id)." AND - entity_type = ".$pdo->quote($entity->getEntityName())." AND - email_address_id = ".$pdo->quote($emailAddress->id)." - "; - $sth = $pdo->prepare($query); - $sth->execute(); - } - } - - foreach ($toUpdate as $address) { - $emailAddress = $this->getByAddress($address); - if ($emailAddress) { - $emailAddress->set(array( - 'optOut' => $hash[$address]['optOut'], - 'invalid' => $hash[$address]['invalid'], - )); - $this->save($emailAddress); - } - } - - foreach ($toCreate as $address) { - $emailAddress = $this->getByAddress($address); - if (!$emailAddress) { - $emailAddress = $this->get(); - - $emailAddress->set(array( - 'name' => $address, - 'optOut' => $hash[$address]['optOut'], - 'invalid' => $hash[$address]['invalid'], - )); - $this->save($emailAddress); - } else { - if ($emailAddress->get('optOut') != $hash[$address]['optOut'] || $emailAddress->get('invalid') != $hash[$address]['invalid']) { - $emailAddress->set(array( - 'optOut' => $hash[$address]['optOut'], - 'invalid' => $hash[$address]['invalid'], - )); - $this->save($emailAddress); - } - } - - $query = " - INSERT entity_email_address - (entity_id, entity_type, email_address_id, `primary`) - VALUES - ( - ".$pdo->quote($entity->id).", - ".$pdo->quote($entity->getEntityName()).", - ".$pdo->quote($emailAddress->id).", - ".$pdo->quote($address === $primary)." - ) - "; - $sth = $pdo->prepare($query); - $sth->execute(); - } - - if ($primary) { - $emailAddress = $this->getByAddress($primary); - if ($emailAddress) { - $query = " - UPDATE entity_email_address - SET `primary` = 0 - WHERE - entity_id = ".$pdo->quote($entity->id)." AND - entity_type = ".$pdo->quote($entity->getEntityName())." AND - `primary` = 1 AND - deleted = 0 - "; - $sth = $pdo->prepare($query); - $sth->execute(); - - $query = " - UPDATE entity_email_address - SET `primary` = 1 - WHERE - entity_id = ".$pdo->quote($entity->id)." AND - entity_type = ".$pdo->quote($entity->getEntityName())." AND - email_address_id = ".$pdo->quote($emailAddress->id)." AND - deleted = 0 - "; - $sth = $pdo->prepare($query); - $sth->execute(); - } - } - - - } else { - $entityRepository = $this->getEntityManager()->getRepository($entity->getEntityName()); - if (!empty($email)) { - if ($email != $entity->getFetched('emailAddress')) { + + foreach ($hash as $key => $data) { + $new = true; + $changed = false; + + if ($hash[$key]['primary']) { + $primary = $key; + } + + if (array_key_exists($key, $hashPrev)) { + $new = false; + $changed = $hash[$key]['optOut'] != $hashPrev[$key]['optOut'] || $hash[$key]['invalid'] != $hashPrev[$key]['invalid']; + if ($hash[$key]['primary']) { + if ($hash[$key]['primary'] == $hashPrev[$key]['primary']) { + $primary = false; + } + } + } + + if ($new) { + $toCreate[] = $key; + } + if ($changed) { + $toUpdate[] = $key; + } + } + + foreach ($hashPrev as $key => $data) { + if (!array_key_exists($key, $hash)) { + $toRemove[] = $key; + } + } + + foreach ($toRemove as $address) { + $emailAddress = $this->getByAddress($address); + if ($emailAddress) { + $query = " + UPDATE entity_email_address + SET `deleted` = 1, `primary` = 0 + WHERE + entity_id = ".$pdo->quote($entity->id)." AND + entity_type = ".$pdo->quote($entity->getEntityName())." AND + email_address_id = ".$pdo->quote($emailAddress->id)." + "; + $sth = $pdo->prepare($query); + $sth->execute(); + } + } + + foreach ($toUpdate as $address) { + $emailAddress = $this->getByAddress($address); + if ($emailAddress) { + $emailAddress->set(array( + 'optOut' => $hash[$address]['optOut'], + 'invalid' => $hash[$address]['invalid'], + )); + $this->save($emailAddress); + } + } + + foreach ($toCreate as $address) { + $emailAddress = $this->getByAddress($address); + if (!$emailAddress) { + $emailAddress = $this->get(); + + $emailAddress->set(array( + 'name' => $address, + 'optOut' => $hash[$address]['optOut'], + 'invalid' => $hash[$address]['invalid'], + )); + $this->save($emailAddress); + } else { + if ($emailAddress->get('optOut') != $hash[$address]['optOut'] || $emailAddress->get('invalid') != $hash[$address]['invalid']) { + $emailAddress->set(array( + 'optOut' => $hash[$address]['optOut'], + 'invalid' => $hash[$address]['invalid'], + )); + $this->save($emailAddress); + } + } + + $query = " + INSERT entity_email_address + (entity_id, entity_type, email_address_id, `primary`) + VALUES + ( + ".$pdo->quote($entity->id).", + ".$pdo->quote($entity->getEntityName()).", + ".$pdo->quote($emailAddress->id).", + ".$pdo->quote($address === $primary)." + ) + "; + $sth = $pdo->prepare($query); + $sth->execute(); + } + + if ($primary) { + $emailAddress = $this->getByAddress($primary); + if ($emailAddress) { + $query = " + UPDATE entity_email_address + SET `primary` = 0 + WHERE + entity_id = ".$pdo->quote($entity->id)." AND + entity_type = ".$pdo->quote($entity->getEntityName())." AND + `primary` = 1 AND + deleted = 0 + "; + $sth = $pdo->prepare($query); + $sth->execute(); + + $query = " + UPDATE entity_email_address + SET `primary` = 1 + WHERE + entity_id = ".$pdo->quote($entity->id)." AND + entity_type = ".$pdo->quote($entity->getEntityName())." AND + email_address_id = ".$pdo->quote($emailAddress->id)." AND + deleted = 0 + "; + $sth = $pdo->prepare($query); + $sth->execute(); + } + } + + + } else { + $entityRepository = $this->getEntityManager()->getRepository($entity->getEntityName()); + if (!empty($email)) { + if ($email != $entity->getFetched('emailAddress')) { - $emailAddressNew = $this->where(array('lower' => strtolower($email)))->findOne(); - $isNewEmailAddress = false; - if (!$emailAddressNew) { - $emailAddressNew = $this->get(); - $emailAddressNew->set('name', $email); - $this->save($emailAddressNew); - $isNewEmailAddress = true; - } + $emailAddressNew = $this->where(array('lower' => strtolower($email)))->findOne(); + $isNewEmailAddress = false; + if (!$emailAddressNew) { + $emailAddressNew = $this->get(); + $emailAddressNew->set('name', $email); + $this->save($emailAddressNew); + $isNewEmailAddress = true; + } - $emailOld = $entity->getFetched('emailAddress'); - if (!empty($emailOld)) { - $emailAddressOld = $this->getByAddress($emailOld); - $entityRepository->unrelate($entity, 'emailAddresses', $emailAddressOld); - } - $entityRepository->relate($entity, 'emailAddresses', $emailAddressNew); + $emailOld = $entity->getFetched('emailAddress'); + if (!empty($emailOld)) { + $emailAddressOld = $this->getByAddress($emailOld); + $entityRepository->unrelate($entity, 'emailAddresses', $emailAddressOld); + } + $entityRepository->relate($entity, 'emailAddresses', $emailAddressNew); - $query = " - UPDATE entity_email_address - SET `primary` = 1 - WHERE - entity_id = ".$pdo->quote($entity->id)." AND - entity_type = ".$pdo->quote($entity->getEntityName())." AND - email_address_id = ".$pdo->quote($emailAddressNew->id)." - "; - $sth = $pdo->prepare($query); - $sth->execute(); - } - } else { - $emailOld = $entity->getFetched('emailAddress'); - if (!empty($emailOld)) { - $emailAddressOld = $this->getByAddress($emailOld); - $entityRepository->unrelate($entity, 'emailAddresses', $emailAddressOld); - } - } - } - } + $query = " + UPDATE entity_email_address + SET `primary` = 1 + WHERE + entity_id = ".$pdo->quote($entity->id)." AND + entity_type = ".$pdo->quote($entity->getEntityName())." AND + email_address_id = ".$pdo->quote($emailAddressNew->id)." + "; + $sth = $pdo->prepare($query); + $sth->execute(); + } + } else { + $emailOld = $entity->getFetched('emailAddress'); + if (!empty($emailOld)) { + $emailAddressOld = $this->getByAddress($emailOld); + $entityRepository->unrelate($entity, 'emailAddresses', $emailAddressOld); + } + } + } + } } diff --git a/application/Espo/Repositories/ExternalAccount.php b/application/Espo/Repositories/ExternalAccount.php index 1f029ab73c..a010221b20 100644 --- a/application/Espo/Repositories/ExternalAccount.php +++ b/application/Espo/Repositories/ExternalAccount.php @@ -26,14 +26,14 @@ 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; - } + public function get($id = null) + { + $entity = parent::get($id); + if (empty($entity) && !empty($id)) { + $entity = $this->get(); + $entity->id = $id; + } + return $entity; + } } diff --git a/application/Espo/Repositories/Integration.php b/application/Espo/Repositories/Integration.php index 63840582f9..47c06f8cc9 100644 --- a/application/Espo/Repositories/Integration.php +++ b/application/Espo/Repositories/Integration.php @@ -26,14 +26,14 @@ 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; - } + public function get($id = null) + { + $entity = parent::get($id); + if (empty($entity) && !empty($id)) { + $entity = $this->get(); + $entity->id = $id; + } + return $entity; + } } diff --git a/application/Espo/Repositories/PhoneNumber.php b/application/Espo/Repositories/PhoneNumber.php index ad079a05f6..8f5ff2e668 100644 --- a/application/Espo/Repositories/PhoneNumber.php +++ b/application/Espo/Repositories/PhoneNumber.php @@ -26,286 +26,286 @@ use Espo\ORM\Entity; class PhoneNumber extends \Espo\Core\ORM\Repositories\RDB { - public function getIds($arr = array()) - { - $ids = array(); - if (!empty($arr)) { - $a = array_map(function ($item) { - return $item; - }, $arr); - $phoneNumbers = $this->where(array( - 'name' => array_map(function ($item) { - return $item; - }, $arr) - ))->find(); - $ids = array(); - $exist = array(); - foreach ($phoneNumbers as $phoneNumber) { - $ids[] = $phoneNumber->id; - $exist[] = $phoneNumber->get('name'); - } - foreach ($arr as $phone) { - if (empty($phone)) { - continue; - } - if (!in_array($phone, $exist)) { - $phoneNumber = $this->get(); - $phoneNumber->set('name', $phone); - $this->save($phoneNumber); - $ids[] = $phoneNumber->id; - } - } - } - return $ids; - } - - public function getPhoneNumberData(Entity $entity) - { - $data = array(); - - $pdo = $this->getEntityManager()->getPDO(); - $sql = " - SELECT phone_number.name, phone_number.type, entity_phone_number.primary - FROM entity_phone_number - JOIN phone_number ON phone_number.id = entity_phone_number.phone_number_id AND phone_number.deleted = 0 - WHERE - entity_phone_number.entity_id = ".$pdo->quote($entity->id)." AND - entity_phone_number.entity_type = ".$pdo->quote($entity->getEntityName())." AND - entity_phone_number.deleted = 0 - ORDER BY entity_phone_number.primary DESC - "; - $sth = $pdo->prepare($sql); - $sth->execute(); - if ($rows = $sth->fetchAll()) { - foreach ($rows as $row) { - $obj = new \StdClass(); - $obj->phoneNumber = $row['name']; - $obj->primary = ($row['primary'] == '1') ? true : false; - $obj->type = $row['type']; - - $data[] = $obj; - } - } - - return $data; - } - - public function getByNumber($number) - { - return $this->where(array('name' => $number))->findOne(); - } - - public function storeEntityPhoneNumber(Entity $entity) - { - $phone = trim($entity->get('phoneNumber')); - $phoneNumberData = null; - - if ($entity->has('phoneNumberData')) { - $phoneNumberData = $entity->get('phoneNumberData'); - } - - $pdo = $this->getEntityManager()->getPDO(); - - if ($phoneNumberData !== null && is_array($phoneNumberData)) { - $previousPhoneNumberData = array(); - if (!$entity->isNew()) { - $previousPhoneNumberData = $this->getPhoneNumberData($entity); - } - - $hash = array(); - foreach ($phoneNumberData as $row) { - $key = $row->phoneNumber; - if (!empty($key)) { - $hash[$key] = array( - 'primary' => $row->primary ? true : false, - 'type' => $row->type, - ); - } - } - - $hashPrev = array(); - foreach ($previousPhoneNumberData as $row) { - $key = $row->phoneNumber; - if (!empty($key)) { - $hashPrev[$key] = array( - 'primary' => $row->primary ? true : false, - 'type' => $row->type, - ); - } - } - - $primary = false; - $toCreate = array(); - $toUpdate = array(); - $toRemove = array(); + public function getIds($arr = array()) + { + $ids = array(); + if (!empty($arr)) { + $a = array_map(function ($item) { + return $item; + }, $arr); + $phoneNumbers = $this->where(array( + 'name' => array_map(function ($item) { + return $item; + }, $arr) + ))->find(); + $ids = array(); + $exist = array(); + foreach ($phoneNumbers as $phoneNumber) { + $ids[] = $phoneNumber->id; + $exist[] = $phoneNumber->get('name'); + } + foreach ($arr as $phone) { + if (empty($phone)) { + continue; + } + if (!in_array($phone, $exist)) { + $phoneNumber = $this->get(); + $phoneNumber->set('name', $phone); + $this->save($phoneNumber); + $ids[] = $phoneNumber->id; + } + } + } + return $ids; + } + + public function getPhoneNumberData(Entity $entity) + { + $data = array(); + + $pdo = $this->getEntityManager()->getPDO(); + $sql = " + SELECT phone_number.name, phone_number.type, entity_phone_number.primary + FROM entity_phone_number + JOIN phone_number ON phone_number.id = entity_phone_number.phone_number_id AND phone_number.deleted = 0 + WHERE + entity_phone_number.entity_id = ".$pdo->quote($entity->id)." AND + entity_phone_number.entity_type = ".$pdo->quote($entity->getEntityName())." AND + entity_phone_number.deleted = 0 + ORDER BY entity_phone_number.primary DESC + "; + $sth = $pdo->prepare($sql); + $sth->execute(); + if ($rows = $sth->fetchAll()) { + foreach ($rows as $row) { + $obj = new \StdClass(); + $obj->phoneNumber = $row['name']; + $obj->primary = ($row['primary'] == '1') ? true : false; + $obj->type = $row['type']; + + $data[] = $obj; + } + } + + return $data; + } + + public function getByNumber($number) + { + return $this->where(array('name' => $number))->findOne(); + } + + public function storeEntityPhoneNumber(Entity $entity) + { + $phone = trim($entity->get('phoneNumber')); + $phoneNumberData = null; + + if ($entity->has('phoneNumberData')) { + $phoneNumberData = $entity->get('phoneNumberData'); + } + + $pdo = $this->getEntityManager()->getPDO(); + + if ($phoneNumberData !== null && is_array($phoneNumberData)) { + $previousPhoneNumberData = array(); + if (!$entity->isNew()) { + $previousPhoneNumberData = $this->getPhoneNumberData($entity); + } + + $hash = array(); + foreach ($phoneNumberData as $row) { + $key = $row->phoneNumber; + if (!empty($key)) { + $hash[$key] = array( + 'primary' => $row->primary ? true : false, + 'type' => $row->type, + ); + } + } + + $hashPrev = array(); + foreach ($previousPhoneNumberData as $row) { + $key = $row->phoneNumber; + if (!empty($key)) { + $hashPrev[$key] = array( + 'primary' => $row->primary ? true : false, + 'type' => $row->type, + ); + } + } + + $primary = false; + $toCreate = array(); + $toUpdate = array(); + $toRemove = array(); - - foreach ($hash as $key => $data) { - $new = true; - $changed = false; - - if ($hash[$key]['primary']) { - $primary = $key; - } - - if (array_key_exists($key, $hashPrev)) { - $new = false; - $changed = $hash[$key]['type'] != $hashPrev[$key]['type']; - if ($hash[$key]['primary']) { - if ($hash[$key]['primary'] == $hashPrev[$key]['primary']) { - $primary = false; - } - } - } - - if ($new) { - $toCreate[] = $key; - } - if ($changed) { - $toUpdate[] = $key; - } - } - - foreach ($hashPrev as $key => $data) { - if (!array_key_exists($key, $hash)) { - $toRemove[] = $key; - } - } - - foreach ($toRemove as $number) { - $phoneNumber = $this->getByNumber($number); - if ($phoneNumber) { - $query = " - UPDATE entity_phone_number - SET `deleted` = 1, `primary` = 0 - WHERE - entity_id = ".$pdo->quote($entity->id)." AND - entity_type = ".$pdo->quote($entity->getEntityName())." AND - phone_number_id = ".$pdo->quote($phoneNumber->id)." - "; - $sth = $pdo->prepare($query); - $sth->execute(); - } - } - - foreach ($toUpdate as $number) { - $phoneNumber = $this->getByNumber($number); - if ($phoneNumber) { - $phoneNumber->set(array( - 'type' => $hash[$number]['type'], - )); - $this->save($phoneNumber); - } - } - - foreach ($toCreate as $number) { - $phoneNumber = $this->getByNumber($number); - if (!$phoneNumber) { - $phoneNumber = $this->get(); - - $phoneNumber->set(array( - 'name' => $number, - 'type' => $hash[$number]['type'], - )); - $this->save($phoneNumber); - } else { - if ($phoneNumber->get('type') != $hash[$number]['type']) { - $phoneNumber->set(array( - 'type' => $hash[$number]['type'], - )); - $this->save($phoneNumber); - } - } - - $query = " - INSERT entity_phone_number - (entity_id, entity_type, phone_number_id, `primary`) - VALUES - ( - ".$pdo->quote($entity->id).", - ".$pdo->quote($entity->getEntityName()).", - ".$pdo->quote($phoneNumber->id).", - ".$pdo->quote($number === $primary)." - ) - "; - $sth = $pdo->prepare($query); - $sth->execute(); - } - - if ($primary) { - $phoneNumber = $this->getByNumber($primary); - if ($phoneNumber) { - $query = " - UPDATE entity_phone_number - SET `primary` = 0 - WHERE - entity_id = ".$pdo->quote($entity->id)." AND - entity_type = ".$pdo->quote($entity->getEntityName())." AND - `primary` = 1 AND - deleted = 0 - "; - $sth = $pdo->prepare($query); - $sth->execute(); - - $query = " - UPDATE entity_phone_number - SET `primary` = 1 - WHERE - entity_id = ".$pdo->quote($entity->id)." AND - entity_type = ".$pdo->quote($entity->getEntityName())." AND - phone_number_id = ".$pdo->quote($phoneNumber->id)." AND - deleted = 0 - "; - $sth = $pdo->prepare($query); - $sth->execute(); - } - } - - - } else { - $entityRepository = $this->getEntityManager()->getRepository($entity->getEntityName()); - if (!empty($phone)) { - if ($phone != $entity->getFetched('phoneNumber')) { + + foreach ($hash as $key => $data) { + $new = true; + $changed = false; + + if ($hash[$key]['primary']) { + $primary = $key; + } + + if (array_key_exists($key, $hashPrev)) { + $new = false; + $changed = $hash[$key]['type'] != $hashPrev[$key]['type']; + if ($hash[$key]['primary']) { + if ($hash[$key]['primary'] == $hashPrev[$key]['primary']) { + $primary = false; + } + } + } + + if ($new) { + $toCreate[] = $key; + } + if ($changed) { + $toUpdate[] = $key; + } + } + + foreach ($hashPrev as $key => $data) { + if (!array_key_exists($key, $hash)) { + $toRemove[] = $key; + } + } + + foreach ($toRemove as $number) { + $phoneNumber = $this->getByNumber($number); + if ($phoneNumber) { + $query = " + UPDATE entity_phone_number + SET `deleted` = 1, `primary` = 0 + WHERE + entity_id = ".$pdo->quote($entity->id)." AND + entity_type = ".$pdo->quote($entity->getEntityName())." AND + phone_number_id = ".$pdo->quote($phoneNumber->id)." + "; + $sth = $pdo->prepare($query); + $sth->execute(); + } + } + + foreach ($toUpdate as $number) { + $phoneNumber = $this->getByNumber($number); + if ($phoneNumber) { + $phoneNumber->set(array( + 'type' => $hash[$number]['type'], + )); + $this->save($phoneNumber); + } + } + + foreach ($toCreate as $number) { + $phoneNumber = $this->getByNumber($number); + if (!$phoneNumber) { + $phoneNumber = $this->get(); + + $phoneNumber->set(array( + 'name' => $number, + 'type' => $hash[$number]['type'], + )); + $this->save($phoneNumber); + } else { + if ($phoneNumber->get('type') != $hash[$number]['type']) { + $phoneNumber->set(array( + 'type' => $hash[$number]['type'], + )); + $this->save($phoneNumber); + } + } + + $query = " + INSERT entity_phone_number + (entity_id, entity_type, phone_number_id, `primary`) + VALUES + ( + ".$pdo->quote($entity->id).", + ".$pdo->quote($entity->getEntityName()).", + ".$pdo->quote($phoneNumber->id).", + ".$pdo->quote($number === $primary)." + ) + "; + $sth = $pdo->prepare($query); + $sth->execute(); + } + + if ($primary) { + $phoneNumber = $this->getByNumber($primary); + if ($phoneNumber) { + $query = " + UPDATE entity_phone_number + SET `primary` = 0 + WHERE + entity_id = ".$pdo->quote($entity->id)." AND + entity_type = ".$pdo->quote($entity->getEntityName())." AND + `primary` = 1 AND + deleted = 0 + "; + $sth = $pdo->prepare($query); + $sth->execute(); + + $query = " + UPDATE entity_phone_number + SET `primary` = 1 + WHERE + entity_id = ".$pdo->quote($entity->id)." AND + entity_type = ".$pdo->quote($entity->getEntityName())." AND + phone_number_id = ".$pdo->quote($phoneNumber->id)." AND + deleted = 0 + "; + $sth = $pdo->prepare($query); + $sth->execute(); + } + } + + + } else { + $entityRepository = $this->getEntityManager()->getRepository($entity->getEntityName()); + if (!empty($phone)) { + if ($phone != $entity->getFetched('phoneNumber')) { - $phoneNumberNew = $this->where(array('name' => $phone))->findOne(); - $isNewPhoneNumber = false; - if (!$phoneNumberNew) { - $phoneNumberNew = $this->get(); - $phoneNumberNew->set('name', $phone); - $defaultType = $this->getEntityManager()->getEspoMetadata()->get('entityDefs.' . $entity->getEntityName() . '.fields.phoneNumber.defaultType'); - - $phoneNumberNew->set('type', $defaultType); - - $this->save($phoneNumberNew); - $isNewPhoneNumber = true; - } + $phoneNumberNew = $this->where(array('name' => $phone))->findOne(); + $isNewPhoneNumber = false; + if (!$phoneNumberNew) { + $phoneNumberNew = $this->get(); + $phoneNumberNew->set('name', $phone); + $defaultType = $this->getEntityManager()->getEspoMetadata()->get('entityDefs.' . $entity->getEntityName() . '.fields.phoneNumber.defaultType'); + + $phoneNumberNew->set('type', $defaultType); + + $this->save($phoneNumberNew); + $isNewPhoneNumber = true; + } - $phoneOld = $entity->getFetched('phoneNumber'); - if (!empty($phoneOld)) { - $phoneNumberOld = $this->getByNumber($phoneOld); - $entityRepository->unrelate($entity, 'phoneNumbers', $phoneNumberOld); - } - $entityRepository->relate($entity, 'phoneNumbers', $phoneNumberNew); + $phoneOld = $entity->getFetched('phoneNumber'); + if (!empty($phoneOld)) { + $phoneNumberOld = $this->getByNumber($phoneOld); + $entityRepository->unrelate($entity, 'phoneNumbers', $phoneNumberOld); + } + $entityRepository->relate($entity, 'phoneNumbers', $phoneNumberNew); - $query = " - UPDATE entity_phone_number - SET `primary` = 1 - WHERE - entity_id = ".$pdo->quote($entity->id)." AND - entity_type = ".$pdo->quote($entity->getEntityName())." AND - phone_number_id = ".$pdo->quote($phoneNumberNew->id)." - "; - $sth = $pdo->prepare($query); - $sth->execute(); - } - } else { - $phoneOld = $entity->getFetched('phoneNumber'); - if (!empty($phoneOld)) { - $phoneNumberOld = $this->getByNumber($phoneOld); - $entityRepository->unrelate($entity, 'phoneNumbers', $phoneNumberOld); - } - } - } - } + $query = " + UPDATE entity_phone_number + SET `primary` = 1 + WHERE + entity_id = ".$pdo->quote($entity->id)." AND + entity_type = ".$pdo->quote($entity->getEntityName())." AND + phone_number_id = ".$pdo->quote($phoneNumberNew->id)." + "; + $sth = $pdo->prepare($query); + $sth->execute(); + } + } else { + $phoneOld = $entity->getFetched('phoneNumber'); + if (!empty($phoneOld)) { + $phoneNumberOld = $this->getByNumber($phoneOld); + $entityRepository->unrelate($entity, 'phoneNumbers', $phoneNumberOld); + } + } + } + } } diff --git a/application/Espo/Repositories/Preferences.php b/application/Espo/Repositories/Preferences.php index 086c8f7be7..b3412f485e 100644 --- a/application/Espo/Repositories/Preferences.php +++ b/application/Espo/Repositories/Preferences.php @@ -26,115 +26,124 @@ use Espo\ORM\Entity; class Preferences extends \Espo\Core\ORM\Repository { - protected $dependencies = array( - 'fileManager', - 'metadata', - 'config', - ); - - protected $defaultAttributesFromSettings = array( - 'defaultCurrency', - 'dateFormat', - 'timeFormat', - 'decimalMark', - 'thousandSeparator', - 'weekStart', - 'timeZone', - 'language', - 'exportDelimiter' - ); - - protected $data = array(); - - protected $entityName = 'Preferences'; - - protected function getFileManager() - { - return $this->getInjection('fileManager'); - } - - protected function getMetadata() - { - return $this->getInjection('metadata'); - } - - protected function getConfig() - { - return $this->getInjection('config'); - } - - protected function getFilePath($id) - { - return 'data/preferences/' . $id . '.json'; - } - - public function get($id = null) - { - if ($id) { - $entity = $this->entityFactory->create('Preferences'); - $entity->id = $id; - if (empty($this->data[$id])) { - $fileName = $this->getFilePath($id); - - if (file_exists($fileName)) { - $this->data[$id] = json_decode($this->getFileManager()->getContents($fileName), true); - } else { - $fields = $this->getMetadata()->get('entityDefs.Preferences.fields'); - $defaults = array(); - $defaults['dashboardLayout'] = $this->getMetadata()->get('app.defaultDashboardLayout'); - foreach ($fields as $field => $d) { - if (array_key_exists('default', $d)) { - $defaults[$field] = $d['default']; - } - } - foreach ($this->defaultAttributesFromSettings as $attr) { - $defaults[$attr] = $this->getConfig()->get($attr); - } - - $this->data[$id] = $defaults; - } - } - - $entity->set($this->data[$id]); - $d = $entity->toArray(); - return $entity; - } - } - - public function save(Entity $entity) - { - if ($entity->id) { - $this->data[$entity->id] = $entity->toArray(); - - $fileName = $this->getFilePath($entity->id); - $this->getFileManager()->putContents($fileName, json_encode($this->data[$entity->id])); - return $entity; - } - } - - public function remove(Entity $entity) - { - $fileName = $this->getFilePath($id); - unlink($fileName); - if (!file_exists($fileName)) { - return true; - } - } + protected $dependencies = array( + 'fileManager', + 'metadata', + 'config', + ); + + protected $defaultAttributesFromSettings = array( + 'defaultCurrency', + 'dateFormat', + 'timeFormat', + 'decimalMark', + 'thousandSeparator', + 'weekStart', + 'timeZone', + 'language', + 'exportDelimiter' + ); + + protected $data = array(); + + protected $entityName = 'Preferences'; + + protected function getFileManager() + { + return $this->getInjection('fileManager'); + } + + protected function getMetadata() + { + return $this->getInjection('metadata'); + } + + protected function getConfig() + { + return $this->getInjection('config'); + } + + protected function getFilePath($id) + { + return 'data/preferences/' . $id . '.json'; + } + + public function get($id = null) + { + if ($id) { + $entity = $this->entityFactory->create('Preferences'); + $entity->id = $id; + if (empty($this->data[$id])) { + $fileName = $this->getFilePath($id); + + if (file_exists($fileName)) { + $this->data[$id] = json_decode($this->getFileManager()->getContents($fileName), true); + } else { + $fields = $this->getMetadata()->get('entityDefs.Preferences.fields'); + $defaults = array(); + $defaults['dashboardLayout'] = $this->getMetadata()->get('app.defaultDashboardLayout'); + foreach ($fields as $field => $d) { + if (array_key_exists('default', $d)) { + $defaults[$field] = $d['default']; + } + } + foreach ($this->defaultAttributesFromSettings as $attr) { + $defaults[$attr] = $this->getConfig()->get($attr); + } + + $this->data[$id] = $defaults; + } + } + + $entity->set($this->data[$id]); + $d = $entity->toArray(); + return $entity; + } + } + + public function save(Entity $entity) + { + if ($entity->id) { + $this->data[$entity->id] = $entity->toArray(); + + $fileName = $this->getFilePath($entity->id); + $this->getFileManager()->putContents($fileName, json_encode($this->data[$entity->id])); + return $entity; + } + } + + public function remove(Entity $entity) + { + $fileName = $this->getFilePath($id); + unlink($fileName); + if (!file_exists($fileName)) { + return true; + } + } + + public function resetToDefaults($userId) + { + $fileName = $this->getFilePath($userId); + $this->getFileManager()->unlink($fileName); + if ($entity = $this->get($userId)) { + return $entity->toArray(); + } + } - public function find(array $params) - { - } - - public function findOne(array $params) - { - } + public function find(array $params) + { + } + + public function findOne(array $params) + { + } - public function getAll() - { - } - - public function count(array $params) - { - } + public function getAll() + { + } + + public function count(array $params) + { + } } diff --git a/application/Espo/Repositories/UniqueId.php b/application/Espo/Repositories/UniqueId.php index 20772a3640..2b82c61855 100644 --- a/application/Espo/Repositories/UniqueId.php +++ b/application/Espo/Repositories/UniqueId.php @@ -26,11 +26,11 @@ use Espo\ORM\Entity; class UniqueId extends \Espo\Core\ORM\Repositories\RDB { - protected function getNewEntity() - { - $entity = parent::getNewEntity(); - $entity->set('name', uniqid()); - return $entity; - } + protected function getNewEntity() + { + $entity = parent::getNewEntity(); + $entity->set('name', uniqid()); + return $entity; + } } diff --git a/application/Espo/Repositories/User.php b/application/Espo/Repositories/User.php index e5007a37c9..e78bfcd94f 100644 --- a/application/Espo/Repositories/User.php +++ b/application/Espo/Repositories/User.php @@ -28,37 +28,37 @@ use \Espo\Core\Exceptions\Error; class User extends \Espo\Core\ORM\Repositories\RDB { - protected function beforeSave(Entity $entity) - { - if ($entity->isNew()) { - $userName = $entity->get('userName'); - if (empty($userName)) { - throw new Error(); - } - - $user = $this->where(array( - 'userName' => $userName - ))->findOne(); - - if ($user) { - throw new Error(); - } - } else { - if ($entity->isFieldChanged('userName')) { - $userName = $entity->get('userName'); - if (empty($userName)) { - throw new Error(); - } - - $user = $this->where(array( - 'userName' => $userName, - 'id!=' => $entity->id - ))->findOne(); - if ($user) { - throw new Error(); - } - } - } - } + protected function beforeSave(Entity $entity) + { + if ($entity->isNew()) { + $userName = $entity->get('userName'); + if (empty($userName)) { + throw new Error(); + } + + $user = $this->where(array( + 'userName' => $userName + ))->findOne(); + + if ($user) { + throw new Error(); + } + } else { + if ($entity->isFieldChanged('userName')) { + $userName = $entity->get('userName'); + if (empty($userName)) { + throw new Error(); + } + + $user = $this->where(array( + 'userName' => $userName, + 'id!=' => $entity->id + ))->findOne(); + if ($user) { + throw new Error(); + } + } + } + } } diff --git a/application/Espo/Resources/i18n/de_DE/Admin.json b/application/Espo/Resources/i18n/de_DE/Admin.json index 4bdde3c7c5..fef2b03caf 100644 --- a/application/Espo/Resources/i18n/de_DE/Admin.json +++ b/application/Espo/Resources/i18n/de_DE/Admin.json @@ -1,128 +1,145 @@ { - "labels": { - "Enabled": "Aktiv", - "Disabled": "Inaktiv", - "System": "System", - "Users": "Benutzer", - "Email": "E-Mail", - "Data": "Daten", - "Customization": "Anpassung", - "Available Fields": "Verfügbare Felder", - "Layout": "Aktuelles Layout", - "Enabled": "Aktiv", - "Disabled": "Inaktiv", - "Add Panel": "Panel hinzufügen", - "Add Field": "Feld hinzufügen", - "Settings": "Einstellungen", - "Scheduled Jobs": "Geplante Jobs", - "Upgrade": "Upgrade", - "Clear Cache": "Cache leeren", - "Rebuild": "Neu aufbauen", - "Users": "Benutzer", - "Teams": "Teams", - "Roles": "Rollen", - "Outbound Emails": "Ausgehende E-Mails", - "Inbound Emails": "Eingehende E-Mails", - "Email Templates": "E-Mail Vorlagen", - "Import": "Import", - "Layout Manager": "Layouts anpassen", - "Field Manager": "Felder anpassen", - "User Interface": "Benutzeroberfläche", - "Auth Tokens": "Auth Tokens", - "Authentication": "Authentifizierung:", - "Currency": "Währung" - }, - "layouts": { - "list": "Liste", - "detail": "Detail", - "listSmall": "Liste (Klein)", - "detailSmall": "Detail (Klein)", - "filters": "Suchfilter", - "massUpdate": "Massenänderung", - "relationships": "Beziehungen" - }, - "fieldTypes": { - "address": "Adresse", - "array": "Array", - "foreign": "Fremd", - "duration": "Dauer", - "password": "Passwort", - "parsonName": "Person Name", - "autoincrement": "Automatisch hochzählen", - "bool": "Bool", - "currency": "Währung", - "date": "Datum", - "datetime": "Datum\/Zeit", - "email": "E-Mail", - "enum": "Einfachauswahl", - "enumInt": "Einfachauswahl Ganzzahlwerte", - "enumFloat": "Einfachauswahl Fließkommawerte", - "float": "Fließkomma", - "int": "Ganzzahl", - "link": "Link", - "linkMultiple": "Mehrfachlinks", - "linkParent": "Mutterlink", - "multienim": "Mehrfachauswahl", - "phone": "Telefon", - "text": "Textbox", - "url": "URL", - "varchar": "Text (max. 255)", - "file": "Datei", - "image": "Bild" - }, - "fields": { - "type": "Typ", - "name": "Name", - "label": "Bezeichnung", - "required": "Erforderlich", - "default": "Standard", - "maxLength": "Maximallänge", - "options": "Optionen (Datenbank Werte, nicht übersetzt)", - "after": "Nach (Feld)", - "before": "Vor (Feld)", - "link": "Link", - "field": "Feld", - "min": "Min", - "max": "Max", - "translation": "Übersetzung", - "previewSize": "Vorschau Größe" - }, - "messages": { - "upgradeVersion": "Ihr EspoCRM wird nun auf Version {version}<\/strong> aktualisiert. Dies kann eine Weile dauern.", - "upgradeDone": "Ihr EspoCRM wurde auf Version {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.", - "selectEntityType": "Modul links auswählen", - "selectUpgradePackage": "Aktualisierungspaket auswählen", - "selectLayout": "Layout zum Editieren links auswählen" - }, - "descriptions": { - "settings": "Systemeinstellungen der Applikation.", - "scheduledJob": "Aufgaben die durch einen Cronjob ausgeführt werden.", - "upgrade": "EspoCRM aktualisieren.", - "clearCache": "Alle Cache Dateien leeren.", - "rebuild": "Wiederherstellung des Backends und Leeren des Cache.", - "users": "Benutzerverwaltung.", - "teams": "Teamverwaltung.", - "roles": "Rollenverwaltung.", - "outboundEmails": "SMTP Einstellungen für ausgehende E-Mails.", - "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": "Layouts anpassen (Liste, Detailansicht, Bearbeitungsansicht, Suche, Massenaktualisierung).", - "fieldManager": "Neue Felder erstellen oder bestehende anpassen.", - "userInterface": "Benutzeroberfläche anpassen.", - "authTokens": "Aktive Auth Sessions. IP Adresse und letztes Zugriffsdatum", - "authentication": "Authentifizierungs Einstellungen.", - "currency": "Währungseinstellungen und Kurse" - }, - "options": { - "previewSize": { - "x-small": "X-Small", - "small": "Small", - "medium": "Medium", - "large": "Large" - } - } + "labels": { + "Enabled": "Aktiv", + "Disabled": "Inaktiv", + "System": "System", + "Users": "Benutzer", + "Email": "E-Mail", + "Data": "Daten", + "Customization": "Anpassung", + "Available Fields": "Verfügbare Felder", + "Layout": "Aktuelles Layout", + "Add Panel": "Panel hinzufügen", + "Add Field": "Feld hinzufügen", + "Settings": "Einstellungen", + "Scheduled Jobs": "Geplante Jobs", + "Upgrade": "Aktualisierung", + "Clear Cache": "Cache leeren", + "Rebuild": "Neu aufbauen", + "Teams": "Teams", + "Roles": "Rollen", + "Outbound Emails": "Ausgehende E-Mails", + "Inbound Emails": "Eingehende E-Mails", + "Email Templates": "E-Mail Vorlagen", + "Import": "Import", + "Layout Manager": "Layouts anpassen", + "Field Manager": "Felder anpassen", + "User Interface": "Benutzeroberfläche", + "Auth Tokens": "Auth Tokens", + "Authentication": "Authentifizierung", + "Currency": "Währung", + "Integrations": "Integrationen", + "Extensions": "Erweiterungen", + "Upload": "Hochladen", + "Installing...": "Installiere...", + "Upgrading...": "Aktualisiere....", + "Upgraded successfully": "Erfolgreich aktualisiert", + "Installed successfully": "Erfolgreich installiert", + "Ready for upgrade": "Bereit für Aktualisierung", + "Run Upgrade": "Aktualisierung duchführen", + "Install": "Installieren", + "Ready for installation": "Bereit für Installation", + "Uninstalling...": "Deinstalliere...", + "Uninstalled": "Deinstalliert" + }, + "layouts": { + "list": "Liste", + "detail": "Detail", + "listSmall": "Liste (Klein)", + "detailSmall": "Detail (Klein)", + "filters": "Suchfilter", + "massUpdate": "Massenänderung", + "relationships": "Beziehungen" + }, + "fieldTypes": { + "address": "Adresse", + "array": "Mehrfachauswahl", + "foreign": "Fremdbezug", + "duration": "Dauer", + "password": "Passwort", + "parsonName": "Person Name", + "autoincrement": "Automatisch hochzählen", + "bool": "Bool", + "currency": "Währung", + "date": "Datum", + "datetime": "Datum/Zeit", + "email": "E-Mail", + "enum": "Einfachauswahl", + "enumInt": "Einfachauswahl Ganzzahlwerte", + "enumFloat": "Einfachauswahl Fließkommawerte", + "float": "Fließkomma", + "int": "Ganzzahl", + "link": "Link", + "linkMultiple": "Mehrfachlinks", + "linkParent": "Übergeordneter Link", + "multienim": "Mehrfachauswahl", + "phone": "Telefon", + "text": "Textbox", + "url": "URL", + "varchar": "Text (max. 255)", + "file": "Datei", + "image": "Bild", + "multiEnum": "Mehrfachauswahl" + }, + "fields": { + "type": "Typ", + "name": "Name", + "label": "Bezeichnung", + "required": "Erforderlich", + "default": "Standard", + "maxLength": "Maximallänge", + "options": "Optionen", + "after": "Nach (Feld)", + "before": "Vor (Feld)", + "link": "Link", + "field": "Feld", + "min": "Min", + "max": "Max", + "translation": "Übersetzung", + "previewSize": "Vorschau Größe" + }, + "messages": { + "upgradeVersion": "Ihr EspoCRM wird nun auf Version {version} aktualisiert. Dies kann einige Zeit dauern.", + "upgradeDone": "Ihr EspoCRM wurde auf Version {version} aktualisiert. Laden Sie Sie Ihr Browser Fenster neu.", + "upgradeBackup": "Wir empfehlen, vor der Aktualisierung von EspoCRM das Programmverzeichnis sowie die Datenbank zu sichern.", + "thousandSeparatorEqualsDecimalMark": "Das Tausendertrennzeichen kann nicht gleich dem Dezimaltrennzeichen sein", + "userHasNoEmailAddress": "Der Benutzer hat keine E-Mail Adresse.", + "selectEntityType": "Modul links auswählen", + "selectUpgradePackage": "Aktualisierungspaket auswählen", + "downloadUpgradePackage": "Benötigte Aktualisierungs Paket(e) hier herunterladen.", + "selectLayout": "Layout zum Editieren links auswählen", + "selectExtensionPackage": "Erweiterungspaket auswählen", + "extensionInstalled": "Erweiterung {name} {version} wurde installiert.", + "installExtension": "Erweiterung {name} {version} ist bereit für die Installation", + "uninstallConfirmation": "Wollen Sie die Erweiterung wirklich deinstallieren?" + }, + "descriptions": { + "settings": "Systemeinstellungen der Applikation.", + "scheduledJob": "Aufgaben die durch einen Cronjob ausgeführt werden.", + "upgrade": "EspoCRM aktualisieren.", + "clearCache": "Alle Cache Dateien leeren.", + "rebuild": "Wiederherstellung des Backends und Leeren des Cache.", + "users": "Benutzerverwaltung.", + "teams": "Teamverwaltung.", + "roles": "Rollenverwaltung.", + "outboundEmails": "SMTP Einstellungen für ausgehende E-Mails.", + "inboundEmails": "IMAP Gruppenkonten. E-Mail Import und E-Mails für Fälle.", + "emailTemplates": "Vorlagen für ausgehende E-Mails.", + "import": "Datenimport aus CSV Datei.", + "layoutManager": "Layouts anpassen (Liste, Detailansicht, Bearbeitungsansicht, Suche, Massenaktualisierung).", + "fieldManager": "Neue Felder erstellen oder bestehende anpassen.", + "userInterface": "Benutzeroberfläche anpassen.", + "authTokens": "Aktive Auth Sessions. IP Adresse und letztes Zugriffsdatum.", + "authentication": "Authentifizierungs Einstellungen.", + "currency": "Währungseinstellungen und Kurse", + "extensions": "Erweiterungen installieren oder deinstallieren" + }, + "options": { + "previewSize": { + "x-small": "X-Small", + "small": "Small", + "medium": "Medium", + "large": "Large" + } + } } diff --git a/application/Espo/Resources/i18n/de_DE/AuthToken.json b/application/Espo/Resources/i18n/de_DE/AuthToken.json index de64e57778..f654263f73 100644 --- a/application/Espo/Resources/i18n/de_DE/AuthToken.json +++ b/application/Espo/Resources/i18n/de_DE/AuthToken.json @@ -1,9 +1,9 @@ { - "fields": { - "user": "Benutzer", - "ipAddress": "IP Adresse", - "lastAccess": "Letztes Zugriffsdatum", - "createdAt": "Login Datum" + "fields": { + "user": "Benutzer", + "ipAddress": "IP Adresse", + "lastAccess": "Letztes Zugriffsdatum", + "createdAt": "Login Datum" - } + } } diff --git a/application/Espo/Resources/i18n/de_DE/DashletOptions.json b/application/Espo/Resources/i18n/de_DE/DashletOptions.json new file mode 100644 index 0000000000..3af2aff35d --- /dev/null +++ b/application/Espo/Resources/i18n/de_DE/DashletOptions.json @@ -0,0 +1,10 @@ +{ + "fields": { + "title": "Funktion", + "dateFrom": "Von Datum", + "dateTo": "Bis Datum", + "autorefreshInterval": "Aktualisierungsintervall", + "displayRecords": "Sätze anzeigen", + "isDoubleHeight": "Zweifache Höhe" + } +} diff --git a/application/Espo/Resources/i18n/de_DE/Email.json b/application/Espo/Resources/i18n/de_DE/Email.json index 26c19c5e34..e8c5dc2f44 100644 --- a/application/Espo/Resources/i18n/de_DE/Email.json +++ b/application/Espo/Resources/i18n/de_DE/Email.json @@ -1,36 +1,51 @@ { - "fields": { - "name": "Betreff", - "parent": "Bezieht sich auf", - "status": "Status", - "dateSent": "Sendedatum", - "from": "Von", - "to": "An", - "cc": "CC", - "bcc": "BCC", - "isHtml": "Ist HTML", - "body": "Inhalt", - "subject": "Betreff", - "attachments": "Anhänge", - "selectTemplate": "Vorlage wählen", - "fromEmailAddress": "Von Adresse", - "toEmailAddresses": "An Adresse", - "emailAddress": "E-Mail Adresse" - }, - "links": { - }, - "options": { - "Draft": "Entwurf", - "Sending": "wird gesendet", - "Sent": "Gesendet", - "Archived": "Archiviert" - }, - "labels": { - "Create Email": "E-Mail archivieren", - "Compose": "Erstellen" - }, - "presetFilters": { - "sent": "Gesendet", - "archived": "Archiviert" - } + "fields": { + "name": "Betreff", + "parent": "Bezieht sich auf", + "status": "Status", + "dateSent": "Sendedatum", + "from": "Von", + "to": "An", + "cc": "CC", + "bcc": "BCC", + "isHtml": "Ist HTML", + "body": "Inhalt", + "subject": "Betreff", + "attachments": "Anhänge", + "selectTemplate": "Vorlage wählen", + "fromEmailAddress": "Von Adresse", + "toEmailAddresses": "An Adresse", + "emailAddress": "E-Mail Adresse", + "deliveryDate": "Zustelldatum" + }, + "links": { + }, + "options": { + "Draft": "Entwurf", + "Sending": "Wird gesendet", + "Sent": "Gesendet", + "Archived": "Archiviert" + }, + "labels": { + "Create Email": "E-Mail archivieren", + "Archive Email": "E-Mail archivieren", + "Compose": "Erstellen", + "Reply": "Antworten", + "Reply to All": "Allen antworten", + "Forward": "Weiterleiten", + "Original message": "Originalnachricht", + "Forwarded message": "Weitergeleitete Nachricht:", + "Email Accounts": "E-Mail Konten", + "Send Test Email": "Test E-Mail senden", + "Send": "Senden", + "Email Address": "E-Mail Adresse" + }, + "messages": { + "noSmtpSetup": "Keine SMTP Einstellung, {link}. ", + "testEmailSent": "Eine Test E-Mail wurde gesendet" + }, + "presetFilters": { + "sent": "Gesendet", + "archived": "Archiviert" + } } diff --git a/application/Espo/Resources/i18n/de_DE/EmailAccount.json b/application/Espo/Resources/i18n/de_DE/EmailAccount.json new file mode 100644 index 0000000000..1d63d51046 --- /dev/null +++ b/application/Espo/Resources/i18n/de_DE/EmailAccount.json @@ -0,0 +1,29 @@ +{ + "fields": { + "name": "Name", + "status": "Status", + "host": "Host", + "username": "Benutzername", + "password": "Passwort", + "port": "Port", + "monitoredFolders": "Überwachte Ordner", + "ssl": "SSL", + "fetchSince": "Holen seit" + }, + "links": { + }, + "options": { + "status": { + "Active": "Aktiv", + "Inactive": "Inaktiv" + } + }, + "labels": { + "Create EmailAccount": "E-Mail Konto erstellen", + "IMAP": "IMAP", + "Main": "Wichtig" + }, + "messages": { + "couldNotConnectToImap": "Kann keine Verbindung zum IMAP Server herstellen" + } +} diff --git a/application/Espo/Resources/i18n/de_DE/EmailAddress.json b/application/Espo/Resources/i18n/de_DE/EmailAddress.json index 610168541b..f4d7d2e21d 100644 --- a/application/Espo/Resources/i18n/de_DE/EmailAddress.json +++ b/application/Espo/Resources/i18n/de_DE/EmailAddress.json @@ -1,7 +1,7 @@ { - "labels": { - "Primary": "Primär", - "Opted Out": "Keine E-Mails", - "Invalid": "Ungültig" - } + "labels": { + "Primary": "Primär", + "Opted Out": "Keine E-Mails", + "Invalid": "Ungültig" + } } diff --git a/application/Espo/Resources/i18n/de_DE/EmailTemplate.json b/application/Espo/Resources/i18n/de_DE/EmailTemplate.json index efd6c42953..b40970e594 100644 --- a/application/Espo/Resources/i18n/de_DE/EmailTemplate.json +++ b/application/Espo/Resources/i18n/de_DE/EmailTemplate.json @@ -1,16 +1,16 @@ { - "fields": { - "name": "Name", - "status": "Status", - "isHtml": "Ist HTML", - "body": "Inhalt", - "subject": "Betreff", - "attachments": "Anhänge", - "insertField": "" - }, - "links": { - }, - "labels": { - "Create EmailTemplate": "Neue E-Mail Vorlage" - } + "fields": { + "name": "Name", + "status": "Status", + "isHtml": "Ist HTML", + "body": "Inhalt", + "subject": "Betreff", + "attachments": "Anhänge", + "insertField": "Project-Id-Version: \nPOT-Creation-Date: \nPO-Revision-Date: \nLast-Translator: \nLanguage-Team: EspoCRM \nMIME-Version: 1.0\nContent-Type: text/plain; charset=UTF-8\nContent-Transfer-Encoding: 8bit\nLanguage: de_DE\n" + }, + "links": { + }, + "labels": { + "Create EmailTemplate": "E-Mail Vorlage erstellen" + } } diff --git a/application/Espo/Resources/i18n/de_DE/Extension.json b/application/Espo/Resources/i18n/de_DE/Extension.json new file mode 100644 index 0000000000..e273b67174 --- /dev/null +++ b/application/Espo/Resources/i18n/de_DE/Extension.json @@ -0,0 +1,15 @@ +{ + "fields": { + "name": "Name", + "version": "Version", + "description": "Beschreibung", + "isInstalled": "Installiert" + }, + "labels": { + "Uninstall": "Deinstallieren", + "Install": "Installieren" + }, + "messages": { + "uninstalled": "Erweiterung {name} wurde deinstalliert" + } +} diff --git a/application/Espo/Resources/i18n/de_DE/ExternalAccount.json b/application/Espo/Resources/i18n/de_DE/ExternalAccount.json new file mode 100644 index 0000000000..8bfae5ae26 --- /dev/null +++ b/application/Espo/Resources/i18n/de_DE/ExternalAccount.json @@ -0,0 +1,8 @@ +{ + "labels": { + "Connect": "Verbinden", + "Connected": "Verbunden" + }, + "help": { + } +} diff --git a/application/Espo/Resources/i18n/de_DE/Global.json b/application/Espo/Resources/i18n/de_DE/Global.json index e473de5f0c..dbb131731c 100644 --- a/application/Espo/Resources/i18n/de_DE/Global.json +++ b/application/Espo/Resources/i18n/de_DE/Global.json @@ -1,420 +1,450 @@ { - "scopeNames": { - "Email": "E-Mail", - "User": "Benutzer", - "Team": "Team", - "Role": "Rolle", - "EmailTemplate": "E-Mail Vorlage", - "OutboundEmail": "Ausgehende E-Mail", - "ScheduledJob": "Geplante Aufgabe" - }, - "scopeNamesPlural": { - "Email": "E-Mails", - "User": "Benutzer", - "Team": "Teams", - "Role": "Rollen", - "EmailTemplate": "E-Mail Vorlagen", - "OutboundEmail": "Ausgehende E-Mails", - "ScheduledJob": "Geplante Jobs" - }, - "labels": { - "Misc": "Verschiedenes", - "Merge": "Zusammenführen", - "None": "Kein(e)", - "by": "von", - "Saved": "Gespeichert.", - "Error": "Fehler", - "Select": "Auswählen", - "Not valid": "Ungültig", - "Please wait...": "Bitte warten...", - "Please wait": "Bitte warten", - "Loading...": "Lade...", - "Uploading...": "Lade hoch...", - "Sending...": "Wird gesendet...", - "Removed": "Entfernt", - "Posted": "Geposted", - "Linked": "Verlinkt", - "Unlinked": "Verknüpfung gelöscht", - "Access denied": "Zugriff verweigert", - "Access": "Zugang", - "Are you sure?": "Sind Sie sicher?", - "Record has been removed": "Datensatz wurde gelöscht", - "Wrong username/password": "Falscher Benutzername\/Passwort", - "Post cannot be empty": "Notiz dard nicht leer sein", - "Removing...": "Entferne...", - "Unlinking...": "Lösche Verknüpfung...", - "Posting...": "Poste...", - "Username can not be empty!": "Der Benutzername darf nicht leer sein!", - "Cache is not enabled": "Cache ist nicht aktiviert", - "Cache has been cleared": "Der Cache wurde geleert", - "Rebuild has been done": "Wiederherstellen wurde durchgeführt", - "Saving...": "Speichere...", - "Modified": "Verändert", - "Created": "Erstellt", - "Create": "Erstellen", - "create": "Erstellen", - "Overview": "Überblick", - "Details": "Details", - "Add Filter": "Filter hinzufügen", - "Add Dashlet": "Dashlet hinzufügen", - "Add": "Hinzufügen", - "Reset": "Zurücksetzen", - "Menu": "Menü", - "More": "Mehr", - "Search": "Suchen", - "Only My": "Nur Meine", - "Open": "Offen", - "Admin": "Admin", - "About": "Über", - "Refresh": "Aktualisieren", - "Remove": "Entfernen", - "Options": "Optionen", - "Username": "Benutzername", - "Password": "Passwort", - "Login": "Anmelden", - "Log Out": "Abmelden", - "Preferences": "Benutzereinstellungen", - "State": "Bundesland", - "Street": "Straße", - "Country": "Land", - "City": "Ort", - "PostalCode": "PLZ", - "Followed": "Beobachtet", - "Follow": "Beobachten", - "Clear Local Cache": "Lokalen Cache leeren", - "Actions": "Aktionen", - "Delete": "Löschen", - "Update": "Aktualisieren", - "Save": "Speichern", - "Edit": "Bearbeiten", - "Cancel": "Abbrechen", - "Unlink": "Link entfernen", - "Mass Update": "Massenänderung", - "Export": "Exportieren", - "No Data": "Keine Daten", - "All": "Alle", - "Active": "Aktiv", - "Inactive": "Inaktiv", - "Write your comment here": "Notiz hier einfügen", - "Post": "Senden", - "Stream": "Vorgänge", - "Show more": "Mehr anzeigen", - "Dashlet Options": "Dashlet Optionen", - "Full Form": "Komplettes Formular", - "Insert": "Einfügen", - "Person": "Person", - "First Name": "Vorname", - "Last Name": "Nachname", - "Original": "Original", - "You": "Sie", - "you": "Sie", - "change": "ändern", - "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", - "duplicate": "Der Datensatz den Sie erstellen wollen, könnte eine Dublette sein", - "fieldIsRequired": "{field} wird benötigt", - "fieldShouldBeEmail": "{field} muss eine gültige E-Mail sein", - "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", - "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", - "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", - "open": "Offen", - "active": "Aktiv" - }, - "fields": { - "name": "Name", - "firstName": "Vorname", - "lastName": "Nachname", - "salutationName": "Anrede", - "assignedUser": "Zugewiesener Benutzer", - "emailAddress": "E-Mail", - "assignedUserName": "Zugewiesener Benutzername", - "teams": "Teams", - "createdAt": "Erstellt am", - "modifiedAt": "Geändert am", - "createdBy": "Erstellt von", - "modifiedBy": "Geändert von", - "title": "Funktion", - "dateFrom": "Von Datum", - "dateTo": "Bis Datum", - "autorefreshInterval": "Aktualisierungsintervall", - "displayRecords": "Sätze anzeigen" - }, - "links": { - "teams": "Teams", - "users": "Benutzer" - }, - "dashlets": { - "Stream": "Vorgänge" - }, - "streamMessages": { - "create": "{user} hat {entityType} {entity} erstellt", - "createAssigned": "{user} hat {entityType} {entity} erstellt und an {assignee} zugewiesen", - "assign": "{user} hat {entityType} {entity} an {assignee} zugewiesen", - "post": "{user} hat zu {entityType} {entity} notiert", - "attach": "{user} hat zu {entityType} {entity} hinzugefügt", - "status": "{user} hat {field} von {entityType} {entity} aktualisiert", - "update": "{user} hat {entityType} {entity} aktualisiert", - "createRelated": "{user} hat {relatedEntityType} {relatedEntity} verbunden mit {entityType} {entity} erstellt", - "emailReceived": "{entity} wurde für {entityType} {entity} empfangen", - - "createThis": "{user} hat {entityType} erstellt", - "createAssignedThis": "{user} hat {entityType} erstellt und an {assignee} zugewiesen", - "assignThis": "{user} hat {entityType} an {assignee} zugewiesen", - "postThis": "{user} hat notiert", - "attachThis": "{user} hat hinzugefügt", - "statusThis": "{user} hat {field} aktualiisiert", - "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": ["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": { - "Mr.": "Mr.", - "Mrs.": "Mrs.", - "Dr.": "Dr.", - "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":"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", - "today": "Heute", - "past": "Vergangenheit", - "future": "Zukunft" - }, - "intSearchRanges": { - "equals": "Gleich", - "notEquals": "Nicht gleich", - "greaterThan": "Größer als", - "lessThan": "Weniger als", - "greaterThanOrEquals": "Größer oder gleich als", - "lessThanOrEquals": "Weniger oder gleich als", - "between": "Zwischen" - }, - "autorefreshInterval": { - "0": "Kein(e)", - "0.5": "30 Sekunden", - "1": "1 Minute", - "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", - "font":{ - "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" - }, - "link":{ - "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", - "url":"Video URL?", - "providers":"(YouTube, Vimeo, Vine, Instagram oder DailyMotion)" - }, - "table":{ - "table":"Tabelle" - }, - "hr":{ - "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" - }, - "lists":{ - "unordered":"Unsortierte Liste", - "ordered":"Nummerierte Liste" - }, - "options":{ - "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" - }, - "color":{ - "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" - }, - "history":{ - "undo":"Rückgängig", - "redo":"Wiederholen" - } - } - } + "scopeNames": { + "Email": "E-Mail", + "User": "Benutzer", + "Team": "Team", + "Role": "Rolle", + "EmailTemplate": "E-Mail Vorlage", + "EmailAccount": "E-Mail Konto", + "EmailAccountScope": "E-Mail Konto", + "OutboundEmail": "Ausgehende E-Mail", + "ScheduledJob": "Geplante Aufgabe", + "ExternalAccount": "Externes Konto", + "Extension": "Erweiterung" + }, + "scopeNamesPlural": { + "Email": "E-Mails", + "User": "Benutzer", + "Team": "Teams", + "Role": "Rollen", + "EmailTemplate": "E-Mail Vorlagen", + "EmailAccount": "E-Mail Konten", + "EmailAccountScope": "E-Mail Konten", + "OutboundEmail": "Ausgehende E-Mails", + "ScheduledJob": "Geplante Jobs", + "ExternalAccount": "Externe Konten", + "Extension": "Erweiterungen" + }, + "labels": { + "Misc": "Verschiedenes", + "Merge": "Zusammenführen", + "None": "Kein(e)", + "by": "von", + "Saved": "Gespeichert.", + "Error": "Fehler", + "Select": "Auswählen", + "Not valid": "Ungültig", + "Please wait...": "Bitte warten...", + "Please wait": "Bitte warten", + "Loading...": "Lade...", + "Uploading...": "Lade hoch...", + "Sending...": "Wird gesendet...", + "Removed": "Gelöscht", + "Posted": "Geposted", + "Linked": "Verlinkt", + "Unlinked": "Verknüpfung gelöscht", + "Access denied": "Zugriff verweigert", + "Access": "Zugang", + "Are you sure?": "Sind Sie sicher?", + "Record has been removed": "Datensatz wurde gelöscht", + "Wrong username/password": "Falscher Benutzername/Passwort", + "Post cannot be empty": "Notiz darf nicht leer sein", + "Removing...": "Lösche...", + "Unlinking...": "Lösche Verknüpfung...", + "Posting...": "Poste...", + "Username can not be empty!": "Der Benutzername darf nicht leer sein!", + "Cache is not enabled": "Cache ist nicht aktiviert", + "Cache has been cleared": "Der Cache wurde geleert", + "Rebuild has been done": "Wiederherstellen wurde durchgeführt", + "Saving...": "Speichere...", + "Modified": "Verändert", + "Created": "Erstellt", + "Create": "Erstellen", + "create": "erstellen", + "Overview": "Überblick", + "Details": "Details", + "Add Filter": "Filter hinzufügen", + "Add Dashlet": "Dashlet hinzufügen", + "Add": "Hinzufügen", + "Reset": "Zurücksetzen", + "Menu": "Menü", + "More": "Mehr", + "Search": "Suchen", + "Only My": "Nur Meine", + "Open": "Offen", + "Admin": "Admin", + "About": "Über", + "Refresh": "Aktualisieren", + "Remove": "Löschen", + "Options": "Optionen", + "Username": "Benutzername", + "Password": "Passwort", + "Login": "Anmelden", + "Log Out": "Abmelden", + "Preferences": "Benutzereinstellungen", + "State": "Bundesland/Kanton", + "Street": "Straße", + "Country": "Land", + "City": "Ort", + "PostalCode": "PLZ", + "Followed": "Beobachtet", + "Follow": "Beobachten", + "Clear Local Cache": "Lokalen Cache leeren", + "Actions": "Aktionen", + "Delete": "Löschen", + "Update": "Aktualisieren", + "Save": "Speichern", + "Edit": "Bearbeiten", + "Cancel": "Abbrechen", + "Unlink": "Link entfernen", + "Mass Update": "Massenänderung", + "Export": "Exportieren", + "No Data": "Keine Daten", + "No Access": "Kein Zugang", + "All": "Alle", + "Active": "Aktiv", + "Inactive": "Inaktiv", + "Write your comment here": "Notiz hier einfügen", + "Post": "Senden", + "Stream": "Vorgänge", + "Show more": "Mehr anzeigen", + "Dashlet Options": "Dashlet Optionen", + "Full Form": "Komplettes Formular", + "Insert": "Einfügen", + "Person": "Person", + "First Name": "Vorname", + "Last Name": "Nachname", + "Original": "Original", + "You": "Sie", + "you": "Sie", + "change": "ändern", + "Change": "Ändern", + "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", + "Today": "Heute", + "Tomorrow": "Morgen", + "Yesterday": "Gestern" + }, + "messages": { + "notModified": "Sie haben den Datensatz nicht geändert", + "duplicate": "Der Datensatz den Sie erstellen wollen, könnte eine Dublette sein", + "fieldIsRequired": "{field} wird benötigt", + "fieldShouldBeEmail": "{field} muss eine gültige E-Mail sein", + "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", + "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", + "resetPreferencesDone": "Die Einstellungen wurden auf Standardwerte zurückgesetzt", + "assignmentEmailNotificationSubject": "EspoCRM {entityType}: {Entity.name}", + "assignmentEmailNotificationBody": "{assignerUserName} hat {entityType} '{Entity.name}' an Sie zugewiesen {recordUrl}", + "confirmation": "Sind Sie sicher?", + "resetPreferencesConfirmation": "Sind Sie sicher dass Sie die Einstellungen auf Standardwerte zurücksetzen wollen?", + "removeRecordConfirmation": "Sind Sie sicher, dass Sie den Eintrag löschen wollen?", + "unlinkRecordConfirmation": "Sind Sie sicher dass Sie diese Beziehung lösen möchten?", + "removeSelectedRecordsConfirmation": "Sind Sie sicher dass Sie die ausgewählten Sätze löschen möchten?", + "massUpdateResult": "{count} Einträge wurden aktualisiert", + "massUpdateResultSingle": "{count} Eintrag wurde aktualisiert", + "noRecordsUpdated": "Es wurden keine Einträge aktualisiert", + "massRemoveResult": "{count} Einträge wurden gelöscht", + "massRemoveResultSingle": "{count} Eintrag wurde gelöscht", + "noRecordsRemoved": "Es wurden keine Einträge gelöscht" + }, + "boolFilters": { + "onlyMy": "Nur Meine", + "open": "Offen", + "active": "Aktiv" + }, + "fields": { + "name": "Name", + "firstName": "Vorname", + "lastName": "Nachname", + "salutationName": "Anrede", + "assignedUser": "Zugewiesener Benutzer", + "emailAddress": "E-Mail", + "assignedUserName": "Zugewiesener Benutzername", + "teams": "Teams", + "createdAt": "Erstellt am", + "modifiedAt": "Geändert am", + "createdBy": "Erstellt von", + "modifiedBy": "Geändert von" + }, + "links": { + "assignedUser": "Zugewiesener Benutzer", + "createdBy": "Erstellt von", + "modifiedBy": "Geändert von", + "team": "Team", + "roles": "Rollen", + "teams": "Teams", + "users": "Benutzer" + }, + "dashlets": { + "Stream": "Vorgänge" + }, + "streamMessages": { + "create": "{user} hat {entityType} {entity} erstellt", + "createAssigned": "{user} hat {entityType} {entity} erstellt und an {assignee} zugewiesen", + "assign": "{user} hat {entityType} {entity} an {assignee} zugewiesen", + "post": "{user} hat zu {entityType} {entity} notiert", + "attach": "{user} hat zu {entityType} {entity} hinzugefügt", + "status": "{user} hat {field} von {entityType} {entity} aktualisiert", + "update": "{user} hat {entityType} {entity} aktualisiert", + "createRelated": "{user} hat {relatedEntityType} {relatedEntity} verbunden mit {entityType} {entity} erstellt", + "emailReceived": "E-Mail {email} wurde empfangen für {entityType} {entity}", + "emailReceivedInitial": "E-Mail {email} wurde empfangen und hat {entityType} {entity} erstellt", + "mentionInPost": "{user} erwähnte {mentioned} zu {entityType} {entity}", + + "createThis": "{user} hat {entityType} erstellt", + "createAssignedThis": "{user} hat {entityType} erstellt und an {assignee} zugewiesen", + "assignThis": "{user} hat {entityType} an {assignee} zugewiesen", + "postThis": "{user} hat notiert", + "attachThis": "{user} hat hinzugefügt", + "statusThis": "{user} hat {field} 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", + "emailReceivedInitialThis": "E-Mail {email} wurde empfangen und {entityType} wurde erstellt" + }, + "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"] + }, + "options": { + "salutationName": { + "Mr.": "Mr.", + "Mrs.": "Mrs.", + "Dr.": "Dr.", + "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": "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", + "today": "Heute", + "past": "Vergangenheit", + "future": "Zukunft", + "currentMonth": "Aktuelles Monat", + "lastMonth": "Letzten Monat", + "currentQuarter": "Aktuelles Quartal", + "lastQuarter": "Letztes Quartal", + "currentYear": "Aktuelles Jahr", + "lastYear": "Letztes Jahr" + }, + "intSearchRanges": { + "equals": "Gleich", + "notEquals": "Nicht gleich", + "greaterThan": "Größer als", + "lessThan": "Weniger als", + "greaterThanOrEquals": "Größer oder gleich als", + "lessThanOrEquals": "Weniger oder gleich als", + "between": "Zwischen" + }, + "autorefreshInterval": { + "0": "Kein(e)", + "0.5": "30 Sekunden", + "1": "1 Minute", + "2": "2 Minuten", + "5": "5 Minuten", + "10": "10 Minuten" + }, + "phoneNumber": { + "Mobile": "Telefon Mobil", + "Office": "Telefon Büro", + "Fax": "Fax", + "Home": "Telefon Privat", + "Other": "Andere" + } + }, + "sets": { + "summernote": { + "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" + }, + "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" + }, + "link":{ + "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", + "url": "Video URL?", + "providers": "(YouTube, Vimeo, Vine, Instagram oder DailyMotion)" + }, + "table":{ + "table": "Tabelle" + }, + "hr":{ + "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" + }, + "lists":{ + "unordered": "Unsortierte Liste", + "ordered": "Nummerierte Liste" + }, + "options":{ + "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" + }, + "color":{ + "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" + }, + "history":{ + "undo": "Rückgängig", + "redo": "Wiederholen" + } + } + } } diff --git a/application/Espo/Resources/i18n/de_DE/Import.json b/application/Espo/Resources/i18n/de_DE/Import.json new file mode 100644 index 0000000000..f4c8005db9 --- /dev/null +++ b/application/Espo/Resources/i18n/de_DE/Import.json @@ -0,0 +1,15 @@ +{ + "labels": { + "Revert": "Zurückkehren", + "Return to Import": "Zurück zum Import", + "Run Import": "Import durchführen", + "Back": "Zurück", + "Field Mapping": "Feldzuordnung", + "Default Values": "Standardwerte", + "Add Field": "Feld hinzufügen", + "Created": "Erstellt", + "Updated": "Aktualisiert", + "Result": "Resultat", + "Show records": "Datensätze zeigen" + } +} diff --git a/application/Espo/Resources/i18n/de_DE/Integration.json b/application/Espo/Resources/i18n/de_DE/Integration.json new file mode 100644 index 0000000000..fc93914a95 --- /dev/null +++ b/application/Espo/Resources/i18n/de_DE/Integration.json @@ -0,0 +1,14 @@ +{ + "fields": { + "enabled": "Aktiv", + "clientId": "Client ID", + "clientSecret": "Client Geheimnis", + "redirectUri": "Redirect URI" + }, + "messages": { + "selectIntegration": "Integration in Menü auswählen" + }, + "help": { + "Google": "

Holen Sie die OAuth 2.0 Credentials über die Google Developers Console.

Visit Google Developers Console um OAuth 2.0 Credentials wie eine Client ID und Client Geheimnis zu erhalten die sowohl Google als auch EspoCRM bekannt sind.

" + } +} diff --git a/application/Espo/Resources/i18n/de_DE/Note.json b/application/Espo/Resources/i18n/de_DE/Note.json index 73456d53bd..bb12836623 100644 --- a/application/Espo/Resources/i18n/de_DE/Note.json +++ b/application/Espo/Resources/i18n/de_DE/Note.json @@ -1,6 +1,6 @@ { - "fields": { - "post": "Senden", - "attachments": "Anhänge" - } + "fields": { + "post": "Senden", + "attachments": "Anhänge" + } } diff --git a/application/Espo/Resources/i18n/de_DE/Preferences.json b/application/Espo/Resources/i18n/de_DE/Preferences.json index e6d2a77f4c..058fd962fd 100644 --- a/application/Espo/Resources/i18n/de_DE/Preferences.json +++ b/application/Espo/Resources/i18n/de_DE/Preferences.json @@ -1,37 +1,37 @@ { - "fields": { - "dateFormat": "Datumsformat", - "timeFormat": "Zeitformat", - "timeZone": "Zeitzone", - "weekStart": "Erster Tag der Woche", - "thousandSeparator": "Tausender Trennzeichen", - "decimalMark": "Dezimaltrennzeichen", - "defaultCurrency": "Standardwährung", - "currencyList": "Währungsliste", - "language": "Sprache", - - "smtpServer": "Server", - "smtpPort": "Port", - "smtpAuth": "Autorisierung", - "smtpSecurity": "Sicherheit", - "smtpUsername": "Benutzername", - "emailAddress": "E-Mail", - "smtpPassword": "Passwort", - "smtpEmailAddress": "E-Mail Adresse", - - "exportDelimiter": "Export Trennzeichen", - - "receiveAssignmentEmailNotifications": "E-Mail Nachrichten bei Zuweisungen erhalten" - }, - "links": { - }, - "options": { - "weekStart": { - "0": "Sonntag", - "1": "Montag" - } - }, - "labels": { - "Notifications": "Benachrichtigungen" - } + "fields": { + "dateFormat": "Datumsformat", + "timeFormat": "Zeitformat", + "timeZone": "Zeitzone", + "weekStart": "Erster Tag der Woche", + "thousandSeparator": "Tausender Trennzeichen", + "decimalMark": "Dezimaltrennzeichen", + "defaultCurrency": "Standardwährung", + "currencyList": "Währungsliste", + "language": "Sprache", + + "smtpServer": "Server", + "smtpPort": "Port", + "smtpAuth": "Autorisierung", + "smtpSecurity": "Sicherheit", + "smtpUsername": "Benutzername", + "emailAddress": "E-Mail", + "smtpPassword": "Passwort", + "smtpEmailAddress": "E-Mail Adresse", + + "exportDelimiter": "Export Trennzeichen", + + "receiveAssignmentEmailNotifications": "E-Mail Nachrichten bei Zuweisungen erhalten" + }, + "links": { + }, + "options": { + "weekStart": { + "0": "Sonntag", + "1": "Montag" + } + }, + "labels": { + "Notifications": "Benachrichtigungen" + } } diff --git a/application/Espo/Resources/i18n/de_DE/Role.json b/application/Espo/Resources/i18n/de_DE/Role.json index 4f0a2765fe..216654dc94 100644 --- a/application/Espo/Resources/i18n/de_DE/Role.json +++ b/application/Espo/Resources/i18n/de_DE/Role.json @@ -1,35 +1,35 @@ { - "fields": { - "name": "Name", - "roles": "Rollen" - }, - "links": { - "users": "Benutzer", - "teams": "Teams" - }, - "labels": { - "Access": "Zugang", - "Create Role": "Neue Rolle" - }, - "options": { - "accessList": { - "not-set": "nicht gesetzt", - "enabled": "Aktiv", - "disabled": "Inaktiv" - }, - "levelList": { - "all": "Alle", - "team": "Team", - "own": "Eigene", - "no": "Nein" - } - }, - "actions": { - "read": "Lesen", - "edit": "Bearbeiten", - "delete": "Löschen" - }, - "messages": { - "changesAfterClearCache": "Alle Änderungen werden erst nach Leeren des Caches wirksam." - } + "fields": { + "name": "Name", + "roles": "Rollen" + }, + "links": { + "users": "Benutzer", + "teams": "Teams" + }, + "labels": { + "Access": "Zugang", + "Create Role": "Rolle erstellen" + }, + "options": { + "accessList": { + "not-set": "nicht gesetzt", + "enabled": "Aktiv", + "disabled": "Inaktiv" + }, + "levelList": { + "all": "Alle", + "team": "Team", + "own": "Eigene", + "no": "Nein" + } + }, + "actions": { + "read": "Lesen", + "edit": "Bearbeiten", + "delete": "Löschen" + }, + "messages": { + "changesAfterClearCache": "Alle Änderungen werden erst nach Leeren des Caches wirksam." + } } diff --git a/application/Espo/Resources/i18n/de_DE/ScheduledJob.json b/application/Espo/Resources/i18n/de_DE/ScheduledJob.json index 3c5a366d0b..4913207edd 100644 --- a/application/Espo/Resources/i18n/de_DE/ScheduledJob.json +++ b/application/Espo/Resources/i18n/de_DE/ScheduledJob.json @@ -1,30 +1,30 @@ { - "fields": { - "name": "Name", - "status": "Status", - "job": "Job", - "scheduling": "Planung (in Crontab Notation)" - }, - "links": { - "log": "Protokoll" - }, - "labels": { - "Create ScheduledJob": "Geplante Aufgabe erstellen" - }, - "options": { - "job": { - "CheckInboundEmails": "Eingehende E-Mail überprüfen", - "Cleanup": "Aufräumen" - }, - "cronSetup": { - "linux": "Hinweis: Fügen Sie diese Zeile zu Ihrer Crontab Datei hinzu, um geplante Aufgaben durchführen zu können:", - "mac": "Hinweis: Fügen Sie diese Zeile zu Ihrer Crontab Datei hinzu, um geplante Aufgaben durchführen zu können:", - "windows": "Hinweis: Erstellen Sie eine Stapeldatei mit den folgenden Kommandos um geplante Aufgaben mit dem Windows Aufgabenplaner durchzuführen:", - "default": "Hinweis: fügen Sie dieses Kommando zum CronJob hinzu (Geplante Aufgaben):" - }, - "status": { - "Active": "Aktiv", - "Inactive": "Inaktiv" - } - } + "fields": { + "name": "Name", + "status": "Status", + "job": "Job", + "scheduling": "Planung (in Crontab Notation)" + }, + "links": { + "log": "Protokoll" + }, + "labels": { + "Create ScheduledJob": "Geplante Aufgabe erstellen" + }, + "options": { + "job": { + "CheckInboundEmails": "Eingehende E-Mail überprüfen", + "Cleanup": "Aufräumen" + }, + "cronSetup": { + "linux": "Hinweis: Fügen Sie diese Zeile zu Ihrer Crontab Datei hinzu, um geplante Aufgaben durchführen zu können:", + "mac": "Hinweis: Fügen Sie diese Zeile zu Ihrer Crontab Datei hinzu, um geplante Aufgaben durchführen zu können:", + "windows": "Hinweis: Erstellen Sie eine Stapeldatei mit den folgenden Kommandos um geplante Aufgaben mit dem Windows Aufgabenplaner durchzuführen:", + "default": "Hinweis: fügen Sie dieses Kommando zum CronJob hinzu (Geplante Aufgaben):" + }, + "status": { + "Active": "Aktiv", + "Inactive": "Inaktiv" + } + } } diff --git a/application/Espo/Resources/i18n/de_DE/ScheduledJobLogRecord.json b/application/Espo/Resources/i18n/de_DE/ScheduledJobLogRecord.json index 5009a56e80..e4d2838497 100644 --- a/application/Espo/Resources/i18n/de_DE/ScheduledJobLogRecord.json +++ b/application/Espo/Resources/i18n/de_DE/ScheduledJobLogRecord.json @@ -1,6 +1,6 @@ { - "fields": { - "status": "Status", - "executionTime": "Ausführungszeit" - } + "fields": { + "status": "Status", + "executionTime": "Ausführungszeit" + } } diff --git a/application/Espo/Resources/i18n/de_DE/Settings.json b/application/Espo/Resources/i18n/de_DE/Settings.json index 82a185afb7..2227758a0a 100644 --- a/application/Espo/Resources/i18n/de_DE/Settings.json +++ b/application/Espo/Resources/i18n/de_DE/Settings.json @@ -1,76 +1,77 @@ { - "fields": { - "useCache": "Benutzer Cache", - "dateFormat": "Datumsformat", - "timeFormat": "Zeitformat", - "timeZone": "Zeitzone", - "weekStart": "Erster Tag der Woche", - "thousandSeparator": "Tausender Trennzeichen", - "decimalMark": "Dezimaltrennzeichen", - "defaultCurrency": "Standardwährung", - "baseCurrency": "Basiswährung", - "baseCurrency": "Basiswährung", - "currencyRates": "Wechselkurse", - - "currencyList": "Währungsliste", - "language": "Sprache", - - "companyLogo": "Firmenlogo", - - "smtpServer": "Server", - "smtpPort": "Port", - "smtpAuth": "Autorisierung", - "smtpSecurity": "Sicherheit", - "smtpUsername": "Benutzername", - "emailAddress": "E-Mail", - "smtpPassword": "Passwort", - "outboundEmailFromName": "Von Name", - "outboundEmailFromAddress": "Von Adresse", - "outboundEmailIsShared": "Kann von allen Benutzern verwendet werden", - - "recordsPerPage": "Datensätze pro Seite", - "recordsPerPageSmall": "Datensätze pro Seite (Klein)", - "tabList": "Reiter Liste", - "quickCreateList": "Liste Schnellerstellung", - - "exportDelimiter": "Export Trennzeichen", - - "authenticationMethod": "Authentifizierungs Methode", - "ldapHost": "Host", - "ldapPort": "Port", - "ldapAuth": "Autorisierung", - "ldapUsername": "Benutzername", - "ldapPassword": "Passwort", - "ldapBindRequiresDn": "Bind erfordert Dn", - "ldapBaseDn": "Basis Dn", - "ldapAccountCanonicalForm": "Kanonische Form Konto", - "ldapAccountDomainName": "Domain Name Konto", - "ldapTryUsernameSplit": "Benutzernamen Split versuchen", - "ldapCreateEspoUser": "Benutzer in EspoCRM erstellen", - "ldapSecurity": "Sicherheit", - "ldapUserLoginFilter": "Login Filter benutzen", - "ldapAccountDomainNameShort": "Domain Name Konto kurz", - "ldapOptReferrals": "Opt Referrals", - "disableExport": "Export deaktivieren (nur Admin ist berechtigt)", - "assignmentEmailNotifications": "E-Mail Nachrichten bei Zuweisungen senden", - "assignmentEmailNotificationsEntityList": "Module für Benachrichtigungen" - }, - "options": { - "weekStart": { - "0": "Sonntag", - "1": "Montag" - } - }, - "tooltips": { - "recordsPerPageSmall": "Anzahl Sätze in Beziehungssubpanels" - }, - "labels": { - "System": "System", - "Locale": "Lokale Einstellungen", - "SMTP": "SMTP", - "Configuration": "Konfiguration", - "Notifications": "Benachrichtigungen", - "Currency Settings": "Währunsgseinstellungen", - "Currency Rtes": "Währungskurse" - } + "fields": { + "useCache": "Benutzer Cache", + "dateFormat": "Datumsformat", + "timeFormat": "Zeitformat", + "timeZone": "Zeitzone", + "weekStart": "Erster Tag der Woche", + "thousandSeparator": "Tausender Trennzeichen", + "decimalMark": "Dezimaltrennzeichen", + "defaultCurrency": "Standardwährung", + "baseCurrency": "Basiswährung", + "currencyRates": "Wechselkurse", + + "currencyList": "Währungsliste", + "language": "Sprache", + + "companyLogo": "Firmenlogo", + + "smtpServer": "Server", + "smtpPort": "Port", + "smtpAuth": "Autorisierung", + "smtpSecurity": "Sicherheit", + "smtpUsername": "Benutzername", + "emailAddress": "E-Mail", + "smtpPassword": "Passwort", + "outboundEmailFromName": "Von Name", + "outboundEmailFromAddress": "Von Adresse", + "outboundEmailIsShared": "Kann von allen Benutzern verwendet werden", + + "recordsPerPage": "Datensätze pro Seite", + "recordsPerPageSmall": "Datensätze pro Seite (Klein)", + "tabList": "Reiter Liste", + "quickCreateList": "Liste Schnellerstellung", + + "exportDelimiter": "Export Trennzeichen", + + "authenticationMethod": "Authentifizierungs Methode", + "ldapHost": "Host", + "ldapPort": "Port", + "ldapAuth": "Autorisierung", + "ldapUsername": "Benutzername", + "ldapPassword": "Passwort", + "ldapBindRequiresDn": "Bind erfordert Dn", + "ldapBaseDn": "Basis Dn", + "ldapAccountCanonicalForm": "Kanonische Form Konto", + "ldapAccountDomainName": "Domain Name Konto", + "ldapTryUsernameSplit": "Benutzernamen Split versuchen", + "ldapCreateEspoUser": "Benutzer in EspoCRM erstellen", + "ldapSecurity": "Sicherheit", + "ldapUserLoginFilter": "Login Filter benutzen", + "ldapAccountDomainNameShort": "Domain Name Konto kurz", + "ldapOptReferrals": "Opt Referrals", + "disableExport": "Export deaktivieren (nur Admin ist berechtigt)", + "assignmentEmailNotifications": "E-Mail Nachrichten bei Zuweisungen senden", + "assignmentEmailNotificationsEntityList": "Module für Benachrichtigungen", + + "b2cMode": "B2C Modus" + }, + "options": { + "weekStart": { + "0": "Sonntag", + "1": "Montag" + } + }, + "tooltips": { + "recordsPerPageSmall": "Anzahl Sätze in Beziehungssubpanels" + }, + "labels": { + "System": "System", + "Locale": "Lokale Einstellungen", + "SMTP": "SMTP", + "Configuration": "Konfiguration", + "Notifications": "Benachrichtigungen", + "Currency Settings": "Währunsgseinstellungen", + "Currency Rtes": "Währungskurse" + } } diff --git a/application/Espo/Resources/i18n/de_DE/Team.json b/application/Espo/Resources/i18n/de_DE/Team.json index f03efea60b..aa1c50ca6d 100644 --- a/application/Espo/Resources/i18n/de_DE/Team.json +++ b/application/Espo/Resources/i18n/de_DE/Team.json @@ -1,15 +1,16 @@ { - "fields": { - "name": "Name", - "roles": "Rollen" - }, - "links": { - "users": "Benutzer" - }, - "tooltips": { - "roles": "Alle Benutzer dieses Teams erben die Zugriffsrechte von ausgewählten Rollen." - }, - "labels": { - "Create Team": "Neues Team" - } + "fields": { + "name": "Name", + "roles": "Rollen", + "positionList": "Stellungen" + }, + "links": { + "users": "Benutzer" + }, + "tooltips": { + "roles": "Alle Benutzer dieses Teams erben die Zugriffsrechte von ausgewählten Rollen." + }, + "labels": { + "Create Team": "Team erstellen" + } } diff --git a/application/Espo/Resources/i18n/de_DE/User.json b/application/Espo/Resources/i18n/de_DE/User.json index ed25e99a3d..9a61d43a18 100644 --- a/application/Espo/Resources/i18n/de_DE/User.json +++ b/application/Espo/Resources/i18n/de_DE/User.json @@ -1,35 +1,39 @@ { - "fields": { - "name": "Name", - "userName": "Benutzername", - "title": "Funktion", - "isAdmin": "Ist Admin", - "defaultTeam": "Standard Team:", - "emailAddress": "E-Mail", - "phoneNumber": "Telefon", - "roles": "Rollen", - "password": "Passwort", - "passwordConfirm": "Passwort bestätigen", - "newPassword": "Neues Passwort" - }, - "links": { - "teams": "Teams", - "roles": "Rollen" - }, - "labels": { - "Create User": "Neuer Benutzer", - "Generate": "Erzeugen", - "Access": "Zugang", - "Preferences": "Benutzereinstellungen", - "Change Password": "Passwort ändern" - }, - "tooltips": { - "defaultTeam": "Alle Datensätze dieses Benutzers werden standardmäßig seinem Team zugeordnet." - }, - "messages": { - "passwordWillBeSent": "Das Passwort wird an die E-Mail Adresse des Benutzers gesendet", - "accountInfoEmailSubject": "Kontoinformation", - "accountInfoEmailBody": "Ihre Kontoinformation: Benutzername: {userName} - Passwort: {password} {siteUrl}", - "passwordChanged": "Das Passwort wurde geändert" - } + "fields": { + "name": "Name", + "userName": "Benutzername", + "title": "Funktion", + "isAdmin": "Ist Admin", + "defaultTeam": "Standard Team", + "emailAddress": "E-Mail", + "phoneNumber": "Telefon", + "roles": "Rollen", + "password": "Passwort", + "passwordConfirm": "Passwort bestätigen", + "newPassword": "Neues Passwort" + }, + "links": { + "teams": "Teams", + "roles": "Rollen" + }, + "labels": { + "Create User": "Benutzer erstellen", + "Generate": "Erzeugen", + "Access": "Zugang", + "Preferences": "Benutzereinstellungen", + "Change Password": "Passwort ändern" + }, + "tooltips": { + "defaultTeam": "Alle Datensätze dieses Benutzers werden standardmäßig seinem Team zugeordnet.", + "userName": "Buchstaben a-z, Zahlen 0-9 und Unterstriche sind erlaubt.", + "isAdmin": "Der Admin Benutzer hat vollen Zugriff auf alle Funktionen.", + "teams": "Die Teams denen dieser Benutzer angehört. Zugriffsberechtigungen werden von der Rolle des Teams vererbt.", + "roles": "Zusätzliche Zugriffsrollen. Nur zu verwenden wenn der Benutzer keinem Team angehört bzw. wenn die Zugriffsberechtigungen nur für diesen Benutzer angepasst werden müssen." + }, + "messages": { + "passwordWillBeSent": "Das Passwort wird an die E-Mail Adresse des Benutzers gesendet", + "accountInfoEmailSubject": "Kontoinformation", + "accountInfoEmailBody": "Ihre Kontoinformation: Benutzername: {userName} - Passwort: {password} {siteUrl}", + "passwordChanged": "Das Passwort wurde geändert" + } } diff --git a/application/Espo/Resources/i18n/en_US/Admin.json b/application/Espo/Resources/i18n/en_US/Admin.json index 29d4ad92c7..a4c76c6153 100644 --- a/application/Espo/Resources/i18n/en_US/Admin.json +++ b/application/Espo/Resources/i18n/en_US/Admin.json @@ -1,147 +1,145 @@ { - "labels": { - "Enabled": "Enabled", - "Disabled": "Disabled", - "System": "System", - "Users": "Users", - "Email": "Email", - "Data": "Data", - "Customization": "Customization", - "Available Fields": "Available Fields", - "Layout": "Layout", - "Enabled": "Enabled", - "Disabled": "Disabled", - "Add Panel": "Add Panel", - "Add Field": "Add Field", - "Settings": "Settings", - "Scheduled Jobs": "Scheduled Jobs", - "Upgrade": "Upgrade", - "Clear Cache": "Clear Cache", - "Rebuild": "Rebuild", - "Users": "Users", - "Teams": "Teams", - "Roles": "Roles", - "Outbound Emails": "Outbound Emails", - "Inbound Emails": "Inbound Emails", - "Email Templates": "Email Templates", - "Import": "Import", - "Layout Manager": "Layout Manager", - "Field Manager": "Field Manager", - "User Interface": "User Interface", - "Auth Tokens": "Auth Tokens", - "Authentication": "Authentication", - "Currency": "Currency", - "Integrations": "Integrations", - "Extensions": "Extensions", - "Upload": "Upload", - "Installing...": "Installing...", - "Upgrading...": "Upgrading...", - "Upgraded successfully": "Upgraded successfully", - "Installed successfully": "Installed successfully", - "Ready for upgrade": "Ready for upgrade", - "Run Upgrade": "Run Upgrade", - "Install": "Install", - "Ready for installation": "Ready for installation", - "Uninstalling...": "Uninstalling...", - "Uninstalled": "Uninstalled" - }, - "layouts": { - "list": "List", - "detail": "Detail", - "listSmall": "List (Small)", - "detailSmall": "Detail (Small)", - "filters": "Search Filters", - "massUpdate": "Mass Update", - "relationships": "Relationships" - }, - "fieldTypes": { - "address": "Address", - "array": "Array", - "foreign": "Foreign", - "duration": "Duration", - "password": "Password", - "parsonName": "Person Name", - "autoincrement": "Auto-increment", - "bool": "Bool", - "currency": "Currency", - "date": "Date", - "datetime": "DateTime", - "email": "Email", - "enum": "Enum", - "enumInt": "Enum Integer", - "enumFloat": "Enum Float", - "float": "Float", - "int": "Int", - "link": "Link", - "linkMultiple": "Link Multiple", - "linkParent": "Link Parent", - "multienim": "Multienum", - "phone": "Phone", - "text": "Text", - "url": "Url", - "varchar": "Varchar", - "file": "File", - "image": "Image" - }, - "fields": { - "type": "Type", - "name": "Name", - "label": "Label", - "required": "Required", - "default": "Default", - "maxLength": "Max Length", - "options": "Options (raw values, not translated)", - "after": "After (field)", - "before": "Before (field)", - "link": "Link", - "field": "Field", - "min": "Min", - "max": "Max", - "translation": "Translation", - "previewSize": "Preview Size" - }, - "messages": { - "upgradeVersion": "Your EspoCRM will be upgraded to version {version}. This can take some time.", - "upgradeDone": "Your EspoCRM has been upgraded to version {version}. Refresh your browser window.", - "upgradeBackup": "We recommend you to make backup of your EspoCRM files and data before upgrade.", - "thousandSeparatorEqualsDecimalMark": "Thousand separator can not be same as decimal mark", - "userHasNoEmailAddress": "User has not email address.", - "selectEntityType": "Select entity type in the left menu.", - "selectUpgradePackage": "Select upgrade package", - "downloadUpgradePackage": "Download needed upgrade package(s) here.", - "selectLayout": "Select needed layout in the left menu and edit it.", - "selectExtensionPackage": "Select extension package", - "extensionInstalled": "Extension {name} {version} has been installed.", - "installExtension": "Extension {name} {version} is ready for an istallation.", - "uninstallConfirmation": "Are you really want to uninstall the extension?" - }, - "descriptions": { - "settings": "System settings of application.", - "scheduledJob": "Jobs which are executed by cron.", - "upgrade": "Upgrade EspoCRM.", - "clearCache": "Clear all backend cache.", - "rebuild": "Rebuild backend and clear cache.", - "users": "Users management.", - "teams": "Teams management.", - "roles": "Roles management.", - "outboundEmails": "SMTP settings for outgoing emails.", - "inboundEmails": "Group IMAP email accouts. Email import and Email-to-Case.", - "emailTemplates": "Templates for outbound emails.", - "import": "Import data from CSV file.", - "layoutManager": "Customize layouts (list, detail, edit, search, mass update).", - "fieldManager": "Create new fields or customize existing ones.", - "userInterface": "Configure UI.", - "authTokens": "Active auth sessions. IP address and last access date.", - "authentication": "Authentication settings.", - "currency": "Currency settings and rates.", - "extensions": "Install or uninstall extensions." - }, - "options": { - "previewSize": { - "x-small": "X-Small", - "small": "Small", - "medium": "Medium", - "large": "Large" - } - } + "labels": { + "Enabled": "Enabled", + "Disabled": "Disabled", + "System": "System", + "Users": "Users", + "Email": "Email", + "Data": "Data", + "Customization": "Customization", + "Available Fields": "Available Fields", + "Layout": "Layout", + "Add Panel": "Add Panel", + "Add Field": "Add Field", + "Settings": "Settings", + "Scheduled Jobs": "Scheduled Jobs", + "Upgrade": "Upgrade", + "Clear Cache": "Clear Cache", + "Rebuild": "Rebuild", + "Teams": "Teams", + "Roles": "Roles", + "Outbound Emails": "Outbound Emails", + "Inbound Emails": "Inbound Emails", + "Email Templates": "Email Templates", + "Import": "Import", + "Layout Manager": "Layout Manager", + "Field Manager": "Field Manager", + "User Interface": "User Interface", + "Auth Tokens": "Auth Tokens", + "Authentication": "Authentication", + "Currency": "Currency", + "Integrations": "Integrations", + "Extensions": "Extensions", + "Upload": "Upload", + "Installing...": "Installing...", + "Upgrading...": "Upgrading...", + "Upgraded successfully": "Upgraded successfully", + "Installed successfully": "Installed successfully", + "Ready for upgrade": "Ready for upgrade", + "Run Upgrade": "Run Upgrade", + "Install": "Install", + "Ready for installation": "Ready for installation", + "Uninstalling...": "Uninstalling...", + "Uninstalled": "Uninstalled" + }, + "layouts": { + "list": "List", + "detail": "Detail", + "listSmall": "List (Small)", + "detailSmall": "Detail (Small)", + "filters": "Search Filters", + "massUpdate": "Mass Update", + "relationships": "Relationships" + }, + "fieldTypes": { + "address": "Address", + "array": "Array", + "foreign": "Foreign", + "duration": "Duration", + "password": "Password", + "parsonName": "Person Name", + "autoincrement": "Auto-increment", + "bool": "Boolean", + "currency": "Currency", + "date": "Date", + "datetime": "DateTime", + "email": "Email", + "enum": "Enum", + "enumInt": "Enum Integer", + "enumFloat": "Enum Float", + "float": "Float", + "int": "Int", + "link": "Link", + "linkMultiple": "Link Multiple", + "linkParent": "Link Parent", + "multienim": "Multienum", + "phone": "Phone", + "text": "Text", + "url": "Url", + "varchar": "Varchar", + "file": "File", + "image": "Image", + "multiEnum": "Multi-Enum" + }, + "fields": { + "type": "Type", + "name": "Name", + "label": "Label", + "required": "Required", + "default": "Default", + "maxLength": "Max Length", + "options": "Options", + "after": "After (field)", + "before": "Before (field)", + "link": "Link", + "field": "Field", + "min": "Min", + "max": "Max", + "translation": "Translation", + "previewSize": "Preview Size" + }, + "messages": { + "upgradeVersion": "Your EspoCRM will be upgraded to version {version}. This can take some time.", + "upgradeDone": "Your EspoCRM has been upgraded to version {version}. Refresh your browser window.", + "upgradeBackup": "We recommend you to make backup of your EspoCRM files and data before upgrade.", + "thousandSeparatorEqualsDecimalMark": "Thousand separator can not be same as decimal mark", + "userHasNoEmailAddress": "User has not email address.", + "selectEntityType": "Select entity type in the left menu.", + "selectUpgradePackage": "Select upgrade package", + "downloadUpgradePackage": "Download needed upgrade package(s) here.", + "selectLayout": "Select needed layout in the left menu and edit it.", + "selectExtensionPackage": "Select extension package", + "extensionInstalled": "Extension {name} {version} has been installed.", + "installExtension": "Extension {name} {version} is ready for an installation.", + "uninstallConfirmation": "Are you really want to uninstall the extension?" + }, + "descriptions": { + "settings": "System settings of application.", + "scheduledJob": "Jobs which are executed by cron.", + "upgrade": "Upgrade EspoCRM.", + "clearCache": "Clear all backend cache.", + "rebuild": "Rebuild backend and clear cache.", + "users": "Users management.", + "teams": "Teams management.", + "roles": "Roles management.", + "outboundEmails": "SMTP settings for outgoing emails.", + "inboundEmails": "Group IMAP email accouts. Email import and Email-to-Case.", + "emailTemplates": "Templates for outbound emails.", + "import": "Import data from CSV file.", + "layoutManager": "Customize layouts (list, detail, edit, search, mass update).", + "fieldManager": "Create new fields or customize existing ones.", + "userInterface": "Configure UI.", + "authTokens": "Active auth sessions. IP address and last access date.", + "authentication": "Authentication settings.", + "currency": "Currency settings and rates.", + "extensions": "Install or uninstall extensions." + }, + "options": { + "previewSize": { + "x-small": "X-Small", + "small": "Small", + "medium": "Medium", + "large": "Large" + } + } } diff --git a/application/Espo/Resources/i18n/en_US/AuthToken.json b/application/Espo/Resources/i18n/en_US/AuthToken.json index 16f85074ba..28d25d7f9d 100644 --- a/application/Espo/Resources/i18n/en_US/AuthToken.json +++ b/application/Espo/Resources/i18n/en_US/AuthToken.json @@ -1,9 +1,9 @@ { - "fields": { - "user": "User", - "ipAddress": "IP Address", - "lastAccess": "Last Access Date", - "createdAt": "Login Date" + "fields": { + "user": "User", + "ipAddress": "IP Address", + "lastAccess": "Last Access Date", + "createdAt": "Login Date" - } + } } diff --git a/application/Espo/Resources/i18n/en_US/DashletOptions.json b/application/Espo/Resources/i18n/en_US/DashletOptions.json index 1bb364da83..a25417fd22 100644 --- a/application/Espo/Resources/i18n/en_US/DashletOptions.json +++ b/application/Espo/Resources/i18n/en_US/DashletOptions.json @@ -1,10 +1,10 @@ { - "fields": { - "title": "Title", - "dateFrom": "Date From", - "dateTo": "Date To", - "autorefreshInterval": "Auto-refresh Interval", - "displayRecords": "Display Records", - "isDoubleHeight": "Height 2x" - } + "fields": { + "title": "Title", + "dateFrom": "Date From", + "dateTo": "Date To", + "autorefreshInterval": "Auto-refresh Interval", + "displayRecords": "Display Records", + "isDoubleHeight": "Height 2x" + } } diff --git a/application/Espo/Resources/i18n/en_US/Email.json b/application/Espo/Resources/i18n/en_US/Email.json index 6a278f5dc3..6a116832b6 100644 --- a/application/Espo/Resources/i18n/en_US/Email.json +++ b/application/Espo/Resources/i18n/en_US/Email.json @@ -1,44 +1,51 @@ { - "fields": { - "name": "Subject", - "parent": "Parent", - "status": "Status", - "dateSent": "Date Sent", - "from": "From", - "to": "To", - "cc": "CC", - "bcc": "BCC", - "isHtml": "Is Html", - "body": "Body", - "subject": "Subject", - "attachments": "Attachments", - "selectTemplate": "Select Template", - "fromEmailAddress": "From Address", - "toEmailAddresses": "To Address", - "emailAddress": "Email Address", - "deliveryDate": "Delivery Date" - }, - "links": { - }, - "options": { - "Draft": "Draft", - "Sending": "Sending", - "Sent": "Sent", - "Archived": "Archived" - }, - "labels": { - "Create Email": "Archive Email", - "Archive Email": "Archive Email", - "Compose": "Compose", - "Reply": "Reply", - "Reply to All": "Reply to All", - "Forward": "Forward", - "Original message": "Original message", - "Forwarded message": "Forwarded message", - "Email Accounts": "Email Accounts" - }, - "presetFilters": { - "sent": "Sent", - "archived": "Archived" - } + "fields": { + "name": "Subject", + "parent": "Parent", + "status": "Status", + "dateSent": "Date Sent", + "from": "From", + "to": "To", + "cc": "CC", + "bcc": "BCC", + "isHtml": "Is Html", + "body": "Body", + "subject": "Subject", + "attachments": "Attachments", + "selectTemplate": "Select Template", + "fromEmailAddress": "From Address", + "toEmailAddresses": "To Address", + "emailAddress": "Email Address", + "deliveryDate": "Delivery Date" + }, + "links": { + }, + "options": { + "Draft": "Draft", + "Sending": "Sending", + "Sent": "Sent", + "Archived": "Archived" + }, + "labels": { + "Create Email": "Archive Email", + "Archive Email": "Archive Email", + "Compose": "Compose", + "Reply": "Reply", + "Reply to All": "Reply to All", + "Forward": "Forward", + "Original message": "Original message", + "Forwarded message": "Forwarded message", + "Email Accounts": "Email Accounts", + "Send Test Email": "Send Test Email", + "Send": "Send", + "Email Address": "Email Address" + }, + "messages": { + "noSmtpSetup": "No SMTP setup. {link}.", + "testEmailSent": "Test email has been sent" + }, + "presetFilters": { + "sent": "Sent", + "archived": "Archived" + } } diff --git a/application/Espo/Resources/i18n/en_US/EmailAccount.json b/application/Espo/Resources/i18n/en_US/EmailAccount.json index b0775ba57a..10845a516e 100644 --- a/application/Espo/Resources/i18n/en_US/EmailAccount.json +++ b/application/Espo/Resources/i18n/en_US/EmailAccount.json @@ -1,29 +1,29 @@ { - "fields": { - "name": "Name", - "status": "Status", - "host": "Host", - "username": "Username", - "password": "Password", - "port": "Port", - "monitoredFolders": "Monitored Folders", - "ssl": "SSL", - "fetchSince": "Fetch Since" - }, - "links": { - }, - "options": { - "status": { - "Active": "Active", - "Inactive": "Inactive" - } - }, - "labels": { - "Create EmailAccount": "Create Email Account", - "IMAP": "IMAP", - "Main": "Main" - }, - "messages": { - "couldNotConnectToImap": "Could not connect to IMAP server" - } + "fields": { + "name": "Name", + "status": "Status", + "host": "Host", + "username": "Username", + "password": "Password", + "port": "Port", + "monitoredFolders": "Monitored Folders", + "ssl": "SSL", + "fetchSince": "Fetch Since" + }, + "links": { + }, + "options": { + "status": { + "Active": "Active", + "Inactive": "Inactive" + } + }, + "labels": { + "Create EmailAccount": "Create Email Account", + "IMAP": "IMAP", + "Main": "Main" + }, + "messages": { + "couldNotConnectToImap": "Could not connect to IMAP server" + } } diff --git a/application/Espo/Resources/i18n/en_US/EmailAddress.json b/application/Espo/Resources/i18n/en_US/EmailAddress.json index 2f9d2aa22c..b85616ab14 100644 --- a/application/Espo/Resources/i18n/en_US/EmailAddress.json +++ b/application/Espo/Resources/i18n/en_US/EmailAddress.json @@ -1,7 +1,7 @@ { - "labels": { - "Primary": "Primary", - "Opted Out": "Opted Out", - "Invalid": "Invalid" - } + "labels": { + "Primary": "Primary", + "Opted Out": "Opted Out", + "Invalid": "Invalid" + } } diff --git a/application/Espo/Resources/i18n/en_US/EmailTemplate.json b/application/Espo/Resources/i18n/en_US/EmailTemplate.json index 4e37bc0c6c..a56d7f31e9 100644 --- a/application/Espo/Resources/i18n/en_US/EmailTemplate.json +++ b/application/Espo/Resources/i18n/en_US/EmailTemplate.json @@ -1,16 +1,16 @@ { - "fields": { - "name": "Name", - "status": "Status", - "isHtml": "Is Html", - "body": "Body", - "subject": "Subject", - "attachments": "Attachments", - "insertField": "" - }, - "links": { - }, - "labels": { - "Create EmailTemplate": "Create Email Template" - } + "fields": { + "name": "Name", + "status": "Status", + "isHtml": "Is Html", + "body": "Body", + "subject": "Subject", + "attachments": "Attachments", + "insertField": "" + }, + "links": { + }, + "labels": { + "Create EmailTemplate": "Create Email Template" + } } diff --git a/application/Espo/Resources/i18n/en_US/Extension.json b/application/Espo/Resources/i18n/en_US/Extension.json index dd3af846a0..3482a65475 100644 --- a/application/Espo/Resources/i18n/en_US/Extension.json +++ b/application/Espo/Resources/i18n/en_US/Extension.json @@ -1,15 +1,15 @@ { - "fields": { - "name": "Name", - "version": "Version", - "description": "Description", - "isInstalled": "Installed" - }, - "labels": { - "Uninstall": "Uninstall", - "Install": "Install" - }, - "messages": { - "uninstalled": "Extension {name} has been uninstalled" - } + "fields": { + "name": "Name", + "version": "Version", + "description": "Description", + "isInstalled": "Installed" + }, + "labels": { + "Uninstall": "Uninstall", + "Install": "Install" + }, + "messages": { + "uninstalled": "Extension {name} has been uninstalled" + } } diff --git a/application/Espo/Resources/i18n/en_US/ExternalAccount.json b/application/Espo/Resources/i18n/en_US/ExternalAccount.json index 841a36bcd5..edb8e19f1d 100644 --- a/application/Espo/Resources/i18n/en_US/ExternalAccount.json +++ b/application/Espo/Resources/i18n/en_US/ExternalAccount.json @@ -1,8 +1,8 @@ { - "labels": { - "Connect": "Connect", - "Connected": "Connected" - }, - "help": { - } + "labels": { + "Connect": "Connect", + "Connected": "Connected" + }, + "help": { + } } diff --git a/application/Espo/Resources/i18n/en_US/Global.json b/application/Espo/Resources/i18n/en_US/Global.json index 480c6318c7..5a79ae64ca 100644 --- a/application/Espo/Resources/i18n/en_US/Global.json +++ b/application/Espo/Resources/i18n/en_US/Global.json @@ -1,431 +1,450 @@ { - "scopeNames": { - "Email": "Email", - "User": "User", - "Team": "Team", - "Role": "Role", - "EmailTemplate": "Email Template", - "EmailAccount": "Email Account", - "OutboundEmail": "Outbound Email", - "ScheduledJob": "Scheduled Job", - "ExternalAccount": "External Account", - "Extension": "Extension" - }, - "scopeNamesPlural": { - "Email": "Emails", - "User": "Users", - "Team": "Teams", - "Role": "Roles", - "EmailTemplate": "Email Templates", - "EmailAccount": "Email Accounts", - "OutboundEmail": "Outbound Emails", - "ScheduledJob": "Scheduled Jobs", - "ExternalAccount": "External Accounts", - "Extension": "Extensions" - }, - "labels": { - "Misc": "Misc", - "Merge": "Merge", - "None": "None", - "by": "by", - "Saved": "Saved", - "Error": "Error", - "Select": "Select", - "Not valid": "Not valid", - "Please wait...": "Please wait...", - "Please wait": "Please wait", - "Loading...": "Loading...", - "Uploading...": "Uploading...", - "Sending...": "Sending...", - "Removed": "Removed", - "Posted": "Posted", - "Linked": "Linked", - "Unlinked": "Unlinked", - "Access denied": "Access denied", - "Access": "Access", - "Are you sure?": "Are you sure?", - "Record has been removed": "Record has been removed", - "Wrong username/password": "Wrong username/password", - "Post cannot be empty": "Post cannot be empty", - "Removing...": "Removing...", - "Unlinking...": "Unlinking...", - "Posting...": "Posting...", - "Username can not be empty!": "Username can not be empty!", - "Cache is not enabled": "Cache is not enabled", - "Cache has been cleared": "Cache has been cleared", - "Rebuild has been done": "Rebuild has been done", - "Saving...": "Saving...", - "Modified": "Modified", - "Created": "Created", - "Create": "Create", - "create": "create", - "Overview": "Overview", - "Details": "Details", - "Add Filter": "Add Filter", - "Add Dashlet": "Add Dashlet", - "Add": "Add", - "Reset": "Reset", - "Menu": "Menu", - "More": "More", - "Search": "Search", - "Only My": "Only My", - "Open": "Open", - "Admin": "Admin", - "About": "About", - "Refresh": "Refresh", - "Remove": "Remove", - "Options": "Options", - "Username": "Username", - "Password": "Password", - "Login": "Login", - "Log Out": "Log Out", - "Preferences": "Preferences", - "State": "State", - "Street": "Street", - "Country": "Country", - "City": "City", - "PostalCode": "Postal Code", - "Followed": "Followed", - "Follow": "Follow", - "Clear Local Cache": "Clear Local Cache", - "Actions": "Actions", - "Delete": "Delete", - "Update": "Update", - "Save": "Save", - "Edit": "Edit", - "Cancel": "Cancel", - "Unlink": "Unlink", - "Mass Update": "Mass Update", - "Export": "Export", - "No Data": "No Data", - "All": "All", - "Active": "Active", - "Inactive": "Inactive", - "Write your comment here": "Write your comment here", - "Post": "Post", - "Stream": "Stream", - "Show more": "Show more", - "Dashlet Options": "Dashlet Options", - "Full Form": "Full Form", - "Insert": "Insert", - "Person": "Person", - "First Name": "First Name", - "Last Name": "Last Name", - "Original": "Original", - "You": "You", - "you": "you", - "change": "change", - "Primary": "Primary", - "Save Filters": "Save Filters", - "Administration": "Administration", - "Run Import": "Run Import", - "Duplicate": "Duplicate", - "Notifications": "Notifications", - "Mark all read": "Mark all read", - "See more": "See more", - "Today": "Today", - "Tomorrow": "Tomorrow", - "Yesterday": "Yesterday" - }, - "messages": { - "notModified": "You have not modified the record", - "duplicate": "The record you are creating seems to be a duplicate", - "fieldIsRequired": "{field} is required", - "fieldShouldBeEmail": "{field} should be valid email", - "fieldShouldBeFloat": "{field} should be valid float", - "fieldShouldBeInt": "{field} should be valid integer", - "fieldShouldBeDate": "{field} should be valid date", - "fieldShouldBeDatetime": "{field} should be valid date/time", - "fieldShouldAfter": "{field} should be after {otherField}", - "fieldShouldBefore": "{field} should be before {otherField}", - "fieldShouldBeBetween": "{field} should be between {min} and {max}", - "fieldShouldBeLess": "{field} should be less then {value}", - "fieldShouldBeGreater": "{field} should be greater then {value}", - "fieldBadPasswordConfirm": "{field} confirmed improperly", - "assignmentEmailNotificationSubject": "EspoCRM {entityType}: {Entity.name}", - "assignmentEmailNotificationBody": "{assignerUserName} has assigned {entityType} '{Entity.name}' to you\n\n{recordUrl}", - "confirmation": "Are you sure?", - "removeRecordConfirmation": "Are you sure you want to remove the record?", - "unlinkRecordConfirmation": "Are you sure you want to unlink relationship?", - "removeSelectedRecordsConfirmation": "Are you sure you want to remove selected records?" - }, - "boolFilters": { - "onlyMy": "Only My", - "open": "Open", - "active": "Active" - }, - "fields": { - "name": "Name", - "firstName": "First Name", - "lastName": "Last Name", - "salutationName": "Salutation", - "assignedUser": "Assigned User", - "emailAddress": "Email", - "assignedUserName": "Assigned User Name", - "teams": "Teams", - "createdAt": "Created At", - "modifiedAt": "Modified At", - "createdBy": "Created By", - "modifiedBy": "Modified By" - }, - "links": { - "teams": "Teams", - "users": "Users" - }, - "dashlets": { - "Stream": "Stream" - }, - "streamMessages": { - "create": "{user} created {entityType} {entity}", - "createAssigned": "{user} created {entityType} {entity} assigned to {assignee}", - "assign": "{user} assigned {entityType} {entity} to {assignee}", - "post": "{user} posted on {entityType} {entity}", - "attach": "{user} attached on {entityType} {entity}", - "status": "{user} updated {field} on {entityType} {entity}", - "update": "{user} updated {entityType} {entity}", - "createRelated": "{user} created {relatedEntityType} {relatedEntity} linked to {entityType} {entity}", - "emailReceived": "{entity} has been received for {entityType} {entity}", - "mentionInPost": "{user} mentioned {mentioned} on {entityType} {entity}", - - "createThis": "{user} created this {entityType}", - "createAssignedThis": "{user} created this {entityType} assigned to {assignee}", - "assignThis": "{user} assigned this {entityType} to {assignee}", - "postThis": "{user} posted", - "attachThis": "{user} attached", - "statusThis": "{user} updated {field}", - "updateThis": "{user} updated this {entityType}", - "createRelatedThis": "{user} created {relatedEntityType} {relatedEntity} linked to this {entityType}", - "emailReceivedThis": "{entity} has been received" - }, - "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"] - }, - "options": { - "salutationName": { - "Mr.": "Mr.", - "Mrs.": "Mrs.", - "Dr.": "Dr.", - "Drs.": "Drs." - }, - "language": { - "af_ZA":"Afrikaans", - "az_AZ":"Azerbaijani", - "be_BY":"Belarusian", - "bg_BG":"Bulgarian", - "bn_IN":"Bengali", - "bs_BA":"Bosnian", - "ca_ES":"Catalan", - "cs_CZ":"Czech", - "cy_GB":"Welsh", - "da_DK":"Danish", - "de_DE":"German", - "el_GR":"Greek", - "en_GB":"English (UK)", - "en_US":"English (US)", - "es_ES":"Spanish (Spain)", - "et_EE":"Estonian", - "eu_ES":"Basque", - "fa_IR":"Persian", - "fi_FI":"Finnish", - "fo_FO":"Faroese", - "fr_CA":"French (Canada)", - "fr_FR":"French (France)", - "ga_IE":"Irish", - "gl_ES":"Galician", - "gn_PY":"Guarani", - "he_IL":"Hebrew", - "hi_IN":"Hindi", - "hr_HR":"Croatian", - "hu_HU":"Hungarian", - "hy_AM":"Armenian", - "id_ID":"Indonesian", - "is_IS":"Icelandic", - "it_IT":"Italian", - "ja_JP":"Japanese", - "ka_GE":"Georgian", - "km_KH":"Khmer", - "ko_KR":"Korean", - "ku_TR":"Kurdish", - "lt_LT":"Lithuanian", - "lv_LV":"Latvian", - "mk_MK":"Macedonian", - "ml_IN":"Malayalam", - "ms_MY":"Malay", - "nb_NO":"Norwegian Bokmål", - "nn_NO":"Norwegian Nynorsk", - "ne_NP":"Nepali", - "nl_NL":"Dutch", - "pa_IN":"Punjabi", - "pl_PL":"Polish", - "ps_AF":"Pashto", - "pt_BR":"Portuguese (Brazil)", - "pt_PT":"Portuguese (Portugal)", - "ro_RO":"Romanian", - "ru_RU":"Russian", - "sk_SK":"Slovak", - "sl_SI":"Slovene", - "sq_AL":"Albanian", - "sr_RS":"Serbian", - "sv_SE":"Swedish", - "sw_KE":"Swahili", - "ta_IN":"Tamil", - "te_IN":"Telugu", - "th_TH":"Thai", - "tl_PH":"Tagalog", - "tr_TR":"Turkish", - "uk_UA":"Ukrainian", - "ur_PK":"Urdu", - "vi_VN":"Vietnamese", - "zh_CN":"Simplified Chinese (China)", - "zh_HK":"Traditional Chinese (Hong Kong)", - "zh_TW":"Traditional Chinese (Taiwan)" - }, - "dateSearchRanges": { - "on": "On", - "notOn": "Not On", - "after": "After", - "before": "Before", - "between": "Between", - "today": "Today", - "past": "Past", - "future": "Future", - "currentMonth": "Current Month", - "lastMonth": "Last Month", - "currentQuarter": "Current Quarter", - "lastQuarter": "Last Quarter", - "currentYear": "Current Year", - "lastYear": "Last Year" - }, - "intSearchRanges": { - "equals": "Equals", - "notEquals": "Not Equals", - "greaterThan": "Greater Than", - "lessThan": "Less Than", - "greaterThanOrEquals": "Greater Than or Equals", - "lessThanOrEquals": "Less Than or Equals", - "between": "Between" - }, - "autorefreshInterval": { - "0": "None", - "0.5": "30 seconds", - "1": "1 minute", - "2": "2 minutes", - "5": "5 minutes", - "10": "10 minutes" - }, - "phoneNumber": { - "Mobile": "Mobile", - "Office": "Office", - "Fax": "Fax", - "Home": "Home", - "Other": "Other" - } - }, - "sets": { - "summernote": { - "NOTICE": "You can find translation here: https://github.com/HackerWins/summernote/tree/master/lang", - "font":{ - "bold":"Bold", - "italic":"Italic", - "underline":"Underline", - "strike":"Strike", - "clear":"Remove Font Style", - "height":"Line Height", - "name":"Font Family", - "size":"Font Size" - }, - "image":{ - "image":"Picture", - "insert":"Insert Image", - "resizeFull":"Resize Full", - "resizeHalf":"Resize Half", - "resizeQuarter":"Resize Quarter", - "floatLeft":"Float Left", - "floatRight":"Float Right", - "floatNone":"Float None", - "dragImageHere":"Drag an image here", - "selectFromFiles":"Select from files", - "url":"Image URL", - "remove":"Remove Image" - }, - "link":{ - "link":"Link", - "insert":"Insert Link", - "unlink":"Unlink", - "edit":"Edit", - "textToDisplay":"Text to display", - "url":"To what URL should this link go?", - "openInNewWindow":"Open in new window" - }, - "video":{ - "video":"Video", - "videoLink":"Video Link", - "insert":"Insert Video", - "url":"Video URL?", - "providers":"(YouTube, Vimeo, Vine, Instagram, or DailyMotion)" - }, - "table":{ - "table":"Table" - }, - "hr":{ - "insert":"Insert Horizontal Rule" - }, - "style":{ - "style":"Style", - "normal":"Normal", - "blockquote":"Quote", - "pre":"Code", - "h1":"Header 1", - "h2":"Header 2", - "h3":"Header 3", - "h4":"Header 4", - "h5":"Header 5", - "h6":"Header 6" - }, - "lists":{ - "unordered":"Unordered list", - "ordered":"Ordered list" - }, - "options":{ - "help":"Help", - "fullscreen":"Full Screen", - "codeview":"Code View" - }, - "paragraph":{ - "paragraph":"Paragraph", - "outdent":"Outdent", - "indent":"Indent", - "left":"Align left", - "center":"Align center", - "right":"Align right", - "justify":"Justify full" - }, - "color":{ - "recent":"Recent Color", - "more":"More Color", - "background":"BackColor", - "foreground":"FontColor", - "transparent":"Transparent", - "setTransparent":"Set transparent", - "reset":"Reset", - "resetToDefault":"Reset to default" - }, - "shortcut":{ - "shortcuts":"Keyboard shortcuts", - "close":"Close", - "textFormatting":"Text formatting", - "action":"Action", - "paragraphFormatting":"Paragraph formatting", - "documentStyle":"Document Style" - }, - "history":{ - "undo":"Undo", - "redo":"Redo" - } - } - } + "scopeNames": { + "Email": "Email", + "User": "User", + "Team": "Team", + "Role": "Role", + "EmailTemplate": "Email Template", + "EmailAccount": "Email Account", + "EmailAccountScope": "Email Account", + "OutboundEmail": "Outbound Email", + "ScheduledJob": "Scheduled Job", + "ExternalAccount": "External Account", + "Extension": "Extension" + }, + "scopeNamesPlural": { + "Email": "Emails", + "User": "Users", + "Team": "Teams", + "Role": "Roles", + "EmailTemplate": "Email Templates", + "EmailAccount": "Email Accounts", + "EmailAccountScope": "Email Accounts", + "OutboundEmail": "Outbound Emails", + "ScheduledJob": "Scheduled Jobs", + "ExternalAccount": "External Accounts", + "Extension": "Extensions" + }, + "labels": { + "Misc": "Misc", + "Merge": "Merge", + "None": "None", + "by": "by", + "Saved": "Saved", + "Error": "Error", + "Select": "Select", + "Not valid": "Not valid", + "Please wait...": "Please wait...", + "Please wait": "Please wait", + "Loading...": "Loading...", + "Uploading...": "Uploading...", + "Sending...": "Sending...", + "Removed": "Removed", + "Posted": "Posted", + "Linked": "Linked", + "Unlinked": "Unlinked", + "Access denied": "Access denied", + "Access": "Access", + "Are you sure?": "Are you sure?", + "Record has been removed": "Record has been removed", + "Wrong username/password": "Wrong username/password", + "Post cannot be empty": "Post cannot be empty", + "Removing...": "Removing...", + "Unlinking...": "Unlinking...", + "Posting...": "Posting...", + "Username can not be empty!": "Username can not be empty!", + "Cache is not enabled": "Cache is not enabled", + "Cache has been cleared": "Cache has been cleared", + "Rebuild has been done": "Rebuild has been done", + "Saving...": "Saving...", + "Modified": "Modified", + "Created": "Created", + "Create": "Create", + "create": "create", + "Overview": "Overview", + "Details": "Details", + "Add Filter": "Add Filter", + "Add Dashlet": "Add Dashlet", + "Add": "Add", + "Reset": "Reset", + "Menu": "Menu", + "More": "More", + "Search": "Search", + "Only My": "Only My", + "Open": "Open", + "Admin": "Admin", + "About": "About", + "Refresh": "Refresh", + "Remove": "Remove", + "Options": "Options", + "Username": "Username", + "Password": "Password", + "Login": "Login", + "Log Out": "Log Out", + "Preferences": "Preferences", + "State": "State", + "Street": "Street", + "Country": "Country", + "City": "City", + "PostalCode": "Postal Code", + "Followed": "Followed", + "Follow": "Follow", + "Clear Local Cache": "Clear Local Cache", + "Actions": "Actions", + "Delete": "Delete", + "Update": "Update", + "Save": "Save", + "Edit": "Edit", + "Cancel": "Cancel", + "Unlink": "Unlink", + "Mass Update": "Mass Update", + "Export": "Export", + "No Data": "No Data", + "No Access": "No Access", + "All": "All", + "Active": "Active", + "Inactive": "Inactive", + "Write your comment here": "Write your comment here", + "Post": "Post", + "Stream": "Stream", + "Show more": "Show more", + "Dashlet Options": "Dashlet Options", + "Full Form": "Full Form", + "Insert": "Insert", + "Person": "Person", + "First Name": "First Name", + "Last Name": "Last Name", + "Original": "Original", + "You": "You", + "you": "you", + "change": "change", + "Change": "Change", + "Primary": "Primary", + "Save Filters": "Save Filters", + "Administration": "Administration", + "Run Import": "Run Import", + "Duplicate": "Duplicate", + "Notifications": "Notifications", + "Mark all read": "Mark all read", + "See more": "See more", + "Today": "Today", + "Tomorrow": "Tomorrow", + "Yesterday": "Yesterday" + }, + "messages": { + "notModified": "You have not modified the record", + "duplicate": "The record you are creating seems to be a duplicate", + "fieldIsRequired": "{field} is required", + "fieldShouldBeEmail": "{field} should be valid email", + "fieldShouldBeFloat": "{field} should be valid float", + "fieldShouldBeInt": "{field} should be valid integer", + "fieldShouldBeDate": "{field} should be valid date", + "fieldShouldBeDatetime": "{field} should be valid date/time", + "fieldShouldAfter": "{field} should be after {otherField}", + "fieldShouldBefore": "{field} should be before {otherField}", + "fieldShouldBeBetween": "{field} should be between {min} and {max}", + "fieldShouldBeLess": "{field} should be less then {value}", + "fieldShouldBeGreater": "{field} should be greater then {value}", + "fieldBadPasswordConfirm": "{field} confirmed improperly", + "resetPreferencesDone": "Preferences has been reset to defaults", + "assignmentEmailNotificationSubject": "EspoCRM {entityType}: {Entity.name}", + "assignmentEmailNotificationBody": "{assignerUserName} has assigned {entityType} '{Entity.name}' to you\n\n{recordUrl}", + "confirmation": "Are you sure?", + "resetPreferencesConfirmation": "Are you sure you want to reset preferences to defaults?", + "removeRecordConfirmation": "Are you sure you want to remove the record?", + "unlinkRecordConfirmation": "Are you sure you want to unlink relationship?", + "removeSelectedRecordsConfirmation": "Are you sure you want to remove selected records?", + "massUpdateResult": "{count} records have been updated", + "massUpdateResultSingle": "{count} record has been updated", + "noRecordsUpdated": "No records were updated", + "massRemoveResult": "{count} records have been removed", + "massRemoveResultSingle": "{count} record has been removed", + "noRecordsRemoved": "No records were removed" + }, + "boolFilters": { + "onlyMy": "Only My", + "open": "Open", + "active": "Active" + }, + "fields": { + "name": "Name", + "firstName": "First Name", + "lastName": "Last Name", + "salutationName": "Salutation", + "assignedUser": "Assigned User", + "emailAddress": "Email", + "assignedUserName": "Assigned User Name", + "teams": "Teams", + "createdAt": "Created At", + "modifiedAt": "Modified At", + "createdBy": "Created By", + "modifiedBy": "Modified By" + }, + "links": { + "assignedUser": "Assigned User", + "createdBy": "Created By", + "modifiedBy": "Modified By", + "team": "Team", + "roles": "Roles", + "teams": "Teams", + "users": "Users" + }, + "dashlets": { + "Stream": "Stream" + }, + "streamMessages": { + "create": "{user} created {entityType} {entity}", + "createAssigned": "{user} created {entityType} {entity} assigned to {assignee}", + "assign": "{user} assigned {entityType} {entity} to {assignee}", + "post": "{user} posted on {entityType} {entity}", + "attach": "{user} attached on {entityType} {entity}", + "status": "{user} updated {field} on {entityType} {entity}", + "update": "{user} updated {entityType} {entity}", + "createRelated": "{user} created {relatedEntityType} {relatedEntity} linked to {entityType} {entity}", + "emailReceived": "Email {email} has been received for {entityType} {entity}", + "emailReceivedInitial": "Email {email} has been received and created {entityType} {entity}", + "mentionInPost": "{user} mentioned {mentioned} on {entityType} {entity}", + + "createThis": "{user} created this {entityType}", + "createAssignedThis": "{user} created this {entityType} assigned to {assignee}", + "assignThis": "{user} assigned this {entityType} to {assignee}", + "postThis": "{user} posted", + "attachThis": "{user} attached", + "statusThis": "{user} updated {field}", + "updateThis": "{user} updated this {entityType}", + "createRelatedThis": "{user} created {relatedEntityType} {relatedEntity} linked to this {entityType}", + "emailReceivedThis": "Email {email} has been received", + "emailReceivedInitialThis": "Email {email} has been received and created this {entityType}" + }, + "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"] + }, + "options": { + "salutationName": { + "Mr.": "Mr.", + "Mrs.": "Mrs.", + "Dr.": "Dr.", + "Drs.": "Drs." + }, + "language": { + "af_ZA":"Afrikaans", + "az_AZ":"Azerbaijani", + "be_BY":"Belarusian", + "bg_BG":"Bulgarian", + "bn_IN":"Bengali", + "bs_BA":"Bosnian", + "ca_ES":"Catalan", + "cs_CZ":"Czech", + "cy_GB":"Welsh", + "da_DK":"Danish", + "de_DE":"German", + "el_GR":"Greek", + "en_GB":"English (UK)", + "en_US":"English (US)", + "es_ES":"Spanish (Spain)", + "et_EE":"Estonian", + "eu_ES":"Basque", + "fa_IR":"Persian", + "fi_FI":"Finnish", + "fo_FO":"Faroese", + "fr_CA":"French (Canada)", + "fr_FR":"French (France)", + "ga_IE":"Irish", + "gl_ES":"Galician", + "gn_PY":"Guarani", + "he_IL":"Hebrew", + "hi_IN":"Hindi", + "hr_HR":"Croatian", + "hu_HU":"Hungarian", + "hy_AM":"Armenian", + "id_ID":"Indonesian", + "is_IS":"Icelandic", + "it_IT":"Italian", + "ja_JP":"Japanese", + "ka_GE":"Georgian", + "km_KH":"Khmer", + "ko_KR":"Korean", + "ku_TR":"Kurdish", + "lt_LT":"Lithuanian", + "lv_LV":"Latvian", + "mk_MK":"Macedonian", + "ml_IN":"Malayalam", + "ms_MY":"Malay", + "nb_NO":"Norwegian Bokmål", + "nn_NO":"Norwegian Nynorsk", + "ne_NP":"Nepali", + "nl_NL":"Dutch", + "pa_IN":"Punjabi", + "pl_PL":"Polish", + "ps_AF":"Pashto", + "pt_BR":"Portuguese (Brazil)", + "pt_PT":"Portuguese (Portugal)", + "ro_RO":"Romanian", + "ru_RU":"Russian", + "sk_SK":"Slovak", + "sl_SI":"Slovene", + "sq_AL":"Albanian", + "sr_RS":"Serbian", + "sv_SE":"Swedish", + "sw_KE":"Swahili", + "ta_IN":"Tamil", + "te_IN":"Telugu", + "th_TH":"Thai", + "tl_PH":"Tagalog", + "tr_TR":"Turkish", + "uk_UA":"Ukrainian", + "ur_PK":"Urdu", + "vi_VN":"Vietnamese", + "zh_CN":"Simplified Chinese (China)", + "zh_HK":"Traditional Chinese (Hong Kong)", + "zh_TW":"Traditional Chinese (Taiwan)" + }, + "dateSearchRanges": { + "on": "On", + "notOn": "Not On", + "after": "After", + "before": "Before", + "between": "Between", + "today": "Today", + "past": "Past", + "future": "Future", + "currentMonth": "Current Month", + "lastMonth": "Last Month", + "currentQuarter": "Current Quarter", + "lastQuarter": "Last Quarter", + "currentYear": "Current Year", + "lastYear": "Last Year" + }, + "intSearchRanges": { + "equals": "Equals", + "notEquals": "Not Equals", + "greaterThan": "Greater Than", + "lessThan": "Less Than", + "greaterThanOrEquals": "Greater Than or Equals", + "lessThanOrEquals": "Less Than or Equals", + "between": "Between" + }, + "autorefreshInterval": { + "0": "None", + "0.5": "30 seconds", + "1": "1 minute", + "2": "2 minutes", + "5": "5 minutes", + "10": "10 minutes" + }, + "phoneNumber": { + "Mobile": "Mobile", + "Office": "Office", + "Fax": "Fax", + "Home": "Home", + "Other": "Other" + } + }, + "sets": { + "summernote": { + "NOTICE": "You can find translation here: https://github.com/HackerWins/summernote/tree/master/lang", + "font":{ + "bold":"Bold", + "italic":"Italic", + "underline":"Underline", + "strike":"Strike", + "clear":"Remove Font Style", + "height":"Line Height", + "name":"Font Family", + "size":"Font Size" + }, + "image":{ + "image":"Picture", + "insert":"Insert Image", + "resizeFull":"Resize Full", + "resizeHalf":"Resize Half", + "resizeQuarter":"Resize Quarter", + "floatLeft":"Float Left", + "floatRight":"Float Right", + "floatNone":"Float None", + "dragImageHere":"Drag an image here", + "selectFromFiles":"Select from files", + "url":"Image URL", + "remove":"Remove Image" + }, + "link":{ + "link":"Link", + "insert":"Insert Link", + "unlink":"Unlink", + "edit":"Edit", + "textToDisplay":"Text to display", + "url":"To what URL should this link go?", + "openInNewWindow":"Open in new window" + }, + "video":{ + "video":"Video", + "videoLink":"Video Link", + "insert":"Insert Video", + "url":"Video URL?", + "providers":"(YouTube, Vimeo, Vine, Instagram, or DailyMotion)" + }, + "table":{ + "table":"Table" + }, + "hr":{ + "insert":"Insert Horizontal Rule" + }, + "style":{ + "style":"Style", + "normal":"Normal", + "blockquote":"Quote", + "pre":"Code", + "h1":"Header 1", + "h2":"Header 2", + "h3":"Header 3", + "h4":"Header 4", + "h5":"Header 5", + "h6":"Header 6" + }, + "lists":{ + "unordered":"Unordered list", + "ordered":"Ordered list" + }, + "options":{ + "help":"Help", + "fullscreen":"Full Screen", + "codeview":"Code View" + }, + "paragraph":{ + "paragraph":"Paragraph", + "outdent":"Outdent", + "indent":"Indent", + "left":"Align left", + "center":"Align center", + "right":"Align right", + "justify":"Justify full" + }, + "color":{ + "recent":"Recent Color", + "more":"More Color", + "background":"BackColor", + "foreground":"FontColor", + "transparent":"Transparent", + "setTransparent":"Set transparent", + "reset":"Reset", + "resetToDefault":"Reset to default" + }, + "shortcut":{ + "shortcuts":"Keyboard shortcuts", + "close":"Close", + "textFormatting":"Text formatting", + "action":"Action", + "paragraphFormatting":"Paragraph formatting", + "documentStyle":"Document Style" + }, + "history":{ + "undo":"Undo", + "redo":"Redo" + } + } + } } diff --git a/application/Espo/Resources/i18n/en_US/Import.json b/application/Espo/Resources/i18n/en_US/Import.json index 0eb8be2a83..c9cefbb76e 100644 --- a/application/Espo/Resources/i18n/en_US/Import.json +++ b/application/Espo/Resources/i18n/en_US/Import.json @@ -1,15 +1,15 @@ { - "labels": { - "Revert": "Revert", - "Return to Import": "Return to Import", - "Run Import": "Run Import", - "Back": "Back", - "Field Mapping": "Field Mapping", - "Default Values": "Default Values", - "Add Field": "Add Field", - "Created": "Created", - "Updated": "Updated", - "Result": "Result", - "Show records": "Show records" - } + "labels": { + "Revert": "Revert", + "Return to Import": "Return to Import", + "Run Import": "Run Import", + "Back": "Back", + "Field Mapping": "Field Mapping", + "Default Values": "Default Values", + "Add Field": "Add Field", + "Created": "Created", + "Updated": "Updated", + "Result": "Result", + "Show records": "Show records" + } } diff --git a/application/Espo/Resources/i18n/en_US/Integration.json b/application/Espo/Resources/i18n/en_US/Integration.json index 37aed3d2e5..1001dc1dda 100644 --- a/application/Espo/Resources/i18n/en_US/Integration.json +++ b/application/Espo/Resources/i18n/en_US/Integration.json @@ -1,14 +1,14 @@ { - "fields": { - "enabled": "Enabled", - "clientId": "Client ID", - "clientSecret": "Client Secret", - "redirectUri": "Redirect URI" - }, - "messages": { - "selectIntegration": "Select an integration in menu." - }, - "help": { - "Google": "

Obtain OAuth 2.0 credentials from the Google Developers Console.

Visit Google Developers Console to obtain OAuth 2.0 credentials such as a Client ID and Client Secret that are known to both Google and EspoCRM application.

" - } + "fields": { + "enabled": "Enabled", + "clientId": "Client ID", + "clientSecret": "Client Secret", + "redirectUri": "Redirect URI" + }, + "messages": { + "selectIntegration": "Select an integration in menu." + }, + "help": { + "Google": "

Obtain OAuth 2.0 credentials from the Google Developers Console.

Visit Google Developers Console to obtain OAuth 2.0 credentials such as a Client ID and Client Secret that are known to both Google and EspoCRM application.

" + } } diff --git a/application/Espo/Resources/i18n/en_US/Note.json b/application/Espo/Resources/i18n/en_US/Note.json index e3819a324f..cdf96c0e43 100644 --- a/application/Espo/Resources/i18n/en_US/Note.json +++ b/application/Espo/Resources/i18n/en_US/Note.json @@ -1,6 +1,6 @@ { - "fields": { - "post": "Post", - "attachments": "Attachments" - } + "fields": { + "post": "Post", + "attachments": "Attachments" + } } diff --git a/application/Espo/Resources/i18n/en_US/Preferences.json b/application/Espo/Resources/i18n/en_US/Preferences.json index 93fdd7cd55..3be28e87ec 100644 --- a/application/Espo/Resources/i18n/en_US/Preferences.json +++ b/application/Espo/Resources/i18n/en_US/Preferences.json @@ -1,37 +1,37 @@ { - "fields": { - "dateFormat": "Date Format", - "timeFormat": "Time Format", - "timeZone": "Time Zone", - "weekStart": "First Day of Week", - "thousandSeparator": "Thousand Separator", - "decimalMark": "Decimal Mark", - "defaultCurrency": "Default Currency", - "currencyList": "Currency List", - "language": "Language", - - "smtpServer": "Server", - "smtpPort": "Port", - "smtpAuth": "Auth", - "smtpSecurity": "Security", - "smtpUsername": "Username", - "emailAddress": "Email", - "smtpPassword": "Password", - "smtpEmailAddress": "Email Address", - - "exportDelimiter": "Export Delimiter", - - "receiveAssignmentEmailNotifications": "Receive Email Notifications upon Assignment" - }, - "links": { - }, - "options": { - "weekStart": { - "0": "Sunday", - "1": "Monday" - } - }, - "labels": { - "Notifications": "Notifications" - } + "fields": { + "dateFormat": "Date Format", + "timeFormat": "Time Format", + "timeZone": "Time Zone", + "weekStart": "First Day of Week", + "thousandSeparator": "Thousand Separator", + "decimalMark": "Decimal Mark", + "defaultCurrency": "Default Currency", + "currencyList": "Currency List", + "language": "Language", + + "smtpServer": "Server", + "smtpPort": "Port", + "smtpAuth": "Auth", + "smtpSecurity": "Security", + "smtpUsername": "Username", + "emailAddress": "Email", + "smtpPassword": "Password", + "smtpEmailAddress": "Email Address", + + "exportDelimiter": "Export Delimiter", + + "receiveAssignmentEmailNotifications": "Receive Email Notifications upon Assignment" + }, + "links": { + }, + "options": { + "weekStart": { + "0": "Sunday", + "1": "Monday" + } + }, + "labels": { + "Notifications": "Notifications" + } } diff --git a/application/Espo/Resources/i18n/en_US/Role.json b/application/Espo/Resources/i18n/en_US/Role.json index fce516a200..4ae0f2c97d 100644 --- a/application/Espo/Resources/i18n/en_US/Role.json +++ b/application/Espo/Resources/i18n/en_US/Role.json @@ -1,35 +1,35 @@ { - "fields": { - "name": "Name", - "roles": "Roles" - }, - "links": { - "users": "Users", - "teams": "Teams" - }, - "labels": { - "Access": "Access", - "Create Role": "Create Role" - }, - "options": { - "accessList": { - "not-set": "not-set", - "enabled": "enabled", - "disabled": "disabled" - }, - "levelList": { - "all": "all", - "team": "team", - "own": "own", - "no": "no" - } - }, - "actions": { - "read": "Read", - "edit": "Edit", - "delete": "Delete" - }, - "messages": { - "changesAfterClearCache": "All changes in an access control will be applied after cache will be cleared." - } + "fields": { + "name": "Name", + "roles": "Roles" + }, + "links": { + "users": "Users", + "teams": "Teams" + }, + "labels": { + "Access": "Access", + "Create Role": "Create Role" + }, + "options": { + "accessList": { + "not-set": "not-set", + "enabled": "enabled", + "disabled": "disabled" + }, + "levelList": { + "all": "all", + "team": "team", + "own": "own", + "no": "no" + } + }, + "actions": { + "read": "Read", + "edit": "Edit", + "delete": "Delete" + }, + "messages": { + "changesAfterClearCache": "All changes in an access control will be applied after cache will be cleared." + } } diff --git a/application/Espo/Resources/i18n/en_US/ScheduledJob.json b/application/Espo/Resources/i18n/en_US/ScheduledJob.json index e204a2981d..60ad08fa87 100644 --- a/application/Espo/Resources/i18n/en_US/ScheduledJob.json +++ b/application/Espo/Resources/i18n/en_US/ScheduledJob.json @@ -1,30 +1,30 @@ { - "fields": { - "name": "Name", - "status": "Status", - "job": "Job", - "scheduling": "Scheduling (crontab notation)" - }, - "links": { - "log": "Log" - }, - "labels": { - "Create ScheduledJob": "Create Scheduled Job" - }, - "options": { - "job": { - "CheckInboundEmails": "Check Inbound Emails", - "Cleanup": "Clean-up" - }, - "cronSetup": { - "linux": "Note: Add this line to the crontab file to run Espo Scheduled Jobs:", - "mac": "Note: Add this line to the crontab file to run Espo Scheduled Jobs:", - "windows": "Note: Create a batch file with the following commands to run Espo Scheduled Jobs using Windows Scheduled Tasks:", - "default": "Note: Add this command to Cron Job (Scheduled Task):" - }, - "status": { - "Active": "Active", - "Inactive": "Inactive" - } - } + "fields": { + "name": "Name", + "status": "Status", + "job": "Job", + "scheduling": "Scheduling (crontab notation)" + }, + "links": { + "log": "Log" + }, + "labels": { + "Create ScheduledJob": "Create Scheduled Job" + }, + "options": { + "job": { + "CheckInboundEmails": "Check Inbound Emails", + "Cleanup": "Clean-up" + }, + "cronSetup": { + "linux": "Note: Add this line to the crontab file to run Espo Scheduled Jobs:", + "mac": "Note: Add this line to the crontab file to run Espo Scheduled Jobs:", + "windows": "Note: Create a batch file with the following commands to run Espo Scheduled Jobs using Windows Scheduled Tasks:", + "default": "Note: Add this command to Cron Job (Scheduled Task):" + }, + "status": { + "Active": "Active", + "Inactive": "Inactive" + } + } } diff --git a/application/Espo/Resources/i18n/en_US/ScheduledJobLogRecord.json b/application/Espo/Resources/i18n/en_US/ScheduledJobLogRecord.json index 46cf66bee6..381f648f53 100644 --- a/application/Espo/Resources/i18n/en_US/ScheduledJobLogRecord.json +++ b/application/Espo/Resources/i18n/en_US/ScheduledJobLogRecord.json @@ -1,6 +1,6 @@ { - "fields": { - "status": "Status", - "executionTime": "Execution Time" - } + "fields": { + "status": "Status", + "executionTime": "Execution Time" + } } diff --git a/application/Espo/Resources/i18n/en_US/Settings.json b/application/Espo/Resources/i18n/en_US/Settings.json index cc325ac200..b58b1fea31 100644 --- a/application/Espo/Resources/i18n/en_US/Settings.json +++ b/application/Espo/Resources/i18n/en_US/Settings.json @@ -1,76 +1,77 @@ { - "fields": { - "useCache": "Use Cache", - "dateFormat": "Date Format", - "timeFormat": "Time Format", - "timeZone": "Time Zone", - "weekStart": "First Day of Week", - "thousandSeparator": "Thousand Separator", - "decimalMark": "Decimal Mark", - "defaultCurrency": "Default Currency", - "baseCurrency": "Base Currency", - "baseCurrency": "Base Currency", - "currencyRates": "Rate Values", - - "currencyList": "Currency List", - "language": "Language", - - "companyLogo": "Company Logo", - - "smtpServer": "Server", - "smtpPort": "Port", - "smtpAuth": "Auth", - "smtpSecurity": "Security", - "smtpUsername": "Username", - "emailAddress": "Email", - "smtpPassword": "Password", - "outboundEmailFromName": "From Name", - "outboundEmailFromAddress": "From Address", - "outboundEmailIsShared": "Is Shared", - - "recordsPerPage": "Records Per Page", - "recordsPerPageSmall": "Records Per Page (Small)", - "tabList": "Tab List", - "quickCreateList": "Quick Create List", - - "exportDelimiter": "Export Delimiter", - - "authenticationMethod": "Authentication Method", - "ldapHost": "Host", - "ldapPort": "Port", - "ldapAuth": "Auth", - "ldapUsername": "Username", - "ldapPassword": "Password", - "ldapBindRequiresDn": "Bind Requires Dn", - "ldapBaseDn": "Base Dn", - "ldapAccountCanonicalForm": "Account Canonical Form", - "ldapAccountDomainName": "Account Domain Name", - "ldapTryUsernameSplit": "Try Username Split", - "ldapCreateEspoUser": "Create User in EspoCRM", - "ldapSecurity": "Security", - "ldapUserLoginFilter": "User Login Filter", - "ldapAccountDomainNameShort": "Account Domain Name Short", - "ldapOptReferrals": "Opt Referrals", - "disableExport": "Disable Export (only admin is allowed)", - "assignmentEmailNotifications": "Send Email Notifications upon Assignment", - "assignmentEmailNotificationsEntityList": "Entities to Notify About" - }, - "options": { - "weekStart": { - "0": "Sunday", - "1": "Monday" - } - }, - "tooltips": { - "recordsPerPageSmall": "Count of records in relatinship panels." - }, - "labels": { - "System": "System", - "Locale": "Locale", - "SMTP": "SMTP", - "Configuration": "Configuration", - "Notifications": "Notifications", - "Currency Settings": "Currency Settings", - "Currency Rtes": "Currency Rates" - } + "fields": { + "useCache": "Use Cache", + "dateFormat": "Date Format", + "timeFormat": "Time Format", + "timeZone": "Time Zone", + "weekStart": "First Day of Week", + "thousandSeparator": "Thousand Separator", + "decimalMark": "Decimal Mark", + "defaultCurrency": "Default Currency", + "baseCurrency": "Base Currency", + "currencyRates": "Rate Values", + + "currencyList": "Currency List", + "language": "Language", + + "companyLogo": "Company Logo", + + "smtpServer": "Server", + "smtpPort": "Port", + "smtpAuth": "Auth", + "smtpSecurity": "Security", + "smtpUsername": "Username", + "emailAddress": "Email", + "smtpPassword": "Password", + "outboundEmailFromName": "From Name", + "outboundEmailFromAddress": "From Address", + "outboundEmailIsShared": "Is Shared", + + "recordsPerPage": "Records Per Page", + "recordsPerPageSmall": "Records Per Page (Small)", + "tabList": "Tab List", + "quickCreateList": "Quick Create List", + + "exportDelimiter": "Export Delimiter", + + "authenticationMethod": "Authentication Method", + "ldapHost": "Host", + "ldapPort": "Port", + "ldapAuth": "Auth", + "ldapUsername": "Username", + "ldapPassword": "Password", + "ldapBindRequiresDn": "Bind Requires Dn", + "ldapBaseDn": "Base Dn", + "ldapAccountCanonicalForm": "Account Canonical Form", + "ldapAccountDomainName": "Account Domain Name", + "ldapTryUsernameSplit": "Try Username Split", + "ldapCreateEspoUser": "Create User in EspoCRM", + "ldapSecurity": "Security", + "ldapUserLoginFilter": "User Login Filter", + "ldapAccountDomainNameShort": "Account Domain Name Short", + "ldapOptReferrals": "Opt Referrals", + "disableExport": "Disable Export (only admin is allowed)", + "assignmentEmailNotifications": "Send Email Notifications upon Assignment", + "assignmentEmailNotificationsEntityList": "Entities to Notify About", + + "b2cMode": "B2C Mode" + }, + "options": { + "weekStart": { + "0": "Sunday", + "1": "Monday" + } + }, + "tooltips": { + "recordsPerPageSmall": "Count of records in relatinship panels." + }, + "labels": { + "System": "System", + "Locale": "Locale", + "SMTP": "SMTP", + "Configuration": "Configuration", + "Notifications": "Notifications", + "Currency Settings": "Currency Settings", + "Currency Rtes": "Currency Rates" + } } diff --git a/application/Espo/Resources/i18n/en_US/Team.json b/application/Espo/Resources/i18n/en_US/Team.json index ded74f5a25..e934be28c1 100644 --- a/application/Espo/Resources/i18n/en_US/Team.json +++ b/application/Espo/Resources/i18n/en_US/Team.json @@ -1,15 +1,17 @@ { - "fields": { - "name": "Name", - "roles": "Roles" - }, - "links": { - "users": "Users" - }, - "tooltips": { - "roles": "All users from this team will get access settings from selected roles." - }, - "labels": { - "Create Team": "Create Team" - } + "fields": { + "name": "Name", + "roles": "Roles", + "positionList": "Position List" + }, + "links": { + "users": "Users" + }, + "tooltips": { + "roles": "Access Roles. Users of this team obtain access control level from selected roles.", + "positionList": "Available positions in this team. E.g. Salesperson, Manager." + }, + "labels": { + "Create Team": "Create Team" + } } diff --git a/application/Espo/Resources/i18n/en_US/User.json b/application/Espo/Resources/i18n/en_US/User.json index 0f47fb9def..fc5615be4a 100644 --- a/application/Espo/Resources/i18n/en_US/User.json +++ b/application/Espo/Resources/i18n/en_US/User.json @@ -1,36 +1,41 @@ { - "fields": { - "name": "Name", - "userName": "User Name", - "title": "Title", - "isAdmin": "Is Admin", - "defaultTeam": "Default Team", - "emailAddress": "Email", - "phoneNumber": "Phone", - "roles": "Roles", - "password": "Password", - "passwordConfirm": "Confirm Password", - "newPassword": "New Password" - }, - "links": { - "teams": "Teams", - "roles": "Roles" - }, - "labels": { - "Create User": "Create User", - "Generate": "Generate", - "Access": "Access", - "Preferences": "Preferences", - "Change Password": "Change Password" - }, - "tooltips": { - "defaultTeam": "All records created by this user will be related to this team by default.", - "userName": "Letters a-z, numbers 0-9 and underscores are allowed." - }, - "messages": { - "passwordWillBeSent": "Password will be sent to user's email address.", - "accountInfoEmailSubject": "Account info", - "accountInfoEmailBody": "Your account information:\n\nUsername: {userName}\nPassword: {password}\n\n{siteUrl}", - "passwordChanged": "Password has been changed" - } + "fields": { + "name": "Name", + "userName": "User Name", + "title": "Title", + "isAdmin": "Is Admin", + "defaultTeam": "Default Team", + "emailAddress": "Email", + "phoneNumber": "Phone", + "roles": "Roles", + "teamRole": "Position", + "password": "Password", + "passwordConfirm": "Confirm Password", + "newPassword": "New Password" + }, + "links": { + "teams": "Teams", + "roles": "Roles" + }, + "labels": { + "Create User": "Create User", + "Generate": "Generate", + "Access": "Access", + "Preferences": "Preferences", + "Change Password": "Change Password", + "Teams and Access Control": "Teams and Access Control" + }, + "tooltips": { + "defaultTeam": "All records created by this user will be related to this team by default.", + "userName": "Letters a-z, numbers 0-9 and underscores are allowed.", + "isAdmin": "Admin user can access everything.", + "teams": "Teams which this user belongs to. Access control level is inherited from team's roles.", + "roles": "Additional access roles. Use it if user doesn't belong to any team or you need to extend access control level only for this user." + }, + "messages": { + "passwordWillBeSent": "Password will be sent to user's email address.", + "accountInfoEmailSubject": "Account info", + "accountInfoEmailBody": "Your account information:\n\nUsername: {userName}\nPassword: {password}\n\n{siteUrl}", + "passwordChanged": "Password has been changed" + } } diff --git a/application/Espo/Resources/i18n/es_ES/Admin.json b/application/Espo/Resources/i18n/es_ES/Admin.json index 8cecd418bb..eea619aabb 100644 --- a/application/Espo/Resources/i18n/es_ES/Admin.json +++ b/application/Espo/Resources/i18n/es_ES/Admin.json @@ -1,122 +1,145 @@ { - "labels": { - "Enabled": "Activado", - "Disabled": "Desactivado", - "System": "Sistema", - "Users": "Usuarios", - "Email": "Correo electrónico", - "Data": "Datos", - "Customization": "Personalizar", - "Available Fields": "Campos Disponibles", - "Layout": "Diseño", - "Enabled": "Activado", - "Disabled": "Desactivado", - "Add Panel": "Añadir Panel", - "Add Field": "Añadir Campo", - "Settings": "Opciones", - "Scheduled Jobs": "Tareas Programadas", - "Upgrade": "Actualizar", - "Clear Cache": "Limpiar Cache", - "Rebuild": "Reconstruir", - "Users": "Usuarios", - "Teams": "Equipos", - "Roles": "Roles", - "Outbound Emails": "Correos Salientes", - "Inbound Emails": "Correos Entrantes", - "Email Templates": "Platillas de Correo", - "Import": "Importar", - "Layout Manager": "Administrador de Diseño", - "Field Manager": "Administrador de Campos", - "User Interface": "Interfaz de Usuario" - }, - "layouts": { - "list": "Lista", - "detail": "Detalle", - "listSmall": "List (Small)", - "detailSmall": "Detail (Small)", - "filters": "Filtros de Búsqueda", - "massUpdate": "Actualización Masiva", - "relationships": "Relaciones" - }, - "fieldTypes": { - "address": "Dirección", - "array": "Array", - "foreign": "Foreign", - "duration": "Duración", - "password": "Contraseña", - "parsonName": "Nombre", - "autoincrement": "Auto incrementar", - "bool": "Booleano", - "currency": "Moneda", - "date": "Fecha", - "datetime": "Fecha/Hora", - "email": "Correo electrónico", - "enum": "Enum", - "enumInt": "Enum Integer", - "enumFloat": "Enum Float", - "float": "Float", - "int": "Int", - "link": "Enlace", - "linkMultiple": "Enlace Múltiple", - "linkParent": "Enlace Padre", - "multienim": "Multienum", - "phone": "Teléfono", - "text": "Texto", - "url": "Url", - "varchar": "Varchar", - "file": "Archivo", - "image": "Imagen" - }, - "fields": { - "type": "Tipo", - "name": "Nombre", - "label": "Etiqueta", - "required": "Requerido", - "default": "Por Defecto", - "maxLength": "Longitud máxima", - "options": "Options (raw values, not translated)", - "after": "After (field)", - "before": "Before (field)", - "link": "Enlace", - "field": "Campo", - "min": "Mínimo", - "max": "Máximo", - "translation": "Traducción", - "previewSize": "Tamaño de vista previa" - }, - "messages": { - "upgradeVersion": "Su EspoCRM será actualizado a la versión {version}. Tomará algún tiempo.", - "upgradeDone": "Su EspoCRM ha sido actualizado a la versión {version}. Refresque su ventana del navegador.", - "upgradeBackup": "Le recomendamos que haga copias de seguridad de sus archivos y datos EspoCRM antes de la actualización.", - "thousandSeparatorEqualsDecimalMark": "El separador de miles no puede ser la misma que marca decimal", - "userHasNoEmailAddress": "El usuario no tiene la dirección de correo electrónico.", - "selectEntityType": "Seleccione el tipo de entidad en el menú de la izquierda.", - "selectUpgradePackage": "Seleccione Actualizar Paquete", - "selectLayout": "Seleccione el diseño necesario en el menú de la izquierda y editarlo." - }, - "descriptions": { - "settings": "Configuración del sistema de aplicación.", - "scheduledJob": "Trabajos que se ejecutan por cron.(cron Jobs)", - "upgrade": "Actualiza EspoCRM.", - "clearCache": "Limpiar cache de Administración.", - "rebuild": "Reconstruir y limpiar el cache de Administración.", - "users": "Gestión de usuarios.", - "teams": "Gestión de Equipos", - "roles": "Gestión de Roles", - "outboundEmails": "Opciones SMTP para correo saliente.", - "inboundEmails": "Cuentas de correo IMAP Grupo. Importación-correo y dirección de correo electrónico a la sentencia.", - "emailTemplates": "Plantillas para mensajes de correo electrónico salientes.", - "import": "Importar datos desde CSV.", - "layoutManager": "Customize layouts (list, detail, edit, search, mass update).", - "fieldManager": "Crear nuevos campos o personalizar los ya existentes.", - "userInterface": "Configurar UI." - }, - "options": { - "previewSize": { - "x-small": "X-Small", - "small": "Pequeño", - "medium": "Mediano", - "large": "Grande" - } - } + "labels": { + "Enabled": "Activado", + "Disabled": "Desactivado", + "System": "Sistema", + "Users": "Usuarios", + "Email": "Correo electrónico", + "Data": "Datos", + "Customization": "Personalizar", + "Available Fields": "Campos Disponibles", + "Layout": "Diseño", + "Add Panel": "Añadir Panel", + "Add Field": "Añadir Campo", + "Settings": "Opciones", + "Scheduled Jobs": "Tareas Programadas", + "Upgrade": "Actualizar", + "Clear Cache": "Limpiar Cache", + "Rebuild": "Reconstruir", + "Teams": "Equipos", + "Roles": "Roles", + "Outbound Emails": "Correos Salientes", + "Inbound Emails": "Correos Entrantes", + "Email Templates": "Plantillas de Correo", + "Import": "Importar", + "Layout Manager": "Administrador de Diseño", + "Field Manager": "Administrador de Campos", + "User Interface": "Interfaz de Usuario", + "Auth Tokens": "Tokens Certificados", + "Authentication": "Autenticación", + "Currency": "Moneda", + "Integrations": "Integracion", + "Extensions": "Extensiones", + "Upload": "Subir", + "Installing...": "Instalando...", + "Upgrading...": "Actualizando", + "Upgraded successfully": "Actualización exitosa", + "Installed successfully": "Instalado de forma exitosa", + "Ready for upgrade": "Listo para actualizar", + "Run Upgrade": "Actualizar", + "Install": "Instalar", + "Ready for installation": "Listo para instalación", + "Uninstalling...": "Desinstalando", + "Uninstalled": "Desinstalado" + }, + "layouts": { + "list": "Lista", + "detail": "Detalle", + "listSmall": "Lista (Pequeña)", + "detailSmall": "Detalle (Pequeño)", + "filters": "Filtros de Búsqueda", + "massUpdate": "Actualización Masiva", + "relationships": "Relaciones" + }, + "fieldTypes": { + "address": "Dirección", + "array": "Arreglo", + "foreign": "Externo", + "duration": "Duración", + "password": "Contraseña", + "parsonName": "Nombre", + "autoincrement": "Auto incrementar", + "bool": "Boolean", + "currency": "Moneda", + "date": "Fecha", + "datetime": "Fecha/Hora", + "email": "Correo electrónico", + "enum": "Enum", + "enumInt": "Enum Entero", + "enumFloat": "Enum Decimal", + "float": "Decimal", + "int": "Ent", + "link": "Enlace", + "linkMultiple": "Enlace Múltiple", + "linkParent": "Enlace Padre", + "multienim": "Multienum", + "phone": "Teléfono", + "text": "Texto", + "url": "Url", + "varchar": "Varchar", + "file": "Archivo", + "image": "Imagen", + "multiEnum": "Multi-Enum" + }, + "fields": { + "type": "Tipo", + "name": "Asunto", + "label": "Etiqueta", + "required": "Requerido", + "default": "Por Defecto", + "maxLength": "Longitud máxima", + "options": "Opciones", + "after": "Después (campo)", + "before": "Antes (campo)", + "link": "Enlace", + "field": "Campo", + "min": "Mínimo", + "max": "Máximo", + "translation": "Traducción", + "previewSize": "Tamaño de vista previa" + }, + "messages": { + "upgradeVersion": "Su EspoCRM será actualizado a la versión {version}. Tomará algún tiempo.", + "upgradeDone": "Su EspoCRM ha sido actualizado a la versión {version}. Refresque su ventana del navegador.", + "upgradeBackup": "Le recomendamos que haga copias de seguridad de sus archivos y datos EspoCRM antes de la actualización.", + "thousandSeparatorEqualsDecimalMark": "El separador de miles no puede ser el mismo que marca decimal", + "userHasNoEmailAddress": "El usuario no tiene dirección de correo electrónico.", + "selectEntityType": "Seleccione el tipo de entidad en el menú de la izquierda.", + "selectUpgradePackage": "Seleccione Actualizar Paquete", + "downloadUpgradePackage": "La descarga necesita paquete(s) actualizados de acá.", + "selectLayout": "Seleccione el diseño necesario en el menú de la izquierda y editarlo.", + "selectExtensionPackage": "Seleccionar extensión del paquete", + "extensionInstalled": "La Extensión {name} {version} ha sido instalada", + "installExtension": "La Extensión {name} {version} está lista para instalar.", + "uninstallConfirmation": "¿Realmente desea desistalar la extensión?" + }, + "descriptions": { + "settings": "Configuración del sistema de aplicación.", + "scheduledJob": "Trabajos que se ejecutan por cron.(cron Jobs)", + "upgrade": "Actualiza EspoCRM.", + "clearCache": "Limpiar cache de Administración.", + "rebuild": "Reconstruir y limpiar el cache de Administración.", + "users": "Gestión de usuarios.", + "teams": "Gestión de Equipos", + "roles": "Gestión de Roles", + "outboundEmails": "Opciones SMTP para correo saliente.", + "inboundEmails": "Cuentas de correo Grupo IMAP . Importación-correo y dirección de correo electrónico a la sentencia.", + "emailTemplates": "Plantillas para mensajes de correo electrónico salientes.", + "import": "Importar datos desde CSV.", + "layoutManager": "Personalizar diseños (listas, detalles, editar, buscar, actualización masiva).", + "fieldManager": "Crear nuevos campos o personalizar los ya existentes.", + "userInterface": "Configurar IU.", + "authTokens": "Sesiones certificas activas. Direcciones IP y última fecha de acceso", + "authentication": "Opciones de autenticación", + "currency": "Opciones y tarifas de Moneda", + "extensions": "Instalar o desinstalar extensiones" + }, + "options": { + "previewSize": { + "x-small": "Muy Pequeño", + "small": "Pequeño", + "medium": "Mediano", + "large": "Grande" + } + } } diff --git a/application/Espo/Resources/i18n/es_ES/AuthToken.json b/application/Espo/Resources/i18n/es_ES/AuthToken.json new file mode 100644 index 0000000000..ce5579056d --- /dev/null +++ b/application/Espo/Resources/i18n/es_ES/AuthToken.json @@ -0,0 +1,9 @@ +{ + "fields": { + "user": "Usuario", + "ipAddress": "Dirección IP", + "lastAccess": "Fecha Último Acceso", + "createdAt": "Creado el" + + } +} diff --git a/application/Espo/Resources/i18n/es_ES/DashletOptions.json b/application/Espo/Resources/i18n/es_ES/DashletOptions.json new file mode 100644 index 0000000000..66e94ce265 --- /dev/null +++ b/application/Espo/Resources/i18n/es_ES/DashletOptions.json @@ -0,0 +1,10 @@ +{ + "fields": { + "title": "Título", + "dateFrom": "Fecha de", + "dateTo": "Fecha Para", + "autorefreshInterval": "Intervalo de Auto-Refrescar", + "displayRecords": "Mostrar Registros", + "isDoubleHeight": "Altitud 2x" + } +} diff --git a/application/Espo/Resources/i18n/es_ES/Email.json b/application/Espo/Resources/i18n/es_ES/Email.json index 9c03c3f914..d372290273 100644 --- a/application/Espo/Resources/i18n/es_ES/Email.json +++ b/application/Espo/Resources/i18n/es_ES/Email.json @@ -1,32 +1,51 @@ { - "fields": { - "name": "Asunto", - "parent": "Padre", - "status": "Estado", - "dateSent": "Enviado", - "from": "De", - "to": "a", - "cc": "CC", - "bcc": "BCC", - "isHtml": "Es Html", - "body": "Cuerpo", - "subject": "Asunto", - "attachments": "Adjuntos", - "selectTemplate": "Seleccione una Plantilla", - "fromEmailAddress": "De la dirección", - "toEmailAddresses": "a la Dirección", - "emailAddress": "Correo Electrónico" - }, - "links": { - }, - "options": { - "Draft": "Borrador", - "Sending": "Enviando", - "Sent": "Enviado", - "Archived": "Archivado" - }, - "labels": { - "Create Email": "Archivar Correo", - "Compose": "Componer" - } + "fields": { + "name": "Sujeto", + "parent": "Padre", + "status": "Estado", + "dateSent": "Enviado", + "from": "De", + "to": "a", + "cc": "CC", + "bcc": "BCC", + "isHtml": "Es Html", + "body": "Cuerpo", + "subject": "Sujeto", + "attachments": "Adjuntos", + "selectTemplate": "Seleccione una Plantilla", + "fromEmailAddress": "De la dirección", + "toEmailAddresses": "a la Dirección", + "emailAddress": "Correo Electrónico", + "deliveryDate": "Fecha Entrega" + }, + "links": { + }, + "options": { + "Draft": "Borrador", + "Sending": "Enviando", + "Sent": "Enviado", + "Archived": "Archivado" + }, + "labels": { + "Create Email": "Archivar Correo", + "Archive Email": "Archivar Correo", + "Compose": "Nuevo", + "Reply": "Responder", + "Reply to All": "Responder a Todos", + "Forward": "Adelante", + "Original message": "Mensaje Original", + "Forwarded message": "Mensaje reenviado", + "Email Accounts": "Cuentas de Correo Electrónico", + "Send Test Email": "Send Test Email", + "Send": "Send", + "Email Address": "Correo Electrónico" + }, + "messages": { + "noSmtpSetup": "No SMTP setup. {link}.", + "testEmailSent": "Test email has been sent" + }, + "presetFilters": { + "sent": "Enviado", + "archived": "Archivado" + } } diff --git a/application/Espo/Resources/i18n/es_ES/EmailAccount.json b/application/Espo/Resources/i18n/es_ES/EmailAccount.json new file mode 100644 index 0000000000..e8eb7274c7 --- /dev/null +++ b/application/Espo/Resources/i18n/es_ES/EmailAccount.json @@ -0,0 +1,29 @@ +{ + "fields": { + "name": "Asunto", + "status": "Estado", + "host": "Host", + "username": "Nombre de Usuario", + "password": "Contraseña", + "port": "Puerto", + "monitoredFolders": "Carpetas supervisadas", + "ssl": "SSL", + "fetchSince": "Traer Desde" + }, + "links": { + }, + "options": { + "status": { + "Active": "Activo", + "Inactive": "Inactivo" + } + }, + "labels": { + "Create EmailAccount": "Crear Cuenta de Correo Electrónico", + "IMAP": "IMAP", + "Main": "Principal" + }, + "messages": { + "couldNotConnectToImap": "No se pudo conectar con el servidor IMAP" + } +} diff --git a/application/Espo/Resources/i18n/es_ES/EmailAddress.json b/application/Espo/Resources/i18n/es_ES/EmailAddress.json index 5590c03242..24322ce27c 100644 --- a/application/Espo/Resources/i18n/es_ES/EmailAddress.json +++ b/application/Espo/Resources/i18n/es_ES/EmailAddress.json @@ -1,7 +1,7 @@ { - "labels": { - "Primary": "Primario", - "Opted Out": "optado por no", - "Invalid": "Inválido" - } + "labels": { + "Primary": "Primario", + "Opted Out": "optado por no", + "Invalid": "Inválido" + } } diff --git a/application/Espo/Resources/i18n/es_ES/EmailTemplate.json b/application/Espo/Resources/i18n/es_ES/EmailTemplate.json index e6445b7745..dbf86f399a 100644 --- a/application/Espo/Resources/i18n/es_ES/EmailTemplate.json +++ b/application/Espo/Resources/i18n/es_ES/EmailTemplate.json @@ -1,16 +1,16 @@ { - "fields": { - "name": "Nombre", - "status": "Estado", - "isHtml": "Es Html", - "body": "Cuerpo", - "subject": "Asunto", - "attachments": "Adjuntos", - "insertField": "" - }, - "links": { - }, - "labels": { - "Create EmailTemplate": "Crear Plantilla de Correo" - } + "fields": { + "name": "Asunto", + "status": "Estado", + "isHtml": "Es Html", + "body": "Cuerpo", + "subject": "Sujeto", + "attachments": "Adjuntos", + "insertField": "Project-Id-Version: \nPOT-Creation-Date: \nPO-Revision-Date: \nLast-Translator: \nLanguage-Team: EspoCRM \nMIME-Version: 1.0\nContent-Type: text/plain; charset=UTF-8\nContent-Transfer-Encoding: 8bit\nLanguage: es_ES\n" + }, + "links": { + }, + "labels": { + "Create EmailTemplate": "Crear Plantilla de Correo" + } } diff --git a/application/Espo/Resources/i18n/es_ES/Extension.json b/application/Espo/Resources/i18n/es_ES/Extension.json new file mode 100644 index 0000000000..e1c3e33a7e --- /dev/null +++ b/application/Espo/Resources/i18n/es_ES/Extension.json @@ -0,0 +1,15 @@ +{ + "fields": { + "name": "Asunto", + "version": "Version", + "description": "Descripción", + "isInstalled": "Instalado" + }, + "labels": { + "Uninstall": "Desinstalar", + "Install": "Instalar" + }, + "messages": { + "uninstalled": "Extension {name} ha sido desinstalada" + } +} diff --git a/application/Espo/Resources/i18n/es_ES/ExternalAccount.json b/application/Espo/Resources/i18n/es_ES/ExternalAccount.json new file mode 100644 index 0000000000..9cd8d5bf5a --- /dev/null +++ b/application/Espo/Resources/i18n/es_ES/ExternalAccount.json @@ -0,0 +1,8 @@ +{ + "labels": { + "Connect": "Conectar", + "Connected": "Conectado" + }, + "help": { + } +} diff --git a/application/Espo/Resources/i18n/es_ES/Global.json b/application/Espo/Resources/i18n/es_ES/Global.json index cac2b2b4dd..30303b4375 100644 --- a/application/Espo/Resources/i18n/es_ES/Global.json +++ b/application/Espo/Resources/i18n/es_ES/Global.json @@ -1,395 +1,450 @@ { - "scopeNames": { - "Email": "Correo electrónico", - "User": "Usuario", - "Team": "Equipo", - "Role": "Rol", - "EmailTemplate": "Plantilla de Correo", - "OutboundEmail": "Correo Saliente", - "ScheduledJob": "Tarea Programada" - }, - "scopeNamesPlural": { - "Email": "Correos", - "User": "Usuarios", - "Team": "Equipos", - "Role": "Roles", - "EmailTemplate": "Platillas de Correo", - "OutboundEmail": "Correos Salientes", - "ScheduledJob": "Tareas Programadas" - }, - "labels": { - "Misc": "Misc", - "Merge": "Fundir", - "None": "Ninguno", - "by": "por", - "Saved": "Guardado", - "Error": "Error", - "Select": "Seleccionar", - "Not valid": "Inválido", - "Please wait...": "Por favor espere...", - "Please wait": "Por favor espere", - "Loading...": "Cargando...", - "Uploading...": "Subiendo...", - "Sending...": "Enviando...", - "Posted": "Publicado", - "Linked": "Enlazado", - "Unlinked": "Desenlazado", - "Access denied": "Acceso denegado", - "Access": "Acceso", - "Are you sure?": "Are you sure?", - "Record has been removed": "Registro Eliminado", - "Wrong username/password": "Nombre de usuario/contraseña incorrectos", - "Post cannot be empty": "La entrada no puede estar vacia", - "Removing...": "Removiendo...", - "Unlinking...": "Desenlazando...", - "Posting...": "Publicando...", - "Username can not be empty!": "Nombre de usuario no puede estar vacío!", - "Cache is not enabled": "Cache no está habilitado", - "Cache has been cleared": "Cache Limpiado Correctamente", - "Rebuild has been done": "Se ha reconstruido", - "Saving...": "Guardando...", - "Modified": "Modificado", - "Created": "Creado", - "Create": "Crear", - "create": "crear", - "Overview": "Vista", - "Details": "Detalles", - "Add Filter": "Añadir Filtro", - "Add Dashlet": "Añadir Dashlet", - "Add": "Añadir", - "Reset": "Resetear", - "Menu": "Menú", - "More": "Más", - "Search": "Buscar", - "Only My": "Solo Yo", - "Open": "Abrir", - "Admin": "Administrador", - "About": "Acerca", - "Refresh": "Refrescar", - "Remove": "Remover", - "Options": "Optiones", - "Username": "Nombre de Usuario", - "Password": "Contraseña", - "Login": "Entrar", - "Log Out": "Salir", - "Preferences": "Preferencias", - "State": "Estado/Distrito", - "Street": "Calle", - "Country": "país", - "City": "Ciudad", - "PostalCode": "Código Postal", - "Followed": "Seguido", - "Follow": "Seguir", - "Clear Local Cache": "Borrar Cache Local", - "Actions": "Acciones", - "Delete": "Borrar", - "Update": "Actualizar", - "Save": "Guardar", - "Edit": "Editar", - "Cancel": "Cancelar", - "Unlink": "Desenlazar", - "Mass Update": "Actualización Masiva", - "Export": "Exportar", - "No Data": "Sin Datos", - "All": "Todos", - "Active": "Activo", - "Inactive": "Inactivo", - "Write your comment here": "Escriba su comentario aquí", - "Post": "Entrada", - "Stream": "Stream", - "Show more": "Mostrar mas", - "Dashlet Options": "Opciones Dashlet", - "Full Form": "Formulario Completo", - "Insert": "Insertar", - "Person": "Persona", - "First Name": "Primer Nombre", - "Last Name": "Apellidos", - "Original": "Original", - "You": "Tu", - "you": "tu", - "change": "cambiar" - }, - "messages": { - "notModified": "Usted no ha modificado el registro", - "duplicate": "El registro que está creando parece ser un duplicado", - "fieldIsRequired": "{field} es requerido", - "fieldShouldBeEmail": "{field} debe se un correo electrónico válido", - "fieldShouldBeFloat": "{field} debe se un decimal válido", - "fieldShouldBeInt": "{field} debe se un entero válido", - "fieldShouldBeDate": "{field} debe se una fecha válida", - "fieldShouldBeDatetime": "{field} debe se una fecha válida fecha/hora", - "fieldShouldAfter": "{field} debe estar después {otherField}", - "fieldShouldBefore": "{field} debe estar antes {otherField}", - "fieldShouldBeBetween": "{field} debe estar entre {min} and {max}", - "fieldShouldBeLess": "{field} debe ser menor que {value}", - "fieldShouldBeGreater": "{field} debe ser mayor que {value}", - "fieldBadPasswordConfirm": "{field} confirmado de forma incorrecta" - }, - "boolFilters": { - "onlyMy": "Solo Yo", - "open": "Abrir", - "active": "Activo" - }, - "fields": { - "name": "Nombre", - "firstName": "Primer Nombre", - "lastName": "Apellidos", - "salutationName": "Saludo", - "assignedUser": "Usuario Asignado", - "emailAddress": "Correo electrónico", - "assignedUserName": "Nombre de Usuario Asignado", - "teams": "Equipos", - "createdAt": "Creado el", - "modifiedAt": "Modificado el", - "createdBy": "Creado Por", - "modifiedBy": "Modificado Por", - "title": "Título", - "dateFrom": "Fecha de", - "dateTo": "Fecha Para", - "autorefreshInterval": "Intervalo de Auto-Refrescar", - "displayRecords": "Mostrar Registros" - }, - "links": { - "teams": "Equipos", - "users": "Usuarios" - }, - "dashlets": { - "Stream": "Stream" - }, - "streamMessages": { - "create": "{user} creado {entityType} {entity}", - "createAssigned": "{user} creado {entityType} {entity} asignado a {assignee}", - "assign": "{user} asignado {entityType} {entity} a {assignee}", - "post": "{user} publicado en {entityType} {entity}", - "attach": "{user} adjunto en {entityType} {entity}", - "status": "{user} actualizado {field} on {entityType} {entity}", - "update": "{user} actualizado {entityType} {entity}", - "createRelated": "{user} creado {relatedEntityType} {relatedEntity} enlazado a {entityType} {entity}", - "emailReceived": "{entity} ha sido recibido por {entityType} {entity}", - - "createThis": "{user} crear este {entityType}", - "createAssignedThis": "{user} crear este {entityType} asignado a {assignee}", - "assignThis": "{user} asignar este {entityType} a {assignee}", - "postThis": "{user} publicado", - "attachThis": "{user} adjunto", - "statusThis": "{user} actualizado {field}", - "updateThis": "{user} actualizado a este {entityType}", - "createRelatedThis": "{user} creado {relatedEntityType} {relatedEntity} enlazado a este {entityType}", - "emailReceivedThis": "{entity} se ha recibido" - }, - "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"] - }, - "options": { - "salutationName": { - "Mr.": "Sr.", - "Mrs.": "Sra.", - "Dr.": "Dr.", - "Drs.": "Drs." - }, - "language": { - "af_ZA": "Afrikaans", - "az_AZ": "Azerbaijani", - "be_BY": "Belarusian", - "bg_BG": "Bulgarian", - "bn_IN": "Bengali", - "bs_BA": "Bosnian", - "ca_ES": "Catalan", - "cs_CZ": "Czech", - "cy_GB": "Welsh", - "da_DK": "Danish", - "de_DE": "German", - "el_GR": "Greek", - "en_GB":"English (UK)", - "en_US":"English (US)", - "es_ES":"Spanish (Spain)", - "et_EE": "Estonian", - "eu_ES": "Basque", - "fa_IR": "Persian", - "fi_FI": "Finnish", - "fo_FO": "Faroese", - "fr_CA":"French (Canada)", - "fr_FR":"French (France)", - "ga_IE": "Irish", - "gl_ES": "Galician", - "gn_PY": "Guarani", - "he_IL": "Hebrew", - "hi_IN": "Hindi", - "hr_HR": "Croatian", - "hu_HU": "Hungarian", - "hy_AM": "Armenian", - "id_ID": "Indonesian", - "is_IS": "Icelandic", - "it_IT": "Italian", - "ja_JP": "Japanese", - "ka_GE": "Georgian", - "km_KH": "Khmer", - "ko_KR": "Korean", - "ku_TR": "Kurdish", - "lt_LT": "Lithuanian", - "lv_LV": "Latvian", - "mk_MK": "Macedonian", - "ml_IN": "Malayalam", - "ms_MY": "Malay", - "nb_NO":"Norwegian Bokmål", - "nn_NO": "Norwegian Nynorsk", - "ne_NP": "Nepali", - "nl_NL": "Dutch", - "pa_IN": "Punjabi", - "pl_PL": "Polish", - "ps_AF": "Pashto", - "pt_BR":"Portuguese (Brazil)", - "pt_PT":"Portuguese (Portugal)", - "ro_RO": "Romanian", - "ru_RU": "Russian", - "sk_SK": "Slovak", - "sl_SI": "Slovene", - "sq_AL": "Albanian", - "sr_RS": "Serbian", - "sv_SE": "Swedish", - "sw_KE": "Swahili", - "ta_IN": "Tamil", - "te_IN": "Telugu", - "th_TH": "Thai", - "tl_PH": "Tagalog", - "tr_TR": "Turkish", - "uk_UA": "Ukrainian", - "ur_PK": "Urdu", - "vi_VN": "Vietnamese", - "zh_CN":"Simplified Chinese (China)", - "zh_HK":"Traditional Chinese (Hong Kong)", - "zh_TW":"Traditional Chinese (Taiwan)" - }, - "dateSearchRanges": { - "on": "Está en", - "notOn": "No está en", - "after": "Después", - "before": "Antes", - "between": "Entre" - }, - "intSearchRanges": { - "equals": "Iguales", - "notEquals": "Diferentes", - "greaterThan": "Mayor que", - "lessThan": "Menor que", - "greaterThanOrEquals": "Mayor o igual que", - "lessThanOrEquals": "Menor o igual que", - "between": "Entre" - }, - "autorefreshInterval": { - "0": "Ninguno", - "0.5": "30 segundos", - "1": "1 minuto", - "2": "2 minutos", - "5": "5 minutos", - "10": "10 minutos" - } - }, - "sets": { - "summernote": { - "NOTICE": "Usted puede encontrar aquí la traducción: https://github.com/HackerWins/summernote/tree/master/lang", - "font":{ - "bold": "Negrita", - "italic": "Itálico", - "underline": "Subrayado", - "strike": "Tachado", - "clear": "Quitar Estilo de Fuente", - "height": "Alto de línea", - "name": "Familia de Fuente", - "size": "Tamaño de Fuente" - }, - "image":{ - "image": "Imagen", - "insert": "Insertar Imagen", - "resizeFull": "Cambiar el tamaño a completo", - "resizeHalf": "Cambiar el tamaño a la mitad", - "resizeQuarter": "Cambiar el tamaño a un cuarto", - "floatLeft": "Flotar Izquierda", - "floatRight": "Flotar Derecha", - "floatNone": "Sin Flotar", - "dragImageHere": "Arrastrar una imagen aquí", - "selectFromFiles": "Seleccionar desde Archivo", - "url": "Url de Imagen", - "remove": "Remover Imagen" - }, - "link":{ - "link": "Enlace", - "insert": "Insertar Enlace", - "unlink": "Desenlazar", - "edit": "Editar", - "textToDisplay": "TExto a mostrar", - "url":"To what URL should this link go?", - "openInNewWindow": "Abrir en nueva ventana" - }, - "video":{ - "video": "Vídeo", - "videoLink": "Enlace al Vídeo", - "insert": "Insertar Vídeo", - "url":"Video URL?", - "providers":"(YouTube, Vimeo, Vine, Instagram, or DailyMotion)" - }, - "table":{ - "table": "Tabla" - }, - "hr":{ - "insert": "Insertar regla horizontal" - }, - "style":{ - "style": "Estilo", - "normal": "Normal", - "blockquote": "Cita", - "pre": "Código", - "h1": "Header 1", - "h2": "Header 2", - "h3": "Header 3", - "h4": "Header 4", - "h5": "Header 5", - "h6": "Header 6" - }, - "lists":{ - "unordered": "Lista sin Ordenar", - "ordered": "Lista Ordenada" - }, - "options":{ - "help": "Ayuda", - "fullscreen": "Pantalla Completa", - "codeview": "Ver Código" - }, - "paragraph":{ - "paragraph": "Párrafo", - "outdent": "Anular sangría", - "indent": "Sangría", - "left": "Alinear Izquierda", - "center": "Alinear Centro", - "right": "Alinear Derecha", - "justify": "Justificado" - }, - "color":{ - "recent": "Color Reciente", - "more": "Mas Colores", - "background": "Color de Fondo", - "foreground": "Color de Fuente", - "transparent": "Transparente", - "setTransparent": "Establecer transparente", - "reset": "Resetear", - "resetToDefault": "Restablecer a (por defecto)" - }, - "shortcut":{ - "shortcuts": "Atajos de teclado", - "close": "Cerrar", - "textFormatting": "Formato de texto", - "action": "Acción", - "paragraphFormatting": "Formato de párrafo", - "documentStyle": "Estilo de Documento" - }, - "history":{ - "undo": "Deshacer", - "redo": "Rehacer" - } - } - } + "scopeNames": { + "Email": "Correo electrónico", + "User": "Usuario", + "Team": "Equipo", + "Role": "Rol", + "EmailTemplate": "Plantilla de Correo", + "EmailAccount": "Cuenta de Email", + "EmailAccountScope": "Cuenta de Email", + "OutboundEmail": "Correo Saliente", + "ScheduledJob": "Tarea Programada", + "ExternalAccount": "Cuenta Externa", + "Extension": "Extension" + }, + "scopeNamesPlural": { + "Email": "Correos", + "User": "Usuarios", + "Team": "Equipos", + "Role": "Roles", + "EmailTemplate": "Plantillas de Correo", + "EmailAccount": "Cuentas de Correo Electrónico", + "EmailAccountScope": "Cuentas de Correo Electrónico", + "OutboundEmail": "Correos Salientes", + "ScheduledJob": "Tareas Programadas", + "ExternalAccount": "Cuentas Externas", + "Extension": "Extensiones" + }, + "labels": { + "Misc": "Misceláneos", + "Merge": "Fundir", + "None": "Ninguno", + "by": "por", + "Saved": "Guardado", + "Error": "Error", + "Select": "Seleccionar", + "Not valid": "Inválido", + "Please wait...": "Por favor espere...", + "Please wait": "Por favor espere", + "Loading...": "Cargando...", + "Uploading...": "Subiendo...", + "Sending...": "Enviando...", + "Removed": "Eliminado", + "Posted": "Publicado", + "Linked": "Enlazado", + "Unlinked": "Desenlazado", + "Access denied": "Acceso denegado", + "Access": "Acceso", + "Are you sure?": "¿Está seguro?", + "Record has been removed": "Registro Eliminado", + "Wrong username/password": "Nombre de usuario/contraseña incorrectos", + "Post cannot be empty": "La entrada no puede estar vacia", + "Removing...": "Removiendo...", + "Unlinking...": "Desenlazando...", + "Posting...": "Publicando...", + "Username can not be empty!": "¡Nombre de usuario no puede estar vacío!", + "Cache is not enabled": "Cache no está habilitado", + "Cache has been cleared": "Cache Limpiado Correctamente", + "Rebuild has been done": "Se ha reconstruido", + "Saving...": "Guardando...", + "Modified": "Modificado", + "Created": "Creado", + "Create": "Crear", + "create": "crear", + "Overview": "Vista", + "Details": "Detalles", + "Add Filter": "Añadir Filtro", + "Add Dashlet": "Añadir Dashlet", + "Add": "Añadir", + "Reset": "Resetear", + "Menu": "Menú", + "More": "Más", + "Search": "Buscar", + "Only My": "Solo Yo", + "Open": "Abrir", + "Admin": "Administrador", + "About": "Acerca", + "Refresh": "Refrescar", + "Remove": "Remover", + "Options": "Opciones", + "Username": "Nombre de Usuario", + "Password": "Contraseña", + "Login": "Entrar", + "Log Out": "Salir", + "Preferences": "Preferencias", + "State": "Estado/Distrito", + "Street": "Calle", + "Country": "país", + "City": "Ciudad", + "PostalCode": "Código Postal", + "Followed": "Seguido", + "Follow": "Seguir", + "Clear Local Cache": "Borrar Cache Local", + "Actions": "Acciones", + "Delete": "Borrar", + "Update": "Actualizar", + "Save": "Guardar", + "Edit": "Editar", + "Cancel": "Cancelar", + "Unlink": "Desenlazar", + "Mass Update": "Actualización Masiva", + "Export": "Exportar", + "No Data": "Sin Datos", + "No Access": "No Access", + "All": "Todos", + "Active": "Activo", + "Inactive": "Inactivo", + "Write your comment here": "Escriba su comentario aquí", + "Post": "Entrada", + "Stream": "Stream", + "Show more": "Mostrar mas", + "Dashlet Options": "Opciones Dashlet", + "Full Form": "Formulario Completo", + "Insert": "Insertar", + "Person": "Persona", + "First Name": "Primer Nombre", + "Last Name": "Apellidos", + "Original": "Original", + "You": "Tu", + "you": "tu", + "change": "cambiar", + "Change": "Change", + "Primary": "Primario", + "Save Filters": "Salvar Filtros", + "Administration": "Administración", + "Run Import": "Importar", + "Duplicate": "Duplicar", + "Notifications": "Notificaciones", + "Mark all read": "Marcar todos como leído", + "See more": "Ver más", + "Today": "Hoy", + "Tomorrow": "Mañana", + "Yesterday": "Ayer" + }, + "messages": { + "notModified": "Usted no ha modificado el registro", + "duplicate": "El registro que está creando parece ser un duplicado", + "fieldIsRequired": "{field} es requerido", + "fieldShouldBeEmail": "{field} debe ser un correo electrónico válido", + "fieldShouldBeFloat": "{field} debe ser un decimal válido", + "fieldShouldBeInt": "{field} debe ser un entero válido", + "fieldShouldBeDate": "{field} debe ser una fecha válida", + "fieldShouldBeDatetime": "{field} debe ser una fecha válida fecha/hora", + "fieldShouldAfter": "{field} debe estar después de {otherField}", + "fieldShouldBefore": "{field} debe estar antes de {otherField}", + "fieldShouldBeBetween": "{field} debe estar entre {min} y {max}", + "fieldShouldBeLess": "{field} debe ser menor que {value}", + "fieldShouldBeGreater": "{field} debe ser mayor que {value}", + "fieldBadPasswordConfirm": "{field} confirmado de forma incorrecta", + "resetPreferencesDone": "Preferences has been reset to defaults", + "assignmentEmailNotificationSubject": "EspoCRM {entityType}: {Entity.name}", + "assignmentEmailNotificationBody": "{assignerUserName} ha asignado {entityType} '{Entity.name}' a tu\n\n{recordUrl}", + "confirmation": "¿Está seguro?", + "resetPreferencesConfirmation": "Are you sure you want to reset preferences to defaults?", + "removeRecordConfirmation": "¿Está seguro que quiere eliminar registros?", + "unlinkRecordConfirmation": "¿Está seguro que quiere desenlazar relación?", + "removeSelectedRecordsConfirmation": "¿Está seguro que quiere eliminar los registros seleccionados?", + "massUpdateResult": "{count} records have been updated", + "massUpdateResultSingle": "{count} record has been updated", + "noRecordsUpdated": "No records were updated", + "massRemoveResult": "{count} records have been removed", + "massRemoveResultSingle": "{count} record has been removed", + "noRecordsRemoved": "No records were removed" + }, + "boolFilters": { + "onlyMy": "Solo Yo", + "open": "Abrir", + "active": "Activo" + }, + "fields": { + "name": "Asunto", + "firstName": "Primer Nombre", + "lastName": "Apellidos", + "salutationName": "Saludo", + "assignedUser": "Usuario Asignado", + "emailAddress": "Correo electrónico", + "assignedUserName": "Nombre de Usuario Asignado", + "teams": "Equipos", + "createdAt": "Creado en", + "modifiedAt": "Modificado el", + "createdBy": "Creado Por", + "modifiedBy": "Modificado Por" + }, + "links": { + "assignedUser": "Usuario Asignado", + "createdBy": "Creado Por", + "modifiedBy": "Modificado Por", + "team": "Equipo", + "roles": "Roles", + "teams": "Equipos", + "users": "Usuarios" + }, + "dashlets": { + "Stream": "Stream" + }, + "streamMessages": { + "create": "{user} creado {entityType} {entity}", + "createAssigned": "{user} creado {entityType} {entity} asignado a {assignee}", + "assign": "{user} asignado {entityType} {entity} a {assignee}", + "post": "{user} publicado en {entityType} {entity}", + "attach": "{user} adjunto en {entityType} {entity}", + "status": "{user} actualizado {field} en {entityType} {entity}", + "update": "{user} actualizado {entityType} {entity}", + "createRelated": "{user} creado {relatedEntityType} {relatedEntity} enlazado a {entityType} {entity}", + "emailReceived": "Email {email} has been received for {entityType} {entity}", + "emailReceivedInitial": "Email {email} has been received and created {entityType} {entity}", + "mentionInPost": "{user} mencionado {mentioned} en {entityType} {entity}", + + "createThis": "{user} crear este {entityType}", + "createAssignedThis": "{user} crear este {entityType} asignado a {assignee}", + "assignThis": "{user} asignar este {entityType} a {assignee}", + "postThis": "{user} publicado", + "attachThis": "{user} adjunto", + "statusThis": "{user} actualizado {field}", + "updateThis": "{user} actualizado a este {entityType}", + "createRelatedThis": "{user} creado {relatedEntityType} {relatedEntity} enlazado a este {entityType}", + "emailReceivedThis": "Email {email} has been received", + "emailReceivedInitialThis": "Email {email} has been received and created this {entityType}" + }, + "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"] + }, + "options": { + "salutationName": { + "Mr.": "Sr.", + "Mrs.": "Sra.", + "Dr.": "Dr.", + "Drs.": "Dres." + }, + "language": { + "af_ZA": "Afrikáans", + "az_AZ": "Azerbaiyán", + "be_BY": "Bielorruso", + "bg_BG": "Bulgaro", + "bn_IN": "Bengalí", + "bs_BA": "Bosnio", + "ca_ES": "Catalán", + "cs_CZ": "Checo", + "cy_GB": "Galés", + "da_DK": "Danés", + "de_DE": "Alemán", + "el_GR": "Griego", + "en_GB": "Inglés (UK)", + "en_US": "Inglés (US)", + "es_ES": "Español (Spain)", + "et_EE": "Estonio", + "eu_ES": "Vasco", + "fa_IR": "Persa", + "fi_FI": "Finlandés", + "fo_FO": "Feroés", + "fr_CA": "Francés (Canada)", + "fr_FR": "Francés (Francia)", + "ga_IE": "Irlandés", + "gl_ES": "Gallego", + "gn_PY": "Guaraní", + "he_IL": "Hebreo", + "hi_IN": "Hindi", + "hr_HR": "Croata", + "hu_HU": "Hungaro", + "hy_AM": "Armenio", + "id_ID": "Indonesio", + "is_IS": "Islandés", + "it_IT": "Italiano", + "ja_JP": "Japonés", + "ka_GE": "Georgiano", + "km_KH": "Camboyano", + "ko_KR": "Coreano", + "ku_TR": "Kurdo", + "lt_LT": "Lituano", + "lv_LV": "Latón", + "mk_MK": "Macedonio", + "ml_IN": "Malabar", + "ms_MY": "Malayo", + "nb_NO": "Noruego Bokmål", + "nn_NO": "Noruego Nynorsk", + "ne_NP": "Nepalí", + "nl_NL": "Holandés", + "pa_IN": "Punyabí", + "pl_PL": "Polaco", + "ps_AF": "Pastún", + "pt_BR": "Portugués (Brasil)", + "pt_PT": "Portugués (Portugal)", + "ro_RO": "Rumano", + "ru_RU": "Ruso", + "sk_SK": "Eslovaco", + "sl_SI": "Esloveno", + "sq_AL": "Albanés", + "sr_RS": "Serbio", + "sv_SE": "Sueco", + "sw_KE": "Suajili", + "ta_IN": "Tamil", + "te_IN": "Télugu", + "th_TH": "Tailandés", + "tl_PH": "Tagalo", + "tr_TR": "Turco", + "uk_UA": "Ucraniano", + "ur_PK": "Urdu", + "vi_VN": "Vietnamita", + "zh_CN": "Chino Simplificado (China)", + "zh_HK": "Chino Tradicional (Hong Kong)", + "zh_TW": "Chino Traditional (Taiwán)" + }, + "dateSearchRanges": { + "on": "Está en", + "notOn": "No está en", + "after": "Después", + "before": "Antes", + "between": "Entre", + "today": "Hoy", + "past": "Pasado", + "future": "Futuro", + "currentMonth": "Mes Actual", + "lastMonth": "Mes Pasado", + "currentQuarter": "Trimestre Actual", + "lastQuarter": "Trimestre Pasado", + "currentYear": "Año Actual", + "lastYear": "Año Pasado" + }, + "intSearchRanges": { + "equals": "Iguales", + "notEquals": "Diferentes", + "greaterThan": "Mayor que", + "lessThan": "Menor que", + "greaterThanOrEquals": "Mayor o igual que", + "lessThanOrEquals": "Menor o igual que", + "between": "Entre" + }, + "autorefreshInterval": { + "0": "Ninguno", + "0.5": "30 segundos", + "1": "1 minuto", + "2": "2 minutos", + "5": "5 minutos", + "10": "10 minutos" + }, + "phoneNumber": { + "Mobile": "Teléfono móvil", + "Office": "Oficina", + "Fax": "Fax", + "Home": "Hogar", + "Other": "Otro" + } + }, + "sets": { + "summernote": { + "NOTICE": "Usted puede encontrar aquí la traducción: https://github.com/HackerWins/summernote/tree/master/lang", + "font":{ + "bold": "Negrita", + "italic": "Itálico", + "underline": "Subrayado", + "strike": "Tachado", + "clear": "Quitar Estilo de Fuente", + "height": "Alto de línea", + "name": "Familia de Fuente", + "size": "Tamaño de Fuente" + }, + "image":{ + "image": "Visualización", + "insert": "Insertar Imagen", + "resizeFull": "Cambiar el tamaño a completo", + "resizeHalf": "Cambiar el tamaño a la mitad", + "resizeQuarter": "Cambiar el tamaño a un cuarto", + "floatLeft": "Flotar Izquierda", + "floatRight": "Flotar Derecha", + "floatNone": "Sin Flotar", + "dragImageHere": "Arrastrar una imagen aquí", + "selectFromFiles": "Seleccionar desde Archivo", + "url": "Url de Imagen", + "remove": "Remover Imagen" + }, + "link":{ + "link": "Enlace", + "insert": "Insertar Enlace", + "unlink": "Desenlazar", + "edit": "Editar", + "textToDisplay": "Texto a mostrar", + "url": "¿A que URL debería ir este enlace?", + "openInNewWindow": "Abrir en nueva ventana" + }, + "video":{ + "video": "Video", + "videoLink": "Enlace al Video", + "insert": "Insertar Video", + "url": "¿URL del Video?", + "providers": "(YouTube, Vimeo, Vine, Instagram, or DailyMotion)" + }, + "table":{ + "table": "Tabla" + }, + "hr":{ + "insert": "Insertar regla horizontal" + }, + "style":{ + "style": "Estilo", + "normal": "Normal", + "blockquote": "Cita", + "pre": "Código", + "h1": "Cabecera 1", + "h2": "Cabecera 2", + "h3": "Cabecera 3", + "h4": "Cabecera 4", + "h5": "Cabecera 5", + "h6": "Cabecera 6" + }, + "lists":{ + "unordered": "Lista sin Ordenar", + "ordered": "Lista Ordenada" + }, + "options":{ + "help": "Ayuda", + "fullscreen": "Pantalla Completa", + "codeview": "Ver Código" + }, + "paragraph":{ + "paragraph": "Párrafo", + "outdent": "Anular sangría", + "indent": "Sangría", + "left": "Alinear Izquierda", + "center": "Alinear Centro", + "right": "Alinear Derecha", + "justify": "Justificado" + }, + "color":{ + "recent": "Color Reciente", + "more": "Mas Colores", + "background": "Color de Fondo", + "foreground": "Color de Fuente", + "transparent": "Transparente", + "setTransparent": "Establecer transparente", + "reset": "Resetear", + "resetToDefault": "Restablecer a (por defecto)" + }, + "shortcut":{ + "shortcuts": "Atajos de teclado", + "close": "Cerrar", + "textFormatting": "Formato de texto", + "action": "Acción", + "paragraphFormatting": "Formato de párrafo", + "documentStyle": "Estilo de Documento" + }, + "history":{ + "undo": "Deshacer", + "redo": "Rehacer" + } + } + } } diff --git a/application/Espo/Resources/i18n/es_ES/Import.json b/application/Espo/Resources/i18n/es_ES/Import.json new file mode 100644 index 0000000000..a0fdfe48bb --- /dev/null +++ b/application/Espo/Resources/i18n/es_ES/Import.json @@ -0,0 +1,15 @@ +{ + "labels": { + "Revert": "Revertir", + "Return to Import": "Regreso a Importar", + "Run Import": "Importar", + "Back": "Anterior", + "Field Mapping": "Mapeo de Campo", + "Default Values": "Valores por Defecto", + "Add Field": "Añadir Campo", + "Created": "Creado", + "Updated": "Actualizado", + "Result": "Resultado", + "Show records": "Mostrar Registros" + } +} diff --git a/application/Espo/Resources/i18n/es_ES/Integration.json b/application/Espo/Resources/i18n/es_ES/Integration.json new file mode 100644 index 0000000000..ec0fdb5c1b --- /dev/null +++ b/application/Espo/Resources/i18n/es_ES/Integration.json @@ -0,0 +1,14 @@ +{ + "fields": { + "enabled": "Activado", + "clientId": "ID Cliente", + "clientSecret": "Secreto Cliente", + "redirectUri": "Redireccionar URI" + }, + "messages": { + "selectIntegration": "Seleccionar una integración en menú" + }, + "help": { + "Google": "

Obtener las credenciales de OAuth 2.0 desde la Consola de Google Developers.

Visita Consola Google Developers para obtener las credenciales de OAuth 2.0 tales como ID Cliente y Secreto de Cliente que son conocidos por ambos Google y la aplicación EspoCRM.

" + } +} diff --git a/application/Espo/Resources/i18n/es_ES/Note.json b/application/Espo/Resources/i18n/es_ES/Note.json index 6a78744a91..0249a3013e 100644 --- a/application/Espo/Resources/i18n/es_ES/Note.json +++ b/application/Espo/Resources/i18n/es_ES/Note.json @@ -1,6 +1,6 @@ { - "fields": { - "post": "Entrada", - "attachments": "Adjuntos" - } + "fields": { + "post": "Entrada", + "attachments": "Adjuntos" + } } diff --git a/application/Espo/Resources/i18n/es_ES/Preferences.json b/application/Espo/Resources/i18n/es_ES/Preferences.json index 5d61786267..3558a03513 100644 --- a/application/Espo/Resources/i18n/es_ES/Preferences.json +++ b/application/Espo/Resources/i18n/es_ES/Preferences.json @@ -1,32 +1,37 @@ { - "fields": { - "dateFormat": "Formato de fecha", - "timeFormat": "Formato de tiempo", - "timeZone": "Zona Horaria", - "weekStart": "Primer día de la semana", - "thousandSeparator": "Separador de miles", - "decimalMark": "Separador decimal", - "defaultCurrency": "Moneda por Defecto", - "currencyList": "Lista de Moneda", - "language": "Lenguaje", - - "smtpServer": "Servidor", - "smtpPort": "Puerto", - "smtpAuth": "Autenticación", - "smtpSecurity": "Securidad", - "smtpUsername": "Nombre de Usuario", - "emailAddress": "Correo electrónico", - "smtpPassword": "Contraseña", - "smtpEmailAddress": "Correo Electrónico", - - "exportDelimiter": "Export Delimiter" - }, - "links": { - }, - "options": { - "weekStart": { - "0": "Domingo", - "1": "Lunes" - } - } + "fields": { + "dateFormat": "Formato de fecha", + "timeFormat": "Formato de tiempo", + "timeZone": "Zona Horaria", + "weekStart": "Primer día de la semana", + "thousandSeparator": "Separador de miles", + "decimalMark": "Separador decimal", + "defaultCurrency": "Moneda por Defecto", + "currencyList": "Lista de Moneda", + "language": "Idioma", + + "smtpServer": "Servidor", + "smtpPort": "Puerto", + "smtpAuth": "Autenticación", + "smtpSecurity": "Seguridad", + "smtpUsername": "Nombre de Usuario", + "emailAddress": "Correo electrónico", + "smtpPassword": "Contraseña", + "smtpEmailAddress": "Correo Electrónico", + + "exportDelimiter": "Exportar Delimitador", + + "receiveAssignmentEmailNotifications": "Recevir Notificaciones por Correo Electrónico al ser Asignado" + }, + "links": { + }, + "options": { + "weekStart": { + "0": "Domingo", + "1": "Lunes" + } + }, + "labels": { + "Notifications": "Notificaciones" + } } diff --git a/application/Espo/Resources/i18n/es_ES/Role.json b/application/Espo/Resources/i18n/es_ES/Role.json index fab61cf0f2..6d277d7619 100644 --- a/application/Espo/Resources/i18n/es_ES/Role.json +++ b/application/Espo/Resources/i18n/es_ES/Role.json @@ -1,32 +1,35 @@ { - "fields": { - "name": "Nombre", - "roles": "Roles" - }, - "links": { - "users": "Usuarios", - "teams": "Equipos" - }, - "labels": { - "Access": "Acceso", - "Create Role": "Crear Rol" - }, - "options": { - "accessList": { - "not-set": "sin establecer", - "enabled": "activado", - "disabled": "desactivado" - }, - "levelList": { - "all": "todos", - "team": "equipo", - "own": "propio", - "no": "no" - } - }, - "actions": { - "read": "Leer", - "edit": "Editar", - "delete": "Borrar" - } + "fields": { + "name": "Asunto", + "roles": "Roles" + }, + "links": { + "users": "Usuarios", + "teams": "Equipos" + }, + "labels": { + "Access": "Acceso", + "Create Role": "Crear Rol" + }, + "options": { + "accessList": { + "not-set": "sin establecer", + "enabled": "activado", + "disabled": "desactivado" + }, + "levelList": { + "all": "todos", + "team": "equipo", + "own": "propio", + "no": "no" + } + }, + "actions": { + "read": "Leer", + "edit": "Editar", + "delete": "Borrar" + }, + "messages": { + "changesAfterClearCache": "Todos los cambios en el control de acceso serán aplicacados después de limpiar la caché" + } } diff --git a/application/Espo/Resources/i18n/es_ES/ScheduledJob.json b/application/Espo/Resources/i18n/es_ES/ScheduledJob.json index f04fa7fcd1..2b590b0cf8 100644 --- a/application/Espo/Resources/i18n/es_ES/ScheduledJob.json +++ b/application/Espo/Resources/i18n/es_ES/ScheduledJob.json @@ -1,30 +1,30 @@ { - "fields": { - "name": "Nombre", - "status": "Estado", - "job": "Trabajo", - "scheduling": "Scheduling (crontab notation)" - }, - "links": { - "log": "Registro de Log" - }, - "labels": { - "Create ScheduledJob": "Crear Tarea programado" - }, - "options": { - "job": { - "CheckInboundEmails": "Comprobar Correos Entrantes", - "Cleanup": "Limpiar" - }, - "cronSetup": { - "linux": "Nota: Añada esta línea al archivo crontab para ejecutar trabajos Espo programadas:", - "mac": "Nota: Añada esta línea al archivo crontab para ejecutar trabajos Espo programadas:", - "windows": "Nota: Crear un archivo por lotes con los siguientes comandos para ejecutar tareas programadas usando Espo tareas programadas de Windows:", - "default": "Note: Add this command to Cron Job (Scheduled Task):" - }, - "status": { - "Active": "Activo", - "Inactive": "Inactivo" - } - } + "fields": { + "name": "Asunto", + "status": "Estado", + "job": "Trabajo", + "scheduling": "Programación (crontab anotación)" + }, + "links": { + "log": "Registro de Log" + }, + "labels": { + "Create ScheduledJob": "Crear Tarea programado" + }, + "options": { + "job": { + "CheckInboundEmails": "Comprobar Correos Entrantes", + "Cleanup": "Limpiar" + }, + "cronSetup": { + "linux": "Nota: Añada esta línea al archivo crontab para ejecutar trabajos Espo programados:", + "mac": "Nota: Añada esta línea al archivo crontab para ejecutar trabajos Espo programados:", + "windows": "Nota: Crear un archivo por lotes con los siguientes comandos para ejecutar trabajos programados de Espo usando tareas programadas de Windows:", + "default": "Nota: Agregar este comando a Cron Job (Tarea Programada):" + }, + "status": { + "Active": "Activo", + "Inactive": "Inactivo" + } + } } diff --git a/application/Espo/Resources/i18n/es_ES/ScheduledJobLogRecord.json b/application/Espo/Resources/i18n/es_ES/ScheduledJobLogRecord.json index d37b200c3a..ad2cf50af4 100644 --- a/application/Espo/Resources/i18n/es_ES/ScheduledJobLogRecord.json +++ b/application/Espo/Resources/i18n/es_ES/ScheduledJobLogRecord.json @@ -1,6 +1,6 @@ { - "fields": { - "status": "Estado", - "executionTime": "Tiempo de Ejecución" - } + "fields": { + "status": "Estado", + "executionTime": "Tiempo de Ejecución" + } } diff --git a/application/Espo/Resources/i18n/es_ES/Settings.json b/application/Espo/Resources/i18n/es_ES/Settings.json index 8ff43d4180..61a14c25e5 100644 --- a/application/Espo/Resources/i18n/es_ES/Settings.json +++ b/application/Espo/Resources/i18n/es_ES/Settings.json @@ -1,44 +1,75 @@ { - "fields": { - "useCache": "Usar Cache", - "dateFormat": "Formato de fecha", - "timeFormat": "Formato de tiempo", - "timeZone": "Zona Horaria", - "weekStart": "Primer día de la semana", - "thousandSeparator": "Separador de miles", - "decimalMark": "Separador decimal", - "defaultCurrency": "Moneda por Defecto", - "currencyList": "Lista de Moneda", - "language": "Lenguaje", - - "smtpServer": "Servidor", - "smtpPort": "Puerto", - "smtpAuth": "Autenticación", - "smtpSecurity": "Securidad", - "smtpUsername": "Nombre de Usuario", - "emailAddress": "Correo electrónico", - "smtpPassword": "Contraseña", - "outboundEmailFromName": "De Nombre", - "outboundEmailFromAddress": "De la dirección", - "outboundEmailIsShared": "Es Compartido", - - "recordsPerPage": "Registros por Página", - "recordsPerPageSmall": "Records Per Page (Small)", - "tabList": "Lista Pestaña", - "quickCreateList": "Crear Lista Rápido", - - "exportDelimiter": "Export Delimiter" - }, - "options": { - "weekStart": { - "0": "Domingo", - "1": "Lunes" - } - }, - "labels": { - "System": "Sistema", - "Locale": "Localización", - "SMTP": "SMTP", - "Configuration": "Configuración" - } + "fields": { + "useCache": "Usar Caché", + "dateFormat": "Formato de fecha", + "timeFormat": "Formato de tiempo", + "timeZone": "Zona Horaria", + "weekStart": "Primer día de la semana", + "thousandSeparator": "Separador de miles", + "decimalMark": "Separador decimal", + "defaultCurrency": "Moneda por Defecto", + "baseCurrency": "Moneda Base", + "currencyRates": "Valores Tarifa", + + "currencyList": "Lista de Moneda", + "language": "Idioma", + + "companyLogo": "Logo Compañia", + + "smtpServer": "Servidor", + "smtpPort": "Puerto", + "smtpAuth": "Autenticación", + "smtpSecurity": "Seguridad", + "smtpUsername": "Nombre de Usuario", + "emailAddress": "Correo electrónico", + "smtpPassword": "Contraseña", + "outboundEmailFromName": "De Nombre", + "outboundEmailFromAddress": "De la dirección", + "outboundEmailIsShared": "Es Compartido", + + "recordsPerPage": "Registros por Página", + "recordsPerPageSmall": "Registros Por Página (Pequeño)", + "tabList": "Lista Pestaña", + "quickCreateList": "Crear Lista Rápida", + + "exportDelimiter": "Exportar Delimitador", + + "authenticationMethod": "Método de Autentificación", + "ldapHost": "Host", + "ldapPort": "Puerto", + "ldapAuth": "Autenticación", + "ldapUsername": "Nombre de Usuario", + "ldapPassword": "Contraseña", + "ldapBindRequiresDn": "Bind Necesita Nd (Nombre Dominio)", + "ldapBaseDn": "ND Base", + "ldapAccountCanonicalForm": "Forma Canónica de la Cuenta", + "ldapAccountDomainName": "Nombre de Dominio de la Cuenta", + "ldapTryUsernameSplit": "Intentar dividir el nombre de Usuario", + "ldapCreateEspoUser": "Crear Usuario en EspoCRM", + "ldapSecurity": "Seguridad", + "ldapUserLoginFilter": "Usar Filtro en el Login", + "ldapAccountDomainNameShort": "Nombre Dominio Corto para la Cuenta", + "ldapOptReferrals": "Referencias Opt", + "disableExport": "Desactivar Exportar (Solo admin está permitido)", + "assignmentEmailNotifications": "Enviar Correos Electrónicos de notificación sobre Asignación", + "assignmentEmailNotificationsEntityList": "Entidades a Notificar" + }, + "options": { + "weekStart": { + "0": "Domingo", + "1": "Lunes" + } + }, + "tooltips": { + "recordsPerPageSmall": "Contador de registros en los paneles de relación" + }, + "labels": { + "System": "Sistema", + "Locale": "Localización", + "SMTP": "SMTP", + "Configuration": "Configuración", + "Notifications": "Notificaciones", + "Currency Settings": "Configuración Moneda", + "Currency Rtes": "Tarifa Moneda" + } } diff --git a/application/Espo/Resources/i18n/es_ES/Team.json b/application/Espo/Resources/i18n/es_ES/Team.json index 41f8be42af..38b5625534 100644 --- a/application/Espo/Resources/i18n/es_ES/Team.json +++ b/application/Espo/Resources/i18n/es_ES/Team.json @@ -1,12 +1,15 @@ { - "fields": { - "name": "Nombre", - "roles": "Roles" - }, - "links": { - "users": "Usuarios" - }, - "labels": { - "Create Team": "Crear Equipo" - } + "fields": { + "name": "Asunto", + "roles": "Roles" + }, + "links": { + "users": "Usuarios" + }, + "tooltips": { + "roles": "Todos los usuarios de este equipo tendrán acceso a la configuración desde los roles seleccionados" + }, + "labels": { + "Create Team": "Crear Equipo" + } } diff --git a/application/Espo/Resources/i18n/es_ES/User.json b/application/Espo/Resources/i18n/es_ES/User.json index 2c8e77f5a3..e37924fc16 100644 --- a/application/Espo/Resources/i18n/es_ES/User.json +++ b/application/Espo/Resources/i18n/es_ES/User.json @@ -1,21 +1,36 @@ { - "fields": { - "name": "Nombre", - "userName": "Nombre de Usuario", - "title": "Título", - "isAdmin": "Es Administrador", - "defaultTeam": "Equipo por Defecto", - "emailAddress": "Correo electrónico", - "phone": "Teléfono", - "roles": "Roles", - "password": "Contraseña", - "passwordConfirm": "Confirmar Contraseña" - }, - "links": { - "teams": "Equipos", - "roles": "Roles" - }, - "labels": { - "Create User": "Crear Usuario" - } + "fields": { + "name": "Asunto", + "userName": "Nombre Usuario", + "title": "Título", + "isAdmin": "Es Administrador", + "defaultTeam": "Equipo por Defecto", + "emailAddress": "Correo electrónico", + "phoneNumber": "Teléfono", + "roles": "Roles", + "password": "Contraseña", + "passwordConfirm": "Confirmar Contraseña", + "newPassword": "Nueva Contraseña" + }, + "links": { + "teams": "Equipos", + "roles": "Roles" + }, + "labels": { + "Create User": "Crear Usuario", + "Generate": "Generar", + "Access": "Acceso", + "Preferences": "Preferencias", + "Change Password": "Cambiar Contraseña" + }, + "tooltips": { + "defaultTeam": "Todos los registros creados por este usuario serán relacionados a este equipo por defecto.", + "userName": "Letras a-z, números 0-9 y guiones bajos están permitidos" + }, + "messages": { + "passwordWillBeSent": "La Contraseña será enviada al correo electrónico del usuario", + "accountInfoEmailSubject": "Información Cuenta", + "accountInfoEmailBody": "Información de tu cuenta:\n\nNombre Usuario: {userName}\nContraseña: {password}\n\n{siteUrl}", + "passwordChanged": "La Contraseña ha sido cambiada" + } } diff --git a/application/Espo/Resources/i18n/fr_FR/Admin.json b/application/Espo/Resources/i18n/fr_FR/Admin.json index 428cd73c68..da5f330549 100644 --- a/application/Espo/Resources/i18n/fr_FR/Admin.json +++ b/application/Espo/Resources/i18n/fr_FR/Admin.json @@ -1,126 +1,123 @@ { - "labels": { - "Enabled": "Activé", - "Disabled": "Désactivé", - "System": "Système", - "Users": "Utilisateurs", - "Email": "Email", - "Data": "Données", - "Customization": "Personalisation", - "Available Fields": "Champs Disponibles", - "Layout": "Disposition", - "Enabled": "Activé", - "Disabled": "Désactivé", - "Add Panel": "Ajouter un Panneau", - "Add Field": "Ajouter un Champs", - "Settings": "Paramètres", - "Scheduled Jobs": "Tâches Planifiées", - "Upgrade": "Mettre à Jour", - "Clear Cache": "Vider le Cache", - "Rebuild": "Reconstruire", - "Users": "Utilisateurs", - "Teams": "Equipes", - "Roles": "Rôles", - "Outbound Emails": "Emails Sortants", - "Inbound Emails": "Emails Entrants", - "Email Templates": "Modèles d'email", - "Import": "Importer", - "Layout Manager": "Gestionnaire de Dispositions", - "Field Manager": "Gestionnaire de Colonnes", - "User Interface": "Interface Utilisateur", - "Auth Tokens": "Jetons d'Identification", - "Authentication": "Authentification" - }, - "layouts": { - "list": "Liste", - "detail": "Détail", - "listSmall": "List (Small)", - "detailSmall": "Detail (Small)", - "filters": "Filtres de Recherche", - "massUpdate": "Mise à Jour en Masse", - "relationships": "Rapports" - }, - "fieldTypes": { - "address": "Adresse", - "array": "Tableau", - "foreign": "Etranger", - "duration": "Durée", - "password": "Mot de Passe", - "parsonName": "Nom Personnel", - "autoincrement": "Auto incrémenté", - "bool": "Boléen", - "currency": "Monnaie", - "date": "Date", - "datetime": "Heure et Date", - "email": "Email", - "enum": "Enumérateur", - "enumInt": "Enumérateur Entier", - "enumFloat": "Enumérateur Flottant", - "float": "Flottant", - "int": "Entier", - "link": "Lien", - "linkMultiple": "Lien Multiple", - "linkParent": "Lien Parent", - "multienim": "Enumérateur Multiple", - "phone": "Téléphone", - "text": "Texte", - "url": "Url", - "varchar": "Varchar", - "file": "Fichier", - "image": "Image" - }, - "fields": { - "type": "Type", - "name": "Nom", - "label": "Label", - "required": "Requis", - "default": "Standard", - "maxLength": "Taille Maximum", - "options": "Options (raw values, not translated)", - "after": "After (field)", - "before": "Before (field)", - "link": "Lien", - "field": "Champs", - "min": "Min", - "max": "Max", - "translation": "Traduction", - "previewSize": "Taille de l'Aperçu" - }, - "messages": { - "upgradeVersion": "Your EspoCRM will be upgraded to version {version}. This can take some time.", - "upgradeDone": "Your EspoCRM has been upgraded to version {version}. Refresh your browser window.", - "upgradeBackup": "We recommend you to make backup of your EspoCRM files and data before upgrade.", - "thousandSeparatorEqualsDecimalMark": "Le séparateur de milliers ne peut être égal au marqueur décimal", - "userHasNoEmailAddress": "L'utilisateur n'a pas d'adresse email.", - "selectEntityType": "Selectionner le type d'entité dans le menu gauche", - "selectUpgradePackage": "Sélectionnez le package de mise à niveau", - "selectLayout": "" - }, - "descriptions": { - "settings": "Paramètres système de l'application", - "scheduledJob": "Tâches ", - "upgrade": "Mettre à niveau EspoCRM.", - "clearCache": "Vider le Cache d'arrière-plan.", - "rebuild": "Reconstruire l'arrière plan et vider le cache.", - "users": "Gestion des utilisateurs.", - "teams": "Gestion des équipes.", - "roles": "Gestion des rôles.", - "outboundEmails": "Paramètres SMTP des emails sortants.", - "inboundEmails": "Group IMAP email accouts. Email import and Email-to-Case.", - "emailTemplates": "Modèles pour les emails sortants.", - "import": "Importer des données depuis un fichier CSV.", - "layoutManager": "Customize layouts (list, detail, edit, search, mass update).", - "fieldManager": "Créer de nouveaux champs ou personnaliser ceux existants.", - "userInterface": "Configurer l'interface utilisateur.", - "authTokens": "Sessions authorisées Activées. Adresse IP et dernière date d'accès.", - "authentication": "Paramètres d'authentification." - }, - "options": { - "previewSize": { - "x-small": "Très petit", - "small": "Petit", - "medium": "Moyen", - "large": "Grand" - } - } + "labels": { + "Enabled": "Activé", + "Disabled": "Désactivé", + "System": "Système", + "Users": "Utilisateurs", + "Email": "Email", + "Data": "Données", + "Customization": "Personalisation", + "Available Fields": "Champs Disponibles", + "Layout": "Disposition", + "Add Panel": "Ajouter un Panneau", + "Add Field": "Ajouter un Champs", + "Settings": "Paramètres", + "Scheduled Jobs": "Tâches Planifiées", + "Upgrade": "Mettre à Jour", + "Clear Cache": "Vider le Cache", + "Rebuild": "Reconstruire", + "Teams": "Equipes", + "Roles": "Rôles", + "Outbound Emails": "Emails Sortants", + "Inbound Emails": "Emails Entrants", + "Email Templates": "Modèles d'email", + "Import": "Importer", + "Layout Manager": "Gestionnaire de Dispositions", + "Field Manager": "Gestionnaire de Colonnes", + "User Interface": "Interface Utilisateur", + "Auth Tokens": "Jetons d'Identification", + "Authentication": "Authentification" + }, + "layouts": { + "list": "Liste", + "detail": "Détail", + "listSmall": "List (Small)", + "detailSmall": "Detail (Small)", + "filters": "Filtres de Recherche", + "massUpdate": "Mise à Jour en Masse", + "relationships": "Rapports" + }, + "fieldTypes": { + "address": "Adresse", + "array": "Tableau", + "foreign": "Etranger", + "duration": "Durée", + "password": "Mot de Passe", + "parsonName": "Nom Personnel", + "autoincrement": "Auto incrémenté", + "bool": "Boléen", + "currency": "Monnaie", + "date": "Date", + "datetime": "Heure et Date", + "email": "Email", + "enum": "Enumérateur", + "enumInt": "Enumérateur Entier", + "enumFloat": "Enumérateur Flottant", + "float": "Flottant", + "int": "Entier", + "link": "Lien", + "linkMultiple": "Lien Multiple", + "linkParent": "Lien Parent", + "multienim": "Enumérateur Multiple", + "phone": "Téléphone", + "text": "Texte", + "url": "Url", + "varchar": "Varchar", + "file": "Fichier", + "image": "Image" + }, + "fields": { + "type": "Type", + "name": "Nom", + "label": "Label", + "required": "Requis", + "default": "Standard", + "maxLength": "Taille Maximum", + "options": "Options", + "after": "After (field)", + "before": "Before (field)", + "link": "Lien", + "field": "Champs", + "min": "Min", + "max": "Max", + "translation": "Traduction", + "previewSize": "Taille de l'Aperçu" + }, + "messages": { + "upgradeVersion": "Your EspoCRM will be upgraded to version {version}. This can take some time.", + "upgradeDone": "Your EspoCRM has been upgraded to version {version}. Refresh your browser window.", + "upgradeBackup": "We recommend you to make backup of your EspoCRM files and data before upgrade.", + "thousandSeparatorEqualsDecimalMark": "Le séparateur de milliers ne peut être égal au marqueur décimal", + "userHasNoEmailAddress": "L'utilisateur n'a pas d'adresse email.", + "selectEntityType": "Selectionner le type d'entité dans le menu gauche", + "selectUpgradePackage": "Sélectionnez le package de mise à niveau", + "selectLayout": "" + }, + "descriptions": { + "settings": "Paramètres système de l'application", + "scheduledJob": "Tâches ", + "upgrade": "Mettre à niveau EspoCRM.", + "clearCache": "Vider le Cache d'arrière-plan.", + "rebuild": "Reconstruire l'arrière plan et vider le cache.", + "users": "Gestion des utilisateurs.", + "teams": "Gestion des équipes.", + "roles": "Gestion des rôles.", + "outboundEmails": "Paramètres SMTP des emails sortants.", + "inboundEmails": "Group IMAP email accouts. Email import and Email-to-Case.", + "emailTemplates": "Modèles pour les emails sortants.", + "import": "Importer des données depuis un fichier CSV.", + "layoutManager": "Customize layouts (list, detail, edit, search, mass update).", + "fieldManager": "Créer de nouveaux champs ou personnaliser ceux existants.", + "userInterface": "Configurer l'interface utilisateur.", + "authTokens": "Sessions authorisées Activées. Adresse IP et dernière date d'accès.", + "authentication": "Paramètres d'authentification." + }, + "options": { + "previewSize": { + "x-small": "Très petit", + "small": "Petit", + "medium": "Moyen", + "large": "Grand" + } + } } diff --git a/application/Espo/Resources/i18n/fr_FR/AuthToken.json b/application/Espo/Resources/i18n/fr_FR/AuthToken.json index 1c9140adcb..f7833d8bf8 100644 --- a/application/Espo/Resources/i18n/fr_FR/AuthToken.json +++ b/application/Espo/Resources/i18n/fr_FR/AuthToken.json @@ -1,9 +1,9 @@ { - "fields": { - "user": "Utilisateur", - "ipAddress": "Adresse IP", - "lastAccess": "Date du dernier accès", - "createdAt": "Date de connexion" + "fields": { + "user": "Utilisateur", + "ipAddress": "Adresse IP", + "lastAccess": "Date du dernier accès", + "createdAt": "Date de connexion" - } + } } diff --git a/application/Espo/Resources/i18n/fr_FR/Email.json b/application/Espo/Resources/i18n/fr_FR/Email.json index f7c7379236..f407e10985 100644 --- a/application/Espo/Resources/i18n/fr_FR/Email.json +++ b/application/Espo/Resources/i18n/fr_FR/Email.json @@ -1,32 +1,32 @@ { - "fields": { - "name": "Sujet", - "parent": "Parent", - "status": "Statut", - "dateSent": "Date d'envoi", - "from": "De", - "to": "Vers", - "cc": "CC", - "bcc": "BCC", - "isHtml": "En HTML", - "body": "Corps", - "subject": "Sujet", - "attachments": "Fichiers Joints", - "selectTemplate": "Selectionner le Modèle", - "fromEmailAddress": "Adresse de l'Emetteur", - "toEmailAddresses": "Adresse du Destinataire", - "emailAddress": "Adresse Email" - }, - "links": { - }, - "options": { - "Draft": "Brouillon", - "Sending": "En Envoi", - "Sent": "Envoyé", - "Archived": "Archivé" - }, - "labels": { - "Create Email": "Archiver les Emails", - "Compose": "Nouveau Message" - } + "fields": { + "name": "Sujet", + "parent": "Parent", + "status": "Statut", + "dateSent": "Date d'envoi", + "from": "De", + "to": "Vers", + "cc": "CC", + "bcc": "BCC", + "isHtml": "En HTML", + "body": "Corps", + "subject": "Sujet", + "attachments": "Fichiers Joints", + "selectTemplate": "Selectionner le Modèle", + "fromEmailAddress": "Adresse de l'Emetteur", + "toEmailAddresses": "Adresse du Destinataire", + "emailAddress": "Adresse Email" + }, + "links": { + }, + "options": { + "Draft": "Brouillon", + "Sending": "En Envoi", + "Sent": "Envoyé", + "Archived": "Archivé" + }, + "labels": { + "Create Email": "Archiver les Emails", + "Compose": "Nouveau Message" + } } diff --git a/application/Espo/Resources/i18n/fr_FR/EmailAddress.json b/application/Espo/Resources/i18n/fr_FR/EmailAddress.json index f9a58d2100..4399d99a34 100644 --- a/application/Espo/Resources/i18n/fr_FR/EmailAddress.json +++ b/application/Espo/Resources/i18n/fr_FR/EmailAddress.json @@ -1,7 +1,7 @@ { - "labels": { - "Primary": "Premier", - "Opted Out": "Opted Out", - "Invalid": "Invalide" - } + "labels": { + "Primary": "Premier", + "Opted Out": "Opted Out", + "Invalid": "Invalide" + } } diff --git a/application/Espo/Resources/i18n/fr_FR/EmailTemplate.json b/application/Espo/Resources/i18n/fr_FR/EmailTemplate.json index 4dd183fa79..a9a8a7f90c 100644 --- a/application/Espo/Resources/i18n/fr_FR/EmailTemplate.json +++ b/application/Espo/Resources/i18n/fr_FR/EmailTemplate.json @@ -1,16 +1,16 @@ { - "fields": { - "name": "Nom", - "status": "Statut", - "isHtml": "En HTML", - "body": "Corps", - "subject": "Sujet", - "attachments": "Fichiers Joints", - "insertField": "" - }, - "links": { - }, - "labels": { - "Create EmailTemplate": "Créer un modèle d'email" - } + "fields": { + "name": "Nom", + "status": "Statut", + "isHtml": "En HTML", + "body": "Corps", + "subject": "Sujet", + "attachments": "Fichiers Joints", + "insertField": "" + }, + "links": { + }, + "labels": { + "Create EmailTemplate": "Créer un modèle d'email" + } } diff --git a/application/Espo/Resources/i18n/fr_FR/Global.json b/application/Espo/Resources/i18n/fr_FR/Global.json index 58b639d2cb..141b73557b 100644 --- a/application/Espo/Resources/i18n/fr_FR/Global.json +++ b/application/Espo/Resources/i18n/fr_FR/Global.json @@ -1,397 +1,397 @@ { - "scopeNames": { - "Email": "Email", - "User": "Utilisateur", - "Team": "Equipe", - "Role": "Rôle", - "EmailTemplate": "Modèle d'Email", - "OutboundEmail": "Email Sortant", - "ScheduledJob": "Tâche Planifiée" - }, - "scopeNamesPlural": { - "Email": "Courriers", - "User": "Utilisateurs", - "Team": "Equipes", - "Role": "Rôles", - "EmailTemplate": "Modèles d'email", - "OutboundEmail": "Emails Sortants", - "ScheduledJob": "Tâches Planifiées" - }, - "labels": { - "Misc": "Divers", - "Merge": "Fusionner", - "None": "Aucun", - "by": "par", - "Saved": "Sauvegardé", - "Error": "Erreur", - "Select": "Selectionner", - "Not valid": "Invalide", - "Please wait...": "Veuillez patienter...", - "Please wait": "Veuillez patienter", - "Loading...": "Chargement...", - "Uploading...": "Téléchargement ...", - "Sending...": "Envoi en cours ...", - "Removed": "Supprimé", - "Posted": "Posté", - "Linked": "Associé", - "Unlinked": "Dissocié", - "Access denied": "Accès refusé", - "Access": "Accès", - "Are you sure?": "Are you sure?", - "Record has been removed": "Enregistrement éffacé", - "Wrong username/password": "Nom d'utilisateur/mot de passe erroné", - "Post cannot be empty": "Le poste ne peut être vide", - "Removing...": "Effacement...", - "Unlinking...": "Dissociation...", - "Posting...": "Envoi...", - "Username can not be empty!": "Le nom d'utilisateur doit être renseigné !", - "Cache is not enabled": "Le cache n'est pas activé", - "Cache has been cleared": "Le Cache a été vidé", - "Rebuild has been done": "Refonte terminée", - "Saving...": "Enregistrement...", - "Modified": "Modifié", - "Created": "Créé", - "Create": "Créer", - "create": "créer", - "Overview": "vue d'ensemble", - "Details": "Informations", - "Add Filter": "Ajouter un Filtre", - "Add Dashlet": "Ajouter un Dashlet", - "Add": "Ajouter", - "Reset": "Remise à zéro", - "Menu": "Menu", - "More": "Plus", - "Search": "Rechercher", - "Only My": "Seulement Moi", - "Open": "Ouvrir", - "Admin": "Admin", - "About": "A propos", - "Refresh": "Actualiser", - "Remove": "Supprimer", - "Options": "Options", - "Username": "Nom d'utilisateur", - "Password": "Mot de Passe", - "Login": "Connexion", - "Log Out": "Déconnexion", - "Preferences": "Préférences", - "State": "Département", - "Street": "Rue", - "Country": "Pays", - "City": "Ville", - "PostalCode": "Code Postal", - "Followed": "Suivi", - "Follow": "Suivre", - "Clear Local Cache": "Vider le Cache Local", - "Actions": "Actions", - "Delete": "Effacer", - "Update": "Mettre à jour", - "Save": "Enregistrer", - "Edit": "Edition", - "Cancel": "Annuler", - "Unlink": "Dissocier", - "Mass Update": "Mise à Jour en Masse", - "Export": "Exporter", - "No Data": "Données vides", - "All": "Tout", - "Active": "Activer", - "Inactive": "Désactiver", - "Write your comment here": "Ecrire ici votre commentaire", - "Post": "Poster", - "Stream": "Flux", - "Show more": "En savoir plus", - "Dashlet Options": "Options du Dashlet", - "Full Form": "Formulaire Complet", - "Insert": "Insertion", - "Person": "Personne", - "First Name": "Prénom", - "Last Name": "Nom de Famille", - "Original": "Original", - "You": "Vous", - "you": "vous", - "change": "Modifier", - "Primary": "Premier" - }, - "messages": { - "notModified": "Vous n'avez pas modifié l'enregistrement", - "duplicate": "La création de l'enregistrement ressemble à un doublon", - "fieldIsRequired": "{field} est requise", - "fieldShouldBeEmail": "{field} doit être une adresse email valide", - "fieldShouldBeFloat": "{field} doit être un flottant valide", - "fieldShouldBeInt": "{field} doit être un entier valide", - "fieldShouldBeDate": "{field} doit être une date valide", - "fieldShouldBeDatetime": "{field} doit être une date/heure valide", - "fieldShouldAfter": "{field} doit se situer après {otherField}", - "fieldShouldBefore": "{field} doit se situer avant {otherField}", - "fieldShouldBeBetween": "{field} doit se situer entre {min} et {max}", - "fieldShouldBeLess": "{field} doit être inférieur à {value}", - "fieldShouldBeGreater": "{field} doit être supérieur à {value}", - "fieldBadPasswordConfirm": "{field} confirmation inappropriée" - }, - "boolFilters": { - "onlyMy": "Seulement Moi", - "open": "Ouvrir", - "active": "Activer" - }, - "fields": { - "name": "Nom", - "firstName": "Prénom", - "lastName": "Nom de Famille", - "salutationName": "Salutation", - "assignedUser": "Utilisateur Assigné", - "emailAddress": "Email", - "assignedUserName": "Nom d'Utilisateur Assigné", - "teams": "Equipes", - "createdAt": "Créé le", - "modifiedAt": "Modifié le", - "createdBy": "Créé par", - "modifiedBy": "Modifié par", - "title": "Titre", - "dateFrom": "Date de Reception", - "dateTo": "Date d'Envoi", - "autorefreshInterval": "Intervalle d'Auto-actualisation", - "displayRecords": "Afficher les Enregistrements" - }, - "links": { - "teams": "Equipes", - "users": "Utilisateurs" - }, - "dashlets": { - "Stream": "Flux" - }, - "streamMessages": { - "create": "{user} a créé {entityType} {entity}", - "createAssigned": "{user} a créé {entityType} {entity} assigné à {assignee}", - "assign": "{user} a assigné {entityType} {entity} à {assignee}", - "post": "{user} a posté sur {entityType} {entity}", - "attach": "{user} attaché à {entityType} {entity}", - "status": "{user} a mis à jour {field} sur {entityType} {entity}", - "update": "{user} a mis à jour {entityType} {entity}", - "createRelated": "{user} created {relatedEntityType} {relatedEntity} linked to {entityType} {entity}", - "emailReceived": "{entity} a été reçu pour {entityType} {entity}", - - "createThis": "{user} a créé {entityType}", - "createAssignedThis": "{user} a créé {entityType} assigné à {assignee}", - "assignThis": "{user} a assigné {entityType} à {assignee}", - "postThis": "{user} a posté", - "attachThis": "{user} a attaché", - "statusThis": "{user} a mis à jour {field}", - "updateThis": "{user} a mis à jour {entityType}", - "createRelatedThis": "{user} created {relatedEntityType} {relatedEntity} linked to this {entityType}", - "emailReceivedThis": "{entity} a été reçu" - }, - "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"] - }, - "options": { - "salutationName": { - "Mr.": "Mr.", - "Mrs.": "Mme", - "Dr.": "Dr.", - "Drs.": "Dr." - }, - "language": { - "af_ZA": "Afrikaner", - "az_AZ": "Azerbaïdjanais", - "be_BY": "Biélorusse", - "bg_BG": "Bulgare", - "bn_IN": "Bengali", - "bs_BA": "Bosnien", - "ca_ES": "Catalan", - "cs_CZ": "Tchèque", - "cy_GB": "Gallois", - "da_DK": "Danois", - "de_DE": "Allemand", - "el_GR": "Grec", - "en_GB":"English (UK)", - "en_US":"English (US)", - "es_ES":"Spanish (Spain)", - "et_EE": "Estonien", - "eu_ES": "Basque", - "fa_IR": "Farsi", - "fi_FI": "Finlandais", - "fo_FO": "féroïen", - "fr_CA":"French (Canada)", - "fr_FR":"French (France)", - "ga_IE": "Irlandais", - "gl_ES": "Galicien", - "gn_PY": "Guarani", - "he_IL": "Hébreu", - "hi_IN": "Hindi", - "hr_HR": "Croate", - "hu_HU": "Hongrois", - "hy_AM": "Arménien", - "id_ID": "Indonésien", - "is_IS": "Islandais", - "it_IT": "Italien", - "ja_JP": "Japonais", - "ka_GE": "Georgien", - "km_KH": "Khmer", - "ko_KR": "Coréen", - "ku_TR": "Kurde", - "lt_LT": "Lithuanien", - "lv_LV": "Lettonien", - "mk_MK": "Macedonien", - "ml_IN": "Malayalam", - "ms_MY": "Malais", - "nb_NO": "Norvegien Bokmål", - "nn_NO": "Norvegien Nynorsk", - "ne_NP": "Népalais", - "nl_NL": "Néerlandais", - "pa_IN": "Pendjabi", - "pl_PL": "Polonais", - "ps_AF": "Pachtoune", - "pt_BR":"Portuguese (Brazil)", - "pt_PT":"Portuguese (Portugal)", - "ro_RO": "Roumain", - "ru_RU": "Russe", - "sk_SK": "Slovaque", - "sl_SI": "Slovène", - "sq_AL": "Albanais", - "sr_RS": "Serbe", - "sv_SE": "Suèdois", - "sw_KE": "Swahili", - "ta_IN": "Tamoul", - "te_IN": "Télougou", - "th_TH": "Thailandais", - "tl_PH": "Tagalog", - "tr_TR": "Turc", - "uk_UA": "Ucrainien", - "ur_PK": "Urdu", - "vi_VN": "Vietnamien", - "zh_CN":"Simplified Chinese (China)", - "zh_HK":"Traditional Chinese (Hong Kong)", - "zh_TW":"Traditional Chinese (Taiwan)" - }, - "dateSearchRanges": { - "on": "En Marche", - "notOn": "Arrêté", - "after": "Après", - "before": "Avant", - "between": "Entre" - }, - "intSearchRanges": { - "equals": "Egual", - "notEquals": "Différent", - "greaterThan": "Supérieur à", - "lessThan": "Inférieur à", - "greaterThanOrEquals": "Supérieur ou Egual à", - "lessThanOrEquals": "Inférieur ou Egual à", - "between": "Entre" - }, - "autorefreshInterval": { - "0": "Aucun", - "0.5": "30 secondes", - "1": "1 minute", - "2": "2 minutes", - "5": "5 minutes", - "10": "10 minutes" - } - }, - "sets": { - "summernote": { - "NOTICE": "You can find translation here: https://github.com/HackerWins/summernote/tree/master/lang", - "font":{ - "bold": "Gras", - "italic": "Italique", - "underline": "Souligné", - "strike": "Touche", - "clear": "Retirer le Style de Police", - "height": "Hauteur de Ligne", - "name": "Police de Caractère", - "size": "Taille de Police" - }, - "image":{ - "image": "Image", - "insert": "Insérer une Image", - "resizeFull": "Redimensioner à 100%", - "resizeHalf": "Redimensioner à 50%", - "resizeQuarter": "Redimensioner à 25%", - "floatLeft": "Flottant Gauche", - "floatRight": "Flottant Droit", - "floatNone": "Aucun Flottant", - "dragImageHere": "Glisser une Image ici", - "selectFromFiles": "Parcourir", - "url": "Url de l'Image", - "remove": "Supprimer l'Image" - }, - "link":{ - "link": "Lien", - "insert": "Insérer un Lien", - "unlink": "Dissocier", - "edit": "Edition", - "textToDisplay": "Texte à Afficher", - "url":"To what URL should this link go?", - "openInNewWindow": "Ouvrir dans une Nouvelle Fenêtre" - }, - "video":{ - "video": "Vidéo", - "videoLink": "Lien Vidéo", - "insert": "Insérer une Vidéo", - "url":"Video URL?", - "providers":"(YouTube, Vimeo, Vine, Instagram, or DailyMotion)" - }, - "table":{ - "table": "Tableau" - }, - "hr":{ - "insert": "Insérer une Régle Horizontale" - }, - "style":{ - "style": "Style", - "normal": "Normal", - "blockquote": "Guillemet", - "pre": "Code", - "h1": "Entête 1", - "h2": "Entête 2", - "h3": "Entête 3", - "h4": "Entête 4", - "h5": "Entête 5", - "h6": "Entête 6" - }, - "lists":{ - "unordered": "Liste non Ordonnée", - "ordered": "Liste Ordonnée" - }, - "options":{ - "help": "Aide", - "fullscreen": "Plein Ecran", - "codeview": "Visualiser le Code" - }, - "paragraph":{ - "paragraph": "Paragraphe", - "outdent": "Désindenter", - "indent": "Indenter", - "left": "Aligné à Gauche", - "center": "Centré", - "right": "Aligné à Droite", - "justify": "Justifié" - }, - "color":{ - "recent": "Couleur Récente", - "more": "Plus de Couleur", - "background": "Couleur de Fond", - "foreground": "Couleur de Police", - "transparent": "Transparent", - "setTransparent": "Réglage Transparent", - "reset": "Remise à zéro", - "resetToDefault": "Réglages par défaut" - }, - "shortcut":{ - "shortcuts": "Raccourcis Clavier", - "close": "Fermer", - "textFormatting": "Mise en forme du texte", - "action": "Action", - "paragraphFormatting": "Mise en forme du Paragraphe", - "documentStyle": "Style du Document" - }, - "history":{ - "undo": "Annuler", - "redo": "Restaurer" - } - } - } + "scopeNames": { + "Email": "Email", + "User": "Utilisateur", + "Team": "Equipe", + "Role": "Rôle", + "EmailTemplate": "Modèle d'Email", + "OutboundEmail": "Email Sortant", + "ScheduledJob": "Tâche Planifiée" + }, + "scopeNamesPlural": { + "Email": "Courriers", + "User": "Utilisateurs", + "Team": "Equipes", + "Role": "Rôles", + "EmailTemplate": "Modèles d'email", + "OutboundEmail": "Emails Sortants", + "ScheduledJob": "Tâches Planifiées" + }, + "labels": { + "Misc": "Divers", + "Merge": "Fusionner", + "None": "Aucun", + "by": "par", + "Saved": "Sauvegardé", + "Error": "Erreur", + "Select": "Selectionner", + "Not valid": "Invalide", + "Please wait...": "Veuillez patienter...", + "Please wait": "Veuillez patienter", + "Loading...": "Chargement...", + "Uploading...": "Téléchargement ...", + "Sending...": "Envoi en cours ...", + "Removed": "Supprimé", + "Posted": "Posté", + "Linked": "Associé", + "Unlinked": "Dissocié", + "Access denied": "Accès refusé", + "Access": "Accès", + "Are you sure?": "Are you sure?", + "Record has been removed": "Enregistrement éffacé", + "Wrong username/password": "Nom d'utilisateur/mot de passe erroné", + "Post cannot be empty": "Le poste ne peut être vide", + "Removing...": "Effacement...", + "Unlinking...": "Dissociation...", + "Posting...": "Envoi...", + "Username can not be empty!": "Le nom d'utilisateur doit être renseigné !", + "Cache is not enabled": "Le cache n'est pas activé", + "Cache has been cleared": "Le Cache a été vidé", + "Rebuild has been done": "Refonte terminée", + "Saving...": "Enregistrement...", + "Modified": "Modifié", + "Created": "Créé", + "Create": "Créer", + "create": "créer", + "Overview": "vue d'ensemble", + "Details": "Informations", + "Add Filter": "Ajouter un Filtre", + "Add Dashlet": "Ajouter un Dashlet", + "Add": "Ajouter", + "Reset": "Remise à zéro", + "Menu": "Menu", + "More": "Plus", + "Search": "Rechercher", + "Only My": "Seulement Moi", + "Open": "Ouvrir", + "Admin": "Admin", + "About": "A propos", + "Refresh": "Actualiser", + "Remove": "Supprimer", + "Options": "Options", + "Username": "Nom d'utilisateur", + "Password": "Mot de Passe", + "Login": "Connexion", + "Log Out": "Déconnexion", + "Preferences": "Préférences", + "State": "Département", + "Street": "Rue", + "Country": "Pays", + "City": "Ville", + "PostalCode": "Code Postal", + "Followed": "Suivi", + "Follow": "Suivre", + "Clear Local Cache": "Vider le Cache Local", + "Actions": "Actions", + "Delete": "Effacer", + "Update": "Mettre à jour", + "Save": "Enregistrer", + "Edit": "Edition", + "Cancel": "Annuler", + "Unlink": "Dissocier", + "Mass Update": "Mise à Jour en Masse", + "Export": "Exporter", + "No Data": "Données vides", + "All": "Tout", + "Active": "Activer", + "Inactive": "Désactiver", + "Write your comment here": "Ecrire ici votre commentaire", + "Post": "Poster", + "Stream": "Flux", + "Show more": "En savoir plus", + "Dashlet Options": "Options du Dashlet", + "Full Form": "Formulaire Complet", + "Insert": "Insertion", + "Person": "Personne", + "First Name": "Prénom", + "Last Name": "Nom de Famille", + "Original": "Original", + "You": "Vous", + "you": "vous", + "change": "Modifier", + "Primary": "Premier" + }, + "messages": { + "notModified": "Vous n'avez pas modifié l'enregistrement", + "duplicate": "La création de l'enregistrement ressemble à un doublon", + "fieldIsRequired": "{field} est requise", + "fieldShouldBeEmail": "{field} doit être une adresse email valide", + "fieldShouldBeFloat": "{field} doit être un flottant valide", + "fieldShouldBeInt": "{field} doit être un entier valide", + "fieldShouldBeDate": "{field} doit être une date valide", + "fieldShouldBeDatetime": "{field} doit être une date/heure valide", + "fieldShouldAfter": "{field} doit se situer après {otherField}", + "fieldShouldBefore": "{field} doit se situer avant {otherField}", + "fieldShouldBeBetween": "{field} doit se situer entre {min} et {max}", + "fieldShouldBeLess": "{field} doit être inférieur à {value}", + "fieldShouldBeGreater": "{field} doit être supérieur à {value}", + "fieldBadPasswordConfirm": "{field} confirmation inappropriée" + }, + "boolFilters": { + "onlyMy": "Seulement Moi", + "open": "Ouvrir", + "active": "Activer" + }, + "fields": { + "name": "Nom", + "firstName": "Prénom", + "lastName": "Nom de Famille", + "salutationName": "Salutation", + "assignedUser": "Utilisateur Assigné", + "emailAddress": "Email", + "assignedUserName": "Nom d'Utilisateur Assigné", + "teams": "Equipes", + "createdAt": "Créé le", + "modifiedAt": "Modifié le", + "createdBy": "Créé par", + "modifiedBy": "Modifié par", + "title": "Titre", + "dateFrom": "Date de Reception", + "dateTo": "Date d'Envoi", + "autorefreshInterval": "Intervalle d'Auto-actualisation", + "displayRecords": "Afficher les Enregistrements" + }, + "links": { + "teams": "Equipes", + "users": "Utilisateurs" + }, + "dashlets": { + "Stream": "Flux" + }, + "streamMessages": { + "create": "{user} a créé {entityType} {entity}", + "createAssigned": "{user} a créé {entityType} {entity} assigné à {assignee}", + "assign": "{user} a assigné {entityType} {entity} à {assignee}", + "post": "{user} a posté sur {entityType} {entity}", + "attach": "{user} attaché à {entityType} {entity}", + "status": "{user} a mis à jour {field} sur {entityType} {entity}", + "update": "{user} a mis à jour {entityType} {entity}", + "createRelated": "{user} created {relatedEntityType} {relatedEntity} linked to {entityType} {entity}", + "emailReceived": "{entity} a été reçu pour {entityType} {entity}", + + "createThis": "{user} a créé {entityType}", + "createAssignedThis": "{user} a créé {entityType} assigné à {assignee}", + "assignThis": "{user} a assigné {entityType} à {assignee}", + "postThis": "{user} a posté", + "attachThis": "{user} a attaché", + "statusThis": "{user} a mis à jour {field}", + "updateThis": "{user} a mis à jour {entityType}", + "createRelatedThis": "{user} created {relatedEntityType} {relatedEntity} linked to this {entityType}", + "emailReceivedThis": "{entity} a été reçu" + }, + "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"] + }, + "options": { + "salutationName": { + "Mr.": "Mr.", + "Mrs.": "Mme", + "Dr.": "Dr.", + "Drs.": "Dr." + }, + "language": { + "af_ZA": "Afrikaner", + "az_AZ": "Azerbaïdjanais", + "be_BY": "Biélorusse", + "bg_BG": "Bulgare", + "bn_IN": "Bengali", + "bs_BA": "Bosnien", + "ca_ES": "Catalan", + "cs_CZ": "Tchèque", + "cy_GB": "Gallois", + "da_DK": "Danois", + "de_DE": "Allemand", + "el_GR": "Grec", + "en_GB":"English (UK)", + "en_US":"English (US)", + "es_ES":"Spanish (Spain)", + "et_EE": "Estonien", + "eu_ES": "Basque", + "fa_IR": "Farsi", + "fi_FI": "Finlandais", + "fo_FO": "féroïen", + "fr_CA":"French (Canada)", + "fr_FR":"French (France)", + "ga_IE": "Irlandais", + "gl_ES": "Galicien", + "gn_PY": "Guarani", + "he_IL": "Hébreu", + "hi_IN": "Hindi", + "hr_HR": "Croate", + "hu_HU": "Hongrois", + "hy_AM": "Arménien", + "id_ID": "Indonésien", + "is_IS": "Islandais", + "it_IT": "Italien", + "ja_JP": "Japonais", + "ka_GE": "Georgien", + "km_KH": "Khmer", + "ko_KR": "Coréen", + "ku_TR": "Kurde", + "lt_LT": "Lithuanien", + "lv_LV": "Lettonien", + "mk_MK": "Macedonien", + "ml_IN": "Malayalam", + "ms_MY": "Malais", + "nb_NO": "Norvegien Bokmål", + "nn_NO": "Norvegien Nynorsk", + "ne_NP": "Népalais", + "nl_NL": "Néerlandais", + "pa_IN": "Pendjabi", + "pl_PL": "Polonais", + "ps_AF": "Pachtoune", + "pt_BR":"Portuguese (Brazil)", + "pt_PT":"Portuguese (Portugal)", + "ro_RO": "Roumain", + "ru_RU": "Russe", + "sk_SK": "Slovaque", + "sl_SI": "Slovène", + "sq_AL": "Albanais", + "sr_RS": "Serbe", + "sv_SE": "Suèdois", + "sw_KE": "Swahili", + "ta_IN": "Tamoul", + "te_IN": "Télougou", + "th_TH": "Thailandais", + "tl_PH": "Tagalog", + "tr_TR": "Turc", + "uk_UA": "Ucrainien", + "ur_PK": "Urdu", + "vi_VN": "Vietnamien", + "zh_CN":"Simplified Chinese (China)", + "zh_HK":"Traditional Chinese (Hong Kong)", + "zh_TW":"Traditional Chinese (Taiwan)" + }, + "dateSearchRanges": { + "on": "En Marche", + "notOn": "Arrêté", + "after": "Après", + "before": "Avant", + "between": "Entre" + }, + "intSearchRanges": { + "equals": "Egual", + "notEquals": "Différent", + "greaterThan": "Supérieur à", + "lessThan": "Inférieur à", + "greaterThanOrEquals": "Supérieur ou Egual à", + "lessThanOrEquals": "Inférieur ou Egual à", + "between": "Entre" + }, + "autorefreshInterval": { + "0": "Aucun", + "0.5": "30 secondes", + "1": "1 minute", + "2": "2 minutes", + "5": "5 minutes", + "10": "10 minutes" + } + }, + "sets": { + "summernote": { + "NOTICE": "You can find translation here: https://github.com/HackerWins/summernote/tree/master/lang", + "font":{ + "bold": "Gras", + "italic": "Italique", + "underline": "Souligné", + "strike": "Touche", + "clear": "Retirer le Style de Police", + "height": "Hauteur de Ligne", + "name": "Police de Caractère", + "size": "Taille de Police" + }, + "image":{ + "image": "Image", + "insert": "Insérer une Image", + "resizeFull": "Redimensioner à 100%", + "resizeHalf": "Redimensioner à 50%", + "resizeQuarter": "Redimensioner à 25%", + "floatLeft": "Flottant Gauche", + "floatRight": "Flottant Droit", + "floatNone": "Aucun Flottant", + "dragImageHere": "Glisser une Image ici", + "selectFromFiles": "Parcourir", + "url": "Url de l'Image", + "remove": "Supprimer l'Image" + }, + "link":{ + "link": "Lien", + "insert": "Insérer un Lien", + "unlink": "Dissocier", + "edit": "Edition", + "textToDisplay": "Texte à Afficher", + "url":"To what URL should this link go?", + "openInNewWindow": "Ouvrir dans une Nouvelle Fenêtre" + }, + "video":{ + "video": "Vidéo", + "videoLink": "Lien Vidéo", + "insert": "Insérer une Vidéo", + "url":"Video URL?", + "providers":"(YouTube, Vimeo, Vine, Instagram, or DailyMotion)" + }, + "table":{ + "table": "Tableau" + }, + "hr":{ + "insert": "Insérer une Régle Horizontale" + }, + "style":{ + "style": "Style", + "normal": "Normal", + "blockquote": "Guillemet", + "pre": "Code", + "h1": "Entête 1", + "h2": "Entête 2", + "h3": "Entête 3", + "h4": "Entête 4", + "h5": "Entête 5", + "h6": "Entête 6" + }, + "lists":{ + "unordered": "Liste non Ordonnée", + "ordered": "Liste Ordonnée" + }, + "options":{ + "help": "Aide", + "fullscreen": "Plein Ecran", + "codeview": "Visualiser le Code" + }, + "paragraph":{ + "paragraph": "Paragraphe", + "outdent": "Désindenter", + "indent": "Indenter", + "left": "Aligné à Gauche", + "center": "Centré", + "right": "Aligné à Droite", + "justify": "Justifié" + }, + "color":{ + "recent": "Couleur Récente", + "more": "Plus de Couleur", + "background": "Couleur de Fond", + "foreground": "Couleur de Police", + "transparent": "Transparent", + "setTransparent": "Réglage Transparent", + "reset": "Remise à zéro", + "resetToDefault": "Réglages par défaut" + }, + "shortcut":{ + "shortcuts": "Raccourcis Clavier", + "close": "Fermer", + "textFormatting": "Mise en forme du texte", + "action": "Action", + "paragraphFormatting": "Mise en forme du Paragraphe", + "documentStyle": "Style du Document" + }, + "history":{ + "undo": "Annuler", + "redo": "Restaurer" + } + } + } } diff --git a/application/Espo/Resources/i18n/fr_FR/Note.json b/application/Espo/Resources/i18n/fr_FR/Note.json index 1aeca5f257..f4daee3542 100644 --- a/application/Espo/Resources/i18n/fr_FR/Note.json +++ b/application/Espo/Resources/i18n/fr_FR/Note.json @@ -1,6 +1,6 @@ { - "fields": { - "post": "Poster", - "attachments": "Fichiers Joints" - } + "fields": { + "post": "Poster", + "attachments": "Fichiers Joints" + } } diff --git a/application/Espo/Resources/i18n/fr_FR/Preferences.json b/application/Espo/Resources/i18n/fr_FR/Preferences.json index 39803fa3c8..ae69f2e710 100644 --- a/application/Espo/Resources/i18n/fr_FR/Preferences.json +++ b/application/Espo/Resources/i18n/fr_FR/Preferences.json @@ -1,32 +1,32 @@ { - "fields": { - "dateFormat": "Format de Date", - "timeFormat": "Format de l'Heure", - "timeZone": "Fuseau Horaire", - "weekStart": "Premier Jour de la Semaine", - "thousandSeparator": "Séparateur de Milliers", - "decimalMark": "Marqueur Décimal", - "defaultCurrency": "Monnaie Courante", - "currencyList": "Liste des Monnaies", - "language": "Langue", - - "smtpServer": "Serveur", - "smtpPort": "Porte", - "smtpAuth": "Authorization", - "smtpSecurity": "Sécurité", - "smtpUsername": "Nom d'utilisateur", - "emailAddress": "Email", - "smtpPassword": "Mot de Passe", - "smtpEmailAddress": "Adresse Email", - - "exportDelimiter": "Délimiteur de champs (Export)" - }, - "links": { - }, - "options": { - "weekStart": { - "0": "Dimanche", - "1": "Lundi" - } - } + "fields": { + "dateFormat": "Format de Date", + "timeFormat": "Format de l'Heure", + "timeZone": "Fuseau Horaire", + "weekStart": "Premier Jour de la Semaine", + "thousandSeparator": "Séparateur de Milliers", + "decimalMark": "Marqueur Décimal", + "defaultCurrency": "Monnaie Courante", + "currencyList": "Liste des Monnaies", + "language": "Langue", + + "smtpServer": "Serveur", + "smtpPort": "Porte", + "smtpAuth": "Authorization", + "smtpSecurity": "Sécurité", + "smtpUsername": "Nom d'utilisateur", + "emailAddress": "Email", + "smtpPassword": "Mot de Passe", + "smtpEmailAddress": "Adresse Email", + + "exportDelimiter": "Délimiteur de champs (Export)" + }, + "links": { + }, + "options": { + "weekStart": { + "0": "Dimanche", + "1": "Lundi" + } + } } diff --git a/application/Espo/Resources/i18n/fr_FR/Role.json b/application/Espo/Resources/i18n/fr_FR/Role.json index 60fbdeb829..d50ca9a967 100644 --- a/application/Espo/Resources/i18n/fr_FR/Role.json +++ b/application/Espo/Resources/i18n/fr_FR/Role.json @@ -1,32 +1,32 @@ { - "fields": { - "name": "Nom", - "roles": "Rôles" - }, - "links": { - "users": "Utilisateurs", - "teams": "Equipes" - }, - "labels": { - "Access": "Accès", - "Create Role": "Créer un rôle" - }, - "options": { - "accessList": { - "not-set": "Indéfini", - "enabled": "activé", - "disabled": "désactivé" - }, - "levelList": { - "all": "tous", - "team": "équipe", - "own": "Appartient", - "no": "non" - } - }, - "actions": { - "read": "Lire", - "edit": "Edition", - "delete": "Effacer" - } + "fields": { + "name": "Nom", + "roles": "Rôles" + }, + "links": { + "users": "Utilisateurs", + "teams": "Equipes" + }, + "labels": { + "Access": "Accès", + "Create Role": "Créer un rôle" + }, + "options": { + "accessList": { + "not-set": "Indéfini", + "enabled": "activé", + "disabled": "désactivé" + }, + "levelList": { + "all": "tous", + "team": "équipe", + "own": "Appartient", + "no": "non" + } + }, + "actions": { + "read": "Lire", + "edit": "Edition", + "delete": "Effacer" + } } diff --git a/application/Espo/Resources/i18n/fr_FR/ScheduledJob.json b/application/Espo/Resources/i18n/fr_FR/ScheduledJob.json index 17a4138807..590e410152 100644 --- a/application/Espo/Resources/i18n/fr_FR/ScheduledJob.json +++ b/application/Espo/Resources/i18n/fr_FR/ScheduledJob.json @@ -1,30 +1,30 @@ { - "fields": { - "name": "Nom", - "status": "Statut", - "job": "Tâche", - "scheduling": "Scheduling (crontab notation)" - }, - "links": { - "log": "Journal" - }, - "labels": { - "Create ScheduledJob": "Créer une tâche planifiée" - }, - "options": { - "job": { - "CheckInboundEmails": "Vérifier les Emails Entrants", - "Cleanup": "Nettoyer" - }, - "cronSetup": { - "linux": "", - "mac": "", - "windows": "Note: Create a batch file with the following commands to run Espo Scheduled Jobs using Windows Scheduled Tasks:", - "default": "Note: Add this command to Cron Job (Scheduled Task):" - }, - "status": { - "Active": "Activer", - "Inactive": "Désactiver" - } - } + "fields": { + "name": "Nom", + "status": "Statut", + "job": "Tâche", + "scheduling": "Scheduling (crontab notation)" + }, + "links": { + "log": "Journal" + }, + "labels": { + "Create ScheduledJob": "Créer une tâche planifiée" + }, + "options": { + "job": { + "CheckInboundEmails": "Vérifier les Emails Entrants", + "Cleanup": "Nettoyer" + }, + "cronSetup": { + "linux": "", + "mac": "", + "windows": "Note: Create a batch file with the following commands to run Espo Scheduled Jobs using Windows Scheduled Tasks:", + "default": "Note: Add this command to Cron Job (Scheduled Task):" + }, + "status": { + "Active": "Activer", + "Inactive": "Désactiver" + } + } } diff --git a/application/Espo/Resources/i18n/fr_FR/ScheduledJobLogRecord.json b/application/Espo/Resources/i18n/fr_FR/ScheduledJobLogRecord.json index d1be376c8f..5682f68ab6 100644 --- a/application/Espo/Resources/i18n/fr_FR/ScheduledJobLogRecord.json +++ b/application/Espo/Resources/i18n/fr_FR/ScheduledJobLogRecord.json @@ -1,6 +1,6 @@ { - "fields": { - "status": "Statut", - "executionTime": "Temps d'Exécution" - } + "fields": { + "status": "Statut", + "executionTime": "Temps d'Exécution" + } } diff --git a/application/Espo/Resources/i18n/fr_FR/Settings.json b/application/Espo/Resources/i18n/fr_FR/Settings.json index 12c2a910fb..3c19e36ed9 100644 --- a/application/Espo/Resources/i18n/fr_FR/Settings.json +++ b/application/Espo/Resources/i18n/fr_FR/Settings.json @@ -1,63 +1,63 @@ { - "fields": { - "useCache": "Utiliser le Cache", - "dateFormat": "Format de Date", - "timeFormat": "Format de l'Heure", - "timeZone": "Fuseau Horaire", - "weekStart": "Premier Jour de la Semaine", - "thousandSeparator": "Séparateur de Milliers", - "decimalMark": "Marqueur Décimal", - "defaultCurrency": "Monnaie Courante", - "currencyList": "Liste des Monnaies", - "language": "Langue", - - "companyLogo": "Logo de la Société", - - "smtpServer": "Serveur", - "smtpPort": "Porte", - "smtpAuth": "Authorization", - "smtpSecurity": "Sécurité", - "smtpUsername": "Nom d'utilisateur", - "emailAddress": "Email", - "smtpPassword": "Mot de Passe", - "outboundEmailFromName": "Nom de l'Expéditeur", - "outboundEmailFromAddress": "Adresse de l'Emetteur", - "outboundEmailIsShared": "Est partagé", - - "recordsPerPage": "Enregistrements par page", - "recordsPerPageSmall": "Records Per Page (Small)", - "tabList": "Tab List", - "quickCreateList": "Création Rapide de Liste", - - "exportDelimiter": "Délimiteur de champs (Export)", - - "authenticationMethod": "Methode d'Authentification", - "ldapHost": "Hôte", - "ldapPort": "Porte", - "ldapAuth": "Authorization", - "ldapUsername": "Nom d'utilisateur", - "ldapPassword": "Mot de Passe", - "ldapBindRequiresDn": "Bind Requert Nom de Domaine", - "ldapBaseDn": "Base Nom de Domaine", - "ldapAccountCanonicalForm": "Formulaire du Compte Canonique", - "ldapAccountDomainName": "Compte du Nom de Domaine", - "ldapTryUsernameSplit": "Essayer le Nom d'utilisateur séparé", - "ldapCreateEspoUser": "Créer un Utilisateur dans EspoCRM", - "ldapSecurity": "Sécurité", - "ldapUserLoginFilter": "Filtre de Connexion Utilisateur", - "ldapAccountDomainNameShort": "Compte de Nom de Domaine Court", - "ldapOptReferrals": "Opt Referrals" - }, - "options": { - "weekStart": { - "0": "Dimanche", - "1": "Lundi" - } - }, - "labels": { - "System": "Système", - "Locale": "Local", - "SMTP": "SMTP", - "Configuration": "Configuration" - } + "fields": { + "useCache": "Utiliser le Cache", + "dateFormat": "Format de Date", + "timeFormat": "Format de l'Heure", + "timeZone": "Fuseau Horaire", + "weekStart": "Premier Jour de la Semaine", + "thousandSeparator": "Séparateur de Milliers", + "decimalMark": "Marqueur Décimal", + "defaultCurrency": "Monnaie Courante", + "currencyList": "Liste des Monnaies", + "language": "Langue", + + "companyLogo": "Logo de la Société", + + "smtpServer": "Serveur", + "smtpPort": "Porte", + "smtpAuth": "Authorization", + "smtpSecurity": "Sécurité", + "smtpUsername": "Nom d'utilisateur", + "emailAddress": "Email", + "smtpPassword": "Mot de Passe", + "outboundEmailFromName": "Nom de l'Expéditeur", + "outboundEmailFromAddress": "Adresse de l'Emetteur", + "outboundEmailIsShared": "Est partagé", + + "recordsPerPage": "Enregistrements par page", + "recordsPerPageSmall": "Records Per Page (Small)", + "tabList": "Tab List", + "quickCreateList": "Création Rapide de Liste", + + "exportDelimiter": "Délimiteur de champs (Export)", + + "authenticationMethod": "Methode d'Authentification", + "ldapHost": "Hôte", + "ldapPort": "Porte", + "ldapAuth": "Authorization", + "ldapUsername": "Nom d'utilisateur", + "ldapPassword": "Mot de Passe", + "ldapBindRequiresDn": "Bind Requert Nom de Domaine", + "ldapBaseDn": "Base Nom de Domaine", + "ldapAccountCanonicalForm": "Formulaire du Compte Canonique", + "ldapAccountDomainName": "Compte du Nom de Domaine", + "ldapTryUsernameSplit": "Essayer le Nom d'utilisateur séparé", + "ldapCreateEspoUser": "Créer un Utilisateur dans EspoCRM", + "ldapSecurity": "Sécurité", + "ldapUserLoginFilter": "Filtre de Connexion Utilisateur", + "ldapAccountDomainNameShort": "Compte de Nom de Domaine Court", + "ldapOptReferrals": "Opt Referrals" + }, + "options": { + "weekStart": { + "0": "Dimanche", + "1": "Lundi" + } + }, + "labels": { + "System": "Système", + "Locale": "Local", + "SMTP": "SMTP", + "Configuration": "Configuration" + } } diff --git a/application/Espo/Resources/i18n/fr_FR/Team.json b/application/Espo/Resources/i18n/fr_FR/Team.json index 22fe540f09..b6f8dfac28 100644 --- a/application/Espo/Resources/i18n/fr_FR/Team.json +++ b/application/Espo/Resources/i18n/fr_FR/Team.json @@ -1,12 +1,12 @@ { - "fields": { - "name": "Nom", - "roles": "Rôles" - }, - "links": { - "users": "Utilisateurs" - }, - "labels": { - "Create Team": "Créer une Equipe" - } + "fields": { + "name": "Nom", + "roles": "Rôles" + }, + "links": { + "users": "Utilisateurs" + }, + "labels": { + "Create Team": "Créer une Equipe" + } } diff --git a/application/Espo/Resources/i18n/fr_FR/User.json b/application/Espo/Resources/i18n/fr_FR/User.json index 808c0aca7c..8bec49081e 100644 --- a/application/Espo/Resources/i18n/fr_FR/User.json +++ b/application/Espo/Resources/i18n/fr_FR/User.json @@ -1,32 +1,32 @@ { - "fields": { - "name": "Nom", - "userName": "Nom d'utilisateur", - "title": "Titre", - "isAdmin": "Est Admin", - "defaultTeam": "Equipe Standard", - "emailAddress": "Email", - "phoneNumber": "Téléphone", - "roles": "Rôles", - "password": "Mot de Passe", - "passwordConfirm": "Confirmer le Mot de Passe", - "newPassword": "Nouveau Mot de Passe" - }, - "links": { - "teams": "Equipes", - "roles": "Rôles" - }, - "labels": { - "Create User": "Créer un Utilisateur", - "Generate": "Générer", - "Access": "Accès", - "Preferences": "Préférences", - "Change Password": "Changer le Mot de Passe" - }, - "messages": { - "passwordWillBeSent": "Le Mot de Passe sera envoyé à l'adresse email de l'utilisateur", - "accountInfoEmailSubject": "Information du compte", - "accountInfoEmailBody": "Your account information:\n\nUsername: {userName}\nPassword: {password}\n\n{siteUrl}", - "passwordChanged": "Mot de passe changé" - } + "fields": { + "name": "Nom", + "userName": "Nom d'utilisateur", + "title": "Titre", + "isAdmin": "Est Admin", + "defaultTeam": "Equipe Standard", + "emailAddress": "Email", + "phoneNumber": "Téléphone", + "roles": "Rôles", + "password": "Mot de Passe", + "passwordConfirm": "Confirmer le Mot de Passe", + "newPassword": "Nouveau Mot de Passe" + }, + "links": { + "teams": "Equipes", + "roles": "Rôles" + }, + "labels": { + "Create User": "Créer un Utilisateur", + "Generate": "Générer", + "Access": "Accès", + "Preferences": "Préférences", + "Change Password": "Changer le Mot de Passe" + }, + "messages": { + "passwordWillBeSent": "Le Mot de Passe sera envoyé à l'adresse email de l'utilisateur", + "accountInfoEmailSubject": "Information du compte", + "accountInfoEmailBody": "Your account information:\n\nUsername: {userName}\nPassword: {password}\n\n{siteUrl}", + "passwordChanged": "Mot de passe changé" + } } diff --git a/application/Espo/Resources/i18n/nl_NL/Admin.json b/application/Espo/Resources/i18n/nl_NL/Admin.json index 9467cae8c8..53239b54ba 100644 --- a/application/Espo/Resources/i18n/nl_NL/Admin.json +++ b/application/Espo/Resources/i18n/nl_NL/Admin.json @@ -1,16 +1,14 @@ { "labels": { - "Enabled": "Activeren", - "Disabled": "Uitschakelen", + "Enabled": "Geactiveerd", + "Disabled": "Uitgeschakeld", "System": "Systeem", "Users": "Gebruikers", "Email": "Email", "Data": "Data", "Customization": "Aanpassing", "Available Fields": "Beschikbare Velden", - "Layout": "Opmaak", - "Enabled": "Activeren", - "Disabled": "Uitschakelen", + "Layout": "Layout", "Add Panel": "Kader toevoegen", "Add Field": "Veld toevoegen", "Settings": "Instellingen", @@ -18,9 +16,8 @@ "Upgrade": "Upgrade", "Clear Cache": "Cache Opschonen", "Rebuild": "Herbouwen", - "Users": "Gebruikers", "Teams": "Groepen", - "Roles": "Regels", + "Roles": "Rollen", "Outbound Emails": "Uitgaande Emails", "Inbound Emails": "Inkomende Emails", "Email Templates": "Email Templates", @@ -30,29 +27,42 @@ "User Interface": "Gebruikers Interface", "Auth Tokens": "Auth Token", "Authentication": "Authenticatie", - "Currency": "Valuta" + "Currency": "Valuta", + "Integrations": "Integraties", + "Extensions": "Extensies", + "Upload": "Upload", + "Installing...": "Installeren...", + "Upgrading...": "Bezig met upgraden...", + "Upgraded successfully": "Upgrade voltooid", + "Installed successfully": "Installatie voltooid", + "Ready for upgrade": "Gereed voor upgrade", + "Run Upgrade": "Upgrade uitvoeren", + "Install": "Installeren", + "Ready for installation": "Gereed voor installatie", + "Uninstalling...": "Bezig met deinstalleren...", + "Uninstalled": "Gedeinstalleerd" }, "layouts": { - "list": "Toon", + "list": "Lijst", "detail": "Detail", - "listSmall": "List (Small)", - "detailSmall": "Detail (Small)", + "listSmall": "Lijst (klein)", + "detailSmall": "Detail (klein)", "filters": "Zoek Filters", - "massUpdate": "Totale Update", + "massUpdate": "Massa Update", "relationships": "Relaties" }, "fieldTypes": { "address": "Adres", - "array": "Array", + "array": "Rangschikking", "foreign": "Buitenland", - "duration": "Gedurende", + "duration": "Duur", "password": "Wachtwoord", - "parsonName": "Persoons Naam", - "autoincrement": "Auto-increment", + "parsonName": "Naam Persoon", + "autoincrement": "Auto-vermeerdering", "bool": "Bool", "currency": "Valuta", "date": "Datum", - "datetime": "DateTime", + "datetime": "Datum Tijd", "email": "Email", "enum": "Enum", "enumInt": "Enum Integer", @@ -60,7 +70,7 @@ "float": "Drijvende komma", "int": "Int", "link": "Link", - "linkMultiple": "Meerdere Links", + "linkMultiple": "Link Meerdere", "linkParent": "Link Parent", "multienim": "Multienum", "phone": "Telefoon", @@ -68,61 +78,67 @@ "url": "Url", "varchar": "Varchar", "file": "Bestand", - "image": "Plaatje" + "image": "Afbeelding" }, "fields": { "type": "Type", "name": "Record Naam", - "label": "Eigen Veldnaam", - "required": "Nodig", - "default": "Voorkeur", + "label": "Label", + "required": "Verplicht", + "default": "Standaard", "maxLength": "Max Lengte", - "options": "Options (raw values, not translated)", - "after": "After (field)", - "before": "Before (field)", + "options": "Opties", + "after": "Achter (veld)", + "before": "Voor (veld)", "link": "Link", "field": "Veld", "min": "Min", "max": "Max", "translation": "Vertaling", - "previewSize": "Voorbeeld Maat" + "previewSize": "Preview Afmeting" }, "messages": { "upgradeVersion": "Uw EspoCRM wordt geupgrade naar versie {version}. Dit kan enige tijd duren.", "upgradeDone": "Uw EspoCRM wordt geupgrade naar versie {version}. Herstart uw browser scherm.", "upgradeBackup": "We adviseren om eerst een backup te maken van uw EspoCRM bestanden en data, alvorens te upgraden.", - "thousandSeparatorEqualsDecimalMark": "Het duizendtal scheidingsteken mag niet hetzelfde zijn als het honderdtal", - "userHasNoEmailAddress": "Gebruiker heeft geen email adres.", + "thousandSeparatorEqualsDecimalMark": "Het duizendtal scheidingsteken mag niet hetzelfde zijn als het decimaalteken.", + "userHasNoEmailAddress": "Gebruiker heeft geen emailadres.", "selectEntityType": "Selecteer de eenheid soort in het linker menu.", - "selectUpgradePackage": "Selecteer het upgrade pakket", - "selectLayout": "Selecteer de gewenste layout in het linker menu en pas dit aan." + "selectUpgradePackage": "Selecteer het upgradebestand", + "downloadUpgradePackage": "Download benodigde upgrade bestanden hier.", + "selectLayout": "Selecteer de layout in het linker menu en pas deze aan.", + "selectExtensionPackage": "Selecteer extensie bestand", + "extensionInstalled": "Extensie {name} {version} is geinstalleerd.", + "installExtension": "Extensie {name} {version} is gereed voor installatie.", + "uninstallConfirmation": "Extensie definitief verwijderen?" }, "descriptions": { "settings": "Systeem instellingen van het programma.", "scheduledJob": "Opdrachten die uitgevoerd worden door cron.", "upgrade": "Upgrade EspoCRM.", - "clearCache": "Verwijder achtergrond cache.", - "rebuild": "Reconstrueer achtergrond en schoon het geheugen.", + "clearCache": "Verwijder backend cache.", + "rebuild": "Reconstrueer backend en schoon het geheugen.", "users": "Gebruikers beheer.", "teams": "Groepen beheer.", - "roles": "Rechten beheer.", + "roles": "Rollen beheer.", "outboundEmails": "SMTP instellingen voor uitgaande emails.", - "inboundEmails": "Group IMAP email accouts. Email import and Email-to-Case.", + "inboundEmails": "Groep IMAP email accounts. Email importeren en Email-naar-Casus.", "emailTemplates": "Templates voor uitgaande emails.", - "import": "Importeer data van CSV bestand.", - "layoutManager": "Customize layouts (list, detail, edit, search, mass update).", - "fieldManager": "Maak nieuwe of bewerk bestaande velden.", + "import": "Importeer data vanuit CSV bestand.", + "layoutManager": "Bewerk layouts (lijst, detail, bewerk, zoeken, massa update).", + "fieldManager": "Nieuwe velden aanmaken of bestaande velden bewerken.", "userInterface": "Configureer UI.", - "authTokens": "Actieve bevestigde sessie. IP adres en laatste datum.", - "authentication": "Authentication settings.", - "currency": "Currency settings and rates." + "authTokens": "Actieve bevestigde sessie. IP adres en laatste inlogdatum.", + "authentication": "Verificatie-instellingen", + "currency": "Valuta instellingen en tarieven.", + "extensions": "Extensies (de)installeren." }, "options": { "previewSize": { - "x-small": "X-Small", - "small": "Small", - "medium": "Medium", - "large": "Large" + "x-small": "Extra klein", + "small": "Klein", + "medium": "Middel", + "large": "Groot" } } } diff --git a/application/Espo/Resources/i18n/nl_NL/AuthToken.json b/application/Espo/Resources/i18n/nl_NL/AuthToken.json index 8e04b9e451..0142ba7774 100644 --- a/application/Espo/Resources/i18n/nl_NL/AuthToken.json +++ b/application/Espo/Resources/i18n/nl_NL/AuthToken.json @@ -2,8 +2,8 @@ "fields": { "user": "Gebruiker", "ipAddress": "IP Adres", - "lastAccess": "Laatste toegangs datum", - "createdAt": "Login Datum" + "lastAccess": "Datum van laatste toegang", + "createdAt": "Datum Login" } } diff --git a/application/Espo/Resources/i18n/nl_NL/DashletOptions.json b/application/Espo/Resources/i18n/nl_NL/DashletOptions.json new file mode 100644 index 0000000000..24d412e32e --- /dev/null +++ b/application/Espo/Resources/i18n/nl_NL/DashletOptions.json @@ -0,0 +1,10 @@ +{ + "fields": { + "title": "Titel", + "dateFrom": "Datum Vanaf", + "dateTo": "Datum Tot", + "autorefreshInterval": "Automatisch bijwerken interval", + "displayRecords": "Velden weergeven", + "isDoubleHeight": "Hoogte 2x" + } +} diff --git a/application/Espo/Resources/i18n/nl_NL/Email.json b/application/Espo/Resources/i18n/nl_NL/Email.json index 9e631375e7..d3f2e6320b 100644 --- a/application/Espo/Resources/i18n/nl_NL/Email.json +++ b/application/Espo/Resources/i18n/nl_NL/Email.json @@ -15,19 +15,27 @@ "selectTemplate": "Selecteer Template", "fromEmailAddress": "Van Adres", "toEmailAddresses": "Naar Adres", - "emailAddress": "Email Adres" + "emailAddress": "Email Adres", + "deliveryDate": "Afleverdatum" }, "links": { }, "options": { - "Draft": "Tijdelijk", + "Draft": "Concept", "Sending": "Verzenden", "Sent": "Verstuur", "Archived": "Archiveren" }, "labels": { "Create Email": "Archiveer Email", - "Compose": "Maak" + "Archive Email": "Archiveer Email", + "Compose": "Maak", + "Reply": "Antwoord", + "Reply to All": "Antwoord allen", + "Forward": "Doorsturen", + "Original message": "Originele bericht", + "Forwarded message": "Doorgestuurd bericht", + "Email Accounts": "Email Accounts" }, "presetFilters": { "sent": "Verstuur", diff --git a/application/Espo/Resources/i18n/nl_NL/EmailAccount.json b/application/Espo/Resources/i18n/nl_NL/EmailAccount.json new file mode 100644 index 0000000000..81a7882c1c --- /dev/null +++ b/application/Espo/Resources/i18n/nl_NL/EmailAccount.json @@ -0,0 +1,29 @@ +{ + "fields": { + "name": "Record Naam", + "status": "Status", + "host": "Host", + "username": "Gebruikersnaam", + "password": "Wachtwoord", + "port": "Port", + "monitoredFolders": "Gecontroleerde Folders", + "ssl": "SSL", + "fetchSince": "Opgehaald Vanaf" + }, + "links": { + }, + "options": { + "status": { + "Active": "Actief", + "Inactive": "Inactief" + } + }, + "labels": { + "Create EmailAccount": "Email Account Aanmaken", + "IMAP": "IMAP", + "Main": "Hoofd" + }, + "messages": { + "couldNotConnectToImap": "Kan geen verbinding maken met IMAP server" + } +} diff --git a/application/Espo/Resources/i18n/nl_NL/EmailTemplate.json b/application/Espo/Resources/i18n/nl_NL/EmailTemplate.json index feedcd4000..84d8fe8e91 100644 --- a/application/Espo/Resources/i18n/nl_NL/EmailTemplate.json +++ b/application/Espo/Resources/i18n/nl_NL/EmailTemplate.json @@ -11,6 +11,6 @@ "links": { }, "labels": { - "Create EmailTemplate": "Maak Email Template" + "Create EmailTemplate": "Email Template Aanmaken" } } diff --git a/application/Espo/Resources/i18n/nl_NL/Extension.json b/application/Espo/Resources/i18n/nl_NL/Extension.json new file mode 100644 index 0000000000..3fe87fe335 --- /dev/null +++ b/application/Espo/Resources/i18n/nl_NL/Extension.json @@ -0,0 +1,15 @@ +{ + "fields": { + "name": "Record Naam", + "version": "Versie", + "description": "Beschrijving", + "isInstalled": "Geinstalleerd" + }, + "labels": { + "Uninstall": "Deinstalleren", + "Install": "Installeren" + }, + "messages": { + "uninstalled": "Extensie {name} is gedeinstalleerd" + } +} diff --git a/application/Espo/Resources/i18n/nl_NL/ExternalAccount.json b/application/Espo/Resources/i18n/nl_NL/ExternalAccount.json new file mode 100644 index 0000000000..47b5280431 --- /dev/null +++ b/application/Espo/Resources/i18n/nl_NL/ExternalAccount.json @@ -0,0 +1,8 @@ +{ + "labels": { + "Connect": "Verbinden", + "Connected": "Verbonden" + }, + "help": { + } +} diff --git a/application/Espo/Resources/i18n/nl_NL/Global.json b/application/Espo/Resources/i18n/nl_NL/Global.json index b237ab66ba..9bf7d0aa11 100644 --- a/application/Espo/Resources/i18n/nl_NL/Global.json +++ b/application/Espo/Resources/i18n/nl_NL/Global.json @@ -2,20 +2,26 @@ "scopeNames": { "Email": "Email", "User": "Gebruiker", - "Team": "Team", - "Role": "Voorwaarde", + "Team": "Groep", + "Role": "Rol", "EmailTemplate": "Email Template", + "EmailAccount": "Email Account", "OutboundEmail": "Uitgaande Email", - "ScheduledJob": "Geplande Opdracht" + "ScheduledJob": "Geplande Opdracht", + "ExternalAccount": "Extern Account", + "Extension": "Extensie" }, "scopeNamesPlural": { "Email": "Emails", "User": "Gebruikers", "Team": "Groepen", - "Role": "Regels", + "Role": "Rollen", "EmailTemplate": "Email Templates", + "EmailAccount": "Email Accounts", "OutboundEmail": "Uitgaande Emails", - "ScheduledJob": "Geplande Opdrachten" + "ScheduledJob": "Geplande Opdrachten", + "ExternalAccount": "Externe Accounts", + "Extension": "Extensies" }, "labels": { "Misc": "Versch.", @@ -25,7 +31,7 @@ "Saved": "Opgeslagen", "Error": "Fout", "Select": "Selecteer", - "Not valid": "Niet juist", + "Not valid": "Ongeldig", "Please wait...": "Even geduld...", "Please wait": "Even geduld", "Loading...": "Laden...", @@ -35,38 +41,38 @@ "Posted": "Geplaatst", "Linked": "Linked", "Unlinked": "Unlinked", - "Access denied": "Verboden toegang", - "Access": "Rechten", - "Are you sure?": "Are you sure?", + "Access denied": "Toegang gweigerd", + "Access": "Toegang", + "Are you sure?": "Zeker?", "Record has been removed": "Record is verwijderd", - "Wrong username/password": "Verkeerde gebruikersnaam/wachtwoord", - "Post cannot be empty": "Veld kan niet leeg zijn", + "Wrong username/password": "Onjuiste gebruikersnaam/wachtwoord", + "Post cannot be empty": "Veld mag niet leeg zijn", "Removing...": "Verwijderen...", "Unlinking...": "Unlinken...", "Posting...": "Plaatsen...", - "Username can not be empty!": "Gebruikersnaam kan niet leeg zijn!", + "Username can not be empty!": "Gebruikersnaam mag niet leeg zijn!", "Cache is not enabled": "Cache is niet geactiveerd", "Cache has been cleared": "Cache is leeg gemaakt", "Rebuild has been done": "Het reconstrueren is klaar", "Saving...": "Opslaan...", "Modified": "Aangepast", "Created": "Gemaakt", - "Create": "Maak", + "Create": "Aanmaken", "create": "maak", "Overview": "Overzicht", "Details": "Details", - "Add Filter": "Maak Filter", + "Add Filter": "Filter toevoegen", "Add Dashlet": "Dashlet Toevoegen", "Add": "Toevoegen", "Reset": "Reset", "Menu": "Menu", "More": "Meer", "Search": "Zoeken", - "Only My": "Ik Alleen ", + "Only My": "Alleen mijn", "Open": "Open", "Admin": "Admin", "About": "Over", - "Refresh": "Verversen", + "Refresh": "Vernieuwen", "Remove": "Verwijderen", "Options": "Opties", "Username": "Gebruikersnaam", @@ -74,7 +80,7 @@ "Login": "Login", "Log Out": "Uitloggen", "Preferences": "Voorkeuren", - "State": "Deelstaat", + "State": "Provincie", "Street": "Straat", "Country": "Land", "City": "Plaats", @@ -83,23 +89,23 @@ "Follow": "Volgen", "Clear Local Cache": "Lokale Cache Schonen", "Actions": "Acties", - "Delete": "Verwijder", + "Delete": "Verwijderen", "Update": "Update", "Save": "Opslaan", - "Edit": "Aanpassen", + "Edit": "Bewerken", "Cancel": "Annuleren", "Unlink": "Unlink", - "Mass Update": "Totale Update", + "Mass Update": "Massa Update", "Export": "Exporteer", "No Data": "Geen Data", "All": "Alles", - "Active": "Active", - "Inactive": "Inactive", + "Active": "Actief", + "Inactive": "Inactief", "Write your comment here": "Schrijf hier uw opmerkingen", - "Post": "Plaats", + "Post": "Post", "Stream": "Activiteiten", - "Show more": "Meer tonen", - "Dashlet Options": "Kader opties", + "Show more": "Toon meer", + "Dashlet Options": "Kader Opties", "Full Form": "Volledig Formulier", "Insert": "Voeg in", "Person": "Persoon", @@ -112,57 +118,52 @@ "Primary": "Primair", "Save Filters": "Filters opslaan", "Administration": "Administratie", - "Run Import": "Start Import", + "Run Import": "Start Importeren", "Duplicate": "Dupliceer", - "Notifications": "Notificaties", - "Mark all read": "Mark all read", - "See more": "See more" + "Notifications": "Meldingen", + "Mark all read": "Markeer als gelezen", + "See more": "Bekijk meer" }, "messages": { - "notModified": "U heeft het veld niet aangepast", + "notModified": "U heeft niets gewijzigd", "duplicate": "Het veld dat u maakt lijkt een duplicaat", - "fieldIsRequired": "{field} is nodig", - "fieldShouldBeEmail": "{field} moet een geldend mailadres zijn", - "fieldShouldBeFloat": "{field} moet een geldende 'float'waarde zijn", - "fieldShouldBeInt": "{field} moet een geldende integer waarde zijn", - "fieldShouldBeDate": "{field} moet een geldende datum zijn", - "fieldShouldBeDatetime": "{field} moet een geldende datum/tijd zijn", - "fieldShouldAfter": "{field} moet na {otherField} zijn", - "fieldShouldBefore": "{field} moet voor {otherField} zijn", - "fieldShouldBeBetween": "{field} moet tussen {min} en {max}", + "fieldIsRequired": "{field} is verplicht", + "fieldShouldBeEmail": "{field} moet een geldig mailadres zijn", + "fieldShouldBeFloat": "{field} moet een geldige waarde zijn", + "fieldShouldBeInt": "{field} moet een geldige waarde zijn", + "fieldShouldBeDate": "{field} moet een geldige datum zijn", + "fieldShouldBeDatetime": "{field} moet een geldige datum/tijd zijn", + "fieldShouldAfter": "{field} moet na {otherField} komen", + "fieldShouldBefore": "{field} moet voor {otherField} komen", + "fieldShouldBeBetween": "{field} moet een waarde hebben tussen {min} en {max}", "fieldShouldBeLess": "{field} moet minder zijn dan {value}", "fieldShouldBeGreater": "{field} moet groter zijn dan {value}", "fieldBadPasswordConfirm": "{field} onjuist bevestigd", "assignmentEmailNotificationSubject": "EspoCRM {entityType}: {Entity.name}", - "assignmentEmailNotificationBody": "{assignerUserName} has assigned {entityType} '{Entity.name}' to you\n\n{recordUrl}", - "confirmation": "Are you sure?", - "removeRecordConfirmation": "Are you sure you want to remove the record?", - "unlinkRecordConfirmation": "Are you sure you want to unlink relationship?", - "removeSelectedRecordsConfirmation": "Are you sure you want to remove selected records?" + "assignmentEmailNotificationBody": "{assignerUserName} heeft {entityType} '{Entity.name}' toegewezen aan jou\n\n{recordUrl}", + "confirmation": "Zeker?", + "removeRecordConfirmation": "Record verwijderen?", + "unlinkRecordConfirmation": "Relatie ontkoppelen?", + "removeSelectedRecordsConfirmation": "Geselecteerde records verwijderen?" }, "boolFilters": { - "onlyMy": "Ik Alleen ", + "onlyMy": "Alleen mijn", "open": "Open", - "active": "Active" + "active": "Actief" }, "fields": { "name": "Record Naam", "firstName": "Voornaam", "lastName": "Achternaam", - "salutationName": "Groeten", + "salutationName": "Aanhef", "assignedUser": "Toegewezen Gebruiker", "emailAddress": "Email", - "assignedUserName": "Toegewezen Gebruikers Naam", + "assignedUserName": "Toegewezen Gebruikersnaam", "teams": "Groepen", - "createdAt": "Gemaakt op", + "createdAt": "Aangemaakt op", "modifiedAt": "Aangepast op", - "createdBy": "Gemaakt door", - "modifiedBy": "Aangepast door", - "title": "Titel", - "dateFrom": "Datum Vanaf", - "dateTo": "Datum Tot", - "autorefreshInterval": "Auto-herstel Interval", - "displayRecords": "Toon velden" + "createdBy": "Aangemaakt door", + "modifiedBy": "Aangepast door" }, "links": { "teams": "Groepen", @@ -172,17 +173,18 @@ "Stream": "Activiteiten" }, "streamMessages": { - "create": "{user} maakte {entityType} {entity}", - "createAssigned": "{user} maakte {entityType} {entity} toegewezen aan {assignee}", - "assign": "{user} toegewezen {entityType} {entity} aan {assignee}", - "post": "{user} ingevoerd op {entityType} {entity}", + "create": "{user} creërde {entityType} {entity} ", + "createAssigned": "{user} creërde {entityType} {entity} en wees toe aan {assignee}", + "assign": "{user} wees {entityType} {entity} toe aan {assignee}", + "post": "{user} geplaatst op {entityType} {entity}", "attach": "{user} toegevoegd aan {entityType} {entity}", "status": "{user} paste {field} aan op {entityType} {entity}", "update": "{user} paste {entityType} {entity} aan", - "createRelated": "{user} maakte {relatedEntityType} {relatedEntity} gekoppeld aan {entityType} {entity}", + "createRelated": "{user} creërde {relatedEntityType} {relatedEntity} gekoppeld aan {entityType} {entity}", "emailReceived": "{entity} is ontvangen voor {entityType} {entity}", + "mentionInPost": "{user} vermeldde {mentioned} op {entityType} {entity}", - "createThis": "{user} maakte dit {entityType}", + "createThis": "{user} creërde dit {entityType} ", "createAssignedThis": "{user} maakte dit {entityType} toegewezen aan {assignee}", "assignThis": "{user} wees dit {entityType} toe aan {assignee}", "postThis": "{user} gepost", @@ -193,11 +195,11 @@ "emailReceivedThis": "{entity} is ontvangen" }, "lists": { - "monthNames": ["Januari", "Februari", "Maart", "April", "Mei", "Juni", "Juli", "Augustus", "September", "Oktober", "November", "December"], - "monthNamesShort": ["Jan", "Feb", "Mar", "Apr", "Mei", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dec"], - "dayNames": ["Zondag", "Maandag", "Dinsdag", "Woensdag", "Donderdag", "Vrijdag", "Zaterdag"], - "dayNamesShort": ["Zon", "Maa", "Din", "Woe", "Don", "Vrij", "Zat"], - "dayNamesMin": ["Zo", "Ma", "Di", "Wo", "Do", "Vr", "Za"] + "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"] }, "options": { "salutationName": { @@ -219,46 +221,46 @@ "da_DK": "Deens", "de_DE": "Duits", "el_GR": "Grieks", - "en_GB":"English (UK)", - "en_US":"English (US)", - "es_ES":"Spanish (Spain)", + "en_GB": "Engels (UK)", + "en_US": "Engels (VS)", + "es_ES": "Spaans (Spanje)", "et_EE": "Estlands", "eu_ES": "Baskisch", "fa_IR": "Perzisch", "fi_FI": "Fins", "fo_FO": "Faroese", - "fr_CA":"French (Canada)", - "fr_FR":"French (France)", + "fr_CA": "Frans (Canada)", + "fr_FR": "Frans (Frankrijk)", "ga_IE": "Iers", "gl_ES": "Galicisch", "gn_PY": "Guarani", "he_IL": "Hebreeuws", "hi_IN": "Hindies", "hr_HR": "Kroatisch", - "hu_HU": "Hungaars", + "hu_HU": "Hongaars", "hy_AM": "Armeens", "id_ID": "Indonesisch", - "is_IS": "IJSlands", + "is_IS": "IJslands", "it_IT": "Italiaans", "ja_JP": "Japans", "ka_GE": "Georgisch", "km_KH": "Khmer", - "ko_KR": "Koreans", + "ko_KR": "Koreaans", "ku_TR": "Koerdisch", "lt_LT": "Litouws", "lv_LV": "Lets", "mk_MK": "Macedonisch", - "ml_IN": "Malayalam", + "ml_IN": "Maleisisch", "ms_MY": "Maleis", - "nb_NO": "Noorse Bokmål", - "nn_NO": "Noorse Nynorsk", + "nb_NO":"Norwegian Bokmål", + "nn_NO": "Noors Nynorsk", "ne_NP": "Nepalees", "nl_NL": "Nederlands", "pa_IN": "Punjabi", "pl_PL": "Pools", "ps_AF": "Pasjtoe", - "pt_BR":"Portuguese (Brazil)", - "pt_PT":"Portuguese (Portugal)", + "pt_BR": "Portugees (Brazilie", + "pt_PT": "Portugees (Portugal)", "ro_RO": "Roemeens", "ru_RU": "Russisch", "sk_SK": "Slowaaks", @@ -272,12 +274,12 @@ "th_TH": "Thais", "tl_PH": "Tagalog", "tr_TR": "Turks", - "uk_UA": "Oekraïens", + "uk_UA": "OekraГЇens", "ur_PK": "Urdu", - "vi_VN": "Viëtnamees", - "zh_CN":"Simplified Chinese (China)", - "zh_HK":"Traditional Chinese (Hong Kong)", - "zh_TW":"Traditional Chinese (Taiwan)" + "vi_VN": "ViГ«tnamees", + "zh_CN": "Vereenvoudigd Chinees (China)", + "zh_HK": "Traditioneel Chinees (Hong Kong)", + "zh_TW": "Traditioneel Chinees (Taiwan)" }, "dateSearchRanges": { "on": "Op", @@ -290,12 +292,12 @@ "future": "Toekomst" }, "intSearchRanges": { - "equals": "Gelijk", - "notEquals": "Ongelijk", + "equals": "Is gelijk aan", + "notEquals": "Is niet gelijk aan", "greaterThan": "Groter dan", "lessThan": "Minder dan", - "greaterThanOrEquals": "Groter dan of gelijk", - "lessThanOrEquals": "Minder dan of gelijk", + "greaterThanOrEquals": "Groter dan of gelijk aan", + "lessThanOrEquals": "Minder dan of gelijk aan", "between": "Tussen" }, "autorefreshInterval": { @@ -311,7 +313,7 @@ "Office": "Kantoor", "Fax": "Fax", "Home": "Prive", - "Other": "Ander" + "Other": "Overig" } }, "sets": { @@ -322,40 +324,40 @@ "italic": "Italic", "underline": "Onderstreept", "strike": "Opvallend", - "clear": "Verwijder text Font", + "clear": "Verwijder Opmaak Lettertype", "height": "Lijn Hoogte", - "name": "Font Familie", - "size": "Font Grootte" + "name": "Familie Lettertype", + "size": "Lettergrootte" }, "image":{ - "image": "PLaatje", - "insert": "Plaatje invoegen", + "image": "Foto", + "insert": "Afbeelding invoegen", "resizeFull": "Volledig schalen", - "resizeHalf": "Helft verschalen", - "resizeQuarter": "Een kwart verschalen", - "floatLeft": "Float Left", - "floatRight": "Float Right", + "resizeHalf": "Schaal 50%", + "resizeQuarter": "Schaal 25%", + "floatLeft": "Links zweven", + "floatRight": "Rechts zweven", "floatNone": "Float None", - "dragImageHere": "Plaatje naar hier verslepen", - "selectFromFiles": "Selecteer vanuit bestanden", - "url": "URL plaatje", - "remove": "Verwijder plaatje" + "dragImageHere": "Sleep afbeelding naar hier", + "selectFromFiles": "Selecteer uit bestanden", + "url": "Afbeelding URL", + "remove": "Afbeelding verwijderen" }, "link":{ "link": "Link", - "insert": "Koppeling invoegen", + "insert": "Link invoegen", "unlink": "Unlink", - "edit": "Aanpassen", - "textToDisplay": "Toon de tekst", - "url":"To what URL should this link go?", - "openInNewWindow": "In een nieuw scherm openen" + "edit": "Bewerken", + "textToDisplay": "Weer te geven tekst", + "url": "Naar welke URL dient deze link te verwijzen?", + "openInNewWindow": "In nieuw scherm openen" }, "video":{ "video": "Video", "videoLink": "Video Link", - "insert": "Video toevoegen", - "url":"Video URL?", - "providers":"(YouTube, Vimeo, Vine, Instagram, or DailyMotion)" + "insert": "Video invoegen", + "url": "Video URL?", + "providers": "(YouTube, Vimeo, Vine, Instagram of DailyMotion)" }, "table":{ "table": "Tabel" @@ -365,8 +367,8 @@ }, "style":{ "style": "Stijl", - "normal": "Normaal", - "blockquote": "Aanhaling", + "normal": "Standaard", + "blockquote": "Citaat", "pre": "Code", "h1": "Header 1", "h2": "Header 2", @@ -380,40 +382,40 @@ "ordered": "Gesorteerde lijst" }, "options":{ - "help": "Help", + "help": "Hulp", "fullscreen": "Volledig scherm", "codeview": "Code View" }, "paragraph":{ - "paragraph": "Hoofdstuk", + "paragraph": "Paragraaf", "outdent": "Outdent", "indent": "Indent", - "left": "Align left", - "center": "Align center", - "right": "Align right", - "justify": "Justify full" + "left": "Links uitlijnen", + "center": "Centreren", + "right": "Rechts uitlijnen", + "justify": "Rechtsvaardig volledig" }, "color":{ - "recent": "Recent Color", - "more": "More Color", - "background": "BackColor", - "foreground": "FontColor", + "recent": "Recente kleur", + "more": "Meer kleur", + "background": "Achtergrondkleur", + "foreground": "Tekstkleur", "transparent": "Transparent", - "setTransparent": "Set transparent", + "setTransparent": "Transparent instellen", "reset": "Reset", - "resetToDefault": "Reset to default" + "resetToDefault": "Standaardinstellingen terugzetten" }, "shortcut":{ - "shortcuts": "Keyboard shortcuts", - "close": "Close", - "textFormatting": "Text formatting", - "action": "Action", - "paragraphFormatting": "Paragraph formatting", - "documentStyle": "Document Style" + "shortcuts": "Keyboard snelkoppelingen", + "close": "Afsluiten", + "textFormatting": "Tekstopmaak", + "action": "Actie", + "paragraphFormatting": "Paragraafopmaak", + "documentStyle": "Documentopmaak" }, "history":{ - "undo": "Undo", - "redo": "Redo" + "undo": "Herstel", + "redo": "Opnieuw" } } } diff --git a/application/Espo/Resources/i18n/nl_NL/Integration.json b/application/Espo/Resources/i18n/nl_NL/Integration.json new file mode 100644 index 0000000000..45257870be --- /dev/null +++ b/application/Espo/Resources/i18n/nl_NL/Integration.json @@ -0,0 +1,14 @@ +{ + "fields": { + "enabled": "Geactiveerd", + "clientId": "Client ID", + "clientSecret": "Client Geheim", + "redirectUri": "Redirect URI" + }, + "messages": { + "selectIntegration": "Selecteer een integratie in het menu." + }, + "help": { + "Google": "

Obtain OAuth 2.0 credentials from the Google Developers Console.

Visit Google Developers Console to obtain OAuth 2.0 credentials such as a Client ID and Client Secret that are known to both Google and EspoCRM application.

" + } +} diff --git a/application/Espo/Resources/i18n/nl_NL/Note.json b/application/Espo/Resources/i18n/nl_NL/Note.json index 0c8be8d3e3..17517b4853 100644 --- a/application/Espo/Resources/i18n/nl_NL/Note.json +++ b/application/Espo/Resources/i18n/nl_NL/Note.json @@ -1,6 +1,6 @@ { "fields": { - "post": "Plaats", + "post": "Post", "attachments": "Bijlagen" } } diff --git a/application/Espo/Resources/i18n/nl_NL/Preferences.json b/application/Espo/Resources/i18n/nl_NL/Preferences.json index 0c0b78deaa..361247cbbc 100644 --- a/application/Espo/Resources/i18n/nl_NL/Preferences.json +++ b/application/Espo/Resources/i18n/nl_NL/Preferences.json @@ -1,19 +1,19 @@ { "fields": { - "dateFormat": "Datum notatie", + "dateFormat": "Datumnotatie", "timeFormat": "Tijdnotatie", - "timeZone": "Tijd Zone", + "timeZone": "Tijdzone", "weekStart": "Eerste dag van de Week", "thousandSeparator": "Duizendtal scheidingsteken", - "decimalMark": "Duizendtal scheidingsteken", - "defaultCurrency": "Voorkeur Valuta", + "decimalMark": "Decimaal scheidingsteken", + "defaultCurrency": "Standaard Valuta", "currencyList": "Valuta Lijst", "language": "Taal", "smtpServer": "Server", - "smtpPort": "Poort", - "smtpAuth": "Authenticatie", - "smtpSecurity": "Veiligheid", + "smtpPort": "Port", + "smtpAuth": "Auth", + "smtpSecurity": "Beveiliging", "smtpUsername": "Gebruikersnaam", "emailAddress": "Email", "smtpPassword": "Wachtwoord", @@ -21,7 +21,7 @@ "exportDelimiter": "Scheidingsteken Export", - "receiveAssignmentEmailNotifications": "Receive Email Notifications upon Assignment" + "receiveAssignmentEmailNotifications": "Ontvang bevestiging toewijzingen per email." }, "links": { }, @@ -32,6 +32,6 @@ } }, "labels": { - "Notifications": "Notificaties" + "Notifications": "Meldingen" } } diff --git a/application/Espo/Resources/i18n/nl_NL/Role.json b/application/Espo/Resources/i18n/nl_NL/Role.json index 9c5885e0b1..97765fa5b1 100644 --- a/application/Espo/Resources/i18n/nl_NL/Role.json +++ b/application/Espo/Resources/i18n/nl_NL/Role.json @@ -1,15 +1,15 @@ { "fields": { "name": "Record Naam", - "roles": "Regels" + "roles": "Rollen" }, "links": { "users": "Gebruikers", "teams": "Groepen" }, "labels": { - "Access": "Rechten", - "Create Role": "Maak Voorwaarde" + "Access": "Toegang", + "Create Role": "Rol aanmaken" }, "options": { "accessList": { @@ -19,17 +19,17 @@ }, "levelList": { "all": "allemaal", - "team": "team", + "team": "Groep", "own": "eigen", "no": "nee" } }, "actions": { "read": "Lees", - "edit": "Aanpassen", - "delete": "Verwijder" + "edit": "Bewerken", + "delete": "Verwijderen" }, "messages": { - "changesAfterClearCache": "All changes in an access control will be applied after cache will be cleared." + "changesAfterClearCache": "Alle wijzigingen in een toegangscontrolesysteem worden toegepast nadat de cache is geschoond." } } diff --git a/application/Espo/Resources/i18n/nl_NL/ScheduledJob.json b/application/Espo/Resources/i18n/nl_NL/ScheduledJob.json index 07b5d322e0..f8376a96a2 100644 --- a/application/Espo/Resources/i18n/nl_NL/ScheduledJob.json +++ b/application/Espo/Resources/i18n/nl_NL/ScheduledJob.json @@ -3,13 +3,13 @@ "name": "Record Naam", "status": "Status", "job": "Opdracht", - "scheduling": "Scheduling (crontab notation)" + "scheduling": "Scheduling (crontab notatie)" }, "links": { "log": "Log" }, "labels": { - "Create ScheduledJob": "Maak Geplande Opdracht" + "Create ScheduledJob": "Geplande Opdracht Aanmaken" }, "options": { "job": { @@ -17,14 +17,14 @@ "Cleanup": "Opschonen" }, "cronSetup": { - "linux": "Note: Voeg deze regel toe aan uw crontab bestand tbv de geplande Espo opdrachten:", - "mac": "Note: Voeg deze regel toe aan uw crontab bestand tbv de geplande Espo opdrachten:", - "windows": "Note: Maak een batch file met de volgende commando's om de geplande opdrachten voor Espo onder Windows te gebruiken:", - "default": "Note: Add this command to Cron Job (Scheduled Task):" + "linux": "Opgelet; Voeg deze regel toe aan uw crontab bestand tbv de geplande Espo opdrachten:", + "mac": "Opgelet; Voeg deze regel toe aan uw crontab bestand tbv de geplande Espo opdrachten:", + "windows": "Opgelet: Maak een batch bestand met de volgende commando's om de geplande opdrachten voor Espo onder Windows te gebruiken:", + "default": "Opgelet: Voeg deze regel toe aan de Cron Job (geplande opdracht):" }, "status": { - "Active": "Active", - "Inactive": "Inactive" + "Active": "Actief", + "Inactive": "Inactief" } } } diff --git a/application/Espo/Resources/i18n/nl_NL/Settings.json b/application/Espo/Resources/i18n/nl_NL/Settings.json index df5fb60a5a..d29ab2b594 100644 --- a/application/Espo/Resources/i18n/nl_NL/Settings.json +++ b/application/Espo/Resources/i18n/nl_NL/Settings.json @@ -1,59 +1,58 @@ { "fields": { "useCache": "Gebruik Cache", - "dateFormat": "Datum notatie", + "dateFormat": "Datumnotatie", "timeFormat": "Tijdnotatie", - "timeZone": "Tijd Zone", + "timeZone": "Tijdzone", "weekStart": "Eerste dag van de Week", "thousandSeparator": "Duizendtal scheidingsteken", - "decimalMark": "Duizendtal scheidingsteken", - "defaultCurrency": "Voorkeur Valuta", - "baseCurrency": "Base Currency", - "baseCurrency": "Base Currency", - "currencyRates": "Rate Values", + "decimalMark": "Decimaal scheidingsteken", + "defaultCurrency": "Standaard Valuta", + "baseCurrency": "Basisvaluta", + "currencyRates": "Tariefwaarden", "currencyList": "Valuta Lijst", "language": "Taal", - "companyLogo": "Firma logo", + "companyLogo": "Bedrijfslogo", "smtpServer": "Server", - "smtpPort": "Poort", - "smtpAuth": "Authenticatie", - "smtpSecurity": "Veiligheid", + "smtpPort": "Port", + "smtpAuth": "Auth", + "smtpSecurity": "Beveiliging", "smtpUsername": "Gebruikersnaam", "emailAddress": "Email", "smtpPassword": "Wachtwoord", - "outboundEmailFromName": "Naam van", + "outboundEmailFromName": "Van Naam", "outboundEmailFromAddress": "Van Adres", "outboundEmailIsShared": "Is Gedeeld", - "recordsPerPage": "Velden per pagina", - "recordsPerPageSmall": "Records Per Page (Small)", + "recordsPerPage": "Records per pagina", + "recordsPerPageSmall": "Records per pagina (Klein)", "tabList": "Tab lijst", - "quickCreateList": "Snel gemaakte lijst", + "quickCreateList": "Lijst aanmaken", "exportDelimiter": "Scheidingsteken Export", - "authenticationMethod": "Authentication Methode", + "authenticationMethod": "Authenticatie Methode", "ldapHost": "Host", - "ldapPort": "Poort", - "ldapAuth": "Authenticatie", + "ldapPort": "Port", + "ldapAuth": "Auth", "ldapUsername": "Gebruikersnaam", "ldapPassword": "Wachtwoord", - "ldapBindRequiresDn": "Bind heeft Dn Nodig", - "ldapBaseDn": "Base Dn", + "ldapBindRequiresDn": "Bind vereist DN", + "ldapBaseDn": "Basis Dn", "ldapAccountCanonicalForm": "Standaard Formulier Gebruiker", - "ldapAccountDomainName": "Contact Domein Naam", + "ldapAccountDomainName": "Domeinnaam Account", "ldapTryUsernameSplit": "Probeer gesplitste Gebruikersnaam", "ldapCreateEspoUser": "Gebruiker aanmaken in EspoCRM", - "ldapSecurity": "Veiligheid", + "ldapSecurity": "Beveiliging", "ldapUserLoginFilter": "Gebruikers Login Filter", - "ldapAccountDomainNameShort": "Korte Contact Domein Naam", + "ldapAccountDomainNameShort": "Domeinnaam Account", "ldapOptReferrals": "Opt Referentie", - "disableExport": "Disable Export (only admin is allowed)", - "assignmentEmailNotifications": "Send Email Notifications upon Assignment", - "assignmentEmailNotificationsEntityList": "Entities to Notify About" + "disableExport": "Exporteren Uitschakelen (Uitsluitend toegestaan voor Admin)", + "assignmentEmailNotifications": "Verzend Email na Toewijzing", + "assignmentEmailNotificationsEntityList": "Entities om over te informeren" }, "options": { "weekStart": { @@ -62,15 +61,15 @@ } }, "tooltips": { - "recordsPerPageSmall": "Count of records in relatinship panels." + "recordsPerPageSmall": "Aantal records in relatie kaders." }, "labels": { "System": "Systeem", "Locale": "Lokaal", "SMTP": "SMTP", "Configuration": "Configuratie", - "Notifications": "Notificaties", - "Currency Settings": "Currency Settings", - "Currency Rtes": "Currency Rates" + "Notifications": "Meldingen", + "Currency Settings": "Valutainstellingen", + "Currency Rtes": "Valutakoersen" } } diff --git a/application/Espo/Resources/i18n/nl_NL/Team.json b/application/Espo/Resources/i18n/nl_NL/Team.json index 97f0e9f19d..00583cd5d0 100644 --- a/application/Espo/Resources/i18n/nl_NL/Team.json +++ b/application/Espo/Resources/i18n/nl_NL/Team.json @@ -1,15 +1,15 @@ { "fields": { "name": "Record Naam", - "roles": "Regels" + "roles": "Rollen" }, "links": { "users": "Gebruikers" }, "tooltips": { - "roles": "All users from this team will get access settings from selected roles." + "roles": "Alle gebruikers van deze groep krijgen de rechten uit de geselecteerde rollen." }, "labels": { - "Create Team": "Maak een Team" + "Create Team": "Groep Aanmaken" } } diff --git a/application/Espo/Resources/i18n/nl_NL/User.json b/application/Espo/Resources/i18n/nl_NL/User.json index fffc4710c4..01c3669266 100644 --- a/application/Espo/Resources/i18n/nl_NL/User.json +++ b/application/Espo/Resources/i18n/nl_NL/User.json @@ -1,35 +1,36 @@ { "fields": { "name": "Record Naam", - "userName": "Gebruikers Naam", + "userName": "Gebruikesnaam", "title": "Titel", "isAdmin": "Is Admin", - "defaultTeam": "Voorkeur Team", + "defaultTeam": "Standaardgroep", "emailAddress": "Email", "phoneNumber": "Telefoon", - "roles": "Regels", + "roles": "Rollen", "password": "Wachtwoord", "passwordConfirm": "Bevestig Wachtwoord", "newPassword": "Nieuw Wachtwoord" }, "links": { "teams": "Groepen", - "roles": "Regels" + "roles": "Rollen" }, "labels": { "Create User": "Gebruiker Aanmaken", "Generate": "Genereer", - "Access": "Rechten", + "Access": "Toegang", "Preferences": "Voorkeuren", - "Change Password": "Wachtwoord Aanpassen" + "Change Password": "Wachtwoord wijzigen" }, "tooltips": { - "defaultTeam": "All records created by this user will be related to this team by default." + "defaultTeam": "Alle records aangemaakt door gebruiker worden standaard aan de groep gekoppeld.", + "userName": "Letters a-z, cijfers 0-9 en underscores zijn toegestaan." }, "messages": { - "passwordWillBeSent": "Het Wachtwoord wordt naar het email adres van de gebruiker verzonden.", - "accountInfoEmailSubject": "Gebruiker Informatie", - "accountInfoEmailBody": "Uw gebruikers informatie:\n\nUsername: {userName}\nPassword: {password}\n\n{siteUrl}", - "passwordChanged": "Het wachtwoord is aangepast" + "passwordWillBeSent": "Wachtwoord wordt naar het emailadres van de gebruiker verzonden.", + "accountInfoEmailSubject": "Informatie Gebruiker", + "accountInfoEmailBody": "Uw gegevens:\n\nGebruikersnaam: {userName}\nWachtwoord: {password}\n\n{siteUrl}", + "passwordChanged": "Het wachtwoord is gewijzigd" } } diff --git a/application/Espo/Resources/i18n/pl_PL/Admin.json b/application/Espo/Resources/i18n/pl_PL/Admin.json index b1f0ac3893..a4fe02892d 100644 --- a/application/Espo/Resources/i18n/pl_PL/Admin.json +++ b/application/Espo/Resources/i18n/pl_PL/Admin.json @@ -1,128 +1,125 @@ { - "labels": { - "Enabled": "Włączony", - "Disabled": "Wyłączony", - "System": "System", - "Users": "Użytkownik", - "Email": "E-mail", - "Data": "Data", - "Customization": "Dostosowanie", - "Available Fields": "Dostępne Pola", - "Layout": "Układ", - "Enabled": "Włączony", - "Disabled": "Wyłączony", - "Add Panel": "Dodaj Panel", - "Add Field": "Dodaj Pole", - "Settings": "Ustawienia", - "Scheduled Jobs": "Zaplanowane działanie", - "Upgrade": "Aktualizacja", - "Clear Cache": "Wyczyść Pamięć Podręczną", - "Rebuild": "Przebuduj", - "Users": "Użytkownik", - "Teams": "Zespoły", - "Roles": "Rola", - "Outbound Emails": "Poczta Wychodząca", - "Inbound Emails": "Poczta Przychodząca", - "Email Templates": "Szkice Wiadomości", - "Import": "Import", - "Layout Manager": "Menadżer Widoku", - "Field Manager": "Mendżer Pól", - "User Interface": "Interfejs Użytkonika", - "Auth Tokens": "Auth Tokens", - "Authentication": "Autoryzacja", - "Currency": "Waluta" - }, - "layouts": { - "list": "Lista", - "detail": "Detale", - "listSmall": "List (Small)", - "detailSmall": "Detail (Small)", - "filters": "Filtry Wyszukiwania", - "massUpdate": "Masowa Akrualizacja", - "relationships": "Relacje" - }, - "fieldTypes": { - "address": "Adres", - "array": "Tablica", - "foreign": "Zagraniczny", - "duration": "Czas", - "password": "Hasło", - "parsonName": "Imię", - "autoincrement": "Auto-increment", - "bool": "Bool", - "currency": "Waluta", - "date": "Data", - "datetime": "DataCzas", - "email": "E-mail", - "enum": "Enum", - "enumInt": "Enum Integer", - "enumFloat": "Enum Float", - "float": "Float", - "int": "Int", - "link": "Link", - "linkMultiple": "Link Multiple", - "linkParent": "Link Parent", - "multienim": "Multienum", - "phone": "Telefon", - "text": "Tekst", - "url": "Strona Internetowa", - "varchar": "Varchar", - "file": "Plik", - "image": "Obraz" - }, - "fields": { - "type": "Rodzaj", - "name": "Imię", - "label": "Etykieta", - "required": "Wymagany", - "default": "Standardowy", - "maxLength": "Długość Maksymalna", - "options": "Options (raw values, not translated)", - "after": "After (field)", - "before": "Before (field)", - "link": "Link", - "field": "Pole", - "min": "Min", - "max": "Max", - "translation": "Tłumaczenie", - "previewSize": "Podgląd Rozmiaru" - }, - "messages": { - "upgradeVersion": "Twój EspoCRM jest aktualizowany do wersji {version}. To może zająć trochę czasu.", - "upgradeDone": "Twój CRM został zaaktualizowany do najnowszej wersji {version}. Odśwież swoją przeglądarke aby zobaczyć zmiany.", - "upgradeBackup": "Zalecamy abyś wykonał archiwizacje swoich danych, przed aktualizacją.", - "thousandSeparatorEqualsDecimalMark": "Separator dziesiętny nie może być taki sam jak znak oddzielenia", - "userHasNoEmailAddress": "Użytkownik nie ma przypisanego adres e-mail.", - "selectEntityType": "Wybierz jednostkę z menu po lewej stonie.", - "selectUpgradePackage": "Wypierz paczkę do aktualizacji", - "selectLayout": "Wybierz interesujący Cię układ z menu po lewej stronie i zacznij go edytować." - }, - "descriptions": { - "settings": "Ustawienia systemu dla aplikacji.", - "scheduledJob": "Zadania wykonywane przez skrypt cron.", - "upgrade": "Aktualizuj EspoCRM.", - "clearCache": "Wyczyść wszystkie dane zapisane w pamięci podręcznej.", - "rebuild": "Przebuduj oraz wyczyść pamięć podręczną.", - "users": "Zarządzanie użytkonikami.", - "teams": "Zarządzanie zespołami.", - "roles": "Zarządzanie Rolami.", - "outboundEmails": "Ustawienia SMTP dla poczty wychodzącej.", - "inboundEmails": "Glabalne ustawienia IMAP. Importowanie wiadomości i e-mail-do-zadania.", - "emailTemplates": "Szkice wiadomości dla poczty wychodzącej.", - "import": "Importuj dane z pliku CSV.", - "layoutManager": "Customize layouts (list, detail, edit, search, mass update).", - "fieldManager": "Utwórz nowe pole lub dopasuj istniejące.", - "userInterface": "Konfiguruj UI(interfejs użytkownika).", - "authTokens": "Aktywuj autoryzacje sesji. Adres IP oraz data ostaniego wejścia.", - "authentication": "Ustawinia Autoryzacji.", - "currency": "Ustawienia waluty oraz przelicznika." - }, - "options": { - "previewSize": { - "x-small": "Bardzo Małe", - "small": "Małe", - "medium": "Średnie", - "large": "Duże" - } - } + "labels": { + "Enabled": "Włączony", + "Disabled": "Wyłączony", + "System": "System", + "Users": "Użytkownik", + "Email": "E-mail", + "Data": "Data", + "Customization": "Dostosowanie", + "Available Fields": "Dostępne Pola", + "Layout": "Układ", + "Add Panel": "Dodaj Panel", + "Add Field": "Dodaj Pole", + "Settings": "Ustawienia", + "Scheduled Jobs": "Zaplanowane działanie", + "Upgrade": "Aktualizacja", + "Clear Cache": "Wyczyść Pamięć Podręczną", + "Rebuild": "Przebuduj", + "Teams": "Zespoły", + "Roles": "Rola", + "Outbound Emails": "Poczta Wychodząca", + "Inbound Emails": "Poczta Przychodząca", + "Email Templates": "Szkice Wiadomości", + "Import": "Import", + "Layout Manager": "Menadżer Widoku", + "Field Manager": "Mendżer Pól", + "User Interface": "Interfejs Użytkonika", + "Auth Tokens": "Auth Tokens", + "Authentication": "Autoryzacja", + "Currency": "Waluta" + }, + "layouts": { + "list": "Lista", + "detail": "Detale", + "listSmall": "List (Small)", + "detailSmall": "Detail (Small)", + "filters": "Filtry Wyszukiwania", + "massUpdate": "Masowa Akrualizacja", + "relationships": "Relacje" + }, + "fieldTypes": { + "address": "Adres", + "array": "Tablica", + "foreign": "Zagraniczny", + "duration": "Czas", + "password": "Hasło", + "parsonName": "Imię", + "autoincrement": "Auto-increment", + "bool": "Bool", + "currency": "Waluta", + "date": "Data", + "datetime": "DataCzas", + "email": "E-mail", + "enum": "Enum", + "enumInt": "Enum Integer", + "enumFloat": "Enum Float", + "float": "Float", + "int": "Int", + "link": "Link", + "linkMultiple": "Link Multiple", + "linkParent": "Link Parent", + "multienim": "Multienum", + "phone": "Telefon", + "text": "Tekst", + "url": "Strona Internetowa", + "varchar": "Varchar", + "file": "Plik", + "image": "Obraz" + }, + "fields": { + "type": "Rodzaj", + "name": "Imię", + "label": "Etykieta", + "required": "Wymagany", + "default": "Standardowy", + "maxLength": "Długość Maksymalna", + "options": "Options (raw values, not translated)", + "after": "After (field)", + "before": "Before (field)", + "link": "Link", + "field": "Pole", + "min": "Min", + "max": "Max", + "translation": "Tłumaczenie", + "previewSize": "Podgląd Rozmiaru" + }, + "messages": { + "upgradeVersion": "Twój EspoCRM jest aktualizowany do wersji {version}. To może zająć trochę czasu.", + "upgradeDone": "Twój CRM został zaaktualizowany do najnowszej wersji {version}. Odśwież swoją przeglądarke aby zobaczyć zmiany.", + "upgradeBackup": "Zalecamy abyś wykonał archiwizacje swoich danych, przed aktualizacją.", + "thousandSeparatorEqualsDecimalMark": "Separator dziesiętny nie może być taki sam jak znak oddzielenia", + "userHasNoEmailAddress": "Użytkownik nie ma przypisanego adres e-mail.", + "selectEntityType": "Wybierz jednostkę z menu po lewej stonie.", + "selectUpgradePackage": "Wypierz paczkę do aktualizacji", + "selectLayout": "Wybierz interesujący Cię układ z menu po lewej stronie i zacznij go edytować." + }, + "descriptions": { + "settings": "Ustawienia systemu dla aplikacji.", + "scheduledJob": "Zadania wykonywane przez skrypt cron.", + "upgrade": "Aktualizuj EspoCRM.", + "clearCache": "Wyczyść wszystkie dane zapisane w pamięci podręcznej.", + "rebuild": "Przebuduj oraz wyczyść pamięć podręczną.", + "users": "Zarządzanie użytkonikami.", + "teams": "Zarządzanie zespołami.", + "roles": "Zarządzanie Rolami.", + "outboundEmails": "Ustawienia SMTP dla poczty wychodzącej.", + "inboundEmails": "Glabalne ustawienia IMAP. Importowanie wiadomości i e-mail-do-zadania.", + "emailTemplates": "Szkice wiadomości dla poczty wychodzącej.", + "import": "Importuj dane z pliku CSV.", + "layoutManager": "Customize layouts (list, detail, edit, search, mass update).", + "fieldManager": "Utwórz nowe pole lub dopasuj istniejące.", + "userInterface": "Konfiguruj UI(interfejs użytkownika).", + "authTokens": "Aktywuj autoryzacje sesji. Adres IP oraz data ostaniego wejścia.", + "authentication": "Ustawinia Autoryzacji.", + "currency": "Ustawienia waluty oraz przelicznika." + }, + "options": { + "previewSize": { + "x-small": "Bardzo Małe", + "small": "Małe", + "medium": "Średnie", + "large": "Duże" + } + } } diff --git a/application/Espo/Resources/i18n/pl_PL/AuthToken.json b/application/Espo/Resources/i18n/pl_PL/AuthToken.json index f0014c2663..ff9bf365cb 100644 --- a/application/Espo/Resources/i18n/pl_PL/AuthToken.json +++ b/application/Espo/Resources/i18n/pl_PL/AuthToken.json @@ -1,9 +1,9 @@ { - "fields": { - "user": "Użytkownik", - "ipAddress": "IP Adres", - "lastAccess": "Data ostatniego logowania", - "createdAt": "Data Logowania" + "fields": { + "user": "Użytkownik", + "ipAddress": "IP Adres", + "lastAccess": "Data ostatniego logowania", + "createdAt": "Data Logowania" - } + } } diff --git a/application/Espo/Resources/i18n/pl_PL/Email.json b/application/Espo/Resources/i18n/pl_PL/Email.json index e22ed45157..0a00b61ac9 100644 --- a/application/Espo/Resources/i18n/pl_PL/Email.json +++ b/application/Espo/Resources/i18n/pl_PL/Email.json @@ -1,42 +1,42 @@ { - "fields": { - "name": "Temat", - "parent": "Konto", - "status": "Status", - "dateSent": "Data Wysłania", - "from": "Od", - "to": "Do", - "cc": "Kopia Do", - "bcc": "Ukryta Kopia Do", - "isHtml": "Format HTML", - "body": "Treść", - "subject": "Temat", - "attachments": "Załącznik", - "selectTemplate": "Wybierz szkic wiadomości", - "fromEmailAddress": "Z adresu", - "toEmailAddresses": "Do adresu", - "emailAddress": "E-mail Adres" - }, - "links": { - }, - "options": { - "Draft": "Szkic", - "Sending": "Wysyłam", - "Sent": "Wysłane", - "Archived": "Zapisane" - }, - "labels": { - "Create Email": "Archiwizuj e-mail", - "Archive Email": "Archiwizuj e-mail", - "Compose": "Utwórz", - "Reply": "Odpowiedz", - "Reply to All": "Reply to All", - "Forward": "Forward", - "Original message": "Original message", - "Forwarded message": "Forwarded message" - }, - "presetFilters": { - "sent": "Wysłane", - "archived": "Zapisane" - } + "fields": { + "name": "Temat", + "parent": "Konto", + "status": "Status", + "dateSent": "Data Wysłania", + "from": "Od", + "to": "Do", + "cc": "Kopia Do", + "bcc": "Ukryta Kopia Do", + "isHtml": "Format HTML", + "body": "Treść", + "subject": "Temat", + "attachments": "Załącznik", + "selectTemplate": "Wybierz szkic wiadomości", + "fromEmailAddress": "Z adresu", + "toEmailAddresses": "Do adresu", + "emailAddress": "E-mail Adres" + }, + "links": { + }, + "options": { + "Draft": "Szkic", + "Sending": "Wysyłam", + "Sent": "Wysłane", + "Archived": "Zapisane" + }, + "labels": { + "Create Email": "Archiwizuj e-mail", + "Archive Email": "Archiwizuj e-mail", + "Compose": "Utwórz", + "Reply": "Odpowiedz", + "Reply to All": "Reply to All", + "Forward": "Forward", + "Original message": "Original message", + "Forwarded message": "Forwarded message" + }, + "presetFilters": { + "sent": "Wysłane", + "archived": "Zapisane" + } } diff --git a/application/Espo/Resources/i18n/pl_PL/EmailAddress.json b/application/Espo/Resources/i18n/pl_PL/EmailAddress.json index 3212d19a94..4f4aa868dc 100644 --- a/application/Espo/Resources/i18n/pl_PL/EmailAddress.json +++ b/application/Espo/Resources/i18n/pl_PL/EmailAddress.json @@ -1,7 +1,7 @@ { - "labels": { - "Primary": "Główny", - "Opted Out": "Porzucony", - "Invalid": "Błędny" - } + "labels": { + "Primary": "Główny", + "Opted Out": "Porzucony", + "Invalid": "Błędny" + } } diff --git a/application/Espo/Resources/i18n/pl_PL/EmailTemplate.json b/application/Espo/Resources/i18n/pl_PL/EmailTemplate.json index 7be521d5d8..56914bda7c 100644 --- a/application/Espo/Resources/i18n/pl_PL/EmailTemplate.json +++ b/application/Espo/Resources/i18n/pl_PL/EmailTemplate.json @@ -1,16 +1,16 @@ { - "fields": { - "name": "Imię", - "status": "Status", - "isHtml": "Format HTML", - "body": "Treść", - "subject": "Temat", - "attachments": "Załącznik", - "insertField": "" - }, - "links": { - }, - "labels": { - "Create EmailTemplate": "Utwórz Szkic Wiadomości" - } + "fields": { + "name": "Imię", + "status": "Status", + "isHtml": "Format HTML", + "body": "Treść", + "subject": "Temat", + "attachments": "Załącznik", + "insertField": "" + }, + "links": { + }, + "labels": { + "Create EmailTemplate": "Utwórz Szkic Wiadomości" + } } diff --git a/application/Espo/Resources/i18n/pl_PL/Global.json b/application/Espo/Resources/i18n/pl_PL/Global.json index 7d0c980159..0dbec1646e 100644 --- a/application/Espo/Resources/i18n/pl_PL/Global.json +++ b/application/Espo/Resources/i18n/pl_PL/Global.json @@ -1,420 +1,420 @@ { - "scopeNames": { - "Email": "E-mail", - "User": "Użytkownik", - "Team": "Zespół", - "Role": "Rola", - "EmailTemplate": "Szkic wiadomości", - "OutboundEmail": "Poczta Wychodząca", - "ScheduledJob": "Automatyczne działanie" - }, - "scopeNamesPlural": { - "Email": "Emails", - "User": "Użytkownik", - "Team": "Zespoły", - "Role": "Rola", - "EmailTemplate": "Szkice Wiadomości", - "OutboundEmail": "Poczta Wychodząca", - "ScheduledJob": "Zaplanowane działanie" - }, - "labels": { - "Misc": "Misc", - "Merge": "Merge", - "None": "None", - "by": "przez", - "Saved": "Zapisane", - "Error": "Błąd", - "Select": "Wybierz", - "Not valid": "Nie poprawnie", - "Please wait...": "Proszę Czekać...", - "Please wait": "Proszę Czekać", - "Loading...": "Ładuje...", - "Uploading...": "Wgrywam na serwer...", - "Sending...": "Wysyłam...", - "Removed": "Usunięty", - "Posted": "Opublikowany", - "Linked": "Linked", - "Unlinked": "Unlinked", - "Access denied": "Dostęp zabroniony", - "Access": "Dostęp", - "Are you sure?": "Are you sure?", - "Record has been removed": "Rekord został usunięty", - "Wrong username/password": "Zła nazwa użytkonika/hasło", - "Post cannot be empty": "Notatka nie może byc pusta", - "Removing...": "Usuwam...", - "Unlinking...": "Unlinking...", - "Posting...": "Nadaje...", - "Username can not be empty!": "Nazwa użytkownika nie może byc pusta!", - "Cache is not enabled": "Pamięć podręczna jest nie dostępna", - "Cache has been cleared": "Pamięć podręczna została wyczyszczona", - "Rebuild has been done": "Przebudowanie zostało zakończone", - "Saving...": "Zapisuje...", - "Modified": "Zmieniony", - "Created": "Utworzony", - "Create": "Utwórz", - "create": "utwórz", - "Overview": "Podgląd", - "Details": "Detale", - "Add Filter": "Dodaj Filtr", - "Add Dashlet": "Dodaj Podgląd", - "Add": "Dodaj", - "Reset": "Reset", - "Menu": "Menu", - "More": "Więcej", - "Search": "Szukaj", - "Only My": "Tylko Moje", - "Open": "Otwórz", - "Admin": "Admin", - "About": "O", - "Refresh": "Odśwież", - "Remove": "Usuń", - "Options": "Opcje", - "Username": "Użytkownik", - "Password": "Hasło", - "Login": "Login", - "Log Out": "Wyloguj się", - "Preferences": "Preferencje", - "State": "Województwo", - "Street": "Ulica", - "Country": "Kraj", - "City": "Miasto", - "PostalCode": "Kod Pocztowy", - "Followed": "Śledzony", - "Follow": "Śledź", - "Clear Local Cache": "Wyczyść Pamięć Podręczną", - "Actions": "Akcja", - "Delete": "Usuń", - "Update": "Aktualizuj", - "Save": "Zapisz", - "Edit": "Edytuj", - "Cancel": "Anuluj", - "Unlink": "Unlink", - "Mass Update": "Masowa Akrualizacja", - "Export": "Eksportuj", - "No Data": "Brak Danych", - "All": "Wszystko", - "Active": "Aktywny", - "Inactive": "Nie Aktywny", - "Write your comment here": "Dodaj swój komentarz tutaj", - "Post": "Opublikuj", - "Stream": "Komunikator", - "Show more": "Pokaż Więcej", - "Dashlet Options": "Opcje Podglądu", - "Full Form": "Pełen Formularz", - "Insert": "Wstaw", - "Person": "Osoba", - "First Name": "Imię", - "Last Name": "Nazwisko", - "Original": "Originalny", - "You": "Ty", - "you": "ty", - "change": "zmień", - "Primary": "Główny", - "Save Filters": "Zapisz filtry wyszukiwania", - "Administration": "Administracja", - "Run Import": "Uruchom Importowanie", - "Duplicate": "Powielony", - "Notifications": "powiadomienia", - "Mark all read": "Oznacz wszystko jako przeczytane", - "See more": "Zobacz więcej" - }, - "messages": { - "notModified": "Nie zmodyfikowałeś żadnych danych", - "duplicate": "Dane które wprowadziłeś wyglądają na powielone", - "fieldIsRequired": "{field} wymagane", - "fieldShouldBeEmail": "{field} wprowadź poprawny adres e-mail", - "fieldShouldBeFloat": "{field} powinno być poprawnie wyjustowane", - "fieldShouldBeInt": "{field} powinno być poprawną liczbą całkowitą", - "fieldShouldBeDate": "{field} powinno być poprawną datą", - "fieldShouldBeDatetime": "{field} powinno być poprawną datą/czasem", - "fieldShouldAfter": "{field} powinno być po {otherField}", - "fieldShouldBefore": "{field} powinno być po {otherField}", - "fieldShouldBeBetween": "{field} powinno być między {min} i {max}", - "fieldShouldBeLess": "{field} powinno być mniejsze niż {value}", - "fieldShouldBeGreater": "{field} powinno być większe niż {value}", - "fieldBadPasswordConfirm": "{field} błędnie potwierdzony", - "assignmentEmailNotificationSubject": "EspoCRM {entityType}: {Entity.name}", - "assignmentEmailNotificationBody": "{assignerUserName} został przypisany {entityType} '{Entity.name}' do Ciebie\n\n{recordUrl}", - "confirmation": "Are you sure?", - "removeRecordConfirmation": "Are you sure you want to remove the record?", - "unlinkRecordConfirmation": "Are you sure you want to unlink relationship?", - "removeSelectedRecordsConfirmation": "Are you sure you want to remove selected records?" - }, - "boolFilters": { - "onlyMy": "Tylko Moje", - "open": "Otwórz", - "active": "Aktywny" - }, - "fields": { - "name": "Imię", - "firstName": "Imię", - "lastName": "Nazwisko", - "salutationName": "Zwrot", - "assignedUser": "Przypisany użytkownik", - "emailAddress": "E-mail", - "assignedUserName": "Przypisana Nazwa Użytkownika", - "teams": "Zespoły", - "createdAt": "Utworzony do", - "modifiedAt": "Zmodyfikowany do", - "createdBy": "Utworzony przez", - "modifiedBy": "Zmodyfikowany przez", - "title": "Tytuł", - "dateFrom": "Data Od", - "dateTo": "Data Do", - "autorefreshInterval": "Odświeżanie co", - "displayRecords": "Wyświetlane Dane" - }, - "links": { - "teams": "Zespoły", - "users": "Użytkownik" - }, - "dashlets": { - "Stream": "Komunikator" - }, - "streamMessages": { - "create": "{user} utworzony {entityType} {entity}", - "createAssigned": "{user} utworzony {entityType} {entity} assigned to {assignee}", - "assign": "{user} przypisany {entityType} {entity} to {assignee}", - "post": "{user} opublikował {entityType} {entity}", - "attach": "{user} załączył {entityType} {entity}", - "status": "{user} zaaktualizował {field} on {entityType} {entity}", - "update": "{user} zaaktualizował {entityType} {entity}", - "createRelated": "{user} created {relatedEntityType} {relatedEntity} linked to {entityType} {entity}", - "emailReceived": "{entity} został otrzymane dla {entityType} {entity}", - - "createThis": "{user} utwórz to {entityType}", - "createAssignedThis": "{user} utwórz to {entityType} assigned to {assignee}", - "assignThis": "{user} przypisz to {entityType} to {assignee}", - "postThis": "{user} opublikował", - "attachThis": "{user} załączył", - "statusThis": "{user} zaaktualizował {field}", - "updateThis": "{user} aktualizuj to {entityType}", - "createRelatedThis": "{user} created {relatedEntityType} {relatedEntity} linked to this {entityType}", - "emailReceivedThis": "{entity} has been received" - }, - "lists": { - "monthNames": ["Styczeń", "Luty", "Marzec", "Kwiecień", "Maj", "Czerwiec", "Lipiec", "Sierpień", "Wrzesień", "Październik", "Listopad", "Grudzień"], - "monthNamesShort": ["Sty", "Lut", "Mar", "Kwi", "Maj", "Czer", "Lip", "Sie", "Wrze", "Paź", "Lis", "Gru"], - "dayNames": ["Niedziela", "Poniedziałek", "Wtorek", "Środa", "Czwartek", "Piątek", "Sobota"], - "dayNamesShort": ["Ndz", "Pon", "Wto", "Śro", "Czwa", "Pią", "Sob"], - "dayNamesMin": ["Nd", "Pn", "Wt", "Śr", "Czw", "Pi", "So"] - }, - "options": { - "salutationName": { - "Mr.": "Pan.", - "Mrs.": "Pani.", - "Dr.": "Dr.", - "Drs.": "Drs." - }, - "language": { - "af_ZA": "Afrikaans", - "az_AZ": "Azerbaijani", - "be_BY": "Belarusian", - "bg_BG": "Bulgarian", - "bn_IN": "Bengali", - "bs_BA": "Bosnian", - "ca_ES": "Catalan", - "cs_CZ": "Czech", - "cy_GB": "Welsh", - "da_DK": "Danish", - "de_DE": "German", - "el_GR": "Greek", - "en_GB":"English (UK)", - "en_US":"English (US)", - "es_ES":"Spanish (Spain)", - "et_EE": "Estonian", - "eu_ES": "Basque", - "fa_IR": "Persian", - "fi_FI": "Finnish", - "fo_FO": "Faroese", - "fr_CA":"French (Canada)", - "fr_FR":"French (France)", - "ga_IE": "Irish", - "gl_ES": "Galician", - "gn_PY": "Guarani", - "he_IL": "Hebrew", - "hi_IN": "Hindi", - "hr_HR": "Croatian", - "hu_HU": "Hungarian", - "hy_AM": "Armenian", - "id_ID": "Indonesian", - "is_IS": "Icelandic", - "it_IT": "Italian", - "ja_JP": "Japanese", - "ka_GE": "Georgian", - "km_KH": "Khmer", - "ko_KR": "Korean", - "ku_TR": "Kurdish", - "lt_LT": "Lithuanian", - "lv_LV": "Latvian", - "mk_MK": "Macedonian", - "ml_IN": "Malayalam", - "ms_MY": "Malay", - "nb_NO": "Norwegian Bokmål", - "nn_NO": "Norwegian Nynorsk", - "ne_NP": "Nepali", - "nl_NL": "Dutch", - "pa_IN": "Punjabi", - "pl_PL": "Polski", - "ps_AF": "Pashto", - "pt_BR":"Portuguese (Brazil)", - "pt_PT":"Portuguese (Portugal)", - "ro_RO": "Romanian", - "ru_RU": "Russian", - "sk_SK": "Slovak", - "sl_SI": "Slovene", - "sq_AL": "Albanian", - "sr_RS": "Serbian", - "sv_SE": "Swedish", - "sw_KE": "Swahili", - "ta_IN": "Tamil", - "te_IN": "Telugu", - "th_TH": "Thai", - "tl_PH": "Tagalog", - "tr_TR": "Turkish", - "uk_UA": "Ukrainian", - "ur_PK": "Urdu", - "vi_VN": "Vietnamese", - "zh_CN":"Simplified Chinese (China)", - "zh_HK":"Traditional Chinese (Hong Kong)", - "zh_TW":"Traditional Chinese (Taiwan)" - }, - "dateSearchRanges": { - "on": "Włączony", - "notOn": "Nie Włączony", - "after": "Po", - "before": "Przed", - "between": "Między", - "today": "Dziś", - "past": "Przeszłość", - "future": "Przyszłość" - }, - "intSearchRanges": { - "equals": "Równy", - "notEquals": "Nie Równy", - "greaterThan": "Większy Niż", - "lessThan": "Mniejszy Niż", - "greaterThanOrEquals": "Większy lub Równy", - "lessThanOrEquals": "Mniejszy lub Równy", - "between": "Między" - }, - "autorefreshInterval": { - "0": "None", - "0.5": "30 sekund", - "1": "1 minuta", - "2": "2 minuty", - "5": "5 minut", - "10": "10 minut" - }, - "phoneNumber": { - "Mobile": "Komórka", - "Office": "Biuro", - "Fax": "Faks", - "Home": "Domowy", - "Other": "Inny" - } - }, - "sets": { - "summernote": { - "NOTICE": "Możesz znaleść tłumaczenie tutaj: https://github.com/HackerWins/summernote/tree/master/lang", - "font":{ - "bold": "Pogrubiony", - "italic": "Pochylenie", - "underline": "Podkreślenie", - "strike": "Przekreślnie", - "clear": "Usunięto formatowanie tekstu", - "height": "Szerokość Lini", - "name": "Czcionka", - "size": "Rozmiar Czcionki" - }, - "image":{ - "image": "Obraz", - "insert": "Dodaj Obraz", - "resizeFull": "Przeskaluj na pełny rozmiar", - "resizeHalf": "Przeszkaluj na połowę rozmiaru", - "resizeQuarter": "Przeskaluj do 1/4 rozmiaru", - "floatLeft": "Równaj do lewej", - "floatRight": "Równaj do prawej", - "floatNone": "Nie zmieniaj ", - "dragImageHere": "Upuść obraz tutaj", - "selectFromFiles": "Wybierz plik z dysku", - "url": "Adres do Obrazu", - "remove": "Usuń Obraz" - }, - "link":{ - "link":"Link", - "insert":"Insert Link", - "unlink":"Unlink", - "edit": "Edytuj", - "textToDisplay": "Tekst do wyświetlenia", - "url":"To what URL should this link go?", - "openInNewWindow": "Otwórz w nowym oknie" - }, - "video":{ - "video": "Video", - "videoLink":"Video Link", - "insert": "Wstaw Video", - "url":"Video URL?", - "providers":"(YouTube, Vimeo, Vine, Instagram, or DailyMotion)" - }, - "table":{ - "table": "Tabela" - }, - "hr":{ - "insert": "Wstaw Linię Poziomą" - }, - "style":{ - "style": "Styl", - "normal": "Normalny", - "blockquote": "Cytat", - "pre": "Code", - "h1": "Nagłówek 1", - "h2": "Nagłówek 2", - "h3": "Nagłówek 3", - "h4": "Nagłówek 4", - "h5": "Nagłówek 5", - "h6": "Nagłówek 6" - }, - "lists":{ - "unordered": "Niewypunktowana lista", - "ordered": "Wypunktowana lista" - }, - "options":{ - "help": "Pomoc", - "fullscreen": "Pełny Ekran", - "codeview": "Źródło" - }, - "paragraph":{ - "paragraph": "Akapit", - "outdent": "Zmniejsz wcięcie", - "indent": "Zwiększ wcięcie", - "left": "Wyrównaj do lewej", - "center": "Wyrównaj do środka", - "right": "Wyrównaj do prawej", - "justify": "Wyrównaj do lewej i prawej" - }, - "color":{ - "recent": "Ostatni Kolor", - "more": "Więcej Kolorów", - "background": "Kolor Tła", - "foreground": "Kolor Czcionki", - "transparent": "Przeźroczystość", - "setTransparent": "Ustwa przeźroczystość", - "reset": "Reset", - "resetToDefault": "Domyślnie" - }, - "shortcut":{ - "shortcuts": "Skróty klawiaturowe", - "close": "Zamknij", - "textFormatting": "Formatowanie tekstu", - "action": "Akcja", - "paragraphFormatting": "Formatowanie akapitu", - "documentStyle": "Style dokumentu" - }, - "history":{ - "undo": "Cofnij", - "redo":"Redo" - } - } - } + "scopeNames": { + "Email": "E-mail", + "User": "Użytkownik", + "Team": "Zespół", + "Role": "Rola", + "EmailTemplate": "Szkic wiadomości", + "OutboundEmail": "Poczta Wychodząca", + "ScheduledJob": "Automatyczne działanie" + }, + "scopeNamesPlural": { + "Email": "Emails", + "User": "Użytkownik", + "Team": "Zespoły", + "Role": "Rola", + "EmailTemplate": "Szkice Wiadomości", + "OutboundEmail": "Poczta Wychodząca", + "ScheduledJob": "Zaplanowane działanie" + }, + "labels": { + "Misc": "Misc", + "Merge": "Merge", + "None": "None", + "by": "przez", + "Saved": "Zapisane", + "Error": "Błąd", + "Select": "Wybierz", + "Not valid": "Nie poprawnie", + "Please wait...": "Proszę Czekać...", + "Please wait": "Proszę Czekać", + "Loading...": "Ładuje...", + "Uploading...": "Wgrywam na serwer...", + "Sending...": "Wysyłam...", + "Removed": "Usunięty", + "Posted": "Opublikowany", + "Linked": "Linked", + "Unlinked": "Unlinked", + "Access denied": "Dostęp zabroniony", + "Access": "Dostęp", + "Are you sure?": "Are you sure?", + "Record has been removed": "Rekord został usunięty", + "Wrong username/password": "Zła nazwa użytkonika/hasło", + "Post cannot be empty": "Notatka nie może byc pusta", + "Removing...": "Usuwam...", + "Unlinking...": "Unlinking...", + "Posting...": "Nadaje...", + "Username can not be empty!": "Nazwa użytkownika nie może byc pusta!", + "Cache is not enabled": "Pamięć podręczna jest nie dostępna", + "Cache has been cleared": "Pamięć podręczna została wyczyszczona", + "Rebuild has been done": "Przebudowanie zostało zakończone", + "Saving...": "Zapisuje...", + "Modified": "Zmieniony", + "Created": "Utworzony", + "Create": "Utwórz", + "create": "utwórz", + "Overview": "Podgląd", + "Details": "Detale", + "Add Filter": "Dodaj Filtr", + "Add Dashlet": "Dodaj Podgląd", + "Add": "Dodaj", + "Reset": "Reset", + "Menu": "Menu", + "More": "Więcej", + "Search": "Szukaj", + "Only My": "Tylko Moje", + "Open": "Otwórz", + "Admin": "Admin", + "About": "O", + "Refresh": "Odśwież", + "Remove": "Usuń", + "Options": "Opcje", + "Username": "Użytkownik", + "Password": "Hasło", + "Login": "Login", + "Log Out": "Wyloguj się", + "Preferences": "Preferencje", + "State": "Województwo", + "Street": "Ulica", + "Country": "Kraj", + "City": "Miasto", + "PostalCode": "Kod Pocztowy", + "Followed": "Śledzony", + "Follow": "Śledź", + "Clear Local Cache": "Wyczyść Pamięć Podręczną", + "Actions": "Akcja", + "Delete": "Usuń", + "Update": "Aktualizuj", + "Save": "Zapisz", + "Edit": "Edytuj", + "Cancel": "Anuluj", + "Unlink": "Unlink", + "Mass Update": "Masowa Akrualizacja", + "Export": "Eksportuj", + "No Data": "Brak Danych", + "All": "Wszystko", + "Active": "Aktywny", + "Inactive": "Nie Aktywny", + "Write your comment here": "Dodaj swój komentarz tutaj", + "Post": "Opublikuj", + "Stream": "Komunikator", + "Show more": "Pokaż Więcej", + "Dashlet Options": "Opcje Podglądu", + "Full Form": "Pełen Formularz", + "Insert": "Wstaw", + "Person": "Osoba", + "First Name": "Imię", + "Last Name": "Nazwisko", + "Original": "Originalny", + "You": "Ty", + "you": "ty", + "change": "zmień", + "Primary": "Główny", + "Save Filters": "Zapisz filtry wyszukiwania", + "Administration": "Administracja", + "Run Import": "Uruchom Importowanie", + "Duplicate": "Powielony", + "Notifications": "powiadomienia", + "Mark all read": "Oznacz wszystko jako przeczytane", + "See more": "Zobacz więcej" + }, + "messages": { + "notModified": "Nie zmodyfikowałeś żadnych danych", + "duplicate": "Dane które wprowadziłeś wyglądają na powielone", + "fieldIsRequired": "{field} wymagane", + "fieldShouldBeEmail": "{field} wprowadź poprawny adres e-mail", + "fieldShouldBeFloat": "{field} powinno być poprawnie wyjustowane", + "fieldShouldBeInt": "{field} powinno być poprawną liczbą całkowitą", + "fieldShouldBeDate": "{field} powinno być poprawną datą", + "fieldShouldBeDatetime": "{field} powinno być poprawną datą/czasem", + "fieldShouldAfter": "{field} powinno być po {otherField}", + "fieldShouldBefore": "{field} powinno być po {otherField}", + "fieldShouldBeBetween": "{field} powinno być między {min} i {max}", + "fieldShouldBeLess": "{field} powinno być mniejsze niż {value}", + "fieldShouldBeGreater": "{field} powinno być większe niż {value}", + "fieldBadPasswordConfirm": "{field} błędnie potwierdzony", + "assignmentEmailNotificationSubject": "EspoCRM {entityType}: {Entity.name}", + "assignmentEmailNotificationBody": "{assignerUserName} został przypisany {entityType} '{Entity.name}' do Ciebie\n\n{recordUrl}", + "confirmation": "Are you sure?", + "removeRecordConfirmation": "Are you sure you want to remove the record?", + "unlinkRecordConfirmation": "Are you sure you want to unlink relationship?", + "removeSelectedRecordsConfirmation": "Are you sure you want to remove selected records?" + }, + "boolFilters": { + "onlyMy": "Tylko Moje", + "open": "Otwórz", + "active": "Aktywny" + }, + "fields": { + "name": "Imię", + "firstName": "Imię", + "lastName": "Nazwisko", + "salutationName": "Zwrot", + "assignedUser": "Przypisany użytkownik", + "emailAddress": "E-mail", + "assignedUserName": "Przypisana Nazwa Użytkownika", + "teams": "Zespoły", + "createdAt": "Utworzony do", + "modifiedAt": "Zmodyfikowany do", + "createdBy": "Utworzony przez", + "modifiedBy": "Zmodyfikowany przez", + "title": "Tytuł", + "dateFrom": "Data Od", + "dateTo": "Data Do", + "autorefreshInterval": "Odświeżanie co", + "displayRecords": "Wyświetlane Dane" + }, + "links": { + "teams": "Zespoły", + "users": "Użytkownik" + }, + "dashlets": { + "Stream": "Komunikator" + }, + "streamMessages": { + "create": "{user} utworzony {entityType} {entity}", + "createAssigned": "{user} utworzony {entityType} {entity} assigned to {assignee}", + "assign": "{user} przypisany {entityType} {entity} to {assignee}", + "post": "{user} opublikował {entityType} {entity}", + "attach": "{user} załączył {entityType} {entity}", + "status": "{user} zaaktualizował {field} on {entityType} {entity}", + "update": "{user} zaaktualizował {entityType} {entity}", + "createRelated": "{user} created {relatedEntityType} {relatedEntity} linked to {entityType} {entity}", + "emailReceived": "{entity} został otrzymane dla {entityType} {entity}", + + "createThis": "{user} utwórz to {entityType}", + "createAssignedThis": "{user} utwórz to {entityType} assigned to {assignee}", + "assignThis": "{user} przypisz to {entityType} to {assignee}", + "postThis": "{user} opublikował", + "attachThis": "{user} załączył", + "statusThis": "{user} zaaktualizował {field}", + "updateThis": "{user} aktualizuj to {entityType}", + "createRelatedThis": "{user} created {relatedEntityType} {relatedEntity} linked to this {entityType}", + "emailReceivedThis": "{entity} has been received" + }, + "lists": { + "monthNames": ["Styczeń", "Luty", "Marzec", "Kwiecień", "Maj", "Czerwiec", "Lipiec", "Sierpień", "Wrzesień", "Październik", "Listopad", "Grudzień"], + "monthNamesShort": ["Sty", "Lut", "Mar", "Kwi", "Maj", "Czer", "Lip", "Sie", "Wrze", "Paź", "Lis", "Gru"], + "dayNames": ["Niedziela", "Poniedziałek", "Wtorek", "Środa", "Czwartek", "Piątek", "Sobota"], + "dayNamesShort": ["Ndz", "Pon", "Wto", "Śro", "Czwa", "Pią", "Sob"], + "dayNamesMin": ["Nd", "Pn", "Wt", "Śr", "Czw", "Pi", "So"] + }, + "options": { + "salutationName": { + "Mr.": "Pan.", + "Mrs.": "Pani.", + "Dr.": "Dr.", + "Drs.": "Drs." + }, + "language": { + "af_ZA": "Afrikaans", + "az_AZ": "Azerbaijani", + "be_BY": "Belarusian", + "bg_BG": "Bulgarian", + "bn_IN": "Bengali", + "bs_BA": "Bosnian", + "ca_ES": "Catalan", + "cs_CZ": "Czech", + "cy_GB": "Welsh", + "da_DK": "Danish", + "de_DE": "German", + "el_GR": "Greek", + "en_GB":"English (UK)", + "en_US":"English (US)", + "es_ES":"Spanish (Spain)", + "et_EE": "Estonian", + "eu_ES": "Basque", + "fa_IR": "Persian", + "fi_FI": "Finnish", + "fo_FO": "Faroese", + "fr_CA":"French (Canada)", + "fr_FR":"French (France)", + "ga_IE": "Irish", + "gl_ES": "Galician", + "gn_PY": "Guarani", + "he_IL": "Hebrew", + "hi_IN": "Hindi", + "hr_HR": "Croatian", + "hu_HU": "Hungarian", + "hy_AM": "Armenian", + "id_ID": "Indonesian", + "is_IS": "Icelandic", + "it_IT": "Italian", + "ja_JP": "Japanese", + "ka_GE": "Georgian", + "km_KH": "Khmer", + "ko_KR": "Korean", + "ku_TR": "Kurdish", + "lt_LT": "Lithuanian", + "lv_LV": "Latvian", + "mk_MK": "Macedonian", + "ml_IN": "Malayalam", + "ms_MY": "Malay", + "nb_NO": "Norwegian Bokmål", + "nn_NO": "Norwegian Nynorsk", + "ne_NP": "Nepali", + "nl_NL": "Dutch", + "pa_IN": "Punjabi", + "pl_PL": "Polski", + "ps_AF": "Pashto", + "pt_BR":"Portuguese (Brazil)", + "pt_PT":"Portuguese (Portugal)", + "ro_RO": "Romanian", + "ru_RU": "Russian", + "sk_SK": "Slovak", + "sl_SI": "Slovene", + "sq_AL": "Albanian", + "sr_RS": "Serbian", + "sv_SE": "Swedish", + "sw_KE": "Swahili", + "ta_IN": "Tamil", + "te_IN": "Telugu", + "th_TH": "Thai", + "tl_PH": "Tagalog", + "tr_TR": "Turkish", + "uk_UA": "Ukrainian", + "ur_PK": "Urdu", + "vi_VN": "Vietnamese", + "zh_CN":"Simplified Chinese (China)", + "zh_HK":"Traditional Chinese (Hong Kong)", + "zh_TW":"Traditional Chinese (Taiwan)" + }, + "dateSearchRanges": { + "on": "Włączony", + "notOn": "Nie Włączony", + "after": "Po", + "before": "Przed", + "between": "Między", + "today": "Dziś", + "past": "Przeszłość", + "future": "Przyszłość" + }, + "intSearchRanges": { + "equals": "Równy", + "notEquals": "Nie Równy", + "greaterThan": "Większy Niż", + "lessThan": "Mniejszy Niż", + "greaterThanOrEquals": "Większy lub Równy", + "lessThanOrEquals": "Mniejszy lub Równy", + "between": "Między" + }, + "autorefreshInterval": { + "0": "None", + "0.5": "30 sekund", + "1": "1 minuta", + "2": "2 minuty", + "5": "5 minut", + "10": "10 minut" + }, + "phoneNumber": { + "Mobile": "Komórka", + "Office": "Biuro", + "Fax": "Faks", + "Home": "Domowy", + "Other": "Inny" + } + }, + "sets": { + "summernote": { + "NOTICE": "Możesz znaleść tłumaczenie tutaj: https://github.com/HackerWins/summernote/tree/master/lang", + "font":{ + "bold": "Pogrubiony", + "italic": "Pochylenie", + "underline": "Podkreślenie", + "strike": "Przekreślnie", + "clear": "Usunięto formatowanie tekstu", + "height": "Szerokość Lini", + "name": "Czcionka", + "size": "Rozmiar Czcionki" + }, + "image":{ + "image": "Obraz", + "insert": "Dodaj Obraz", + "resizeFull": "Przeskaluj na pełny rozmiar", + "resizeHalf": "Przeszkaluj na połowę rozmiaru", + "resizeQuarter": "Przeskaluj do 1/4 rozmiaru", + "floatLeft": "Równaj do lewej", + "floatRight": "Równaj do prawej", + "floatNone": "Nie zmieniaj ", + "dragImageHere": "Upuść obraz tutaj", + "selectFromFiles": "Wybierz plik z dysku", + "url": "Adres do Obrazu", + "remove": "Usuń Obraz" + }, + "link":{ + "link":"Link", + "insert":"Insert Link", + "unlink":"Unlink", + "edit": "Edytuj", + "textToDisplay": "Tekst do wyświetlenia", + "url":"To what URL should this link go?", + "openInNewWindow": "Otwórz w nowym oknie" + }, + "video":{ + "video": "Video", + "videoLink":"Video Link", + "insert": "Wstaw Video", + "url":"Video URL?", + "providers":"(YouTube, Vimeo, Vine, Instagram, or DailyMotion)" + }, + "table":{ + "table": "Tabela" + }, + "hr":{ + "insert": "Wstaw Linię Poziomą" + }, + "style":{ + "style": "Styl", + "normal": "Normalny", + "blockquote": "Cytat", + "pre": "Code", + "h1": "Nagłówek 1", + "h2": "Nagłówek 2", + "h3": "Nagłówek 3", + "h4": "Nagłówek 4", + "h5": "Nagłówek 5", + "h6": "Nagłówek 6" + }, + "lists":{ + "unordered": "Niewypunktowana lista", + "ordered": "Wypunktowana lista" + }, + "options":{ + "help": "Pomoc", + "fullscreen": "Pełny Ekran", + "codeview": "Źródło" + }, + "paragraph":{ + "paragraph": "Akapit", + "outdent": "Zmniejsz wcięcie", + "indent": "Zwiększ wcięcie", + "left": "Wyrównaj do lewej", + "center": "Wyrównaj do środka", + "right": "Wyrównaj do prawej", + "justify": "Wyrównaj do lewej i prawej" + }, + "color":{ + "recent": "Ostatni Kolor", + "more": "Więcej Kolorów", + "background": "Kolor Tła", + "foreground": "Kolor Czcionki", + "transparent": "Przeźroczystość", + "setTransparent": "Ustwa przeźroczystość", + "reset": "Reset", + "resetToDefault": "Domyślnie" + }, + "shortcut":{ + "shortcuts": "Skróty klawiaturowe", + "close": "Zamknij", + "textFormatting": "Formatowanie tekstu", + "action": "Akcja", + "paragraphFormatting": "Formatowanie akapitu", + "documentStyle": "Style dokumentu" + }, + "history":{ + "undo": "Cofnij", + "redo":"Redo" + } + } + } } diff --git a/application/Espo/Resources/i18n/pl_PL/Note.json b/application/Espo/Resources/i18n/pl_PL/Note.json index 32c9f7a84c..f191707a62 100644 --- a/application/Espo/Resources/i18n/pl_PL/Note.json +++ b/application/Espo/Resources/i18n/pl_PL/Note.json @@ -1,6 +1,6 @@ { - "fields": { - "post": "Opublikuj", - "attachments": "Załącznik" - } + "fields": { + "post": "Opublikuj", + "attachments": "Załącznik" + } } diff --git a/application/Espo/Resources/i18n/pl_PL/Preferences.json b/application/Espo/Resources/i18n/pl_PL/Preferences.json index 3b740dbd8f..68621dab42 100644 --- a/application/Espo/Resources/i18n/pl_PL/Preferences.json +++ b/application/Espo/Resources/i18n/pl_PL/Preferences.json @@ -1,37 +1,37 @@ { - "fields": { - "dateFormat": "Format Daty", - "timeFormat": "Format Czasu", - "timeZone": "Strefa Czasowa", - "weekStart": "Pierwszy dzień tygodnia", - "thousandSeparator": "Separator Dziesiętny", - "decimalMark": "Znak rozdzielenia", - "defaultCurrency": "Domyślna Waluta", - "currencyList": "Domyślana Lista", - "language": "Język", - - "smtpServer": "Server", - "smtpPort": "Port", - "smtpAuth": "Auth", - "smtpSecurity": "Zabezpieczenia", - "smtpUsername": "Użytkownik", - "emailAddress": "E-mail", - "smtpPassword": "Hasło", - "smtpEmailAddress": "E-mail Adres", - - "exportDelimiter": "Znak rodzielenia eksportu", - - "receiveAssignmentEmailNotifications": "Otrzymać informację w trakcie jej przypisywania" - }, - "links": { - }, - "options": { - "weekStart": { - "0": "Niedziela", - "1": "Poniedziałek" - } - }, - "labels": { - "Notifications": "powiadomienia" - } + "fields": { + "dateFormat": "Format Daty", + "timeFormat": "Format Czasu", + "timeZone": "Strefa Czasowa", + "weekStart": "Pierwszy dzień tygodnia", + "thousandSeparator": "Separator Dziesiętny", + "decimalMark": "Znak rozdzielenia", + "defaultCurrency": "Domyślna Waluta", + "currencyList": "Domyślana Lista", + "language": "Język", + + "smtpServer": "Server", + "smtpPort": "Port", + "smtpAuth": "Auth", + "smtpSecurity": "Zabezpieczenia", + "smtpUsername": "Użytkownik", + "emailAddress": "E-mail", + "smtpPassword": "Hasło", + "smtpEmailAddress": "E-mail Adres", + + "exportDelimiter": "Znak rodzielenia eksportu", + + "receiveAssignmentEmailNotifications": "Otrzymać informację w trakcie jej przypisywania" + }, + "links": { + }, + "options": { + "weekStart": { + "0": "Niedziela", + "1": "Poniedziałek" + } + }, + "labels": { + "Notifications": "powiadomienia" + } } diff --git a/application/Espo/Resources/i18n/pl_PL/Role.json b/application/Espo/Resources/i18n/pl_PL/Role.json index 5d9aa70c75..bc78bedb6a 100644 --- a/application/Espo/Resources/i18n/pl_PL/Role.json +++ b/application/Espo/Resources/i18n/pl_PL/Role.json @@ -1,35 +1,35 @@ { - "fields": { - "name": "Imię", - "roles": "Rola" - }, - "links": { - "users": "Użytkownik", - "teams": "Zespoły" - }, - "labels": { - "Access": "Dostęp", - "Create Role": "Utwórz Role " - }, - "options": { - "accessList": { - "not-set": "nie ustawiony", - "enabled": "włączony", - "disabled": "wyłączony" - }, - "levelList": { - "all": "wszystko", - "team": "zespół", - "own": "własny", - "no": "nie" - } - }, - "actions": { - "read": "Przeczytany", - "edit": "Edytuj", - "delete": "Usuń" - }, - "messages": { - "changesAfterClearCache": "Wszystkie zmiany w dostępie zostaną aktywowany w momencie wyczyszczenia pamięci." - } + "fields": { + "name": "Imię", + "roles": "Rola" + }, + "links": { + "users": "Użytkownik", + "teams": "Zespoły" + }, + "labels": { + "Access": "Dostęp", + "Create Role": "Utwórz Role " + }, + "options": { + "accessList": { + "not-set": "nie ustawiony", + "enabled": "włączony", + "disabled": "wyłączony" + }, + "levelList": { + "all": "wszystko", + "team": "zespół", + "own": "własny", + "no": "nie" + } + }, + "actions": { + "read": "Przeczytany", + "edit": "Edytuj", + "delete": "Usuń" + }, + "messages": { + "changesAfterClearCache": "Wszystkie zmiany w dostępie zostaną aktywowany w momencie wyczyszczenia pamięci." + } } diff --git a/application/Espo/Resources/i18n/pl_PL/ScheduledJob.json b/application/Espo/Resources/i18n/pl_PL/ScheduledJob.json index b6d5de63ba..5133cac088 100644 --- a/application/Espo/Resources/i18n/pl_PL/ScheduledJob.json +++ b/application/Espo/Resources/i18n/pl_PL/ScheduledJob.json @@ -1,30 +1,30 @@ { - "fields": { - "name": "Imię", - "status": "Status", - "job": "Zadanie", - "scheduling": "Scheduling (crontab notation)" - }, - "links": { - "log": "Log" - }, - "labels": { - "Create ScheduledJob": "Utwórz zaplanowane działania" - }, - "options": { - "job": { - "CheckInboundEmails": "Sprawdź pocztę przychodzącą", - "Cleanup": "Wyczyść" - }, - "cronSetup": { - "linux": "Uwaga: Dodaj tą linię do pliku crontab, aby uruchomić zaplanowane zadania Espo:", - "mac": "Uwaga: Dodaj tą linię do pliku crontab, aby uruchomić zaplanowane zadania Espo:", - "windows": "Uwaga: Utwórz plik wsadowy z następujących poleceń, aby uruchomić zaplanowane zadania Espo w systemie Windows:", - "default": "Note: Add this command to Cron Job (Scheduled Task):" - }, - "status": { - "Active": "Aktywny", - "Inactive": "Nie Aktywny" - } - } + "fields": { + "name": "Imię", + "status": "Status", + "job": "Zadanie", + "scheduling": "Scheduling (crontab notation)" + }, + "links": { + "log": "Log" + }, + "labels": { + "Create ScheduledJob": "Utwórz zaplanowane działania" + }, + "options": { + "job": { + "CheckInboundEmails": "Sprawdź pocztę przychodzącą", + "Cleanup": "Wyczyść" + }, + "cronSetup": { + "linux": "Uwaga: Dodaj tą linię do pliku crontab, aby uruchomić zaplanowane zadania Espo:", + "mac": "Uwaga: Dodaj tą linię do pliku crontab, aby uruchomić zaplanowane zadania Espo:", + "windows": "Uwaga: Utwórz plik wsadowy z następujących poleceń, aby uruchomić zaplanowane zadania Espo w systemie Windows:", + "default": "Note: Add this command to Cron Job (Scheduled Task):" + }, + "status": { + "Active": "Aktywny", + "Inactive": "Nie Aktywny" + } + } } diff --git a/application/Espo/Resources/i18n/pl_PL/ScheduledJobLogRecord.json b/application/Espo/Resources/i18n/pl_PL/ScheduledJobLogRecord.json index 3e7615b6aa..4c70a67ba3 100644 --- a/application/Espo/Resources/i18n/pl_PL/ScheduledJobLogRecord.json +++ b/application/Espo/Resources/i18n/pl_PL/ScheduledJobLogRecord.json @@ -1,6 +1,6 @@ { - "fields": { - "status": "Status", - "executionTime": "Czas realizacji" - } + "fields": { + "status": "Status", + "executionTime": "Czas realizacji" + } } diff --git a/application/Espo/Resources/i18n/pl_PL/Settings.json b/application/Espo/Resources/i18n/pl_PL/Settings.json index 8c8eeec22f..dc57ae874c 100644 --- a/application/Espo/Resources/i18n/pl_PL/Settings.json +++ b/application/Espo/Resources/i18n/pl_PL/Settings.json @@ -1,76 +1,75 @@ { - "fields": { - "useCache": "Użyj pamięci podręcznej", - "dateFormat": "Format Daty", - "timeFormat": "Format Czasu", - "timeZone": "Strefa Czasowa", - "weekStart": "Pierwszy dzień tygodnia", - "thousandSeparator": "Separator Dziesiętny", - "decimalMark": "Znak rozdzielenia", - "defaultCurrency": "Domyślna Waluta", - "baseCurrency": "Podstawowa Waluta", - "baseCurrency": "Podstawowa Waluta", - "currencyRates": "Kurs Waluty", - - "currencyList": "Domyślana Lista", - "language": "Język", - - "companyLogo": "Logo Firmowe", - - "smtpServer": "Server", - "smtpPort": "Port", - "smtpAuth": "Auth", - "smtpSecurity": "Zabezpieczenia", - "smtpUsername": "Użytkownik", - "emailAddress": "E-mail", - "smtpPassword": "Hasło", - "outboundEmailFromName": "Od", - "outboundEmailFromAddress": "Z adresu", - "outboundEmailIsShared": "Jest Udostępniane", - - "recordsPerPage": "Wyników na stronę", - "recordsPerPageSmall": "Records Per Page (Small)", - "tabList": "Lista ", - "quickCreateList": "Szybkie utworzenie listy", - - "exportDelimiter": "Znak rodzielenia eksportu", - - "authenticationMethod": "Metoda autentykcji", - "ldapHost": "Host", - "ldapPort": "Port", - "ldapAuth": "Auth", - "ldapUsername": "Użytkownik", - "ldapPassword": "Hasło", - "ldapBindRequiresDn": "Bind Requires Dn", - "ldapBaseDn": "Base Dn", - "ldapAccountCanonicalForm": "Account Canonical Form", - "ldapAccountDomainName": "Nazwa konta domeny", - "ldapTryUsernameSplit": "Spróbuj rodzielić nazwę użytkonika", - "ldapCreateEspoUser": "Utwórz uzytkonika w EspoCRM", - "ldapSecurity": "Zabezpieczenia", - "ldapUserLoginFilter": "Filtr użytkoników ", - "ldapAccountDomainNameShort": "Krótka nazwa konta domeny", - "ldapOptReferrals": "Opt Referrals", - "disableExport": "Disable Export (only admin is allowed)", - "assignmentEmailNotifications": "Wyślij powiadominie do użytkonika o przypisaniu", - "assignmentEmailNotificationsEntityList": "Entities to Notify About" - }, - "options": { - "weekStart": { - "0": "Niedziela", - "1": "Poniedziałek" - } - }, - "tooltips": { - "recordsPerPageSmall": "Policz wyniki w panelu relacji." - }, - "labels": { - "System": "System", - "Locale": "Lokalne", - "SMTP": "SMTP", - "Configuration": "Konfiguracja", - "Notifications": "powiadomienia", - "Currency Settings": "Ustwienia Waluty", - "Currency Rtes": "Ustawienia Kursu" - } + "fields": { + "useCache": "Użyj pamięci podręcznej", + "dateFormat": "Format Daty", + "timeFormat": "Format Czasu", + "timeZone": "Strefa Czasowa", + "weekStart": "Pierwszy dzień tygodnia", + "thousandSeparator": "Separator Dziesiętny", + "decimalMark": "Znak rozdzielenia", + "defaultCurrency": "Domyślna Waluta", + "baseCurrency": "Podstawowa Waluta", + "currencyRates": "Kurs Waluty", + + "currencyList": "Domyślana Lista", + "language": "Język", + + "companyLogo": "Logo Firmowe", + + "smtpServer": "Server", + "smtpPort": "Port", + "smtpAuth": "Auth", + "smtpSecurity": "Zabezpieczenia", + "smtpUsername": "Użytkownik", + "emailAddress": "E-mail", + "smtpPassword": "Hasło", + "outboundEmailFromName": "Od", + "outboundEmailFromAddress": "Z adresu", + "outboundEmailIsShared": "Jest Udostępniane", + + "recordsPerPage": "Wyników na stronę", + "recordsPerPageSmall": "Records Per Page (Small)", + "tabList": "Lista ", + "quickCreateList": "Szybkie utworzenie listy", + + "exportDelimiter": "Znak rodzielenia eksportu", + + "authenticationMethod": "Metoda autentykcji", + "ldapHost": "Host", + "ldapPort": "Port", + "ldapAuth": "Auth", + "ldapUsername": "Użytkownik", + "ldapPassword": "Hasło", + "ldapBindRequiresDn": "Bind Requires Dn", + "ldapBaseDn": "Base Dn", + "ldapAccountCanonicalForm": "Account Canonical Form", + "ldapAccountDomainName": "Nazwa konta domeny", + "ldapTryUsernameSplit": "Spróbuj rodzielić nazwę użytkonika", + "ldapCreateEspoUser": "Utwórz uzytkonika w EspoCRM", + "ldapSecurity": "Zabezpieczenia", + "ldapUserLoginFilter": "Filtr użytkoników ", + "ldapAccountDomainNameShort": "Krótka nazwa konta domeny", + "ldapOptReferrals": "Opt Referrals", + "disableExport": "Disable Export (only admin is allowed)", + "assignmentEmailNotifications": "Wyślij powiadominie do użytkonika o przypisaniu", + "assignmentEmailNotificationsEntityList": "Entities to Notify About" + }, + "options": { + "weekStart": { + "0": "Niedziela", + "1": "Poniedziałek" + } + }, + "tooltips": { + "recordsPerPageSmall": "Policz wyniki w panelu relacji." + }, + "labels": { + "System": "System", + "Locale": "Lokalne", + "SMTP": "SMTP", + "Configuration": "Konfiguracja", + "Notifications": "powiadomienia", + "Currency Settings": "Ustwienia Waluty", + "Currency Rtes": "Ustawienia Kursu" + } } diff --git a/application/Espo/Resources/i18n/pl_PL/Team.json b/application/Espo/Resources/i18n/pl_PL/Team.json index 95a14c1b93..a78d7e2860 100644 --- a/application/Espo/Resources/i18n/pl_PL/Team.json +++ b/application/Espo/Resources/i18n/pl_PL/Team.json @@ -1,15 +1,15 @@ { - "fields": { - "name": "Imię", - "roles": "Rola" - }, - "links": { - "users": "Użytkownik" - }, - "tooltips": { - "roles": "Wszyscy użytkownicy z zespołu, otrzymają dostęp do ustawień zgodnie z rolami ." - }, - "labels": { - "Create Team": "Utwórz Zespół" - } + "fields": { + "name": "Imię", + "roles": "Rola" + }, + "links": { + "users": "Użytkownik" + }, + "tooltips": { + "roles": "Wszyscy użytkownicy z zespołu, otrzymają dostęp do ustawień zgodnie z rolami ." + }, + "labels": { + "Create Team": "Utwórz Zespół" + } } diff --git a/application/Espo/Resources/i18n/pl_PL/User.json b/application/Espo/Resources/i18n/pl_PL/User.json index 3cf8c157b0..6336847c2c 100644 --- a/application/Espo/Resources/i18n/pl_PL/User.json +++ b/application/Espo/Resources/i18n/pl_PL/User.json @@ -1,35 +1,35 @@ { - "fields": { - "name": "Imię", - "userName": "Nazwa Użytkownika", - "title": "Tytuł", - "isAdmin": "Czy jest Administratorem", - "defaultTeam": "Domyślny Zespół", - "emailAddress": "E-mail", - "phoneNumber": "Telefon", - "roles": "Rola", - "password": "Hasło", - "passwordConfirm": "Potwierdź Hasło", - "newPassword": "Nowe Hasło" - }, - "links": { - "teams": "Zespoły", - "roles": "Rola" - }, - "labels": { - "Create User": "Utwórz Użytkonika", - "Generate": "Generuj", - "Access": "Dostęp", - "Preferences": "Preferencje", - "Change Password": "Zmień hasło" - }, - "tooltips": { - "defaultTeam": "Wszytskie dane utworzone przez tego użytkonika, zostaną przypisane do domyślnego zespołu." - }, - "messages": { - "passwordWillBeSent": "Hasło zostanie wysłane na adres e-mail użytkonika.", - "accountInfoEmailSubject": "Informacje o koncie", - "accountInfoEmailBody": "Informacje o twoim koncie:\n\nUżytkonik: {userName}\nHasło: {password}\n\n{siteUrl}", - "passwordChanged": "Hasło zostało zmienione" - } + "fields": { + "name": "Imię", + "userName": "Nazwa Użytkownika", + "title": "Tytuł", + "isAdmin": "Czy jest Administratorem", + "defaultTeam": "Domyślny Zespół", + "emailAddress": "E-mail", + "phoneNumber": "Telefon", + "roles": "Rola", + "password": "Hasło", + "passwordConfirm": "Potwierdź Hasło", + "newPassword": "Nowe Hasło" + }, + "links": { + "teams": "Zespoły", + "roles": "Rola" + }, + "labels": { + "Create User": "Utwórz Użytkonika", + "Generate": "Generuj", + "Access": "Dostęp", + "Preferences": "Preferencje", + "Change Password": "Zmień hasło" + }, + "tooltips": { + "defaultTeam": "Wszytskie dane utworzone przez tego użytkonika, zostaną przypisane do domyślnego zespołu." + }, + "messages": { + "passwordWillBeSent": "Hasło zostanie wysłane na adres e-mail użytkonika.", + "accountInfoEmailSubject": "Informacje o koncie", + "accountInfoEmailBody": "Informacje o twoim koncie:\n\nUżytkonik: {userName}\nHasło: {password}\n\n{siteUrl}", + "passwordChanged": "Hasło zostało zmienione" + } } diff --git a/application/Espo/Resources/i18n/pt_BR/Admin.json b/application/Espo/Resources/i18n/pt_BR/Admin.json index d5908ba1cd..0d9ac88d66 100644 --- a/application/Espo/Resources/i18n/pt_BR/Admin.json +++ b/application/Espo/Resources/i18n/pt_BR/Admin.json @@ -9,8 +9,8 @@ "Customization": "Customização", "Available Fields": "Campos Disponíveis", "Layout": "Layout", - - + + "Add Panel": "Adicionar Painel", "Add Field": "Adicionar Campo", "Settings": "Preferências", @@ -18,7 +18,7 @@ "Upgrade": "Atualização", "Clear Cache": "Limpar Cache", "Rebuild": "Reconstruir", - + "Teams": "Times", "Roles": "Regras", "Outbound Emails": "E-mails de Saída", @@ -30,8 +30,8 @@ "User Interface": "Interface do Usuário", "Auth Tokens": "Tokens de Autenticação", "Authentication": "Autenticação", - "Currency": "Moeda", - "Integrations": "Integrações" + "Currency": "Moeda", + "Integrations": "Integrações" }, "layouts": { "list": "Lista", @@ -78,7 +78,7 @@ "required": "Obrigatório", "default": "Padrão", "maxLength": "Tamanho máximo", - "options": "Opções (valores raw, não traduzíveis)", + "options": "Opções", "after": "Antes (field)", "before": "Após (field)", "link": "Link", @@ -116,7 +116,7 @@ "userInterface": "Configurar UI.", "authTokens": "Sessões autenticadas ativas. Endereço de IP e última data de acesso.", "authentication": "Configurações de autenticação.", - "currency": "Configurações de moeda e taxas." + "currency": "Configurações de moeda e taxas." }, "options": { "previewSize": { diff --git a/application/Espo/Resources/i18n/pt_BR/AuthToken.json b/application/Espo/Resources/i18n/pt_BR/AuthToken.json index 9ac0742ce3..1e7c1ed311 100644 --- a/application/Espo/Resources/i18n/pt_BR/AuthToken.json +++ b/application/Espo/Resources/i18n/pt_BR/AuthToken.json @@ -1,9 +1,9 @@ { - "fields": { - "user": "Usuário", - "ipAddress": "Endereço de IP", - "lastAccess": "Último acesso", - "createdAt": "Data do login" + "fields": { + "user": "Usuário", + "ipAddress": "Endereço de IP", + "lastAccess": "Último acesso", + "createdAt": "Data do login" - } + } } diff --git a/application/Espo/Resources/i18n/pt_BR/Email.json b/application/Espo/Resources/i18n/pt_BR/Email.json index 8597139b6a..5a9f5df269 100644 --- a/application/Espo/Resources/i18n/pt_BR/Email.json +++ b/application/Espo/Resources/i18n/pt_BR/Email.json @@ -1,44 +1,44 @@ { - "fields": { - "name": "Assunto", - "parent": "Origem", - "status": "Status", - "dateSent": "Data do envio", - "from": "De", - "to": "Para", - "cc": "CC", - "bcc": "BCC", - "isHtml": "Html", - "body": "Corpo", - "subject": "Assunto", - "attachments": "Anexos", - "selectTemplate": "Escolher Template", - "fromEmailAddress": "E-mail do rementente", - "toEmailAddresses": "E-mail do destinatário", - "emailAddress": "Endereço de E-mail", - "deliveryDate": "Data de envio" - }, - "links": { - }, - "options": { - "Draft": "Rascunho", - "Sending": "Enviando", - "Sent": "Enviado", - "Archived": "Arquivado" - }, - "labels": { - "Create Email": "Criar e-mail", - "Archive Email": "Arquivar e-mail", - "Compose": "Compor", - "Reply": "Responder", - "Reply to All": "Responder a Todos", - "Forward": "Encaminhar", - "Original message": "Mensagem original", - "Forwarded message": "Mensagem encaminhada", - "Email Accounts": "Contas de e-mail" - }, - "presetFilters": { - "sent": "Enviado", - "archived": "Arquivado" - } + "fields": { + "name": "Assunto", + "parent": "Origem", + "status": "Status", + "dateSent": "Data do envio", + "from": "De", + "to": "Para", + "cc": "CC", + "bcc": "BCC", + "isHtml": "Html", + "body": "Corpo", + "subject": "Assunto", + "attachments": "Anexos", + "selectTemplate": "Escolher Template", + "fromEmailAddress": "E-mail do rementente", + "toEmailAddresses": "E-mail do destinatário", + "emailAddress": "Endereço de E-mail", + "deliveryDate": "Data de envio" + }, + "links": { + }, + "options": { + "Draft": "Rascunho", + "Sending": "Enviando", + "Sent": "Enviado", + "Archived": "Arquivado" + }, + "labels": { + "Create Email": "Criar e-mail", + "Archive Email": "Arquivar e-mail", + "Compose": "Compor", + "Reply": "Responder", + "Reply to All": "Responder a Todos", + "Forward": "Encaminhar", + "Original message": "Mensagem original", + "Forwarded message": "Mensagem encaminhada", + "Email Accounts": "Contas de e-mail" + }, + "presetFilters": { + "sent": "Enviado", + "archived": "Arquivado" + } } diff --git a/application/Espo/Resources/i18n/pt_BR/EmailAccount.json b/application/Espo/Resources/i18n/pt_BR/EmailAccount.json index ae036851c7..d23674832f 100644 --- a/application/Espo/Resources/i18n/pt_BR/EmailAccount.json +++ b/application/Espo/Resources/i18n/pt_BR/EmailAccount.json @@ -1,29 +1,29 @@ { - "fields": { - "name": "Nome", - "status": "Status", - "host": "Host", - "username": "Usuário", - "password": "Senha", - "port": "Porta", - "monitoredFolders": "Pastas monitoradas", - "ssl": "SSL", - "fetchSince": "Buscar desde" - }, - "links": { - }, - "options": { - "status": { - "Active": "Ativa", - "Inactive": "Inativa" - } - }, - "labels": { - "Create EmailAccount": "Criar conta de e-mail", - "IMAP": "IMAP", - "Main": "Principal" - }, - "messages": { - "couldNotConnectToImap": "Não foi possível conectar ao servidor IMAP" - } + "fields": { + "name": "Nome", + "status": "Status", + "host": "Host", + "username": "Usuário", + "password": "Senha", + "port": "Porta", + "monitoredFolders": "Pastas monitoradas", + "ssl": "SSL", + "fetchSince": "Buscar desde" + }, + "links": { + }, + "options": { + "status": { + "Active": "Ativa", + "Inactive": "Inativa" + } + }, + "labels": { + "Create EmailAccount": "Criar conta de e-mail", + "IMAP": "IMAP", + "Main": "Principal" + }, + "messages": { + "couldNotConnectToImap": "Não foi possível conectar ao servidor IMAP" + } } diff --git a/application/Espo/Resources/i18n/pt_BR/EmailAddress.json b/application/Espo/Resources/i18n/pt_BR/EmailAddress.json index 58582e9f51..5740e88684 100644 --- a/application/Espo/Resources/i18n/pt_BR/EmailAddress.json +++ b/application/Espo/Resources/i18n/pt_BR/EmailAddress.json @@ -1,7 +1,7 @@ { - "labels": { - "Primary": "Primário", - "Opted Out": "Cancelou (opt-out)", - "Invalid": "Inválido" - } + "labels": { + "Primary": "Primário", + "Opted Out": "Cancelou (opt-out)", + "Invalid": "Inválido" + } } diff --git a/application/Espo/Resources/i18n/pt_BR/ExternalAccount.json b/application/Espo/Resources/i18n/pt_BR/ExternalAccount.json index b62b91cd3a..b9517ef54e 100644 --- a/application/Espo/Resources/i18n/pt_BR/ExternalAccount.json +++ b/application/Espo/Resources/i18n/pt_BR/ExternalAccount.json @@ -1,7 +1,7 @@ { - "labels": { - "Connect": "Conectar" - }, - "help": { - } + "labels": { + "Connect": "Conectar" + }, + "help": { + } } diff --git a/application/Espo/Resources/i18n/pt_BR/Global.json b/application/Espo/Resources/i18n/pt_BR/Global.json index 8f00fc4e34..bf3e171b6b 100644 --- a/application/Espo/Resources/i18n/pt_BR/Global.json +++ b/application/Espo/Resources/i18n/pt_BR/Global.json @@ -5,10 +5,10 @@ "Team": "Time", "Role": "Regra", "EmailTemplate": "Template de E-mail", - "EmailAccount": "Conta de e-mail", + "EmailAccount": "Conta de e-mail", "OutboundEmail": "E-mail de Saída", "ScheduledJob": "Tarefa Agendada", - "ExternalAccount": "Conta externa" + "ExternalAccount": "Conta externa" }, "scopeNamesPlural": { "Email": "E-mails", @@ -16,10 +16,10 @@ "Team": "Times", "Role": "Regras", "EmailTemplate": "Templates de E-mail", - "EmailAccount": "Contas de e-mail", + "EmailAccount": "Contas de e-mail", "OutboundEmail": "E-mails de Saída", "ScheduledJob": "Tarefas Agendadas", - "ExternalAccount": "Contas externas" + "ExternalAccount": "Contas externas" }, "labels": { "Misc": "Misc", @@ -114,13 +114,13 @@ "you": "você", "change": "modificar", "Primary": "Primário", - "Save Filters": "Salvar Filtros", - "Administration": "Administração", - "Run Import": "Executar Importação", - "Duplicate": "Duplicar", - "Notifications": "Notificações", - "Mark all read": "Marcar tudo como lido", - "See more": "Ver mais" + "Save Filters": "Salvar Filtros", + "Administration": "Administração", + "Run Import": "Executar Importação", + "Duplicate": "Duplicar", + "Notifications": "Notificações", + "Mark all read": "Marcar tudo como lido", + "See more": "Ver mais" }, "messages": { "notModified": "Você não modificou o registro", @@ -137,12 +137,12 @@ "fieldShouldBeLess": "{field} deve ser menos que {value}", "fieldShouldBeGreater": "{field} deve ser maior que {value}", "fieldBadPasswordConfirm": "{field} confirmado impropriamente", - "assignmentEmailNotificationSubject": "EspoCRM {entityType}: {Entity.name}", - "assignmentEmailNotificationBody": "{assignerUserName} designou {entityType} '{Entity.name}' para você\n\n{recordUrl}", - "confirmation": "Você tem certeza?", - "removeRecordConfirmation": "Você gostaria mesmo de remover este registro?", - "unlinkRecordConfirmation": "Você gostaria mesmo de desfazer este relacionamento?", - "removeSelectedRecordsConfirmation": "Você gostaria mesmo de remover os registros selecionados?" + "assignmentEmailNotificationSubject": "EspoCRM {entityType}: {Entity.name}", + "assignmentEmailNotificationBody": "{assignerUserName} designou {entityType} '{Entity.name}' para você\n\n{recordUrl}", + "confirmation": "Você tem certeza?", + "removeRecordConfirmation": "Você gostaria mesmo de remover este registro?", + "unlinkRecordConfirmation": "Você gostaria mesmo de desfazer este relacionamento?", + "removeSelectedRecordsConfirmation": "Você gostaria mesmo de remover os registros selecionados?" }, "boolFilters": { "onlyMy": "Meus", @@ -289,9 +289,9 @@ "after": "Anterior", "before": "Posterior", "between": "Entre", - "today": "Hoje", - "past": "Passado", - "future": "Futuro" + "today": "Hoje", + "past": "Passado", + "future": "Futuro" }, "intSearchRanges": { "equals": "Igual", @@ -310,13 +310,13 @@ "5": "5 minutos", "10": "10 minutos" }, - "phoneNumber": { - "Mobile": "Celular", - "Office": "Escritório", - "Fax": "Fax", - "Home": "Residencial", - "Other": "Outro" - } + "phoneNumber": { + "Mobile": "Celular", + "Office": "Escritório", + "Fax": "Fax", + "Home": "Residencial", + "Other": "Outro" + } }, "sets": { "summernote": { diff --git a/application/Espo/Resources/i18n/pt_BR/Integration.json b/application/Espo/Resources/i18n/pt_BR/Integration.json index 821b4bf8a0..5ff1fd9f3f 100644 --- a/application/Espo/Resources/i18n/pt_BR/Integration.json +++ b/application/Espo/Resources/i18n/pt_BR/Integration.json @@ -1,14 +1,14 @@ { - "fields": { - "enabled": "Habilitado", - "clientId": "Client ID", - "clientSecret": "Client Secret", - "redirectUri": "URL de Redirecionamento" - }, - "messages": { - "selectIntegration": "Selecione uma integração no menu." - }, - "help": { - "Google": "

Obtenha as credenciais OAuth 2.0 do Google Developers Console.

Visite o Google Developers Console para obter as credenciais OAuth 2.0 como Client ID e Client Secret comuns ao Google e ao EspoCRM.

" - } + "fields": { + "enabled": "Habilitado", + "clientId": "Client ID", + "clientSecret": "Client Secret", + "redirectUri": "URL de Redirecionamento" + }, + "messages": { + "selectIntegration": "Selecione uma integração no menu." + }, + "help": { + "Google": "

Obtenha as credenciais OAuth 2.0 do Google Developers Console.

Visite o Google Developers Console para obter as credenciais OAuth 2.0 como Client ID e Client Secret comuns ao Google e ao EspoCRM.

" + } } diff --git a/application/Espo/Resources/i18n/pt_BR/Preferences.json b/application/Espo/Resources/i18n/pt_BR/Preferences.json index 384afd6292..8b22a33865 100644 --- a/application/Espo/Resources/i18n/pt_BR/Preferences.json +++ b/application/Espo/Resources/i18n/pt_BR/Preferences.json @@ -20,8 +20,8 @@ "smtpEmailAddress": "Endereço de E-mail", "exportDelimiter": "Delimitador de Exportação", - - "receiveAssignmentEmailNotifications": "Receber e-mail de notificação quando designado" + + "receiveAssignmentEmailNotifications": "Receber e-mail de notificação quando designado" }, "links": { }, @@ -31,7 +31,7 @@ "1": "Segunda" } }, - "labels": { - "Notifications": "Notificações" - } + "labels": { + "Notifications": "Notificações" + } } diff --git a/application/Espo/Resources/i18n/pt_BR/Role.json b/application/Espo/Resources/i18n/pt_BR/Role.json index 49fd2c2f78..08c5aefe2b 100644 --- a/application/Espo/Resources/i18n/pt_BR/Role.json +++ b/application/Espo/Resources/i18n/pt_BR/Role.json @@ -29,7 +29,7 @@ "edit": "Editar", "delete": "Excluir" }, - "messages": { - "changesAfterClearCache": "Todas as modificações no controle de acesso serão aplicadas após a limpeza do cache." - } + "messages": { + "changesAfterClearCache": "Todas as modificações no controle de acesso serão aplicadas após a limpeza do cache." + } } diff --git a/application/Espo/Resources/i18n/pt_BR/Settings.json b/application/Espo/Resources/i18n/pt_BR/Settings.json index 467a291612..a932f56193 100644 --- a/application/Espo/Resources/i18n/pt_BR/Settings.json +++ b/application/Espo/Resources/i18n/pt_BR/Settings.json @@ -8,10 +8,10 @@ "thousandSeparator": "Separador de Milhar", "decimalMark": "Deparador Decimal", "defaultCurrency": "Moeda Padrão", - "baseCurrency": "Moeda Base", - - "currencyRates": "Conversão de Moedas", - + "baseCurrency": "Moeda Base", + + "currencyRates": "Conversão de Moedas", + "currencyList": "Moedas Disponíveis", "language": "Idioma", @@ -34,26 +34,26 @@ "quickCreateList": "Lista de Criação Rápida", "exportDelimiter": "Delimitador de exportação", - - "authenticationMethod": "Método de Autenticação", - "ldapHost": "Host", - "ldapPort": "Porta", - "ldapAuth": "Auth", - "ldapUsername": "Usuário", - "ldapPassword": "Senha", - "ldapBindRequiresDn": "Ligação exige Dn", - "ldapBaseDn": "Dn Base", - "ldapAccountCanonicalForm": "Formulário Canônico de Conta", - "ldapAccountDomainName": "Nome de Domínio da Conta", - "ldapTryUsernameSplit": "Tentar dividir o Nome de Usuário", - "ldapCreateEspoUser": "Criar usuário no EspoCRM", - "ldapSecurity": "Segurança", - "ldapUserLoginFilter": "Filtro para Login de Usuário", - "ldapAccountDomainNameShort": "Nome curto do Domínio da Conta", - "ldapOptReferrals": "Referências Opt", - "disableExport": "Desabilitar exportação (permitido apenas para administradores)", - "assignmentEmailNotifications": "Enviar notificações sobre as designações por e-mail", - "assignmentEmailNotificationsEntityList": "Entidades para notificar" + + "authenticationMethod": "Método de Autenticação", + "ldapHost": "Host", + "ldapPort": "Porta", + "ldapAuth": "Auth", + "ldapUsername": "Usuário", + "ldapPassword": "Senha", + "ldapBindRequiresDn": "Ligação exige Dn", + "ldapBaseDn": "Dn Base", + "ldapAccountCanonicalForm": "Formulário Canônico de Conta", + "ldapAccountDomainName": "Nome de Domínio da Conta", + "ldapTryUsernameSplit": "Tentar dividir o Nome de Usuário", + "ldapCreateEspoUser": "Criar usuário no EspoCRM", + "ldapSecurity": "Segurança", + "ldapUserLoginFilter": "Filtro para Login de Usuário", + "ldapAccountDomainNameShort": "Nome curto do Domínio da Conta", + "ldapOptReferrals": "Referências Opt", + "disableExport": "Desabilitar exportação (permitido apenas para administradores)", + "assignmentEmailNotifications": "Enviar notificações sobre as designações por e-mail", + "assignmentEmailNotificationsEntityList": "Entidades para notificar" }, "options": { "weekStart": { @@ -61,16 +61,16 @@ "1": "Segunda" } }, - "tooltips": { - "recordsPerPageSmall": "Contar registros nos painéis de relacionamento." - }, + "tooltips": { + "recordsPerPageSmall": "Contar registros nos painéis de relacionamento." + }, "labels": { "System": "Sistema", "Locale": "Idioma", "SMTP": "SMTP", "Configuration": "Configuração", - "Notifications": "Notificações", - "Currency Settings": "Configurações de Moeda", - "Currency Rates": "Conversão de moedas" + "Notifications": "Notificações", + "Currency Settings": "Configurações de Moeda", + "Currency Rates": "Conversão de moedas" } } diff --git a/application/Espo/Resources/i18n/pt_BR/Team.json b/application/Espo/Resources/i18n/pt_BR/Team.json index 305642a089..334b8ae2a9 100644 --- a/application/Espo/Resources/i18n/pt_BR/Team.json +++ b/application/Espo/Resources/i18n/pt_BR/Team.json @@ -6,9 +6,9 @@ "links": { "users": "Usuários" }, - "tooltips": { - "roles": "Todos os usuários deste time terão acesso as configurações das regras selecionadas." - }, + "tooltips": { + "roles": "Todos os usuários deste time terão acesso as configurações das regras selecionadas." + }, "labels": { "Create Team": "Criar Time" } diff --git a/application/Espo/Resources/i18n/pt_BR/User.json b/application/Espo/Resources/i18n/pt_BR/User.json index d4f8e5390a..ec0cebb2fe 100644 --- a/application/Espo/Resources/i18n/pt_BR/User.json +++ b/application/Espo/Resources/i18n/pt_BR/User.json @@ -23,9 +23,9 @@ "Preferences": "Preferências", "Change Password": "Trocar Senha" }, - "tooltips": { - "defaultTeam": "Todos os registros criados por este usuário serão relacionados e este time por padrão." - }, + "tooltips": { + "defaultTeam": "Todos os registros criados por este usuário serão relacionados e este time por padrão." + }, "messages": { "passwordWillBeSent": "A senha será enviada para o email do usuário.", "accountInfoEmailSubject": "Informações da Conta", diff --git a/application/Espo/Resources/i18n/ro_RO/Admin.json b/application/Espo/Resources/i18n/ro_RO/Admin.json index dc4f989a89..3e5ecea2f5 100644 --- a/application/Espo/Resources/i18n/ro_RO/Admin.json +++ b/application/Espo/Resources/i18n/ro_RO/Admin.json @@ -1,126 +1,123 @@ { - "labels": { - "Enabled": "Activat", - "Disabled": "Dezactivat", - "System": "Sistem", - "Users": "Utilizatori", - "Email": "Email", - "Data": "Data", - "Customization": "Personalizare", - "Available Fields": "Campuri valabile", - "Layout": "Aspect", - "Enabled": "Activat", - "Disabled": "Dezactivat", - "Add Panel": "Adauga Panou", - "Add Field": "Adauga Camp", - "Settings": "Setari", - "Scheduled Jobs": "Activitati Planificate", - "Upgrade": "Actualizare", - "Clear Cache": "Sterge Cache", - "Rebuild": "Recontruire", - "Users": "Utilizatori", - "Teams": "Echipe", - "Roles": "Roluri", - "Outbound Emails": "Email-uri trimise", - "Inbound Emails": "Email-uri intrate", - "Email Templates": "Template-uri Email", - "Import": "Importare", - "Layout Manager": "Manager Aspect", - "Field Manager": "Manager Campuri", - "User Interface": "Interfata Utilizator", - "Auth Tokens": "Token-uri Autentificare", - "Authentication": "Authentication" - }, - "layouts": { - "list": "Lista", - "detail": "Detalii", - "listSmall": "List (Small)", - "detailSmall": "Detail (Small)", - "filters": "Filtre Cautare", - "massUpdate": "Actualizeaza tot", - "relationships": "Relatii" - }, - "fieldTypes": { - "address": "Adresa", - "array": "Array", - "foreign": "Foreign", - "duration": "Durata", - "password": "Parola", - "parsonName": "Numele Persoanei", - "autoincrement": "Auto-incrementare", - "bool": "Bool", - "currency": "Valuta", - "date": "Data", - "datetime": "DataTimp", - "email": "Email", - "enum": "Enum", - "enumInt": "Enum Integer", - "enumFloat": "Enum Float", - "float": "Float", - "int": "Int", - "link": "Link", - "linkMultiple": "Link Multiplu", - "linkParent": "Link Parinte", - "multienim": "Multienum", - "phone": "Telefon", - "text": "Text", - "url": "Url", - "varchar": "Varchar", - "file": "Fisier", - "image": "Imagine" - }, - "fields": { - "type": "Tip", - "name": "Nume", - "label": "Eticheta", - "required": "Obligatoriu", - "default": "Initial", - "maxLength": "Lungime Maxima", - "options": "Options (raw values, not translated)", - "after": "After (field)", - "before": "Before (field)", - "link": "Link", - "field": "Camp", - "min": "Min", - "max": "Max", - "translation": "Tranducere", - "previewSize": "Previzualizare Marime" - }, - "messages": { - "upgradeVersion": "Aplicatia se va actualiza la versiunea {version}. S-ar putea sa dureze putin...", - "upgradeDone": "Aplicatia a fost actualizata la versiunea {version}. Va rugam sa faceti Refresh.", - "upgradeBackup": "Va rugam sa faceti backup bazei de date si aplicatiei inainte de a face actualizarea.", - "thousandSeparatorEqualsDecimalMark": "Separatorul de mii nu poate fi acelasi cu separatorul de zecimale", - "userHasNoEmailAddress": "Utilizatorul nu are adresa de email.", - "selectEntityType": "Selectati tipul entitatii din meniul din stanga.", - "selectUpgradePackage": "Selectati packetul de actualizare", - "selectLayout": "Selectati aspectul dorit din meniul din stanga si editati-l." - }, - "descriptions": { - "settings": "Setarile de sistem ale aplicatiei.", - "scheduledJob": "Activitati care sunt executate de cron.", - "upgrade": "Actualizare aplicatie.", - "clearCache": "Stergeti tot cache-ul din backend.", - "rebuild": "Reconstruire backend si stergere cache.", - "users": "Management Utilizatori.", - "teams": "Management Echipe.", - "roles": "Management Roluri.", - "outboundEmails": "Setari SMTP pentru trimitere email-uri.", - "inboundEmails": "Grup conturi de email IMAP. Import email și email-la-caz.", - "emailTemplates": "Template-uri pentru email-urile trimise.", - "import": "Importare din fisier CSV.", - "layoutManager": "Customize layouts (list, detail, edit, search, mass update).", - "fieldManager": "Creaza campuri noi, sau personalizeaza-le pe cele existente.", - "userInterface": "Configurare UI.", - "authTokens": "Sesiuni Auth Active. Adresa IP si data ultimei accesari.", - "authentication": "Authentication setttings." - }, - "options": { - "previewSize": { - "x-small": "X-Small", - "small": "Small", - "medium": "Medium", - "large": "Large" - } - } + "labels": { + "Enabled": "Activat", + "Disabled": "Dezactivat", + "System": "Sistem", + "Users": "Utilizatori", + "Email": "Email", + "Data": "Data", + "Customization": "Personalizare", + "Available Fields": "Campuri valabile", + "Layout": "Aspect", + "Add Panel": "Adauga Panou", + "Add Field": "Adauga Camp", + "Settings": "Setari", + "Scheduled Jobs": "Activitati Planificate", + "Upgrade": "Actualizare", + "Clear Cache": "Sterge Cache", + "Rebuild": "Recontruire", + "Teams": "Echipe", + "Roles": "Roluri", + "Outbound Emails": "Email-uri trimise", + "Inbound Emails": "Email-uri intrate", + "Email Templates": "Template-uri Email", + "Import": "Importare", + "Layout Manager": "Manager Aspect", + "Field Manager": "Manager Campuri", + "User Interface": "Interfata Utilizator", + "Auth Tokens": "Token-uri Autentificare", + "Authentication": "Authentication" + }, + "layouts": { + "list": "Lista", + "detail": "Detalii", + "listSmall": "List (Small)", + "detailSmall": "Detail (Small)", + "filters": "Filtre Cautare", + "massUpdate": "Actualizeaza tot", + "relationships": "Relatii" + }, + "fieldTypes": { + "address": "Adresa", + "array": "Array", + "foreign": "Foreign", + "duration": "Durata", + "password": "Parola", + "parsonName": "Numele Persoanei", + "autoincrement": "Auto-incrementare", + "bool": "Bool", + "currency": "Valuta", + "date": "Data", + "datetime": "DataTimp", + "email": "Email", + "enum": "Enum", + "enumInt": "Enum Integer", + "enumFloat": "Enum Float", + "float": "Float", + "int": "Int", + "link": "Link", + "linkMultiple": "Link Multiplu", + "linkParent": "Link Parinte", + "multienim": "Multienum", + "phone": "Telefon", + "text": "Text", + "url": "Url", + "varchar": "Varchar", + "file": "Fisier", + "image": "Imagine" + }, + "fields": { + "type": "Tip", + "name": "Nume", + "label": "Eticheta", + "required": "Obligatoriu", + "default": "Initial", + "maxLength": "Lungime Maxima", + "options": "Options (raw values, not translated)", + "after": "After (field)", + "before": "Before (field)", + "link": "Link", + "field": "Camp", + "min": "Min", + "max": "Max", + "translation": "Tranducere", + "previewSize": "Previzualizare Marime" + }, + "messages": { + "upgradeVersion": "Aplicatia se va actualiza la versiunea {version}. S-ar putea sa dureze putin...", + "upgradeDone": "Aplicatia a fost actualizata la versiunea {version}. Va rugam sa faceti Refresh.", + "upgradeBackup": "Va rugam sa faceti backup bazei de date si aplicatiei inainte de a face actualizarea.", + "thousandSeparatorEqualsDecimalMark": "Separatorul de mii nu poate fi acelasi cu separatorul de zecimale", + "userHasNoEmailAddress": "Utilizatorul nu are adresa de email.", + "selectEntityType": "Selectati tipul entitatii din meniul din stanga.", + "selectUpgradePackage": "Selectati packetul de actualizare", + "selectLayout": "Selectati aspectul dorit din meniul din stanga si editati-l." + }, + "descriptions": { + "settings": "Setarile de sistem ale aplicatiei.", + "scheduledJob": "Activitati care sunt executate de cron.", + "upgrade": "Actualizare aplicatie.", + "clearCache": "Stergeti tot cache-ul din backend.", + "rebuild": "Reconstruire backend si stergere cache.", + "users": "Management Utilizatori.", + "teams": "Management Echipe.", + "roles": "Management Roluri.", + "outboundEmails": "Setari SMTP pentru trimitere email-uri.", + "inboundEmails": "Grup conturi de email IMAP. Import email și email-la-caz.", + "emailTemplates": "Template-uri pentru email-urile trimise.", + "import": "Importare din fisier CSV.", + "layoutManager": "Customize layouts (list, detail, edit, search, mass update).", + "fieldManager": "Creaza campuri noi, sau personalizeaza-le pe cele existente.", + "userInterface": "Configurare UI.", + "authTokens": "Sesiuni Auth Active. Adresa IP si data ultimei accesari.", + "authentication": "Authentication setttings." + }, + "options": { + "previewSize": { + "x-small": "X-Small", + "small": "Small", + "medium": "Medium", + "large": "Large" + } + } } diff --git a/application/Espo/Resources/i18n/ro_RO/AuthToken.json b/application/Espo/Resources/i18n/ro_RO/AuthToken.json index 52508c0c70..dec1e6bf8f 100644 --- a/application/Espo/Resources/i18n/ro_RO/AuthToken.json +++ b/application/Espo/Resources/i18n/ro_RO/AuthToken.json @@ -1,9 +1,9 @@ { - "fields": { - "user": "Utilizator", - "ipAddress": "Adresa IP", - "lastAccess": "Data ultimei accesari", - "createdAt": "Data conectarii" + "fields": { + "user": "Utilizator", + "ipAddress": "Adresa IP", + "lastAccess": "Data ultimei accesari", + "createdAt": "Data conectarii" - } + } } diff --git a/application/Espo/Resources/i18n/ro_RO/Email.json b/application/Espo/Resources/i18n/ro_RO/Email.json index cac9e25f94..f8c6fef6b2 100644 --- a/application/Espo/Resources/i18n/ro_RO/Email.json +++ b/application/Espo/Resources/i18n/ro_RO/Email.json @@ -1,36 +1,36 @@ { - "fields": { - "name": "Subiect", - "parent": "Parinte", - "status": "Status", - "dateSent": "Data trimiterii", - "from": "De la", - "to": "Catre", - "cc": "CC", - "bcc": "BCC", - "isHtml": "In format Html", - "body": "Corp", - "subject": "Subiect", - "attachments": "Atasamente", - "selectTemplate": "Selecteaza Template", - "fromEmailAddress": "De la adresa", - "toEmailAddresses": "La adresa", - "emailAddress": "Adresa Email" - }, - "links": { - }, - "options": { - "Draft": "Ciorna", - "Sending": "Se trimite", - "Sent": "Trimis", - "Archived": "Arhivat" - }, - "labels": { - "Create Email": "Arhiveaza Email", - "Compose": "Compune" - }, - "presetFilters": { - "sent": "Trimis", - "archived": "Arhivat" - } + "fields": { + "name": "Subiect", + "parent": "Parinte", + "status": "Status", + "dateSent": "Data trimiterii", + "from": "De la", + "to": "Catre", + "cc": "CC", + "bcc": "BCC", + "isHtml": "In format Html", + "body": "Corp", + "subject": "Subiect", + "attachments": "Atasamente", + "selectTemplate": "Selecteaza Template", + "fromEmailAddress": "De la adresa", + "toEmailAddresses": "La adresa", + "emailAddress": "Adresa Email" + }, + "links": { + }, + "options": { + "Draft": "Ciorna", + "Sending": "Se trimite", + "Sent": "Trimis", + "Archived": "Arhivat" + }, + "labels": { + "Create Email": "Arhiveaza Email", + "Compose": "Compune" + }, + "presetFilters": { + "sent": "Trimis", + "archived": "Arhivat" + } } diff --git a/application/Espo/Resources/i18n/ro_RO/EmailAddress.json b/application/Espo/Resources/i18n/ro_RO/EmailAddress.json index 0cf110b713..8d55266d25 100644 --- a/application/Espo/Resources/i18n/ro_RO/EmailAddress.json +++ b/application/Espo/Resources/i18n/ro_RO/EmailAddress.json @@ -1,7 +1,7 @@ { - "labels": { - "Primary": "Primar", - "Opted Out": "Optat", - "Invalid": "Invalid" - } + "labels": { + "Primary": "Primar", + "Opted Out": "Optat", + "Invalid": "Invalid" + } } diff --git a/application/Espo/Resources/i18n/ro_RO/EmailTemplate.json b/application/Espo/Resources/i18n/ro_RO/EmailTemplate.json index bd081bef11..3a20eef44b 100644 --- a/application/Espo/Resources/i18n/ro_RO/EmailTemplate.json +++ b/application/Espo/Resources/i18n/ro_RO/EmailTemplate.json @@ -1,16 +1,16 @@ { - "fields": { - "name": "Nume", - "status": "Status", - "isHtml": "In format Html", - "body": "Corp", - "subject": "Subiect", - "attachments": "Atasamente", - "insertField": "" - }, - "links": { - }, - "labels": { - "Create EmailTemplate": "Creare Template Email" - } + "fields": { + "name": "Nume", + "status": "Status", + "isHtml": "In format Html", + "body": "Corp", + "subject": "Subiect", + "attachments": "Atasamente", + "insertField": "" + }, + "links": { + }, + "labels": { + "Create EmailTemplate": "Creare Template Email" + } } diff --git a/application/Espo/Resources/i18n/ro_RO/Global.json b/application/Espo/Resources/i18n/ro_RO/Global.json index bd6b3e926e..10f9713889 100644 --- a/application/Espo/Resources/i18n/ro_RO/Global.json +++ b/application/Espo/Resources/i18n/ro_RO/Global.json @@ -1,412 +1,412 @@ { - "scopeNames": { - "Email": "Email", - "User": "Utilizator", - "Team": "Echipa", - "Role": "Rol", - "EmailTemplate": "Template Email", - "OutboundEmail": "Email iesit ", - "ScheduledJob": "Activitati programate" - }, - "scopeNamesPlural": { - "Email": "Email-uri", - "User": "Utilizatori", - "Team": "Echipe", - "Role": "Roluri", - "EmailTemplate": "Template-uri Email", - "OutboundEmail": "Email-uri trimise", - "ScheduledJob": "Activitati Planificate" - }, - "labels": { - "Misc": "Miscibil", - "Merge": "Imbina", - "None": "Nici unul", - "by": "de", - "Saved": "Salvat", - "Error": "Eroare", - "Select": "Selecteaza", - "Not valid": "Invalid", - "Please wait...": "Va rugam asteptati...", - "Please wait": "Va rugam asteptati", - "Loading...": "Se incarca...", - "Uploading...": "Se incarca...", - "Sending...": "Se trimite...", - "Removed": "Sters", - "Posted": "Publicat", - "Linked": "Conectat", - "Unlinked": "Deconectat", - "Access denied": "Acces refuzat", - "Access": "Acces", - "Are you sure?": "Are you sure?", - "Record has been removed": "Inregistrarea a fost stearsa", - "Wrong username/password": "Numele de utilizator, sau parola nu sunt corecte", - "Post cannot be empty": "Aticolul nu poate fi gol", - "Removing...": "Se sterge...", - "Unlinking...": "Se deconecteaza...", - "Posting...": "Se publica...", - "Username can not be empty!": "Numele de utilizator nu poate fi gol!", - "Cache is not enabled": "Cache-ul nu este activat", - "Cache has been cleared": "Cache-ul a fost sters", - "Rebuild has been done": "Reconstruit cu succes", - "Saving...": "Se salveaza...", - "Modified": "Modificat", - "Created": "Creat", - "Create": "Creaza", - "create": "creaza", - "Overview": "Prezentare generala", - "Details": "Detalii", - "Add Filter": "Adauga Filtru", - "Add Dashlet": "Adauga Dashlet", - "Add": "Adauga", - "Reset": "Reset", - "Menu": "Meniu", - "More": "More", - "Search": "Cautare", - "Only My": "Doar eu", - "Open": "Deschide", - "Admin": "Admin", - "About": "Despre", - "Refresh": "Reimprospatare", - "Remove": "Sterge", - "Options": "Optiuni", - "Username": "Nume Utilizator", - "Password": "Parola", - "Login": "Conectare", - "Log Out": "Deconectare", - "Preferences": "Preferinte", - "State": "Stat", - "Street": "Strada", - "Country": "Tara", - "City": "Oras", - "PostalCode": "Code Postal ", - "Followed": "Urmarit", - "Follow": "Urmareste", - "Clear Local Cache": "Stergere Cache Local", - "Actions": "Actiuni", - "Delete": "Sterge", - "Update": "Actualizare", - "Save": "Salveaza", - "Edit": "Editare", - "Cancel": "Renunta", - "Unlink": "Dezleaga", - "Mass Update": "Actualizeaza tot", - "Export": "Export", - "No Data": "Nu sunt date", - "All": "Toate", - "Active": "Activ", - "Inactive": "Inactiv", - "Write your comment here": "Scrie comentariul aici", - "Post": "Publica", - "Stream": "Curent", - "Show more": "Afiseaza mai mult", - "Dashlet Options": "Optiuni Dashlet", - "Full Form": "Forma intreaga", - "Insert": "Inserare", - "Person": "Persoana", - "First Name": "Prenume", - "Last Name": "Nume", - "Original": "Original", - "You": "Tu", - "you": "tu", - "change": "schimba", - "Primary": "Primar", - "Save Filters": "Save Filters", - "Administration": "Administration", - "Run Import": "Run Import", - "Duplicate": "Duplicat", - "Notifications": "Notifications" - }, - "messages": { - "notModified": "Nu ai modificat inregistrarea", - "duplicate": "Inregistrarea pe care o creezi pare sa fie duplicat", - "fieldIsRequired": "{field} este obligatoriu", - "fieldShouldBeEmail": "{field} trebuie sa fie o adresa de email valida", - "fieldShouldBeFloat": "{field} trebuie sa fie float valid", - "fieldShouldBeInt": "{field} trebuie sa fie intreg valid", - "fieldShouldBeDate": "{field} trebuie sa fie data valida", - "fieldShouldBeDatetime": "{field} trebuie sa fie data/timp valid", - "fieldShouldAfter": "{field} trebuie sa fie dupa {otherField}", - "fieldShouldBefore": "{field} trebuie sa fie inainte de {otherField}", - "fieldShouldBeBetween": "{field} trebuie sa fie intre {min} si {max}", - "fieldShouldBeLess": "{field} trebuie sa fie mai putin de {value}", - "fieldShouldBeGreater": "{field} trebuie sa fie mai mare de {value}", - "fieldBadPasswordConfirm": "{field} confirmat in mod necorespunzator" - }, - "boolFilters": { - "onlyMy": "Doar eu", - "open": "Deschide", - "active": "Activ" - }, - "fields": { - "name": "Nume", - "firstName": "Prenume", - "lastName": "Nume", - "salutationName": "Salut", - "assignedUser": "Utilizator alocat", - "emailAddress": "Email", - "assignedUserName": "Nume utilizator alocat", - "teams": "Echipe", - "createdAt": "Creat la", - "modifiedAt": "Modificat la", - "createdBy": "Creat de", - "modifiedBy": "Modificat de", - "title": "Titlu", - "dateFrom": "Data - de la", - "dateTo": "Data - pana la", - "autorefreshInterval": "Interval Auto-reinprospatare", - "displayRecords": "Afisare inregistrari" - }, - "links": { - "teams": "Echipe", - "users": "Utilizatori" - }, - "dashlets": { - "Stream": "Curent" - }, - "streamMessages": { - "create": "{user} creat {entityType} {entity}", - "createAssigned": "{user} creat {entityType} {entity} si alocat lui {assignee}", - "assign": "{user} alocat {entityType} {entity} lui {assignee}", - "post": "{user} publicat la {entityType} {entity}", - "attach": "{user} atasat la {entityType} {entity}", - "status": "{user} actualizat {field} pe {entityType} {entity}", - "update": "{user} actualizat {entityType} {entity}", - "createRelated": "{user} creat {relatedEntityType} {relatedEntity} si conectat cu {entityType} {entity}", - "emailReceived": "{entity} a fost primit pentru {entityType} {entity}", - - "createThis": "{user} a creat acest {entityType}", - "createAssignedThis": "{user} a creat acest {entityType} alocat lui {assignee}", - "assignThis": "{user} a alocat acest {entityType} lui {assignee}", - "postThis": "{user} publicat", - "attachThis": "{user} atasat", - "statusThis": "{user} a actualizat {field}", - "updateThis": "{user} a actualizat acest {entityType}", - "createRelatedThis": "{user} a creat {relatedEntityType} {relatedEntity} si l-a conectat cu {entityType}", - "emailReceivedThis": "{entity} a fost primit" - }, - "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"] - }, - "options": { - "salutationName": { - "Mr.": "Dl.", - "Mrs.": "D-na.", - "Dr.": "Dr.", - "Drs.": "Dr." - }, - "language": { - "af_ZA": "Afrikaans", - "az_AZ": "Azerbaijani", - "be_BY": "Belarusian", - "bg_BG": "Bulgarian", - "bn_IN": "Bengali", - "bs_BA": "Bosnian", - "ca_ES": "Catalan", - "cs_CZ": "Czech", - "cy_GB": "Welsh", - "da_DK": "Danish", - "de_DE": "German", - "el_GR": "Greek", - "en_GB":"English (UK)", - "en_US":"English (US)", - "es_ES":"Spanish (Spain)", - "et_EE": "Estonian", - "eu_ES": "Basque", - "fa_IR": "Persian", - "fi_FI": "Finnish", - "fo_FO": "Faroese", - "fr_CA":"French (Canada)", - "fr_FR":"French (France)", - "ga_IE": "Irish", - "gl_ES": "Galician", - "gn_PY": "Guarani", - "he_IL": "Hebrew", - "hi_IN": "Hindi", - "hr_HR": "Croatian", - "hu_HU": "Hungarian", - "hy_AM": "Armenian", - "id_ID": "Indonesian", - "is_IS": "Icelandic", - "it_IT": "Italian", - "ja_JP": "Japanese", - "ka_GE": "Georgian", - "km_KH": "Khmer", - "ko_KR": "Korean", - "ku_TR": "Kurdish", - "lt_LT": "Lithuanian", - "lv_LV": "Latvian", - "mk_MK": "Macedonian", - "ml_IN": "Malayalam", - "ms_MY": "Malay", - "nb_NO":"Norwegian Bokmål", - "nn_NO": "Norwegian Nynorsk", - "ne_NP": "Nepali", - "nl_NL": "Dutch", - "pa_IN": "Punjabi", - "pl_PL": "Polish", - "ps_AF": "Pashto", - "pt_BR":"Portuguese (Brazil)", - "pt_PT":"Portuguese (Portugal)", - "ro_RO": "Romana", - "ru_RU": "Russian", - "sk_SK": "Slovak", - "sl_SI": "Slovene", - "sq_AL": "Albanian", - "sr_RS": "Serbian", - "sv_SE": "Swedish", - "sw_KE": "Swahili", - "ta_IN": "Tamil", - "te_IN": "Telugu", - "th_TH": "Thai", - "tl_PH": "Tagalog", - "tr_TR": "Turkish", - "uk_UA": "Ukrainian", - "ur_PK": "Urdu", - "vi_VN": "Vietnamese", - "zh_CN":"Simplified Chinese (China)", - "zh_HK":"Traditional Chinese (Hong Kong)", - "zh_TW":"Traditional Chinese (Taiwan)" - }, - "dateSearchRanges": { - "on": "Pornit", - "notOn": "Oprit", - "after": "Dupa", - "before": "Inainte", - "between": "Intre", - "today": "Astazi", - "past": "Past", - "future": "Future" - }, - "intSearchRanges": { - "equals": "Egal", - "notEquals": "Inegal", - "greaterThan": "Mai mare de", - "lessThan": "Mai mic de", - "greaterThanOrEquals": "Mai mare sau egal", - "lessThanOrEquals": "Mai mic sau egal", - "between": "Intre" - }, - "autorefreshInterval": { - "0": "Nici unul", - "0.5": "30 secunde", - "1": "1 minut", - "2": "2 minute", - "5": "5 minute", - "10": "10 minute" - }, - "phoneNumber": { - "Mobile": "Mobile", - "Office": "Office", - "Fax": "Fax", - "Home": "Home", - "Other": "Altele" - } - }, - "sets": { - "summernote": { - "NOTICE": "Puteti gasi traducerea aici: https://github.com/HackerWins/summernote/tree/master/lang", - "font":{ - "bold": "Bold", - "italic": "Italic", - "underline": "Subliniat", - "strike": "Strike", - "clear": "Sterge stil font", - "height": "Inaltime linie", - "name": "Familie Font ", - "size": "Marime Font" - }, - "image":{ - "image": "Imagine", - "insert": "Inserare Imagine", - "resizeFull": "Redimensionare completa", - "resizeHalf": "Redimensionare la jumatate", - "resizeQuarter": "Redimensionare la sfert", - "floatLeft": "Aliniere la stanga", - "floatRight": "Aliniere la dreapta", - "floatNone": "Fara aliniere", - "dragImageHere": "Trage imaginea aici", - "selectFromFiles": "Selecteaza din fisiere", - "url": "URL Imagine", - "remove": "Stergere imagine" - }, - "link":{ - "link": "Link", - "insert": "Inserare Link", - "unlink": "Dezleaga", - "edit": "Editare", - "textToDisplay": "Text de afisat", - "url":"To what URL should this link go?", - "openInNewWindow": "Deschidere in fereastra noua" - }, - "video":{ - "video": "Video", - "videoLink": "Link Video ", - "insert": "Inserare Video", - "url":"Video URL?", - "providers":"(YouTube, Vimeo, Vine, Instagram, or DailyMotion)" - }, - "table":{ - "table": "Tabel" - }, - "hr":{ - "insert": "Inserare Linie Orizontala" - }, - "style":{ - "style": "Stil", - "normal": "Normal", - "blockquote": "Citat", - "pre": "Cod", - "h1": "Header 1", - "h2": "Header 2", - "h3": "Header 3", - "h4": "Header 4", - "h5": "Header 5", - "h6": "Header 6" - }, - "lists":{ - "unordered": "Lista neordonata", - "ordered": "Lista ordonata" - }, - "options":{ - "help": "Ajutor", - "fullscreen": "Ecran complet", - "codeview": "Vizualizare cod" - }, - "paragraph":{ - "paragraph": "Paragraf", - "outdent": "Neindentat", - "indent": "Indentat", - "left": "Aliniere stanga", - "center": "Aliniere centru", - "right": "Aliniere dreapta", - "justify": "Justify complet" - }, - "color":{ - "recent": "Culoarea recenta", - "more": "Mai multe culori", - "background": "Culoare fundal", - "foreground": "Culoare font", - "transparent": "Transparent", - "setTransparent": "Setare transparenta", - "reset": "Reset", - "resetToDefault": "Reinitializare setari" - }, - "shortcut":{ - "shortcuts": "Scurtaturi taste", - "close": "Inchide", - "textFormatting": "Formatare Text", - "action": "Actiune", - "paragraphFormatting": "Formatare Paragraf", - "documentStyle": "Stil Document " - }, - "history":{ - "undo": "Undo", - "redo": "Redo" - } - } - } + "scopeNames": { + "Email": "Email", + "User": "Utilizator", + "Team": "Echipa", + "Role": "Rol", + "EmailTemplate": "Template Email", + "OutboundEmail": "Email iesit ", + "ScheduledJob": "Activitati programate" + }, + "scopeNamesPlural": { + "Email": "Email-uri", + "User": "Utilizatori", + "Team": "Echipe", + "Role": "Roluri", + "EmailTemplate": "Template-uri Email", + "OutboundEmail": "Email-uri trimise", + "ScheduledJob": "Activitati Planificate" + }, + "labels": { + "Misc": "Miscibil", + "Merge": "Imbina", + "None": "Nici unul", + "by": "de", + "Saved": "Salvat", + "Error": "Eroare", + "Select": "Selecteaza", + "Not valid": "Invalid", + "Please wait...": "Va rugam asteptati...", + "Please wait": "Va rugam asteptati", + "Loading...": "Se incarca...", + "Uploading...": "Se incarca...", + "Sending...": "Se trimite...", + "Removed": "Sters", + "Posted": "Publicat", + "Linked": "Conectat", + "Unlinked": "Deconectat", + "Access denied": "Acces refuzat", + "Access": "Acces", + "Are you sure?": "Are you sure?", + "Record has been removed": "Inregistrarea a fost stearsa", + "Wrong username/password": "Numele de utilizator, sau parola nu sunt corecte", + "Post cannot be empty": "Aticolul nu poate fi gol", + "Removing...": "Se sterge...", + "Unlinking...": "Se deconecteaza...", + "Posting...": "Se publica...", + "Username can not be empty!": "Numele de utilizator nu poate fi gol!", + "Cache is not enabled": "Cache-ul nu este activat", + "Cache has been cleared": "Cache-ul a fost sters", + "Rebuild has been done": "Reconstruit cu succes", + "Saving...": "Se salveaza...", + "Modified": "Modificat", + "Created": "Creat", + "Create": "Creaza", + "create": "creaza", + "Overview": "Prezentare generala", + "Details": "Detalii", + "Add Filter": "Adauga Filtru", + "Add Dashlet": "Adauga Dashlet", + "Add": "Adauga", + "Reset": "Reset", + "Menu": "Meniu", + "More": "More", + "Search": "Cautare", + "Only My": "Doar eu", + "Open": "Deschide", + "Admin": "Admin", + "About": "Despre", + "Refresh": "Reimprospatare", + "Remove": "Sterge", + "Options": "Optiuni", + "Username": "Nume Utilizator", + "Password": "Parola", + "Login": "Conectare", + "Log Out": "Deconectare", + "Preferences": "Preferinte", + "State": "Stat", + "Street": "Strada", + "Country": "Tara", + "City": "Oras", + "PostalCode": "Code Postal ", + "Followed": "Urmarit", + "Follow": "Urmareste", + "Clear Local Cache": "Stergere Cache Local", + "Actions": "Actiuni", + "Delete": "Sterge", + "Update": "Actualizare", + "Save": "Salveaza", + "Edit": "Editare", + "Cancel": "Renunta", + "Unlink": "Dezleaga", + "Mass Update": "Actualizeaza tot", + "Export": "Export", + "No Data": "Nu sunt date", + "All": "Toate", + "Active": "Activ", + "Inactive": "Inactiv", + "Write your comment here": "Scrie comentariul aici", + "Post": "Publica", + "Stream": "Curent", + "Show more": "Afiseaza mai mult", + "Dashlet Options": "Optiuni Dashlet", + "Full Form": "Forma intreaga", + "Insert": "Inserare", + "Person": "Persoana", + "First Name": "Prenume", + "Last Name": "Nume", + "Original": "Original", + "You": "Tu", + "you": "tu", + "change": "schimba", + "Primary": "Primar", + "Save Filters": "Save Filters", + "Administration": "Administration", + "Run Import": "Run Import", + "Duplicate": "Duplicat", + "Notifications": "Notifications" + }, + "messages": { + "notModified": "Nu ai modificat inregistrarea", + "duplicate": "Inregistrarea pe care o creezi pare sa fie duplicat", + "fieldIsRequired": "{field} este obligatoriu", + "fieldShouldBeEmail": "{field} trebuie sa fie o adresa de email valida", + "fieldShouldBeFloat": "{field} trebuie sa fie float valid", + "fieldShouldBeInt": "{field} trebuie sa fie intreg valid", + "fieldShouldBeDate": "{field} trebuie sa fie data valida", + "fieldShouldBeDatetime": "{field} trebuie sa fie data/timp valid", + "fieldShouldAfter": "{field} trebuie sa fie dupa {otherField}", + "fieldShouldBefore": "{field} trebuie sa fie inainte de {otherField}", + "fieldShouldBeBetween": "{field} trebuie sa fie intre {min} si {max}", + "fieldShouldBeLess": "{field} trebuie sa fie mai putin de {value}", + "fieldShouldBeGreater": "{field} trebuie sa fie mai mare de {value}", + "fieldBadPasswordConfirm": "{field} confirmat in mod necorespunzator" + }, + "boolFilters": { + "onlyMy": "Doar eu", + "open": "Deschide", + "active": "Activ" + }, + "fields": { + "name": "Nume", + "firstName": "Prenume", + "lastName": "Nume", + "salutationName": "Salut", + "assignedUser": "Utilizator alocat", + "emailAddress": "Email", + "assignedUserName": "Nume utilizator alocat", + "teams": "Echipe", + "createdAt": "Creat la", + "modifiedAt": "Modificat la", + "createdBy": "Creat de", + "modifiedBy": "Modificat de", + "title": "Titlu", + "dateFrom": "Data - de la", + "dateTo": "Data - pana la", + "autorefreshInterval": "Interval Auto-reinprospatare", + "displayRecords": "Afisare inregistrari" + }, + "links": { + "teams": "Echipe", + "users": "Utilizatori" + }, + "dashlets": { + "Stream": "Curent" + }, + "streamMessages": { + "create": "{user} creat {entityType} {entity}", + "createAssigned": "{user} creat {entityType} {entity} si alocat lui {assignee}", + "assign": "{user} alocat {entityType} {entity} lui {assignee}", + "post": "{user} publicat la {entityType} {entity}", + "attach": "{user} atasat la {entityType} {entity}", + "status": "{user} actualizat {field} pe {entityType} {entity}", + "update": "{user} actualizat {entityType} {entity}", + "createRelated": "{user} creat {relatedEntityType} {relatedEntity} si conectat cu {entityType} {entity}", + "emailReceived": "{entity} a fost primit pentru {entityType} {entity}", + + "createThis": "{user} a creat acest {entityType}", + "createAssignedThis": "{user} a creat acest {entityType} alocat lui {assignee}", + "assignThis": "{user} a alocat acest {entityType} lui {assignee}", + "postThis": "{user} publicat", + "attachThis": "{user} atasat", + "statusThis": "{user} a actualizat {field}", + "updateThis": "{user} a actualizat acest {entityType}", + "createRelatedThis": "{user} a creat {relatedEntityType} {relatedEntity} si l-a conectat cu {entityType}", + "emailReceivedThis": "{entity} a fost primit" + }, + "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"] + }, + "options": { + "salutationName": { + "Mr.": "Dl.", + "Mrs.": "D-na.", + "Dr.": "Dr.", + "Drs.": "Dr." + }, + "language": { + "af_ZA": "Afrikaans", + "az_AZ": "Azerbaijani", + "be_BY": "Belarusian", + "bg_BG": "Bulgarian", + "bn_IN": "Bengali", + "bs_BA": "Bosnian", + "ca_ES": "Catalan", + "cs_CZ": "Czech", + "cy_GB": "Welsh", + "da_DK": "Danish", + "de_DE": "German", + "el_GR": "Greek", + "en_GB":"English (UK)", + "en_US":"English (US)", + "es_ES":"Spanish (Spain)", + "et_EE": "Estonian", + "eu_ES": "Basque", + "fa_IR": "Persian", + "fi_FI": "Finnish", + "fo_FO": "Faroese", + "fr_CA":"French (Canada)", + "fr_FR":"French (France)", + "ga_IE": "Irish", + "gl_ES": "Galician", + "gn_PY": "Guarani", + "he_IL": "Hebrew", + "hi_IN": "Hindi", + "hr_HR": "Croatian", + "hu_HU": "Hungarian", + "hy_AM": "Armenian", + "id_ID": "Indonesian", + "is_IS": "Icelandic", + "it_IT": "Italian", + "ja_JP": "Japanese", + "ka_GE": "Georgian", + "km_KH": "Khmer", + "ko_KR": "Korean", + "ku_TR": "Kurdish", + "lt_LT": "Lithuanian", + "lv_LV": "Latvian", + "mk_MK": "Macedonian", + "ml_IN": "Malayalam", + "ms_MY": "Malay", + "nb_NO":"Norwegian Bokmål", + "nn_NO": "Norwegian Nynorsk", + "ne_NP": "Nepali", + "nl_NL": "Dutch", + "pa_IN": "Punjabi", + "pl_PL": "Polish", + "ps_AF": "Pashto", + "pt_BR":"Portuguese (Brazil)", + "pt_PT":"Portuguese (Portugal)", + "ro_RO": "Romana", + "ru_RU": "Russian", + "sk_SK": "Slovak", + "sl_SI": "Slovene", + "sq_AL": "Albanian", + "sr_RS": "Serbian", + "sv_SE": "Swedish", + "sw_KE": "Swahili", + "ta_IN": "Tamil", + "te_IN": "Telugu", + "th_TH": "Thai", + "tl_PH": "Tagalog", + "tr_TR": "Turkish", + "uk_UA": "Ukrainian", + "ur_PK": "Urdu", + "vi_VN": "Vietnamese", + "zh_CN":"Simplified Chinese (China)", + "zh_HK":"Traditional Chinese (Hong Kong)", + "zh_TW":"Traditional Chinese (Taiwan)" + }, + "dateSearchRanges": { + "on": "Pornit", + "notOn": "Oprit", + "after": "Dupa", + "before": "Inainte", + "between": "Intre", + "today": "Astazi", + "past": "Past", + "future": "Future" + }, + "intSearchRanges": { + "equals": "Egal", + "notEquals": "Inegal", + "greaterThan": "Mai mare de", + "lessThan": "Mai mic de", + "greaterThanOrEquals": "Mai mare sau egal", + "lessThanOrEquals": "Mai mic sau egal", + "between": "Intre" + }, + "autorefreshInterval": { + "0": "Nici unul", + "0.5": "30 secunde", + "1": "1 minut", + "2": "2 minute", + "5": "5 minute", + "10": "10 minute" + }, + "phoneNumber": { + "Mobile": "Mobile", + "Office": "Office", + "Fax": "Fax", + "Home": "Home", + "Other": "Altele" + } + }, + "sets": { + "summernote": { + "NOTICE": "Puteti gasi traducerea aici: https://github.com/HackerWins/summernote/tree/master/lang", + "font":{ + "bold": "Bold", + "italic": "Italic", + "underline": "Subliniat", + "strike": "Strike", + "clear": "Sterge stil font", + "height": "Inaltime linie", + "name": "Familie Font ", + "size": "Marime Font" + }, + "image":{ + "image": "Imagine", + "insert": "Inserare Imagine", + "resizeFull": "Redimensionare completa", + "resizeHalf": "Redimensionare la jumatate", + "resizeQuarter": "Redimensionare la sfert", + "floatLeft": "Aliniere la stanga", + "floatRight": "Aliniere la dreapta", + "floatNone": "Fara aliniere", + "dragImageHere": "Trage imaginea aici", + "selectFromFiles": "Selecteaza din fisiere", + "url": "URL Imagine", + "remove": "Stergere imagine" + }, + "link":{ + "link": "Link", + "insert": "Inserare Link", + "unlink": "Dezleaga", + "edit": "Editare", + "textToDisplay": "Text de afisat", + "url":"To what URL should this link go?", + "openInNewWindow": "Deschidere in fereastra noua" + }, + "video":{ + "video": "Video", + "videoLink": "Link Video ", + "insert": "Inserare Video", + "url":"Video URL?", + "providers":"(YouTube, Vimeo, Vine, Instagram, or DailyMotion)" + }, + "table":{ + "table": "Tabel" + }, + "hr":{ + "insert": "Inserare Linie Orizontala" + }, + "style":{ + "style": "Stil", + "normal": "Normal", + "blockquote": "Citat", + "pre": "Cod", + "h1": "Header 1", + "h2": "Header 2", + "h3": "Header 3", + "h4": "Header 4", + "h5": "Header 5", + "h6": "Header 6" + }, + "lists":{ + "unordered": "Lista neordonata", + "ordered": "Lista ordonata" + }, + "options":{ + "help": "Ajutor", + "fullscreen": "Ecran complet", + "codeview": "Vizualizare cod" + }, + "paragraph":{ + "paragraph": "Paragraf", + "outdent": "Neindentat", + "indent": "Indentat", + "left": "Aliniere stanga", + "center": "Aliniere centru", + "right": "Aliniere dreapta", + "justify": "Justify complet" + }, + "color":{ + "recent": "Culoarea recenta", + "more": "Mai multe culori", + "background": "Culoare fundal", + "foreground": "Culoare font", + "transparent": "Transparent", + "setTransparent": "Setare transparenta", + "reset": "Reset", + "resetToDefault": "Reinitializare setari" + }, + "shortcut":{ + "shortcuts": "Scurtaturi taste", + "close": "Inchide", + "textFormatting": "Formatare Text", + "action": "Actiune", + "paragraphFormatting": "Formatare Paragraf", + "documentStyle": "Stil Document " + }, + "history":{ + "undo": "Undo", + "redo": "Redo" + } + } + } } diff --git a/application/Espo/Resources/i18n/ro_RO/Note.json b/application/Espo/Resources/i18n/ro_RO/Note.json index 984df158ad..d61a78c7c9 100644 --- a/application/Espo/Resources/i18n/ro_RO/Note.json +++ b/application/Espo/Resources/i18n/ro_RO/Note.json @@ -1,6 +1,6 @@ { - "fields": { - "post": "Publica", - "attachments": "Atasamente" - } + "fields": { + "post": "Publica", + "attachments": "Atasamente" + } } diff --git a/application/Espo/Resources/i18n/ro_RO/Preferences.json b/application/Espo/Resources/i18n/ro_RO/Preferences.json index 110f8a8eca..d3131eb5ea 100644 --- a/application/Espo/Resources/i18n/ro_RO/Preferences.json +++ b/application/Espo/Resources/i18n/ro_RO/Preferences.json @@ -1,32 +1,32 @@ { - "fields": { - "dateFormat": "Format Data ", - "timeFormat": "Format Timp", - "timeZone": "Zone Timp", - "weekStart": "Prima zi a saptamanii", - "thousandSeparator": "Separator mii", - "decimalMark": "Semn zecimal", - "defaultCurrency": "Valuta initiala", - "currencyList": "Lista valute", - "language": "Limba", - - "smtpServer": "Server", - "smtpPort": "Port", - "smtpAuth": "Autorizare", - "smtpSecurity": "Securitate", - "smtpUsername": "Nume Utilizator", - "emailAddress": "Email", - "smtpPassword": "Parola", - "smtpEmailAddress": "Adresa Email", - - "exportDelimiter": "Delimitator Export" - }, - "links": { - }, - "options": { - "weekStart": { - "0": "Duminica", - "1": "Luni" - } - } + "fields": { + "dateFormat": "Format Data ", + "timeFormat": "Format Timp", + "timeZone": "Zone Timp", + "weekStart": "Prima zi a saptamanii", + "thousandSeparator": "Separator mii", + "decimalMark": "Semn zecimal", + "defaultCurrency": "Valuta initiala", + "currencyList": "Lista valute", + "language": "Limba", + + "smtpServer": "Server", + "smtpPort": "Port", + "smtpAuth": "Autorizare", + "smtpSecurity": "Securitate", + "smtpUsername": "Nume Utilizator", + "emailAddress": "Email", + "smtpPassword": "Parola", + "smtpEmailAddress": "Adresa Email", + + "exportDelimiter": "Delimitator Export" + }, + "links": { + }, + "options": { + "weekStart": { + "0": "Duminica", + "1": "Luni" + } + } } diff --git a/application/Espo/Resources/i18n/ro_RO/Role.json b/application/Espo/Resources/i18n/ro_RO/Role.json index 6d7896e5ee..8109e36022 100644 --- a/application/Espo/Resources/i18n/ro_RO/Role.json +++ b/application/Espo/Resources/i18n/ro_RO/Role.json @@ -1,32 +1,32 @@ { - "fields": { - "name": "Nume", - "roles": "Roluri" - }, - "links": { - "users": "Utilizatori", - "teams": "Echipe" - }, - "labels": { - "Access": "Acces", - "Create Role": "Creare Rol" - }, - "options": { - "accessList": { - "not-set": "ne setat", - "enabled": "activat", - "disabled": "dezactivat" - }, - "levelList": { - "all": "toate", - "team": "echipa", - "own": "personal", - "no": "nu" - } - }, - "actions": { - "read": "Citeste", - "edit": "Editare", - "delete": "Sterge" - } + "fields": { + "name": "Nume", + "roles": "Roluri" + }, + "links": { + "users": "Utilizatori", + "teams": "Echipe" + }, + "labels": { + "Access": "Acces", + "Create Role": "Creare Rol" + }, + "options": { + "accessList": { + "not-set": "ne setat", + "enabled": "activat", + "disabled": "dezactivat" + }, + "levelList": { + "all": "toate", + "team": "echipa", + "own": "personal", + "no": "nu" + } + }, + "actions": { + "read": "Citeste", + "edit": "Editare", + "delete": "Sterge" + } } diff --git a/application/Espo/Resources/i18n/ro_RO/ScheduledJob.json b/application/Espo/Resources/i18n/ro_RO/ScheduledJob.json index 0f15529c68..6a71931c20 100644 --- a/application/Espo/Resources/i18n/ro_RO/ScheduledJob.json +++ b/application/Espo/Resources/i18n/ro_RO/ScheduledJob.json @@ -1,30 +1,30 @@ { - "fields": { - "name": "Nume", - "status": "Status", - "job": "Activitate", - "scheduling": "Scheduling (crontab notation)" - }, - "links": { - "log": "Log" - }, - "labels": { - "Create ScheduledJob": "Creare activiate programata" - }, - "options": { - "job": { - "CheckInboundEmails": "Verificare Intrari Email", - "Cleanup": "Curatare" - }, - "cronSetup": { - "linux": "Nota: Adauga acesta linie in fisierul crontab pentru a rula Activitatile programate:", - "mac": "Nota: Adauga acesta linie in fisierul crontab pentru a rula Activitatile programate:", - "windows": "Nota: Creaza un fisier batch care sa contina urmatoarele comenzi pentru a rula Activitatile programate, folosind Windows Scheduled Tasks:", - "default": "Note: Add this command to Cron Job (Scheduled Task):" - }, - "status": { - "Active": "Activ", - "Inactive": "Inactiv" - } - } + "fields": { + "name": "Nume", + "status": "Status", + "job": "Activitate", + "scheduling": "Scheduling (crontab notation)" + }, + "links": { + "log": "Log" + }, + "labels": { + "Create ScheduledJob": "Creare activiate programata" + }, + "options": { + "job": { + "CheckInboundEmails": "Verificare Intrari Email", + "Cleanup": "Curatare" + }, + "cronSetup": { + "linux": "Nota: Adauga acesta linie in fisierul crontab pentru a rula Activitatile programate:", + "mac": "Nota: Adauga acesta linie in fisierul crontab pentru a rula Activitatile programate:", + "windows": "Nota: Creaza un fisier batch care sa contina urmatoarele comenzi pentru a rula Activitatile programate, folosind Windows Scheduled Tasks:", + "default": "Note: Add this command to Cron Job (Scheduled Task):" + }, + "status": { + "Active": "Activ", + "Inactive": "Inactiv" + } + } } diff --git a/application/Espo/Resources/i18n/ro_RO/ScheduledJobLogRecord.json b/application/Espo/Resources/i18n/ro_RO/ScheduledJobLogRecord.json index 3bd9a58ad6..3d5204c99d 100644 --- a/application/Espo/Resources/i18n/ro_RO/ScheduledJobLogRecord.json +++ b/application/Espo/Resources/i18n/ro_RO/ScheduledJobLogRecord.json @@ -1,6 +1,6 @@ { - "fields": { - "status": "Status", - "executionTime": "Timp Executie" - } + "fields": { + "status": "Status", + "executionTime": "Timp Executie" + } } diff --git a/application/Espo/Resources/i18n/ro_RO/Settings.json b/application/Espo/Resources/i18n/ro_RO/Settings.json index c4a3f0c237..3168ac0798 100644 --- a/application/Espo/Resources/i18n/ro_RO/Settings.json +++ b/application/Espo/Resources/i18n/ro_RO/Settings.json @@ -1,64 +1,64 @@ { - "fields": { - "useCache": "Foloseste Cache", - "dateFormat": "Format Data ", - "timeFormat": "Format Timp", - "timeZone": "Zone Timp", - "weekStart": "Prima zi a saptamanii", - "thousandSeparator": "Separator mii", - "decimalMark": "Semn zecimal", - "defaultCurrency": "Valuta initiala", - "currencyList": "Lista valute", - "language": "Limba", - - "companyLogo": "Logo Companie", - - "smtpServer": "Server", - "smtpPort": "Port", - "smtpAuth": "Autorizare", - "smtpSecurity": "Securitate", - "smtpUsername": "Nume Utilizator", - "emailAddress": "Email", - "smtpPassword": "Parola", - "outboundEmailFromName": "De la", - "outboundEmailFromAddress": "De la adresa", - "outboundEmailIsShared": "Este Partajat", - - "recordsPerPage": "Inregistrari pe pagina", - "recordsPerPageSmall": "Records Per Page (Small)", - "tabList": "Lista Tab-uri", - "quickCreateList": "Creare lista rapida", - - "exportDelimiter": "Delimitator Export", - - "authenticationMethod": "Authentication Method", - "ldapHost": "Gazda", - "ldapPort": "Port", - "ldapAuth": "Autorizare", - "ldapUsername": "Nume Utilizator", - "ldapPassword": "Parola", - "ldapBindRequiresDn": "Bind Requires Dn", - "ldapBaseDn": "Base Dn", - "ldapAccountCanonicalForm": "Account Canonical Form", - "ldapAccountDomainName": "Account Domain Name", - "ldapTryUsernameSplit": "Try Username Split", - "ldapCreateEspoUser": "Create User in EspoCRM", - "ldapSecurity": "Securitate", - "ldapUserLoginFilter": "User Login Filter", - "ldapAccountDomainNameShort": "Account Domain Name Short", - "ldapOptReferrals": "Opt Referrals", - "disableExport": "Disable Export (only admin is allowed)" - }, - "options": { - "weekStart": { - "0": "Duminica", - "1": "Luni" - } - }, - "labels": { - "System": "Sistem", - "Locale": "Localizare", - "SMTP": "SMTP", - "Configuration": "Configuratie" - } + "fields": { + "useCache": "Foloseste Cache", + "dateFormat": "Format Data ", + "timeFormat": "Format Timp", + "timeZone": "Zone Timp", + "weekStart": "Prima zi a saptamanii", + "thousandSeparator": "Separator mii", + "decimalMark": "Semn zecimal", + "defaultCurrency": "Valuta initiala", + "currencyList": "Lista valute", + "language": "Limba", + + "companyLogo": "Logo Companie", + + "smtpServer": "Server", + "smtpPort": "Port", + "smtpAuth": "Autorizare", + "smtpSecurity": "Securitate", + "smtpUsername": "Nume Utilizator", + "emailAddress": "Email", + "smtpPassword": "Parola", + "outboundEmailFromName": "De la", + "outboundEmailFromAddress": "De la adresa", + "outboundEmailIsShared": "Este Partajat", + + "recordsPerPage": "Inregistrari pe pagina", + "recordsPerPageSmall": "Records Per Page (Small)", + "tabList": "Lista Tab-uri", + "quickCreateList": "Creare lista rapida", + + "exportDelimiter": "Delimitator Export", + + "authenticationMethod": "Authentication Method", + "ldapHost": "Gazda", + "ldapPort": "Port", + "ldapAuth": "Autorizare", + "ldapUsername": "Nume Utilizator", + "ldapPassword": "Parola", + "ldapBindRequiresDn": "Bind Requires Dn", + "ldapBaseDn": "Base Dn", + "ldapAccountCanonicalForm": "Account Canonical Form", + "ldapAccountDomainName": "Account Domain Name", + "ldapTryUsernameSplit": "Try Username Split", + "ldapCreateEspoUser": "Create User in EspoCRM", + "ldapSecurity": "Securitate", + "ldapUserLoginFilter": "User Login Filter", + "ldapAccountDomainNameShort": "Account Domain Name Short", + "ldapOptReferrals": "Opt Referrals", + "disableExport": "Disable Export (only admin is allowed)" + }, + "options": { + "weekStart": { + "0": "Duminica", + "1": "Luni" + } + }, + "labels": { + "System": "Sistem", + "Locale": "Localizare", + "SMTP": "SMTP", + "Configuration": "Configuratie" + } } diff --git a/application/Espo/Resources/i18n/ro_RO/Team.json b/application/Espo/Resources/i18n/ro_RO/Team.json index 163c71b687..d2175de24b 100644 --- a/application/Espo/Resources/i18n/ro_RO/Team.json +++ b/application/Espo/Resources/i18n/ro_RO/Team.json @@ -1,12 +1,12 @@ { - "fields": { - "name": "Nume", - "roles": "Roluri" - }, - "links": { - "users": "Utilizatori" - }, - "labels": { - "Create Team": "Creare Echipa" - } + "fields": { + "name": "Nume", + "roles": "Roluri" + }, + "links": { + "users": "Utilizatori" + }, + "labels": { + "Create Team": "Creare Echipa" + } } diff --git a/application/Espo/Resources/i18n/ro_RO/User.json b/application/Espo/Resources/i18n/ro_RO/User.json index d056952a9a..7bf87d1d7d 100644 --- a/application/Espo/Resources/i18n/ro_RO/User.json +++ b/application/Espo/Resources/i18n/ro_RO/User.json @@ -1,32 +1,32 @@ { - "fields": { - "name": "Nume", - "userName": "Nume Utilizator", - "title": "Titlu", - "isAdmin": "Este Admin", - "defaultTeam": "Echipa Initiala", - "emailAddress": "Email", - "phoneNumber": "Telefon", - "roles": "Roluri", - "password": "Parola", - "passwordConfirm": "Confirmare Parola", - "newPassword": "Parola Noua" - }, - "links": { - "teams": "Echipe", - "roles": "Roluri" - }, - "labels": { - "Create User": "Creare Utilizator", - "Generate": "Generare", - "Access": "Acces", - "Preferences": "Preferinte", - "Change Password": "Schimbare Parola" - }, - "messages": { - "passwordWillBeSent": "Parola va fi trimisa in email-ul utilizatorului.", - "accountInfoEmailSubject": "Informatii cont", - "accountInfoEmailBody": "Your account information:\n\nUsername: {userName}\nPassword: {password}\n\n{siteUrl}", - "passwordChanged": "Parola a fost schimbata" - } + "fields": { + "name": "Nume", + "userName": "Nume Utilizator", + "title": "Titlu", + "isAdmin": "Este Admin", + "defaultTeam": "Echipa Initiala", + "emailAddress": "Email", + "phoneNumber": "Telefon", + "roles": "Roluri", + "password": "Parola", + "passwordConfirm": "Confirmare Parola", + "newPassword": "Parola Noua" + }, + "links": { + "teams": "Echipe", + "roles": "Roluri" + }, + "labels": { + "Create User": "Creare Utilizator", + "Generate": "Generare", + "Access": "Acces", + "Preferences": "Preferinte", + "Change Password": "Schimbare Parola" + }, + "messages": { + "passwordWillBeSent": "Parola va fi trimisa in email-ul utilizatorului.", + "accountInfoEmailSubject": "Informatii cont", + "accountInfoEmailBody": "Your account information:\n\nUsername: {userName}\nPassword: {password}\n\n{siteUrl}", + "passwordChanged": "Parola a fost schimbata" + } } diff --git a/application/Espo/Resources/i18n/ru_RU/Admin.json b/application/Espo/Resources/i18n/ru_RU/Admin.json index 2e0e205d9a..6b6f646f7a 100644 --- a/application/Espo/Resources/i18n/ru_RU/Admin.json +++ b/application/Espo/Resources/i18n/ru_RU/Admin.json @@ -1,128 +1,145 @@ { - "labels": { - "Enabled": "Enabled", - "Disabled": "Disabled", - "System": "System", - "Users": "Users", - "Email": "Email", - "Data": "Data", - "Customization": "Customization", - "Available Fields": "Available Fields", - "Layout": "Layout", - "Enabled": "Enabled", - "Disabled": "Disabled", - "Add Panel": "Add Panel", - "Add Field": "Add Field", - "Settings": "Settings", - "Scheduled Jobs": "Scheduled Jobs", - "Upgrade": "Upgrade", - "Clear Cache": "Clear Cache", - "Rebuild": "Rebuild", - "Users": "Users", - "Teams": "Teams", - "Roles": "Roles", - "Outbound Emails": "Outbound Emails", - "Inbound Emails": "Inbound Emails", - "Email Templates": "Email Templates", - "Import": "Import", - "Layout Manager": "Layout Manager", - "Field Manager": "Field Manager", - "User Interface": "User Interface", - "Auth Tokens": "Auth Tokens", - "Authentication": "Authentication", - "Currency": "Currency" - }, - "layouts": { - "list": "List", - "detail": "Detail", - "listSmall": "List (Small)", - "detailSmall": "Detail (Small)", - "filters": "Search Filters", - "massUpdate": "Mass Update", - "relationships": "Relationships" - }, - "fieldTypes": { - "address": "Address", - "array": "Array", - "foreign": "Foreign", - "duration": "Duration", - "password": "Password", - "parsonName": "Person Name", - "autoincrement": "Auto-increment", - "bool": "Bool", - "currency": "Currency", - "date": "Date", - "datetime": "DateTime", - "email": "Email", - "enum": "Enum", - "enumInt": "Enum Integer", - "enumFloat": "Enum Float", - "float": "Float", - "int": "Int", - "link": "Link", - "linkMultiple": "Link Multiple", - "linkParent": "Link Parent", - "multienim": "Multienum", - "phone": "Phone", - "text": "Text", - "url": "Url", - "varchar": "Varchar", - "file": "File", - "image": "Image" - }, - "fields": { - "type": "Type", - "name": "Name", - "label": "Label", - "required": "Required", - "default": "Default", - "maxLength": "Max Length", - "options": "Options (raw values, not translated)", - "after": "After (field)", - "before": "Before (field)", - "link": "Link", - "field": "Field", - "min": "Min", - "max": "Max", - "translation": "Translation", - "previewSize": "Preview Size" - }, - "messages": { - "upgradeVersion": "Your EspoCRM will be upgraded to version {version}. This can take some time.", - "upgradeDone": "Your EspoCRM has been upgraded to version {version}. Refresh your browser window.", - "upgradeBackup": "We recommend you to make backup of your EspoCRM files and data before upgrade.", - "thousandSeparatorEqualsDecimalMark": "Thousand separator can not be same as decimal mark", - "userHasNoEmailAddress": "User has not email address.", - "selectEntityType": "Select entity type in the left menu.", - "selectUpgradePackage": "Select uprade package", - "selectLayout": "Select needed layout in the left menu and edit it." - }, - "descriptions": { - "settings": "System settings of application.", - "scheduledJob": "Jobs which are executed by cron.", - "upgrade": "Upgrade EspoCRM.", - "clearCache": "Clear all backend cache.", - "rebuild": "Rebuild backend and clear cache.", - "users": "Users management.", - "teams": "Teams management.", - "roles": "Roles management.", - "outboundEmails": "SMTP settings for outgoing emails.", - "inboundEmails": "Group IMAP email accouts. Email import and Email-to-Case.", - "emailTemplates": "Templates for outbound emails.", - "import": "Import data from CSV file.", - "layoutManager": "Customize layouts (list, detail, edit, search, mass update).", - "fieldManager": "Create new fields or customize existing ones.", - "userInterface": "Configure UI.", - "authTokens": "Active auth sessions. IP address and last access date.", - "authentication": "Authentication settings.", - "currency": "Currency settings and rates." - }, - "options": { - "previewSize": { - "x-small": "X-Small", - "small": "Small", - "medium": "Medium", - "large": "Large" - } - } + "labels": { + "Enabled": "Enabled", + "Disabled": "Disabled", + "System": "System", + "Users": "Users", + "Email": "Email", + "Data": "Data", + "Customization": "Customization", + "Available Fields": "Available Fields", + "Layout": "Layout", + "Add Panel": "Add Panel", + "Add Field": "Add Field", + "Settings": "Settings", + "Scheduled Jobs": "Scheduled Jobs", + "Upgrade": "Upgrade", + "Clear Cache": "Clear Cache", + "Rebuild": "Rebuild", + "Teams": "Teams", + "Roles": "Роли", + "Outbound Emails": "Outbound Emails", + "Inbound Emails": "Inbound Emails", + "Email Templates": "Email Templates", + "Import": "Import", + "Layout Manager": "Layout Manager", + "Field Manager": "Field Manager", + "User Interface": "User Interface", + "Auth Tokens": "Auth Tokens", + "Authentication": "Authentication", + "Currency": "Валюта", + "Integrations": "Интеграции", + "Extensions": "Расширения", + "Upload": "Загрузить", + "Installing...": "Установка...", + "Upgrading...": "Обновление...", + "Upgraded successfully": "Обновления успешно установлены", + "Installed successfully": "Успешно установлено", + "Ready for upgrade": "Готов к обновлению", + "Run Upgrade": "Установить обновления", + "Install": "Установить", + "Ready for installation": "Готов к установке", + "Uninstalling...": "Удаление...", + "Uninstalled": "Удалено" + }, + "layouts": { + "list": "Список", + "detail": "Detail", + "listSmall": "List (Small)", + "detailSmall": "Detail (Small)", + "filters": "Search Filters", + "massUpdate": "Mass Update", + "relationships": "Relationships" + }, + "fieldTypes": { + "address": "Address", + "array": "Array", + "foreign": "Foreign", + "duration": "Duration", + "password": "Пароль", + "parsonName": "Person Name", + "autoincrement": "Auto-increment", + "bool": "Bool", + "currency": "Валюта", + "date": "Date", + "datetime": "DateTime", + "email": "Email", + "enum": "Enum", + "enumInt": "Enum Integer", + "enumFloat": "Enum Float", + "float": "Float", + "int": "Int", + "link": "Link", + "linkMultiple": "Link Multiple", + "linkParent": "Link Parent", + "multienim": "Multienum", + "phone": "Phone", + "text": "Text", + "url": "Url", + "varchar": "Varchar", + "file": "File", + "image": "Image", + "multiEnum": "Multi-Enum" + }, + "fields": { + "type": "Type", + "name": "Name", + "label": "Label", + "required": "Required", + "default": "Default", + "maxLength": "Max Length", + "options": "Options", + "after": "After (field)", + "before": "Before (field)", + "link": "Link", + "field": "Field", + "min": "Min", + "max": "Max", + "translation": "Перевод", + "previewSize": "Размер просмотра" + }, + "messages": { + "upgradeVersion": "EspoCRM будет обновлен до версии {version}. Это может занять некоторое время.", + "upgradeDone": "EspoCRM был обновлен до версии {version}. Обновите окно браузера.", + "upgradeBackup": "Мы рекомендуем перед обновлением сделать резервную копию ваших EspoCRM файлов и данных.", + "thousandSeparatorEqualsDecimalMark": "Thousand separator can not be same as decimal mark", + "userHasNoEmailAddress": "User has not email address.", + "selectEntityType": "Выберите тип сущности в меню слева.", + "selectUpgradePackage": "Выберите пакет обновления", + "downloadUpgradePackage": "Скачать необходимые обновления .", + "selectLayout": "Select needed layout in the left menu and edit it.", + "selectExtensionPackage": "Выберите пакет расширения", + "extensionInstalled": "Расширение {name} {version} установлено.", + "installExtension": "Расширение {name} {version} готово к установке.", + "uninstallConfirmation": "Вы действительно хотите удалить расширение?" + }, + "descriptions": { + "settings": "System settings of application.", + "scheduledJob": "Задачи, которые выполняются с помощью cron.", + "upgrade": "Обновить EspoCRM.", + "clearCache": "Clear all backend cache.", + "rebuild": "Rebuild backend and clear cache.", + "users": "Users management.", + "teams": "Teams management.", + "roles": "Roles management.", + "outboundEmails": "SMTP settings for outgoing emails.", + "inboundEmails": "Group IMAP email accouts. Email import and Email-to-Case.", + "emailTemplates": "Templates for outbound emails.", + "import": "Import data from CSV file.", + "layoutManager": "Customize layouts (list, detail, edit, search, mass update).", + "fieldManager": "Create new fields or customize existing ones.", + "userInterface": "Configure UI.", + "authTokens": "Active auth sessions. IP address and last access date.", + "authentication": "Настройки аутентификации.", + "currency": "Currency settings and rates.", + "extensions": "Установить или удалить расширения." + }, + "options": { + "previewSize": { + "x-small": "X-Small", + "small": "Small", + "medium": "Medium", + "large": "Large" + } + } } diff --git a/application/Espo/Resources/i18n/ru_RU/AuthToken.json b/application/Espo/Resources/i18n/ru_RU/AuthToken.json index 7dbbd53cf7..15bc98d145 100644 --- a/application/Espo/Resources/i18n/ru_RU/AuthToken.json +++ b/application/Espo/Resources/i18n/ru_RU/AuthToken.json @@ -1,9 +1,9 @@ { - "fields": { - "user": "Пользователь", - "ipAddress": "IP -адрес", - "lastAccess": "Дата последнего подключения", - "createdAt": "Дата входа" + "fields": { + "user": "Пользователь", + "ipAddress": "IP -адрес", + "lastAccess": "Дата последнего подключения", + "createdAt": "Дата входа" - } + } } diff --git a/application/Espo/Resources/i18n/ru_RU/DashletOptions.json b/application/Espo/Resources/i18n/ru_RU/DashletOptions.json new file mode 100644 index 0000000000..974906e6d0 --- /dev/null +++ b/application/Espo/Resources/i18n/ru_RU/DashletOptions.json @@ -0,0 +1,10 @@ +{ + "fields": { + "title": "Название", + "dateFrom": "Дата от", + "dateTo": "Дата к", + "autorefreshInterval": "Интервал авто-обновления", + "displayRecords": "Отобразить записи", + "isDoubleHeight": "Высота 2x" + } +} diff --git a/application/Espo/Resources/i18n/ru_RU/Email.json b/application/Espo/Resources/i18n/ru_RU/Email.json index 39b0f3b030..b0dcca519c 100644 --- a/application/Espo/Resources/i18n/ru_RU/Email.json +++ b/application/Espo/Resources/i18n/ru_RU/Email.json @@ -1,36 +1,51 @@ { - "fields": { - "name": "Тема/субъект", - "parent": "Источник", - "status": "статус", - "dateSent": "Дата отправки", - "from": "От", - "to": "К", - "cc": "CC", - "bcc": "BCC", - "isHtml": "Is Html", - "body": "Тело", - "subject": "Тема", - "attachments": "Вложения", - "selectTemplate": "Выбрать шаблон", - "fromEmailAddress": "С адреса", - "toEmailAddresses": "На андрес", - "emailAddress": "E-mail адрес" - }, - "links": { - }, - "options": { - "Draft": "Черновик", - "Sending": "Отправляется", - "Sent": "Отправлено", - "Archived": "В архиве" - }, - "labels": { - "Create Email": "Отправить письмо в архив", - "Compose": "Новое сообщение" - }, - "presetFilters": { - "sent": "Отправлено", - "archived": "В архиве" - } + "fields": { + "name": "Тема", + "parent": "Источник", + "status": "статус", + "dateSent": "Дата отправки", + "from": "От", + "to": "К", + "cc": "CC", + "bcc": "BCC", + "isHtml": "Html", + "body": "Тело", + "subject": "Тема", + "attachments": "Вложения", + "selectTemplate": "Выбрать шаблон", + "fromEmailAddress": "С адреса", + "toEmailAddresses": "На андрес", + "emailAddress": "E-mail адрес", + "deliveryDate": "Дата доставки" + }, + "links": { + }, + "options": { + "Draft": "Черновик", + "Sending": "Отправляется", + "Sent": "Отправлено", + "Archived": "В архиве" + }, + "labels": { + "Create Email": "Отправить письмо в архив", + "Archive Email": "Отправить письмо в архив", + "Compose": "Новое сообщение", + "Reply": "Ответить", + "Reply to All": "Ответить всем", + "Forward": "Переслать", + "Original message": "Оригинал сообщение", + "Forwarded message": "Forwarded message", + "Email Accounts": "Email Accounts", + "Send Test Email": "Отправить тестовое сообщение", + "Send": "Отправить", + "Email Address": "E-mail адрес" + }, + "messages": { + "noSmtpSetup": "No SMTP setup. {link}.", + "testEmailSent": "Test email has been sent" + }, + "presetFilters": { + "sent": "Отправлено", + "archived": "В архиве" + } } diff --git a/application/Espo/Resources/i18n/ru_RU/EmailAccount.json b/application/Espo/Resources/i18n/ru_RU/EmailAccount.json new file mode 100644 index 0000000000..4429369965 --- /dev/null +++ b/application/Espo/Resources/i18n/ru_RU/EmailAccount.json @@ -0,0 +1,29 @@ +{ + "fields": { + "name": "Name", + "status": "статус", + "host": "Host", + "username": "Username", + "password": "Пароль", + "port": "Порт", + "monitoredFolders": "Отслеживаемые разделы", + "ssl": "SSL", + "fetchSince": "Fetch Since" + }, + "links": { + }, + "options": { + "status": { + "Active": "Активный", + "Inactive": "Неактивный" + } + }, + "labels": { + "Create EmailAccount": "Create Email Account", + "IMAP": "IMAP", + "Main": "Main" + }, + "messages": { + "couldNotConnectToImap": "Не получается подключиться к серверу IMAP" + } +} diff --git a/application/Espo/Resources/i18n/ru_RU/EmailAddress.json b/application/Espo/Resources/i18n/ru_RU/EmailAddress.json index ed1ab64ad4..66cb46e433 100644 --- a/application/Espo/Resources/i18n/ru_RU/EmailAddress.json +++ b/application/Espo/Resources/i18n/ru_RU/EmailAddress.json @@ -1,7 +1,7 @@ { - "labels": { - "Primary": "Главные", - "Opted Out": "Отписка", - "Invalid": "Неверный адрес" - } + "labels": { + "Primary": "Главные", + "Opted Out": "Отписка", + "Invalid": "Неверный адрес" + } } diff --git a/application/Espo/Resources/i18n/ru_RU/EmailTemplate.json b/application/Espo/Resources/i18n/ru_RU/EmailTemplate.json index 378dfcd6f5..b7d0e0ecc7 100644 --- a/application/Espo/Resources/i18n/ru_RU/EmailTemplate.json +++ b/application/Espo/Resources/i18n/ru_RU/EmailTemplate.json @@ -1,16 +1,16 @@ { - "fields": { - "name": "Имя", - "status": "Статус", - "isHtml": "Html", - "body": "Основная часть", - "subject": "Тема", - "attachments": "Вложения", - "insertField": "Вставить поле" - }, - "links": { - }, - "labels": { - "Create EmailTemplate": "Создать шаблон письма" - } + "fields": { + "name": "Name", + "status": "статус", + "isHtml": "Html", + "body": "Тело", + "subject": "Тема", + "attachments": "Вложения", + "insertField": "Project-Id-Version: Russian Translation\nPOT-Creation-Date: \nPO-Revision-Date: \nLast-Translator: \nLanguage-Team: EspoCRM \nMIME-Version: 1.0\nContent-Type: text/plain; charset=UTF-8\nContent-Transfer-Encoding: 8bit\nLanguage: ru_RU\nX-Generator: Poedit 1.6.5\n" + }, + "links": { + }, + "labels": { + "Create EmailTemplate": "Создать шаблон письма" + } } diff --git a/application/Espo/Resources/i18n/ru_RU/Extension.json b/application/Espo/Resources/i18n/ru_RU/Extension.json new file mode 100644 index 0000000000..8272ec02ed --- /dev/null +++ b/application/Espo/Resources/i18n/ru_RU/Extension.json @@ -0,0 +1,15 @@ +{ + "fields": { + "name": "Name", + "version": "Версия", + "description": "Описание", + "isInstalled": "Установлен" + }, + "labels": { + "Uninstall": "Удалить", + "Install": "Установить" + }, + "messages": { + "uninstalled": "Расширение {name} удалено" + } +} diff --git a/application/Espo/Resources/i18n/ru_RU/ExternalAccount.json b/application/Espo/Resources/i18n/ru_RU/ExternalAccount.json new file mode 100644 index 0000000000..edb8e19f1d --- /dev/null +++ b/application/Espo/Resources/i18n/ru_RU/ExternalAccount.json @@ -0,0 +1,8 @@ +{ + "labels": { + "Connect": "Connect", + "Connected": "Connected" + }, + "help": { + } +} diff --git a/application/Espo/Resources/i18n/ru_RU/Global.json b/application/Espo/Resources/i18n/ru_RU/Global.json index f693948c1f..cb1be7fad6 100644 --- a/application/Espo/Resources/i18n/ru_RU/Global.json +++ b/application/Espo/Resources/i18n/ru_RU/Global.json @@ -1,422 +1,450 @@ { - "scopeNames": { - "Email": "Письмо", - "User": "Пользователь", - "Team": "Группа", - "Role": "Роль", - "EmailTemplate": "Шаблон письма", - "OutboundEmail": "Исходящее письмо", - "ScheduledJob": "Запланированная работа" - }, - "scopeNamesPlural": { - "Email": "Письма", - "User": "Пользователи", - "Team": "Группы", - "Role": "Роль", - "EmailTemplate": "Шаблоны писем", - "OutboundEmail": "Исходящие письма", - "ScheduledJob": "Запланированные задачи" - }, - "labels": {"Misc": "Разное", - "Merge": "Объединить", - "None": "Нет", - "by": "по", - "Saved": "Сохранено", - "Error": "Ошибка", - "Select": "Выбрать", - "Not valid": "Неправильный", - "Please wait...": "Пожалуйста, подождите...", - "Please wait": "Пожалуйста, подождите", - "Loading...": "Загрузка...", - "Uploading...": "Загружается...", - "Sending...": "Отправляется...", - "Removed": "Удалено", - "Posted": "Добавлено", - "Linked": "Ссылка добавлена", - "Unlinked": "Ссылка удалена", - "Access denied": "В доступе отказано", - "Access": "Доступ", - "Are you sure?": "Вы уверены?", - "Record has been removed": "Запись удалена", - "Wrong username/password": "Неверное имя пользователя/пароль", - "Post cannot be empty": "Сообщение не может быть пустым", - "Removing...": "Удаляется...", - "Unlinking...": "Ссылка удаляется...", - "Posting...": "Размещается...", - "Username can not be empty!": "Имя пользователя не может быть пустым!", - "Cache is not enabled": "Кэш не подключен", - "Cache has been cleared": "Кэш очищен", - "Rebuild has been done": "Восстановление выполнено", - "Saving...": "Сохраняется...", - "Modified": "Изменено", - "Created": "Создано", - "Create": "Создать", - "create": "создать", - "Overview": "Обзор", - "Details": "Описание", - "Add Filter": "Добавить фильтр", - "Add Dashlet": "Добавить панель", - "Add": "Добавить", - "Reset": "Сбросить", - "Menu": "Меню", - "More": "Больше", - "Search": "Искать", - "Only My": "Тлько мои", - "Open": "Открыть", - "Admin": "Администратор", - "About": "О программе", - "Refresh": "Обновить", - "Remove": "Удалить", - "Options": "Настройки", - "Username": "Имя пользователя", - "Password": "Пароль", - "Login": "Войти", - "Log Out": "Выйти", - "Preferences": "Настройки", - "State": "Регион", - "Street": "Улица", - "Country": "Страна", - "City": "Город", - "PostalCode": "Почтовый индекс", - "Followed": "Отслеживаемый", - "Follow": "Перейти", - "Clear Local Cache": "Очистить локальный кэш", - "Actions": "Действия", - "Delete": "Удалить", - "Update": "Обновить", - "Save": "Сохранить", - "Edit": "Редактировать", - "Cancel": "Отменить", - "Unlink": "Убрать ссылку", - "Mass Update": "Глобальное редактирование", - "Export": "Экспортировать", - "No Data": "Нет данных", - "All": "Все", - "Active": "Активный", - "Inactive": "Неактивный", - "Write your comment here": "Оставьте свою заметку здесь", - "Post": "Разместить", - "Stream": "Лента", - "Show more": "Загрузить еще", - "Dashlet Options": "Настройки панели", - "Full Form": "Раширенная форма", - "Insert": "Вставить", - "Person": "Личность", - "First Name": "Имя", - "Last Name": "Фамилия", - "Original": "Оригинальный", - "You": "Вы", - "you": "вы", - "change": "изменить", - "Primary": "Главная", - "Save Filters": "Сохранить фильтры", - "Administration": "Администрирование", - "Run Import": "Импортировать", - "Duplicate": "Копия", - "Notifications": "Оповещения", - "Mark all read": "Пометить все как прочитанное", - "See more": "Подробнее" - }, - "messages": { - "notModified": "Вы не внесли изменения в запись", - "duplicate": "Созданная вами запись дублировалась", - "fieldIsRequired": "{field} необходимы", - "fieldShouldBeEmail": "{field} должно быть правильным e-mail", - "fieldShouldBeFloat": "{field} должно быть верное дробное число", - "fieldShouldBeInt": "{field} должно быть верное целое число", - "fieldShouldBeDate": "{field} должна быть верная дата", - "fieldShouldBeDatetime": "{field} должна быть верная дата/время", - "fieldShouldAfter": "{field} должно быть после {otherField}", - "fieldShouldBefore": "{field} должно быть до {otherField}", - "fieldShouldBeBetween": "{field} должно быть между {min} и {max}", - "fieldShouldBeLess": "{field} должно быть меньше чем {value}", - "fieldShouldBeGreater": "{field} должно быть больше чем {value}", - "fieldBadPasswordConfirm": "{field} подтверждено неверно", - "assignmentEmailNotificationSubject": "EspoCRM {entityType}: {Entity.name}", - "assignmentEmailNotificationBody": "{assignerUserName} назначил {entityType} '{Entity.name}' на вас\n\n{recordUrl}", - "confirmation": "Вы уверены?", - "removeRecordConfirmation": "Удалить запись?", - "unlinkRecordConfirmation": "Убрать связь?", - "removeSelectedRecordsConfirmation": "Удалить выбранные записи?" - }, - "boolFilters": { - "onlyMy": "Только мои", - "open": "Открыть", - "active": "Активный" - }, - "fields": { - "name": "Полное имя", - "firstName": "Имя", - "lastName": "Фамилия", - "salutationName": "Пол", - "assignedUser": "Выбранный пользователь", - "emailAddress": "E-mail адрес", - "assignedUserName": "Имя выбранного пользователя", - "teams": "Группы", - "createdAt": "Создан в", - "modifiedAt": "Изменен в", - "createdBy": "Создан (кем)", - "modifiedBy": "Изменен (кем)", - "title": "Название", - "dateFrom": "Дата от", - "dateTo": "Дата к", - "autorefreshInterval": "Интервал авто-обновления", - "displayRecords": "Отобразить записи" - }, - "links": { - "teams": "Группы", - "users": "Пользователи" - }, - "dashlets": { - "Stream": "Лента" - }, - "streamMessages": { - "create": "{user} создал {entityType} {entity}", - "createAssigned": "{user} создал {entityType} {entity} присвоен {assignee}", - "assign": "{user} присвоено {entityType} {entity} к {assignee}", - "post": "{user} опубликован на {entityType} {entity}", - "attach": "{user} прикреплен {entityType} {entity}", - "status": "{user} обновлен {field} на {entityType} {entity}", - "update": "{user} обновлен {entityType} {entity}", - "createRelated": "{user} создан {relatedEntityType} {relatedEntity} привязан к {entityType} {entity}", - "emailReceived": "{entity} было получено для {entityType} {entity}", - - "createThis": "{user} создал это {entityType}", - "createAssignedThis": "{user} создал это {entityType} присвоен {assignee}", - "assignThis": "{user} присвоено это {entityType} к {assignee}", - "postThis": "{user} добавил", - "attachThis": "{user} добавил", - "statusThis": "{user} обновил {field}", - "updateThis": "{user} обновил это {entityType}", - "createRelatedThis": "{user} создал {relatedEntityType} {relatedEntity} привязал к этому {entityType}", - "emailReceivedThis": "{entity} было получено" - }, - "lists": { - "monthNames": ["Январь", "Февраль", "Март", "Апрель", "Май", "Июнь", "Июль", "Август", "Сентябрь", "Октябрь", "Ноябрь", "Декабрь"], - "monthNamesShort": ["Янв", "Фев", "Мар", "Апр", "Май", "Июн", "Июл", "Авг", "Сен", "Окт", "Ноя", "Дек"], - "dayNames": ["Воскресенье", "Понедельник", "Вторник", "Среда", "Четверг", "Пятница", "Суббота"], - "dayNamesShort": ["Вс", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб"], - "dayNamesMin": ["Вс", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб"] - }, - "options": { - "salutationName": { - "Mr.": "Г-н.", - "Mrs.": "Г-жа.", - "Dr.": "Д-р.", - "Drs.": "Д-р.", - "male": "Муж. ", - "female": "Жен. " - }, - "language": { - "af_ZA":"Африкаанс", - "az_AZ":"Азербайджанский", - "be_BY":"Белорусский", - "bg_BG":"Болгарский", - "bn_IN":"Бенгальский", - "bs_BA":"Боснийский", - "ca_ES":"Каталонский", - "cs_CZ":"Чешский", - "cy_GB":"Валлийский", - "da_DK":"Датский", - "de_DE":"Немецкий", - "el_GR":"Греческий", - "en_GB":"Английский (UK)", - "en_US":"Английский (US)", - "es_ES":"Испанский (Испания)", - "et_EE":"Эстонский", - "eu_ES":"Баскский", - "fa_IR":"Персидский", - "fi_FI":"Финский", - "fo_FO":"Фарерский", - "fr_CA":"Французский (Канада)", - "fr_FR":"Французский (Франция)", - "ga_IE":"Ирландский", - "gl_ES":"Галицкий", - "gn_PY":"Гуарани", - "he_IL":"Иврит", - "hi_IN":"Хинди", - "hr_HR":"Хорватский", - "hu_HU":"Венгерский", - "hy_AM":"Армянский", - "id_ID":"Индонезийский", - "is_IS":"Исландский", - "it_IT":"Итальянский", - "ja_JP":"Японский", - "ka_GE":"Грузинский", - "km_KH":"Кхмерийский", - "ko_KR":"Корейский", - "ku_TR":"Курдский", - "lt_LT":"Литовский", - "lv_LV":"Латвийский", - "mk_MK":"Македонский", - "ml_IN":"Малайялам", - "ms_MY":"Малайский", - "nb_NO":"Норвежский букмол", - "nn_NO":"Норвежский нюнорск", - "ne_NP":"Непальский", - "nl_NL":"Нидерландский", - "pa_IN":"Панджабский", - "pl_PL":"Польский", - "ps_AF":"Пушту", - "pt_BR":"Португальский (Бразилия)", - "pt_PT":"Португальский (Португалия)", - "ro_RO":"Румынский", - "ru_RU":"Русский", - "sk_SK":"Словацкий", - "sl_SI":"Словенский", - "sq_AL":"Албанский", - "sr_RS":"Сербский", - "sv_SE":"Шведский", - "sw_KE":"Суахили", - "ta_IN":"Тамильский", - "te_IN":"Телугу", - "th_TH":"Тайский", - "tl_PH":"Тагальский", - "tr_TR":"Турецкий", - "uk_UA":"Украинский", - "ur_PK":"Урду", - "vi_VN":"Вьетнамский", - "zh_CN":"Упрощенный китайский (Китай)", - "zh_HK":"Традиционный китайский (Гонконг)", - "zh_TW":"Традиционный китайский (Тайвань)" - }, - "dateSearchRanges": { - "on": "На", - "notOn": "Не на", - "after": "После", - "before": "До", - "between": "Между", - "today": "Сегодня", - "past": "Прошлое", - "future": "Будущее" - }, - "intSearchRanges": { - "equals": "Равняется", - "notEquals": "Не равняется", - "greaterThan": "Больше чем", - "lessThan": "Меньше чем", - "greaterThanOrEquals": "Больше чем или равняется", - "lessThanOrEquals": "Меньше чем или равняется", - "between": "Между" - }, - "autorefreshInterval": { - "0": "Нет", - "0.5": "30 секунд", - "1": "1 минута", - "2": "2 минуты", - "5": "5 минут", - "10": "10 минут" - }, - "phoneNumber": { - "Mobile": "Мобильный", - "Office": "Офисный", - "Fax": "Факс", - "Home": "Домашний", - "Other": "Дополнительно" - } - }, - "sets": { - "summernote": { - "NOTICE": "You can find translation here: https://github.com/HackerWins/summernote/tree/master/lang", - "font":{ - "bold": "Полужирный", + "scopeNames": { + "Email": "Email", + "User": "Пользователь", + "Team": "Группа", + "Role": "Роль", + "EmailTemplate": "Шаблон письма", + "EmailAccount": "Email Account", + "EmailAccountScope": "Email Account", + "OutboundEmail": "Исходящее письмо", + "ScheduledJob": "Запланированная работа", + "ExternalAccount": "External Account", + "Extension": "Расширение" + }, + "scopeNamesPlural": { + "Email": "Письма", + "User": "Users", + "Team": "Teams", + "Role": "Роли", + "EmailTemplate": "Email Templates", + "EmailAccount": "Email Accounts", + "EmailAccountScope": "Email Accounts", + "OutboundEmail": "Outbound Emails", + "ScheduledJob": "Scheduled Jobs", + "ExternalAccount": "External Accounts", + "Extension": "Расширения" + }, + "labels": { + "Misc": "Разное", + "Merge": "Объединить", + "None": "Нет", + "by": "по", + "Saved": "Сохранено", + "Error": "Ошибка", + "Select": "Выбрать", + "Not valid": "Неправильный", + "Please wait...": "Пожалуйста, подождите...", + "Please wait": "Пожалуйста, подождите", + "Loading...": "Загрузка...", + "Uploading...": "Загружается...", + "Sending...": "Отправляется...", + "Removed": "Удалено", + "Posted": "Добавлено", + "Linked": "Ссылка добавлена", + "Unlinked": "Ссылка удалена", + "Access denied": "В доступе отказано", + "Access": "Доступ", + "Are you sure?": "Вы уверены?", + "Record has been removed": "Запись удалена", + "Wrong username/password": "Неверное имя пользователя/пароль", + "Post cannot be empty": "Сообщение не может быть пустым", + "Removing...": "Удаляется...", + "Unlinking...": "Ссылка удаляется...", + "Posting...": "Размещается...", + "Username can not be empty!": "Имя пользователя не может быть пустым!", + "Cache is not enabled": "Кэш не подключен", + "Cache has been cleared": "Кэш очищен", + "Rebuild has been done": "Восстановление выполнено", + "Saving...": "Сохраняется...", + "Modified": "Изменено", + "Created": "Создано", + "Create": "Создать", + "create": "создать", + "Overview": "Обзор", + "Details": "Описание", + "Add Filter": "Добавить фильтр", + "Add Dashlet": "Добавить панель", + "Add": "Добавить", + "Reset": "Сбросить", + "Menu": "Меню", + "More": "Больше", + "Search": "Искать", + "Only My": "Тлько мои", + "Open": "Открыть", + "Admin": "Администратор", + "About": "О программе", + "Refresh": "Обновить", + "Remove": "Удалить", + "Options": "Options", + "Username": "Username", + "Password": "Пароль", + "Login": "Войти", + "Log Out": "Выйти", + "Preferences": "Настройки", + "State": "Регион", + "Street": "Улица", + "Country": "Страна", + "City": "Город", + "PostalCode": "Почтовый индекс", + "Followed": "Отписаться", + "Follow": "Подписаться", + "Clear Local Cache": "Очистить локальный кэш", + "Actions": "Действия", + "Delete": "Удалить", + "Update": "Обновить", + "Save": "Сохранить", + "Edit": "Редактировать", + "Cancel": "Отменить", + "Unlink": "Убрать ссылку", + "Mass Update": "Mass Update", + "Export": "Экспортировать", + "No Data": "Нет данных", + "No Access": "No Access", + "All": "Все", + "Active": "Активный", + "Inactive": "Неактивный", + "Write your comment here": "Оставьте свою заметку здесь", + "Post": "Разместить", + "Stream": "Лента", + "Show more": "Загрузить еще", + "Dashlet Options": "Настройки панели", + "Full Form": "Раширенная форма", + "Insert": "Вставить", + "Person": "Личность", + "First Name": "First Name", + "Last Name": "Фамилия", + "Original": "Оригинальный", + "You": "Вы", + "you": "вы", + "change": "изменить", + "Change": "Change", + "Primary": "Главные", + "Save Filters": "Сохранить фильтры", + "Administration": "Администрирование", + "Run Import": "Импортировать", + "Duplicate": "Копия", + "Notifications": "Оповещения", + "Mark all read": "Пометить все как прочитанное", + "See more": "Подробнее", + "Today": "Сегодня", + "Tomorrow": "Завтра", + "Yesterday": "Вчера" + }, + "messages": { + "notModified": "Вы не внесли изменения в запись", + "duplicate": "Созданная вами запись дублировалась", + "fieldIsRequired": "{field} необходимы", + "fieldShouldBeEmail": "{field} должно быть правильным e-mail", + "fieldShouldBeFloat": "{field} должно быть верное дробное число", + "fieldShouldBeInt": "{field} должно быть верное целое число", + "fieldShouldBeDate": "{field} должна быть верная дата", + "fieldShouldBeDatetime": "{field} должна быть верная дата/время", + "fieldShouldAfter": "{field} должно быть после {otherField}", + "fieldShouldBefore": "{field} должно быть до {otherField}", + "fieldShouldBeBetween": "{field} должно быть между {min} и {max}", + "fieldShouldBeLess": "{field} должно быть меньше чем {value}", + "fieldShouldBeGreater": "{field} должно быть больше чем {value}", + "fieldBadPasswordConfirm": "{field} подтверждено неверно", + "resetPreferencesDone": "Preferences has been reset to defaults", + "assignmentEmailNotificationSubject": "EspoCRM {entityType}: {Entity.name}", + "assignmentEmailNotificationBody": "{assignerUserName} назначил {entityType} '{Entity.name}' на вас\n\n{recordUrl}", + "confirmation": "Вы уверены?", + "resetPreferencesConfirmation": "Are you sure you want to reset preferences to defaults?", + "removeRecordConfirmation": "Удалить запись?", + "unlinkRecordConfirmation": "Убрать связь?", + "removeSelectedRecordsConfirmation": "Удалить выбранные записи?", + "massUpdateResult": "{count} records have been updated", + "massUpdateResultSingle": "{count} record has been updated", + "noRecordsUpdated": "No records were updated", + "massRemoveResult": "{count} records have been removed", + "massRemoveResultSingle": "{count} record has been removed", + "noRecordsRemoved": "No records were removed" + }, + "boolFilters": { + "onlyMy": "Тлько мои", + "open": "Открыть", + "active": "Активный" + }, + "fields": { + "name": "Name", + "firstName": "First Name", + "lastName": "Фамилия", + "salutationName": "Пол", + "assignedUser": "Выбранный пользователь", + "emailAddress": "Email", + "assignedUserName": "Имя выбранного пользователя", + "teams": "Teams", + "createdAt": "Создан в", + "modifiedAt": "Изменен в", + "createdBy": "Создан (кем)", + "modifiedBy": "Изменен (кем)" + }, + "links": { + "assignedUser": "Выбранный пользователь", + "createdBy": "Создан (кем)", + "modifiedBy": "Изменен (кем)", + "team": "Группа", + "roles": "Роли", + "teams": "Teams", + "users": "Users" + }, + "dashlets": { + "Stream": "Лента" + }, + "streamMessages": { + "create": "{user} создал {entityType} {entity}", + "createAssigned": "{user} создал {entityType} {entity} присвоен {assignee}", + "assign": "{user} присвоено {entityType} {entity} к {assignee}", + "post": "{user} опубликован на {entityType} {entity}", + "attach": "{user} прикреплен {entityType} {entity}", + "status": "{user} обновлен {field} на {entityType} {entity}", + "update": "{user} обновлен {entityType} {entity}", + "createRelated": "{user} создан {relatedEntityType} {relatedEntity} привязан к {entityType} {entity}", + "emailReceived": "{entity} было получено для {entityType} {entity}", + "emailReceivedInitial": "Email {email} has been received and created {entityType} {entity}", + "mentionInPost": "{user} mentioned {mentioned} on {entityType} {entity}", + + "createThis": "{user} создал это {entityType}", + "createAssignedThis": "{user} создал это {entityType} присвоен {assignee}", + "assignThis": "{user} присвоено это {entityType} к {assignee}", + "postThis": "{user} добавил", + "attachThis": "{user} attached", + "statusThis": "{user} обновил {field}", + "updateThis": "{user} обновил это {entityType}", + "createRelatedThis": "{user} создал {relatedEntityType} {relatedEntity} привязал к этому {entityType}", + "emailReceivedThis": "{entity} было получено", + "emailReceivedInitialThis": "Email {email} has been received and created this {entityType}" + }, + "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"] + }, + "options": { + "salutationName": { + "Mr.": "Г-н.", + "Mrs.": "Г-жа.", + "Dr.": "Д-р.", + "Drs.": "Drs." + }, + "language": { + "af_ZA": "Африкаанс", + "az_AZ": "Азербайджанский", + "be_BY": "Белорусский", + "bg_BG": "Болгарский", + "bn_IN": "Бенгальский", + "bs_BA": "Боснийский", + "ca_ES": "Каталонский", + "cs_CZ": "Чешский", + "cy_GB": "Валлийский", + "da_DK": "Датский", + "de_DE": "Немецкий", + "el_GR": "Греческий", + "en_GB": "Английский (UK)", + "en_US": "Английский (US)", + "es_ES": "Испанский (Испания)", + "et_EE": "Эстонский", + "eu_ES": "Баскский", + "fa_IR": "Персидский", + "fi_FI": "Финский", + "fo_FO": "Фарерский", + "fr_CA": "Французский (Канада)", + "fr_FR": "Французский (Франция)", + "ga_IE": "Ирландский", + "gl_ES": "Галицкий", + "gn_PY": "Гуарани", + "he_IL": "Иврит", + "hi_IN": "Хинди", + "hr_HR": "Хорватский", + "hu_HU": "Венгерский", + "hy_AM": "Армянский", + "id_ID": "Индонезийский", + "is_IS": "Исландский", + "it_IT": "Итальянский", + "ja_JP": "Японский", + "ka_GE": "Грузинский", + "km_KH": "Кхмерийский", + "ko_KR": "Корейский", + "ku_TR": "Курдский", + "lt_LT": "Литовский", + "lv_LV": "Латвийский", + "mk_MK": "Македонский", + "ml_IN": "Малайялам", + "ms_MY": "Малайский", + "nb_NO": "Норвежский букмол", + "nn_NO": "Норвежский нюнорск", + "ne_NP": "Непальский", + "nl_NL": "Нидерландский", + "pa_IN": "Панджабский", + "pl_PL": "Польский", + "ps_AF": "Пушту", + "pt_BR": "Португальский (Бразилия)", + "pt_PT": "Португальский (Португалия)", + "ro_RO": "Румынский", + "ru_RU": "Русский", + "sk_SK": "Словацкий", + "sl_SI": "Словенский", + "sq_AL": "Албанский", + "sr_RS": "Сербский", + "sv_SE": "Шведский", + "sw_KE": "Суахили", + "ta_IN": "Тамильский", + "te_IN": "Телугу", + "th_TH": "Тайский", + "tl_PH": "Тагальский", + "tr_TR": "Турецкий", + "uk_UA": "Украинский", + "ur_PK": "Урду", + "vi_VN": "Вьетнамский", + "zh_CN": "Упрощенный китайский (Китай)", + "zh_HK": "Традиционный китайский (Гонконг)", + "zh_TW": "Традиционный китайский (Тайвань)" + }, + "dateSearchRanges": { + "on": "На", + "notOn": "Не на", + "after": "После", + "before": "До", + "between": "Между", + "today": "Сегодня", + "past": "Прошлое", + "future": "Будущее", + "currentMonth": "Current Month", + "lastMonth": "Last Month", + "currentQuarter": "Current Quarter", + "lastQuarter": "Last Quarter", + "currentYear": "Current Year", + "lastYear": "Last Year" + }, + "intSearchRanges": { + "equals": "Равняется", + "notEquals": "Не равняется", + "greaterThan": "Больше чем", + "lessThan": "Меньше чем", + "greaterThanOrEquals": "Больше чем или равняется", + "lessThanOrEquals": "Меньше чем или равняется", + "between": "Между" + }, + "autorefreshInterval": { + "0": "Нет", + "0.5": "30 секунд", + "1": "1 минута", + "2": "2 минуты", + "5": "5 минут", + "10": "10 минут" + }, + "phoneNumber": { + "Mobile": "Мобильный", + "Office": "Офисный", + "Fax": "Факс", + "Home": "Домашний", + "Other": "Дополнительно" + } + }, + "sets": { + "summernote": { + "NOTICE": "You can find translation here: https://github.com/HackerWins/summernote/tree/master/lang", + "font":{ + "bold": "Полужирный", "italic": "Курсив", "underline": "Подчёркнутый", "strike": "Зачеркнутый", - "clear": "Убрать стили шрифта", + "clear": "Убрать стили шрифта", "height": "Высота линии", "name": "Название шрифта", "size": "Размер шрифта" - }, - "image":{ - "image": "Изображение", - "insert": "Вставить изображение", - "resizeFull": "Восстановить размер", - "resizeHalf": "Уменьшить до 50%", - "resizeQuarter": "Уменьшить до 25%", - "floatLeft": "Расположить слева", - "floatRight": "Расположить справа", - "floatNone": "Расположение по-умолчанию", - "dragImageHere": "Перетащите изображение сюда", - "selectFromFiles": "Выбрать из файлов", - "url": "URL изображения", - "remove": "Удалить изображение" - }, - "link":{ - "link": "Ссылка", + }, + "image":{ + "image": "Изображение", + "insert": "Вставить изображение", + "resizeFull": "Восстановить размер", + "resizeHalf": "Уменьшить до 50%", + "resizeQuarter": "Уменьшить до 25%", + "floatLeft": "Расположить слева", + "floatRight": "Расположить справа", + "floatNone": "Расположение по-умолчанию", + "dragImageHere": "Перетащите изображение сюда", + "selectFromFiles": "Выбрать из файлов", + "url": "URL изображения", + "remove": "Удалить изображение" + }, + "link":{ + "link": "Link", "insert": "Вставить ссылку", "unlink": "Убрать ссылку", "edit": "Редактировать", "textToDisplay": "Отображаемый текст", "url": "URL для перехода", "openInNewWindow": "Открывать в новом окне" - }, - "video":{ - "video": "Видео", - "videoLink": "Ссылка на видео", - "insert": "Вставить видео", - "url": "URL видео", - "providers": "(YouTube, Vimeo, Vine, Instagram или DailyMotion)" - }, - "table":{ - "table":"Таблица" - }, - "hr":{ - "insert":"Вставить горизонтальную линию" - }, - "style":{ - "style":"Стиль", - "normal":"Нормальный", - "blockquote":"Цитата", - "pre":"Код", - "h1":"Заголовок 1", - "h2":"Заголовок 2", - "h3":"Заголовок 3", - "h4":"Заголовок 4", - "h5":"Заголовок 5", - "h6":"Заголовок 6" - }, - "lists":{ - "unordered":"Маркированный список", - "ordered":"Нумерованный список" - }, - "options":{ - "help":"Помощь", - "fullscreen":"На весь экран", - "codeview":"Исходный код" - }, - "paragraph":{ - "paragraph": "Параграф", + }, + "video":{ + "video": "Видео", + "videoLink": "Ссылка на видео", + "insert": "Вставить видео", + "url": "URL видео", + "providers": "(YouTube, Vimeo, Vine, Instagram или DailyMotion)" + }, + "table":{ + "table": "Таблица" + }, + "hr":{ + "insert": "Вставить горизонтальную линию" + }, + "style":{ + "style": "Стиль", + "normal": "Нормальный", + "blockquote": "Цитата", + "pre": "Код", + "h1": "Заголовок 1", + "h2": "Заголовок 2", + "h3": "Заголовок 3", + "h4": "Заголовок 4", + "h5": "Заголовок 5", + "h6": "Заголовок 6" + }, + "lists":{ + "unordered": "Маркированный список", + "ordered": "Нумерованный список" + }, + "options":{ + "help": "Помощь", + "fullscreen": "На весь экран", + "codeview": "Исходный код" + }, + "paragraph":{ + "paragraph": "Параграф", "outdent": "Уменьшить отступ", "indent": "Увеличить отступ", "left": "Выровнять по левому краю", "center": "Выровнять по центру", "right": "Выровнять по правому краю", "justify": "Растянуть по ширине" - }, - "color":{ - "recent": "Последний цвет", - "more": "Еще цвета", - "background": "Цвет фона", - "foreground": "Цвет шрифта", - "transparent": "Прозрачный", - "setTransparent": "Сделать прозрачным", - "reset": "Сброс", - "resetToDefault": "Восстановить умолчания" - }, - "shortcut":{ - "shortcuts": "Сочетания клавиш", + }, + "color":{ + "recent": "Последний цвет", + "more": "Еще цвета", + "background": "Цвет фона", + "foreground": "Цвет шрифта", + "transparent": "Прозрачный", + "setTransparent": "Сделать прозрачным", + "reset": "Сбросить", + "resetToDefault": "Восстановить умолчания" + }, + "shortcut":{ + "shortcuts": "Сочетания клавиш", "close": "Закрыть", "textFormatting": "Форматирование текста", "action": "Действие", "paragraphFormatting": "Форматирование параграфа", - "documentStyle": "Стиль документа", - "extraKeys": "Дополнительные комбинации" - }, - "history":{ - "undo":"Отменить", - "redo":"Повтор" - } - } - } + "documentStyle": "Стиль документа" + }, + "history":{ + "undo":"Undo", + "redo": "Повтор" + } + } + } } diff --git a/application/Espo/Resources/i18n/ru_RU/Import.json b/application/Espo/Resources/i18n/ru_RU/Import.json new file mode 100644 index 0000000000..c65df7ea82 --- /dev/null +++ b/application/Espo/Resources/i18n/ru_RU/Import.json @@ -0,0 +1,15 @@ +{ + "labels": { + "Revert": "Revert", + "Return to Import": "Return to Import", + "Run Import": "Импортировать", + "Back": "Back", + "Field Mapping": "Field Mapping", + "Default Values": "Default Values", + "Add Field": "Add Field", + "Created": "Создано", + "Updated": "Updated", + "Result": "Result", + "Show records": "Show records" + } +} diff --git a/application/Espo/Resources/i18n/ru_RU/Integration.json b/application/Espo/Resources/i18n/ru_RU/Integration.json new file mode 100644 index 0000000000..1001dc1dda --- /dev/null +++ b/application/Espo/Resources/i18n/ru_RU/Integration.json @@ -0,0 +1,14 @@ +{ + "fields": { + "enabled": "Enabled", + "clientId": "Client ID", + "clientSecret": "Client Secret", + "redirectUri": "Redirect URI" + }, + "messages": { + "selectIntegration": "Select an integration in menu." + }, + "help": { + "Google": "

Obtain OAuth 2.0 credentials from the Google Developers Console.

Visit Google Developers Console to obtain OAuth 2.0 credentials such as a Client ID and Client Secret that are known to both Google and EspoCRM application.

" + } +} diff --git a/application/Espo/Resources/i18n/ru_RU/Note.json b/application/Espo/Resources/i18n/ru_RU/Note.json index 80a1a57a97..0b348bf481 100644 --- a/application/Espo/Resources/i18n/ru_RU/Note.json +++ b/application/Espo/Resources/i18n/ru_RU/Note.json @@ -1,6 +1,6 @@ { - "fields": { - "post": "Сообщение", - "attachments": "Вложения" - } + "fields": { + "post": "Разместить", + "attachments": "Вложения" + } } diff --git a/application/Espo/Resources/i18n/ru_RU/Preferences.json b/application/Espo/Resources/i18n/ru_RU/Preferences.json index 6f9b33a1bf..6c1d43c3fc 100644 --- a/application/Espo/Resources/i18n/ru_RU/Preferences.json +++ b/application/Espo/Resources/i18n/ru_RU/Preferences.json @@ -1,34 +1,37 @@ { - "fields": { - "dateFormat": "Формат даты", - "timeFormat": "Формат времени", - "timeZone": "Часовой пояс", - "weekStart": "Первый день недели", - "thousandSeparator": "Разделитель разрядов(тысячные)", - "decimalMark": "Десятичный знак", - "defaultCurrency": "Валюта по умолчанию", - "currencyList": "Список валют", - "language": "Язык", - - "smtpServer": "Сервер", - "smtpPort": "Порт", - "smtpAuth": "Авторизация", - "smtpSecurity": "Безопасность", - "smtpUsername": "Имя пользователя", - "emailAddress": "E-mail", - "smtpPassword": "Пароль", - "smtpEmailAddress": "Адрес e-mail", - - "exportDelimiter": "Разделитель (Перемещение)", - - "receiveAssignmentEmailNotifications": "Получать уведомления при назначении" - }, - "links": { - }, - "options": { - "weekStart": { - "0": "Воскресенье", - "1": "Понедельник" - } - } + "fields": { + "dateFormat": "Формат даты", + "timeFormat": "Формат времени", + "timeZone": "Часовой пояс", + "weekStart": "Первый день недели", + "thousandSeparator": "Разделитель разрядов(тысячные)", + "decimalMark": "Десятичный знак", + "defaultCurrency": "Валюта по умолчанию", + "currencyList": "Список валют", + "language": "Язык", + + "smtpServer": "Сервер", + "smtpPort": "Порт", + "smtpAuth": "Авторизация", + "smtpSecurity": "Безопасность", + "smtpUsername": "Username", + "emailAddress": "Email", + "smtpPassword": "Пароль", + "smtpEmailAddress": "E-mail адрес", + + "exportDelimiter": "Разделитель (Перемещение)", + + "receiveAssignmentEmailNotifications": "Получать уведомления при назначении" + }, + "links": { + }, + "options": { + "weekStart": { + "0": "Воскресенье", + "1": "Понедельник" + } + }, + "labels": { + "Notifications": "Оповещения" + } } diff --git a/application/Espo/Resources/i18n/ru_RU/Role.json b/application/Espo/Resources/i18n/ru_RU/Role.json index 159d026c77..c19be65dd0 100644 --- a/application/Espo/Resources/i18n/ru_RU/Role.json +++ b/application/Espo/Resources/i18n/ru_RU/Role.json @@ -1,35 +1,35 @@ { - "fields": { - "name": "Имя", - "roles": "Функции" - }, - "links": { - "users": "Пользователи", - "teams": "Группы" - }, - "labels": { - "Access": "Доступ", - "Create Role": "Создать роль" - }, - "options": { - "accessList": { - "not-set": "не установлен", - "enabled": "включен", - "disabled": "отключен" - }, - "levelList": { - "all": "все", - "team": "группа", - "own": "принадлежит", - "no": "нет" - } - }, - "actions": { - "read": "Чтение", - "edit": "Редактирование", - "delete": "Удаление" - }, - "messages": { - "changesAfterClearCache": "Все изменения применятся только после очистки кэша." - } + "fields": { + "name": "Name", + "roles": "Роли" + }, + "links": { + "users": "Users", + "teams": "Teams" + }, + "labels": { + "Access": "Доступ", + "Create Role": "Создать роль" + }, + "options": { + "accessList": { + "not-set": "не установлен", + "enabled": "включен", + "disabled": "отключен" + }, + "levelList": { + "all": "все", + "team": "группа", + "own": "принадлежит", + "no": "нет" + } + }, + "actions": { + "read": "Чтение", + "edit": "Редактировать", + "delete": "Удалить" + }, + "messages": { + "changesAfterClearCache": "Все изменения применятся только после очистки кэша." + } } diff --git a/application/Espo/Resources/i18n/ru_RU/ScheduledJob.json b/application/Espo/Resources/i18n/ru_RU/ScheduledJob.json index ccb69230f8..183d95d6a0 100644 --- a/application/Espo/Resources/i18n/ru_RU/ScheduledJob.json +++ b/application/Espo/Resources/i18n/ru_RU/ScheduledJob.json @@ -1,30 +1,30 @@ { - "fields": { - "name": "Имя", - "status": "Статус", - "job": "Работа", - "scheduling": "Планирование (crontab notation)" - }, - "links": { - "log": "Лог" - }, - "labels": { - "Create ScheduledJob": "Создать периодическую работу" - }, - "options": { - "job": { - "CheckInboundEmails": "Проверить входящую почту", - "Cleanup": "Очистить" - }, - "cronSetup": { - "linux": "Заметка: Добавьте эту строку в crontab - файл для запуска Планировщика Работ Espo:", - "mac": "Заметка: Добавьте эту строку в crontab - файл для запуска Планировщика Работ Espo:", - "windows": "Заметка: Создайте пакетный файл со следующими командами для запуска Планировщика Работ Espo, используя Планировщик задач Windows:", - "default": "Заметка: Добавьте эту команду в Cron-Работа (Планировщик задач):" - }, - "status": { - "Active": "Активный", - "Inactive": "Неактивный" - } - } + "fields": { + "name": "Name", + "status": "статус", + "job": "Работа", + "scheduling": "Планирование (crontab notation)" + }, + "links": { + "log": "Лог" + }, + "labels": { + "Create ScheduledJob": "Создать периодическую работу" + }, + "options": { + "job": { + "CheckInboundEmails": "Проверить входящую почту", + "Cleanup": "Очистить" + }, + "cronSetup": { + "linux": "Заметка: Добавьте эту строку в crontab - файл для запуска Планировщика Работ Espo:", + "mac": "Заметка: Добавьте эту строку в crontab - файл для запуска Планировщика Работ Espo:", + "windows": "Заметка: Создайте пакетный файл со следующими командами для запуска Планировщика Работ Espo, используя Планировщик задач Windows:", + "default": "Заметка: Добавьте эту команду в Cron-Работа (Планировщик задач):" + }, + "status": { + "Active": "Активный", + "Inactive": "Неактивный" + } + } } diff --git a/application/Espo/Resources/i18n/ru_RU/ScheduledJobLogRecord.json b/application/Espo/Resources/i18n/ru_RU/ScheduledJobLogRecord.json index 4a63acaba3..12d69f6a37 100644 --- a/application/Espo/Resources/i18n/ru_RU/ScheduledJobLogRecord.json +++ b/application/Espo/Resources/i18n/ru_RU/ScheduledJobLogRecord.json @@ -1,6 +1,6 @@ { - "fields": { - "status": "Статус", - "executionTime": "Время запуска" - } + "fields": { + "status": "статус", + "executionTime": "Время запуска" + } } diff --git a/application/Espo/Resources/i18n/ru_RU/Settings.json b/application/Espo/Resources/i18n/ru_RU/Settings.json index 0be82c0b03..e06cc1a774 100644 --- a/application/Espo/Resources/i18n/ru_RU/Settings.json +++ b/application/Espo/Resources/i18n/ru_RU/Settings.json @@ -1,76 +1,77 @@ { - "fields": { - "useCache": "Использовать кэш", - "dateFormat": "Формат даты", - "timeFormat": "Формат времени", - "timeZone": "Часовой пояс", - "weekStart": "Первый день недели", - "thousandSeparator": "Разделитель разрядов(тысячные)", - "decimalMark": "Десятичный знак", - "defaultCurrency": "Валюта по умолчанию", - "baseCurrency": "Базовая валюта", - "baseCurrency": "Базовая валюта", - "currencyRates": "Курсы обмена", - - "currencyList": "Список валют", - "language": "Язык", - - "companyLogo": "Логотип компании", - - "smtpServer": "Сервер", - "smtpPort": "Порт", - "smtpAuth": "Авторизация", - "smtpSecurity": "Безопасность", - "smtpUsername": "Имя пользователя", - "emailAddress": "E-mail", - "smtpPassword": "Пароль", - "outboundEmailFromName": "От имени", - "outboundEmailFromAddress": "От адреса", - "outboundEmailIsShared": "Может использоваться всеми пользователями", - - "recordsPerPage": "Показывать по страницам", - "recordsPerPageSmall": "Показывать по страницам (Мелкий)", - "tabList": "Вкладки", - "quickCreateList": "Быстрое создание списка", - - "exportDelimiter": "Экспортировать разделитель", - - "authenticationMethod": "Метод аутентификации", - "ldapHost": "Хост", - "ldapPort": "Порт", - "ldapAuth": "Авторизация", - "ldapUsername": "Имя пользователя", - "ldapPassword": "Пароль", - "ldapBindRequiresDn": "Привязка по домену", - "ldapBaseDn": "Базовый домен", - "ldapAccountCanonicalForm": "Стандартная форма учетной записи", - "ldapAccountDomainName": "Доменное имя учетной записи", - "ldapTryUsernameSplit": "Попробовать имя пользователя Split", - "ldapCreateEspoUser": "Создать пользователя в EspoCRM", - "ldapSecurity": "Безопасность", - "ldapUserLoginFilter": "Фильтер пользовательской авторизации", - "ldapAccountDomainNameShort": "Краткая учетная запись домена", - "ldapOptReferrals": "Opt Referrals", - "disableExport": "Отмена экпортирования (доступно только администратору)", - "assignmentEmailNotifications": "Оповещать по email при назначении", - "assignmentEmailNotificationsEntityList": "Список вещей для оповещения" - }, - "options": { - "weekStart": { - "0": "Воскресенье", - "1": "Понедельник" - } - }, - "tooltips": { - "recordsPerPageSmall": "Число записей в панелях связей." - }, - "labels": { - "System": "Система", - "Locale": "Локальные настройки", - "SMTP": "SMTP", - "Configuration": "Конфигурация", - "Notifications": "Оповещения", - "Currency Settings": "Настройки валюты", - "Currency Rtes": "Курсы обмена валюты" - } + "fields": { + "useCache": "Использовать кэш", + "dateFormat": "Формат даты", + "timeFormat": "Формат времени", + "timeZone": "Часовой пояс", + "weekStart": "Первый день недели", + "thousandSeparator": "Разделитель разрядов(тысячные)", + "decimalMark": "Десятичный знак", + "defaultCurrency": "Валюта по умолчанию", + "baseCurrency": "Базовая валюта", + "currencyRates": "Курсы обмена", + + "currencyList": "Список валют", + "language": "Язык", + + "companyLogo": "Логотип компании", + + "smtpServer": "Сервер", + "smtpPort": "Порт", + "smtpAuth": "Авторизация", + "smtpSecurity": "Безопасность", + "smtpUsername": "Username", + "emailAddress": "Email", + "smtpPassword": "Пароль", + "outboundEmailFromName": "От имени", + "outboundEmailFromAddress": "С адреса", + "outboundEmailIsShared": "Может использоваться всеми пользователями", + + "recordsPerPage": "Показывать по страницам", + "recordsPerPageSmall": "Показывать по страницам (Мелкий)", + "tabList": "Вкладки", + "quickCreateList": "Быстрое создание списка", + + "exportDelimiter": "Разделитель (Перемещение)", + + "authenticationMethod": "Метод аутентификации", + "ldapHost": "Host", + "ldapPort": "Порт", + "ldapAuth": "Авторизация", + "ldapUsername": "Username", + "ldapPassword": "Пароль", + "ldapBindRequiresDn": "Привязка по домену", + "ldapBaseDn": "Базовый домен", + "ldapAccountCanonicalForm": "Стандартная форма учетной записи", + "ldapAccountDomainName": "Доменное имя учетной записи", + "ldapTryUsernameSplit": "Попробовать имя пользователя Split", + "ldapCreateEspoUser": "Создать пользователя в EspoCRM", + "ldapSecurity": "Безопасность", + "ldapUserLoginFilter": "Фильтер пользовательской авторизации", + "ldapAccountDomainNameShort": "Краткая учетная запись домена", + "ldapOptReferrals": "Opt Referrals", + "disableExport": "Отмена экпортирования (доступно только администратору)", + "assignmentEmailNotifications": "Оповещать по email при назначении", + "assignmentEmailNotificationsEntityList": "Список вещей для оповещения", + + "b2cMode": "B2C Mode" + }, + "options": { + "weekStart": { + "0": "Воскресенье", + "1": "Понедельник" + } + }, + "tooltips": { + "recordsPerPageSmall": "Число записей в панелях связей." + }, + "labels": { + "System": "System", + "Locale": "Локальные настройки", + "SMTP": "SMTP", + "Configuration": "Конфигурация", + "Notifications": "Оповещения", + "Currency Settings": "Настройки валюты", + "Currency Rtes": "Курсы обмена валюты" + } } diff --git a/application/Espo/Resources/i18n/ru_RU/Team.json b/application/Espo/Resources/i18n/ru_RU/Team.json index 92695035bc..05ef8f6dc9 100644 --- a/application/Espo/Resources/i18n/ru_RU/Team.json +++ b/application/Espo/Resources/i18n/ru_RU/Team.json @@ -1,15 +1,15 @@ { - "fields": { - "name": "Имя", - "roles": "Роли" - }, - "links": { - "users": "Пользователи" - }, - "tooltips": { - "roles": "Все пользователи этой команды получат настройки доступа из выбранных ролей." - }, - "labels": { - "Create Team": "Создать группу" - } + "fields": { + "name": "Name", + "roles": "Роли" + }, + "links": { + "users": "Users" + }, + "tooltips": { + "roles": "Все пользователи этой команды получат настройки доступа из выбранных ролей." + }, + "labels": { + "Create Team": "Создать группу" + } } diff --git a/application/Espo/Resources/i18n/ru_RU/User.json b/application/Espo/Resources/i18n/ru_RU/User.json index ece2697562..3e6483b08c 100644 --- a/application/Espo/Resources/i18n/ru_RU/User.json +++ b/application/Espo/Resources/i18n/ru_RU/User.json @@ -1,35 +1,36 @@ { - "fields": { - "name": "Имя", - "userName": "Имя пользователя", - "title": "Название", - "isAdmin": "Администратор", - "defaultTeam": "Группа по умолчанию", - "emailAddress": "E-mail", - "phoneNumber": "Телефон", - "roles": "Роли", - "password": "Пароль", - "passwordConfirm": "Подтвердите пароль", - "newPassword": "Новый пароль" - }, - "links": { - "teams": "Группы", - "roles": "Роли" - }, - "labels": { - "Create User": "Создать пользователя", - "Generate": "Сгенерировать", - "Access": "Доступ", - "Preferences": "Преимущества", - "Change Password": "Изменить пароль" - }, - "tooltips": { - "defaultTeam": "Все записи, созданные этим пользователем, по умолчанию будут относиться к этой команде." - }, - "messages": { - "passwordWillBeSent": "Пароль будет выслан на почтовый адрес пользователя", - "accountInfoEmailSubject": "Информация об учетной записи", - "accountInfoEmailBody": "Информация о Вашей учетной записи:\n\nUsername: {userName}\nPassword: {password}\n\n{siteUrl}", - "passwordChanged": "Пароль изменен" - } + "fields": { + "name": "Name", + "userName": "Имя пользователя", + "title": "Название", + "isAdmin": "Is Admin", + "defaultTeam": "Группа по умолчанию", + "emailAddress": "Email", + "phoneNumber": "Phone", + "roles": "Роли", + "password": "Пароль", + "passwordConfirm": "Подтвердите пароль", + "newPassword": "Новый пароль" + }, + "links": { + "teams": "Teams", + "roles": "Роли" + }, + "labels": { + "Create User": "Создать пользователя", + "Generate": "Сгенерировать", + "Access": "Доступ", + "Preferences": "Настройки", + "Change Password": "Изменить пароль" + }, + "tooltips": { + "defaultTeam": "Все записи, созданные этим пользователем, по умолчанию будут относиться к этой команде.", + "userName": "Letters a-z, numbers 0-9 and underscores are allowed." + }, + "messages": { + "passwordWillBeSent": "Пароль будет выслан на почтовый адрес пользователя", + "accountInfoEmailSubject": "Информация об учетной записи", + "accountInfoEmailBody": "Информация о Вашей учетной записи:\n\nUsername: {userName}\nPassword: {password}\n\n{siteUrl}", + "passwordChanged": "Пароль изменен" + } } diff --git a/application/Espo/Resources/i18n/tr_TR/Admin.json b/application/Espo/Resources/i18n/tr_TR/Admin.json index 40b3cf6aab..042a670ee9 100644 --- a/application/Espo/Resources/i18n/tr_TR/Admin.json +++ b/application/Espo/Resources/i18n/tr_TR/Admin.json @@ -1,122 +1,119 @@ { - "labels": { - "Enabled": "Etkin", - "Disabled": "Devre Dışı", - "System": "Sistem", - "Users": "Kullanıcılar", - "Email": "Eposta", - "Data": "Veri", - "Customization": "Özelleştirme", - "Available Fields": "Uygun Alanlar", - "Layout": "Yerleşim", - "Enabled": "Etkin", - "Disabled": "Devre Dışı", - "Add Panel": "Pano Ekle", - "Add Field": "Alan Ekle", - "Settings": "Ayarlar", - "Scheduled Jobs": "Planlanmış İşler", - "Upgrade": "Yükselt", - "Clear Cache": "Önbelleği Temizle", - "Rebuild": "Onar", - "Users": "Kullanıcılar", - "Teams": "Takımlar", - "Roles": "Görevler", - "Outbound Emails": "Giden Epostalar", - "Inbound Emails": "Gelen Epostalar", - "Email Templates": "Eposta Şablonları", - "Import": "İçeri Aktar", - "Layout Manager": "Yerleşim Yönetimi", - "Field Manager": "Alan Yönetimi", - "User Interface": "Kullanıcı Arayüzü" - }, - "layouts": { - "list": "Liste", - "detail": "Detay", - "listSmall": "List (Small)", - "detailSmall": "Detail (Small)", - "filters": "Arama Filtreleri", - "massUpdate": "Çoklu Güncelleme", - "relationships": "İlişkiler" - }, - "fieldTypes": { - "address": "Adres", - "array": "Sıralama", - "foreign": "Yabancı", - "duration": "Süre", - "password": "Şifre", - "parsonName": "Kişi Adı", - "autoincrement": "Otomatik Arttırım", - "bool": "XXXX", - "currency": "Para Birimi", - "date": "Tarih", - "datetime": "TarihSaat", - "email": "Eposta", - "enum": "Sıralama", - "enumInt": "Tamsayı Sıralama", - "enumFloat": "XXXX Sıralama", - "float": "Hizalama", - "int": "Int", - "link": "Bağlantı", - "linkMultiple": "Çoklu Bağlantı", - "linkParent": "Üst Bağlantı", - "multienim": "Çoklu Sıralama", - "phone": "Telefon", - "text": "Metin", - "url": "Url", - "varchar": "Değişken Karakter", - "file": "Dosya", - "image": "Resim" - }, - "fields": { - "type": "Tür", - "name": "İsim", - "label": "Etiket", - "required": "Gerekli", - "default": "Varsayılan", - "maxLength": "Maks Uzunluk", - "options": "Options (raw values, not translated)", - "after": "After (field)", - "before": "Before (field)", - "link": "Bağlantı", - "field": "Alan", - "min": "Min", - "max": "Maks", - "translation": "Çeviri", - "previewSize": "Önizlme Boyutu" - }, - "messages": { - "upgradeVersion": "EspoCRM yazılımınız {version} sürümüne yükseltilecektir. Bu işlem birkaç dakika sürebilir.", - "upgradeDone": "EspoCRM yazılımınız {version} sürümüne yükseltilmiştir. Tarayıcı pencerenizi lütfen yenileyin..", - "upgradeBackup": "Yükseltmeden önce EspoCRM dosya ve verilerinizi yedeklemenizi öneririz.", - "thousandSeparatorEqualsDecimalMark": "Binlik ayraç ondalık ayraç ile aynı olamaz.", - "userHasNoEmailAddress": "Kullanıcı eposta adresi tanımlamamıştır.", - "selectEntityType": "Soldaki menüden birim türünü seçin.", - "selectUpgradePackage": "Yükseltme paketini seçin.", - "selectLayout": "Gerekli yerleşim düzenini sol menüden seçin ve düzenleyin." - }, - "descriptions": { - "settings": "Uygulamanın sistem ayarları.", - "scheduledJob": "Cron tarafından gerçekleştirilmiş işler.", - "upgrade": "EspoCRM i yükselt.", - "clearCache": "Tüm sunucu önbelleğini temizle.", - "rebuild": "Sunucuyu onar ve önbelleği temizle.", - "users": "Kullanıcı Yönetimi.", - "teams": "Takım Yönetimi.", - "roles": "Görev Yönetimi.", - "outboundEmails": "Giden epostalar için SMTP ayarları.", - "inboundEmails": "IMAP eposta hesaplarını grupla. Eposta içe aktarımı ve dizinleme", - "emailTemplates": "Giden eposta şablonları.", - "import": "CSV dosyasından veri aktar.", - "layoutManager": "Customize layouts (list, detail, edit, search, mass update).", - "fieldManager": "Yeni alan ekle yada varolanı düzenle.", - "userInterface": "Kullanıcı Arayğzünü ayarla." - }, - "options": { - "previewSize": { - "x-small": "Çok Küçük", - "small": "Küçük", - "medium": "Orta", - "large": "Büyük" - } - } + "labels": { + "Enabled": "Etkin", + "Disabled": "Devre Dışı", + "System": "Sistem", + "Users": "Kullanıcılar", + "Email": "Eposta", + "Data": "Veri", + "Customization": "Özelleştirme", + "Available Fields": "Uygun Alanlar", + "Layout": "Yerleşim", + "Add Panel": "Pano Ekle", + "Add Field": "Alan Ekle", + "Settings": "Ayarlar", + "Scheduled Jobs": "Planlanmış İşler", + "Upgrade": "Yükselt", + "Clear Cache": "Önbelleği Temizle", + "Rebuild": "Onar", + "Teams": "Takımlar", + "Roles": "Görevler", + "Outbound Emails": "Giden Epostalar", + "Inbound Emails": "Gelen Epostalar", + "Email Templates": "Eposta Şablonları", + "Import": "İçeri Aktar", + "Layout Manager": "Yerleşim Yönetimi", + "Field Manager": "Alan Yönetimi", + "User Interface": "Kullanıcı Arayüzü" + }, + "layouts": { + "list": "Liste", + "detail": "Detay", + "listSmall": "List (Small)", + "detailSmall": "Detail (Small)", + "filters": "Arama Filtreleri", + "massUpdate": "Çoklu Güncelleme", + "relationships": "İlişkiler" + }, + "fieldTypes": { + "address": "Adres", + "array": "Sıralama", + "foreign": "Yabancı", + "duration": "Süre", + "password": "Şifre", + "parsonName": "Kişi Adı", + "autoincrement": "Otomatik Arttırım", + "bool": "XXXX", + "currency": "Para Birimi", + "date": "Tarih", + "datetime": "TarihSaat", + "email": "Eposta", + "enum": "Sıralama", + "enumInt": "Tamsayı Sıralama", + "enumFloat": "XXXX Sıralama", + "float": "Hizalama", + "int": "Int", + "link": "Bağlantı", + "linkMultiple": "Çoklu Bağlantı", + "linkParent": "Üst Bağlantı", + "multienim": "Çoklu Sıralama", + "phone": "Telefon", + "text": "Metin", + "url": "Url", + "varchar": "Değişken Karakter", + "file": "Dosya", + "image": "Resim" + }, + "fields": { + "type": "Tür", + "name": "İsim", + "label": "Etiket", + "required": "Gerekli", + "default": "Varsayılan", + "maxLength": "Maks Uzunluk", + "options": "Options (raw values, not translated)", + "after": "After (field)", + "before": "Before (field)", + "link": "Bağlantı", + "field": "Alan", + "min": "Min", + "max": "Maks", + "translation": "Çeviri", + "previewSize": "Önizlme Boyutu" + }, + "messages": { + "upgradeVersion": "EspoCRM yazılımınız {version} sürümüne yükseltilecektir. Bu işlem birkaç dakika sürebilir.", + "upgradeDone": "EspoCRM yazılımınız {version} sürümüne yükseltilmiştir. Tarayıcı pencerenizi lütfen yenileyin..", + "upgradeBackup": "Yükseltmeden önce EspoCRM dosya ve verilerinizi yedeklemenizi öneririz.", + "thousandSeparatorEqualsDecimalMark": "Binlik ayraç ondalık ayraç ile aynı olamaz.", + "userHasNoEmailAddress": "Kullanıcı eposta adresi tanımlamamıştır.", + "selectEntityType": "Soldaki menüden birim türünü seçin.", + "selectUpgradePackage": "Yükseltme paketini seçin.", + "selectLayout": "Gerekli yerleşim düzenini sol menüden seçin ve düzenleyin." + }, + "descriptions": { + "settings": "Uygulamanın sistem ayarları.", + "scheduledJob": "Cron tarafından gerçekleştirilmiş işler.", + "upgrade": "EspoCRM i yükselt.", + "clearCache": "Tüm sunucu önbelleğini temizle.", + "rebuild": "Sunucuyu onar ve önbelleği temizle.", + "users": "Kullanıcı Yönetimi.", + "teams": "Takım Yönetimi.", + "roles": "Görev Yönetimi.", + "outboundEmails": "Giden epostalar için SMTP ayarları.", + "inboundEmails": "IMAP eposta hesaplarını grupla. Eposta içe aktarımı ve dizinleme", + "emailTemplates": "Giden eposta şablonları.", + "import": "CSV dosyasından veri aktar.", + "layoutManager": "Customize layouts (list, detail, edit, search, mass update).", + "fieldManager": "Yeni alan ekle yada varolanı düzenle.", + "userInterface": "Kullanıcı Arayğzünü ayarla." + }, + "options": { + "previewSize": { + "x-small": "Çok Küçük", + "small": "Küçük", + "medium": "Orta", + "large": "Büyük" + } + } } diff --git a/application/Espo/Resources/i18n/tr_TR/Email.json b/application/Espo/Resources/i18n/tr_TR/Email.json index 1c75797782..1bca0ce0b0 100644 --- a/application/Espo/Resources/i18n/tr_TR/Email.json +++ b/application/Espo/Resources/i18n/tr_TR/Email.json @@ -1,32 +1,32 @@ { - "fields": { - "name": "Konu", - "parent": "Üst Seçenek", - "status": "Durum", - "dateSent": "Gönderilen Tariht", - "from": "Kimden", - "to": "Kime", - "cc": "CC", - "bcc": "BCC", - "isHtml": "Html olarak gönder", - "body": "Mesaj", - "subject": "Konu", - "attachments": "Dosya Ekle", - "selectTemplate": "Şablonu Seçin", - "fromEmailAddress": "Gönderen Adresi", - "toEmailAddresses": "Alıcı Adresi", - "emailAddress": "Eposta Adresi" - }, - "links": { - }, - "options": { - "Draft": "Taslak", - "Sending": "Gönderiyor", - "Sent": "Gönderildi", - "Archived": "Arşivlendi" - }, - "labels": { - "Create Email": "Epostayı Arşivle", - "Compose": "Yeni Eposta" - } + "fields": { + "name": "Konu", + "parent": "Üst Seçenek", + "status": "Durum", + "dateSent": "Gönderilen Tariht", + "from": "Kimden", + "to": "Kime", + "cc": "CC", + "bcc": "BCC", + "isHtml": "Html olarak gönder", + "body": "Mesaj", + "subject": "Konu", + "attachments": "Dosya Ekle", + "selectTemplate": "Şablonu Seçin", + "fromEmailAddress": "Gönderen Adresi", + "toEmailAddresses": "Alıcı Adresi", + "emailAddress": "Eposta Adresi" + }, + "links": { + }, + "options": { + "Draft": "Taslak", + "Sending": "Gönderiyor", + "Sent": "Gönderildi", + "Archived": "Arşivlendi" + }, + "labels": { + "Create Email": "Epostayı Arşivle", + "Compose": "Yeni Eposta" + } } diff --git a/application/Espo/Resources/i18n/tr_TR/EmailAddress.json b/application/Espo/Resources/i18n/tr_TR/EmailAddress.json index 5b5d1254e8..4cab670c31 100644 --- a/application/Espo/Resources/i18n/tr_TR/EmailAddress.json +++ b/application/Espo/Resources/i18n/tr_TR/EmailAddress.json @@ -1,7 +1,7 @@ { - "labels": { - "Primary": "Öncelikli", - "Opted Out": "SeçildiXXX", - "Invalid": "Geçersiz" - } + "labels": { + "Primary": "Öncelikli", + "Opted Out": "SeçildiXXX", + "Invalid": "Geçersiz" + } } diff --git a/application/Espo/Resources/i18n/tr_TR/EmailTemplate.json b/application/Espo/Resources/i18n/tr_TR/EmailTemplate.json index 65907d775a..1f61a29f94 100644 --- a/application/Espo/Resources/i18n/tr_TR/EmailTemplate.json +++ b/application/Espo/Resources/i18n/tr_TR/EmailTemplate.json @@ -1,16 +1,16 @@ { - "fields": { - "name": "İsim", - "status": "Durum", - "isHtml": "Html olarak gönder", - "body": "Mesaj", - "subject": "Konu", - "attachments": "Dosya Ekle", - "insertField": "" - }, - "links": { - }, - "labels": { - "Create EmailTemplate": "Eposta Şablonu Oluştur" - } + "fields": { + "name": "İsim", + "status": "Durum", + "isHtml": "Html olarak gönder", + "body": "Mesaj", + "subject": "Konu", + "attachments": "Dosya Ekle", + "insertField": "" + }, + "links": { + }, + "labels": { + "Create EmailTemplate": "Eposta Şablonu Oluştur" + } } diff --git a/application/Espo/Resources/i18n/tr_TR/Global.json b/application/Espo/Resources/i18n/tr_TR/Global.json index 980aead1e0..5c4c8e5378 100644 --- a/application/Espo/Resources/i18n/tr_TR/Global.json +++ b/application/Espo/Resources/i18n/tr_TR/Global.json @@ -1,395 +1,395 @@ { - "scopeNames": { - "Email": "Eposta", - "User": "Kullanıcı", - "Team": "Takım", - "Role": "Görev", - "EmailTemplate": "Eposta Şablonu", - "OutboundEmail": "Giden Eposta", - "ScheduledJob": "Zamanlanmış İşler" - }, - "scopeNamesPlural": { - "Email": "Epostalar", - "User": "Kullanıcılar", - "Team": "Takımlar", - "Role": "Görevler", - "EmailTemplate": "Eposta Şablonları", - "OutboundEmail": "Giden Epostalar", - "ScheduledJob": "Planlanmış İşler" - }, - "labels": { - "Misc": "Misc", - "Merge": "Birleştir", - "None": "Hiç", - "by": "tarafından", - "Saved": "Kaydedildi", - "Error": "hata", - "Select": "Seç", - "Not valid": "Geçerli Değil", - "Please wait...": "Lütfen bekleyin...", - "Please wait": "Lütfen bekleyin", - "Loading...": "Yükleniyor...", - "Uploading...": "Yükleniyor...", - "Sending...": "Gönderiliyor...", - "Posted": "Yayınlandı", - "Linked": "Bağlantı Kuruldu", - "Unlinked": "Bağlantı Kesildi", - "Access denied": "Erişim engellendi", - "Access": "Giriş", - "Are you sure?": "Are you sure?", - "Record has been removed": "Kayıt silindi", - "Wrong username/password": "Yanlış kullanıcı adı/şifre", - "Post cannot be empty": "Yorum alanı boş bırakılamaz", - "Removing...": "Kaldırılıyor...", - "Unlinking...": "Bağlantı kesiliyor...", - "Posting...": "Yayınlanıyor...", - "Username can not be empty!": "Kullanıcı adı boş bırakılamaz!", - "Cache is not enabled": "Önbelleğe erişilemiyor", - "Cache has been cleared": "Önbellek temizlendi", - "Rebuild has been done": "Onarım tamamlandı", - "Saving...": "Kaydediliyor...", - "Modified": "Değişiklik uygulandı", - "Created": "Oluşturuldu", - "Create": "Oluştur", - "create": "oluştur", - "Overview": "Genel Bakış", - "Details": "Detaylar", - "Add Filter": "Filtre Ekle", - "Add Dashlet": "Önizleme Alanı Ekle", - "Add": "Ekle", - "Reset": "Sıfırla", - "Menu": "Menü", - "More": "Daha Fazla", - "Search": "Arama", - "Only My": "Sadece Ben", - "Open": "Aç", - "Admin": "Yönetici", - "About": "Hakkında", - "Refresh": "Yenile", - "Remove": "Kaldır", - "Options": "Seçenekler", - "Username": "Kullanıcı Adı", - "Password": "Şifre", - "Login": "Giriş", - "Log Out": "Çıkış", - "Preferences": "Seçenekler", - "State": "Semt", - "Street": "Sokak", - "Country": "Ülke", - "City": "Şehir", - "PostalCode": "Posta Kodu", - "Followed": "Takip Ediliyor", - "Follow": "Takip Et", - "Clear Local Cache": "Önbelleği Temizle", - "Actions": "Hareketler", - "Delete": "Sil", - "Update": "Güncelle", - "Save": "Kaydet", - "Edit": "Düzenle", - "Cancel": "İptal Et", - "Unlink": "Bağlantıyı Kes", - "Mass Update": "Çoklu Güncelleme", - "Export": "Dışa Aktar", - "No Data": "Veri Yok", - "All": "Tümü", - "Active": "Aktif", - "Inactive": "Pasif", - "Write your comment here": "Yorumlarınızı buraya yazın", - "Post": "Yayınla", - "Stream": "Hareket", - "Show more": "Daha fazla göster", - "Dashlet Options": "Önizleme Alanı Seçenekleri", - "Full Form": "Tam Form", - "Insert": "Ekle", - "Person": "Kişi", - "First Name": "isim", - "Last Name": "Soyisim", - "Original": "Orjinal", - "You": "Siz", - "you": "Sen", - "change": "Değiştir" - }, - "messages": { - "notModified": "Kayıdı değiştirmediniz", - "duplicate": "Oluşturmaya çalıştığınız kaydın benzer bir kopyası var", - "fieldIsRequired": "{field} gerekli", - "fieldShouldBeEmail": "{field} geçerli bir eposta adresi olmalı", - "fieldShouldBeFloat": "{field} geçerli bir FLOAT olmalı", - "fieldShouldBeInt": "{field} geçerli bir tamsayı olmalı", - "fieldShouldBeDate": "{field} geçerli bir tarih olmalı", - "fieldShouldBeDatetime": "{field} geçerli bir tarih/saat olmalı", - "fieldShouldAfter": "{field} şu değerden sonra gelmeli: {otherField}", - "fieldShouldBefore": "{field} şu değerden önce gelmeli: {otherField}", - "fieldShouldBeBetween": "{field} şu iki değer arasında olmalı: {min} ve {max}", - "fieldShouldBeLess": "{field} şu değerden daha az olmalı: {value}", - "fieldShouldBeGreater": "{field} şu değerden daha büyük olmalı: {value}", - "fieldBadPasswordConfirm": "{field} hatalı olarak onaylandı" - }, - "boolFilters": { - "onlyMy": "Sadece Ben", - "open": "Aç", - "active": "Aktif" - }, - "fields": { - "name": "İsim", - "firstName": "isim", - "lastName": "Soyisim", - "salutationName": "Hitap", - "assignedUser": "Atanan Kişi", - "emailAddress": "Eposta", - "assignedUserName": "Atanan Kişi Kullanıcı Adı", - "teams": "Takımlar", - "createdAt": "Oluşturuldu:", - "modifiedAt": "Değiştirildi:", - "createdBy": "Tarafından Oluşturuldu", - "modifiedBy": "tarafından Değiştirildi:", - "title": "Başlık", - "dateFrom": "Başlangıç Tarihi", - "dateTo": "Bitiş Tarihi", - "autorefreshInterval": "Otomatik Yenileme Süresi", - "displayRecords": "Kayıtları Göster" - }, - "links": { - "teams": "Takımlar", - "users": "Kullanıcılar" - }, - "dashlets": { - "Stream": "Hareket" - }, - "streamMessages": { - "create": "{user} oluşturdu: {entityType} {entity}", - "createAssigned": "{user} oluşturdu: {entityType} {entity} ve şuna atandı: {assignee}", - "assign": "{user} şunu: {entityType} {entity} şuna ataadı: {assignee}", - "post": "{user} {entityType} {entity} yayınladı.", - "attach": "{user} {entityType} {entity} yi ekledi.", - "status": "{user} {field} {entityType} {entity} yi güncelledi", - "update": "{user} {entityType} {entity} güncelledi.", - "createRelated": "{user} şunu oluşturdu: {relatedEntityType} {relatedEntity} ve şuna bağladı: {entityType} {entity}", - "emailReceived": "{entity} şunun için alındı: {entityType} {entity}", - - "createThis": "{user} oluşturdu: {entityType}", - "createAssignedThis": "{user} oluşturdu: {entityType} ve şuna atandı: {assignee}", - "assignThis": "{user} şunu: {entityType} şuna atadı: {assignee}", - "postThis": "{user} yayınladı", - "attachThis": "{user} ekledi", - "statusThis": "{user} güncelledi: {field}", - "updateThis": "{user} güncelledi: {entityType}", - "createRelatedThis": "{user} şunu oluşturdu: {relatedEntityType} {relatedEntity} ve şuna bağladı: {entityType}", - "emailReceivedThis": "{entity} alındı" - }, - "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"] - }, - "options": { - "salutationName": { - "Mr.": "Bay.", - "Mrs.": "Bayan.", - "Dr.": "Dr.", - "Drs.": "Drs." - }, - "language": { - "af_ZA": "Afrikaca", - "az_AZ": "Azeri Türkçesi", - "be_BY": "Rusça", - "bg_BG": "Bulgarca", - "bn_IN": "Bengalcw", - "bs_BA": "Boşnakça", - "ca_ES": "Katalanca", - "cs_CZ": "Çekce", - "cy_GB": "Galce", - "da_DK": "Danca", - "de_DE": "Almanca", - "el_GR": "Yunanca", - "en_GB":"English (UK)", - "en_US":"English (US)", - "es_ES":"Spanish (Spain)", - "et_EE": "Estonca", - "eu_ES": "Baskça", - "fa_IR": "Farsça", - "fi_FI": "Fince", - "fo_FO": "Faroese", - "fr_CA":"French (Canada)", - "fr_FR":"French (France)", - "ga_IE": "İrlandaca", - "gl_ES": "Galce", - "gn_PY": "Guarani", - "he_IL": "İbranice", - "hi_IN": "Hintçe", - "hr_HR": "Hırvatça", - "hu_HU": "Macarca", - "hy_AM": "Ermenice", - "id_ID": "Indonesian", - "is_IS": "İzlandaca", - "it_IT": "İtalyanca", - "ja_JP": "Japonca", - "ka_GE": "Gürcüce", - "km_KH": "Khmer", - "ko_KR": "Korece", - "ku_TR": "Kürtçe", - "lt_LT": "Litvanca", - "lv_LV": "Letonca", - "mk_MK": "Makedonca", - "ml_IN": "Malay", - "ms_MY": "Malay", - "nb_NO": "Norveç Bokmål", - "nn_NO": "Norwegian Nynorsk", - "ne_NP": "Nepalce", - "nl_NL": "Flemenkçe", - "pa_IN": "Punjabi", - "pl_PL": "Polca", - "ps_AF": "Pashto", - "pt_BR":"Portuguese (Brazil)", - "pt_PT":"Portuguese (Portugal)", - "ro_RO": "Rumence", - "ru_RU": "Rusça", - "sk_SK": "Slovakça", - "sl_SI": "Slovence", - "sq_AL": "Arnavutça", - "sr_RS": "Sırpça", - "sv_SE": "İsveççe", - "sw_KE": "Swahili", - "ta_IN": "Tamil", - "te_IN": "Telugu", - "th_TH": "Taicei", - "tl_PH": "Tagalog", - "tr_TR": "Türkçe", - "uk_UA": "Ukraynaca", - "ur_PK": "Urdu", - "vi_VN": "Vietnamca", - "zh_CN":"Simplified Chinese (China)", - "zh_HK":"Traditional Chinese (Hong Kong)", - "zh_TW":"Traditional Chinese (Taiwan)" - }, - "dateSearchRanges": { - "on": "Da", - "notOn": "NOT ON", - "after": "Sonra", - "before": "Önce", - "between": "Arasında" - }, - "intSearchRanges": { - "equals": "Eşit", - "notEquals": "Eşit Değil", - "greaterThan": "den Büyük", - "lessThan": "den Küçük", - "greaterThanOrEquals": "den Büyük ya da Eşit", - "lessThanOrEquals": "den Küçük ya da Eşit", - "between": "Arasında" - }, - "autorefreshInterval": { - "0": "Hiç", - "0.5": "30 saniye", - "1": "1 dakika", - "2": "2 dakika", - "5": "5 dakika", - "10": "10 dakika" - } - }, - "sets": { - "summernote": { - "NOTICE": "Çeviriyi bu adreste bulabilirsiniz: https://github.com/HackerWins/summernote/tree/master/lang", - "font":{ - "bold": "Kalın", - "italic": "İtalik", - "underline": "Altı Çizili", - "strike": "Üstü Çizili", - "clear": "Yazı Karakterini Kaldır", - "height": "Satır Yüksekliği", - "name": "Yazı Karakteri", - "size": "YazıKarakteri Boyutu" - }, - "image":{ - "image": "Resim", - "insert": "Resim Ekle", - "resizeFull": "Orjinal Boyut", - "resizeHalf": "1/2 Boyut", - "resizeQuarter": "1/4 Boyut", - "floatLeft": "Sola Hizala", - "floatRight": "Sağa Hizala", - "floatNone": "Hizalamayı Kaldır", - "dragImageHere": "Resmi buraya sürükle", - "selectFromFiles": "Dosya seç", - "url": "Resim URL", - "remove": "Resmi Kaldır" - }, - "link":{ - "link": "Bağlantı", - "insert": "Bağlantı Ekle", - "unlink": "Bağlantıyı Kes", - "edit": "Düzenle", - "textToDisplay": "Gösterilecek Metin", - "url":"To what URL should this link go?", - "openInNewWindow": "Yeni Pencerede Aç" - }, - "video":{ - "video": "Video", - "videoLink": "Video Bağlantısı", - "insert": "Video Ekle", - "url":"Video URL?", - "providers":"(YouTube, Vimeo, Vine, Instagram, or DailyMotion)" - }, - "table":{ - "table": "Tablo" - }, - "hr":{ - "insert": "Yatay Cetvel Ekle" - }, - "style":{ - "style": "Stil", - "normal": "Normal", - "blockquote": "QUOTE", - "pre": "Kod", - "h1": "Başlık 1", - "h2": "Başlık 2", - "h3": "Başlık 3", - "h4": "Başlık 4", - "h5": "Başlık 5", - "h6": "Başlık 6" - }, - "lists":{ - "unordered": "Düzenlenmemiş Liste", - "ordered": "Düzenlenmiş Liste" - }, - "options":{ - "help": "Yardım", - "fullscreen": "Tam Ekran", - "codeview": "Kod Görünümü" - }, - "paragraph":{ - "paragraph": "Paragraf", - "outdent": "Girintiyi arttır", - "indent": "Girintiyi azalt", - "left": "Sola hizala", - "center": "Ortaya hizala", - "right": "Sağa hizala", - "justify": "Tam Yasla" - }, - "color":{ - "recent": "Son Kullanılan Renk", - "more": "Daha Fazla Renk", - "background": "Arkaplan Rengi", - "foreground": "Yazı Karakteri Rengi", - "transparent": "Şeffaflık", - "setTransparent": "Şeffaflığı Ayarla", - "reset": "Sıfırla", - "resetToDefault": "Varsayılana Sıfırla" - }, - "shortcut":{ - "shortcuts": "Klavye Kısayolları", - "close": "Kapat", - "textFormatting": "Metin Biçimlendirme", - "action": "Eylem", - "paragraphFormatting": "Paragraf Biçimlendirme", - "documentStyle": "Döküman Stili" - }, - "history":{ - "undo": "Geri Al", - "redo": "Tekrrar Yap" - } - } - } + "scopeNames": { + "Email": "Eposta", + "User": "Kullanıcı", + "Team": "Takım", + "Role": "Görev", + "EmailTemplate": "Eposta Şablonu", + "OutboundEmail": "Giden Eposta", + "ScheduledJob": "Zamanlanmış İşler" + }, + "scopeNamesPlural": { + "Email": "Epostalar", + "User": "Kullanıcılar", + "Team": "Takımlar", + "Role": "Görevler", + "EmailTemplate": "Eposta Şablonları", + "OutboundEmail": "Giden Epostalar", + "ScheduledJob": "Planlanmış İşler" + }, + "labels": { + "Misc": "Misc", + "Merge": "Birleştir", + "None": "Hiç", + "by": "tarafından", + "Saved": "Kaydedildi", + "Error": "hata", + "Select": "Seç", + "Not valid": "Geçerli Değil", + "Please wait...": "Lütfen bekleyin...", + "Please wait": "Lütfen bekleyin", + "Loading...": "Yükleniyor...", + "Uploading...": "Yükleniyor...", + "Sending...": "Gönderiliyor...", + "Posted": "Yayınlandı", + "Linked": "Bağlantı Kuruldu", + "Unlinked": "Bağlantı Kesildi", + "Access denied": "Erişim engellendi", + "Access": "Giriş", + "Are you sure?": "Are you sure?", + "Record has been removed": "Kayıt silindi", + "Wrong username/password": "Yanlış kullanıcı adı/şifre", + "Post cannot be empty": "Yorum alanı boş bırakılamaz", + "Removing...": "Kaldırılıyor...", + "Unlinking...": "Bağlantı kesiliyor...", + "Posting...": "Yayınlanıyor...", + "Username can not be empty!": "Kullanıcı adı boş bırakılamaz!", + "Cache is not enabled": "Önbelleğe erişilemiyor", + "Cache has been cleared": "Önbellek temizlendi", + "Rebuild has been done": "Onarım tamamlandı", + "Saving...": "Kaydediliyor...", + "Modified": "Değişiklik uygulandı", + "Created": "Oluşturuldu", + "Create": "Oluştur", + "create": "oluştur", + "Overview": "Genel Bakış", + "Details": "Detaylar", + "Add Filter": "Filtre Ekle", + "Add Dashlet": "Önizleme Alanı Ekle", + "Add": "Ekle", + "Reset": "Sıfırla", + "Menu": "Menü", + "More": "Daha Fazla", + "Search": "Arama", + "Only My": "Sadece Ben", + "Open": "Aç", + "Admin": "Yönetici", + "About": "Hakkında", + "Refresh": "Yenile", + "Remove": "Kaldır", + "Options": "Seçenekler", + "Username": "Kullanıcı Adı", + "Password": "Şifre", + "Login": "Giriş", + "Log Out": "Çıkış", + "Preferences": "Seçenekler", + "State": "Semt", + "Street": "Sokak", + "Country": "Ülke", + "City": "Şehir", + "PostalCode": "Posta Kodu", + "Followed": "Takip Ediliyor", + "Follow": "Takip Et", + "Clear Local Cache": "Önbelleği Temizle", + "Actions": "Hareketler", + "Delete": "Sil", + "Update": "Güncelle", + "Save": "Kaydet", + "Edit": "Düzenle", + "Cancel": "İptal Et", + "Unlink": "Bağlantıyı Kes", + "Mass Update": "Çoklu Güncelleme", + "Export": "Dışa Aktar", + "No Data": "Veri Yok", + "All": "Tümü", + "Active": "Aktif", + "Inactive": "Pasif", + "Write your comment here": "Yorumlarınızı buraya yazın", + "Post": "Yayınla", + "Stream": "Hareket", + "Show more": "Daha fazla göster", + "Dashlet Options": "Önizleme Alanı Seçenekleri", + "Full Form": "Tam Form", + "Insert": "Ekle", + "Person": "Kişi", + "First Name": "isim", + "Last Name": "Soyisim", + "Original": "Orjinal", + "You": "Siz", + "you": "Sen", + "change": "Değiştir" + }, + "messages": { + "notModified": "Kayıdı değiştirmediniz", + "duplicate": "Oluşturmaya çalıştığınız kaydın benzer bir kopyası var", + "fieldIsRequired": "{field} gerekli", + "fieldShouldBeEmail": "{field} geçerli bir eposta adresi olmalı", + "fieldShouldBeFloat": "{field} geçerli bir FLOAT olmalı", + "fieldShouldBeInt": "{field} geçerli bir tamsayı olmalı", + "fieldShouldBeDate": "{field} geçerli bir tarih olmalı", + "fieldShouldBeDatetime": "{field} geçerli bir tarih/saat olmalı", + "fieldShouldAfter": "{field} şu değerden sonra gelmeli: {otherField}", + "fieldShouldBefore": "{field} şu değerden önce gelmeli: {otherField}", + "fieldShouldBeBetween": "{field} şu iki değer arasında olmalı: {min} ve {max}", + "fieldShouldBeLess": "{field} şu değerden daha az olmalı: {value}", + "fieldShouldBeGreater": "{field} şu değerden daha büyük olmalı: {value}", + "fieldBadPasswordConfirm": "{field} hatalı olarak onaylandı" + }, + "boolFilters": { + "onlyMy": "Sadece Ben", + "open": "Aç", + "active": "Aktif" + }, + "fields": { + "name": "İsim", + "firstName": "isim", + "lastName": "Soyisim", + "salutationName": "Hitap", + "assignedUser": "Atanan Kişi", + "emailAddress": "Eposta", + "assignedUserName": "Atanan Kişi Kullanıcı Adı", + "teams": "Takımlar", + "createdAt": "Oluşturuldu:", + "modifiedAt": "Değiştirildi:", + "createdBy": "Tarafından Oluşturuldu", + "modifiedBy": "tarafından Değiştirildi:", + "title": "Başlık", + "dateFrom": "Başlangıç Tarihi", + "dateTo": "Bitiş Tarihi", + "autorefreshInterval": "Otomatik Yenileme Süresi", + "displayRecords": "Kayıtları Göster" + }, + "links": { + "teams": "Takımlar", + "users": "Kullanıcılar" + }, + "dashlets": { + "Stream": "Hareket" + }, + "streamMessages": { + "create": "{user} oluşturdu: {entityType} {entity}", + "createAssigned": "{user} oluşturdu: {entityType} {entity} ve şuna atandı: {assignee}", + "assign": "{user} şunu: {entityType} {entity} şuna ataadı: {assignee}", + "post": "{user} {entityType} {entity} yayınladı.", + "attach": "{user} {entityType} {entity} yi ekledi.", + "status": "{user} {field} {entityType} {entity} yi güncelledi", + "update": "{user} {entityType} {entity} güncelledi.", + "createRelated": "{user} şunu oluşturdu: {relatedEntityType} {relatedEntity} ve şuna bağladı: {entityType} {entity}", + "emailReceived": "{entity} şunun için alındı: {entityType} {entity}", + + "createThis": "{user} oluşturdu: {entityType}", + "createAssignedThis": "{user} oluşturdu: {entityType} ve şuna atandı: {assignee}", + "assignThis": "{user} şunu: {entityType} şuna atadı: {assignee}", + "postThis": "{user} yayınladı", + "attachThis": "{user} ekledi", + "statusThis": "{user} güncelledi: {field}", + "updateThis": "{user} güncelledi: {entityType}", + "createRelatedThis": "{user} şunu oluşturdu: {relatedEntityType} {relatedEntity} ve şuna bağladı: {entityType}", + "emailReceivedThis": "{entity} alındı" + }, + "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"] + }, + "options": { + "salutationName": { + "Mr.": "Bay.", + "Mrs.": "Bayan.", + "Dr.": "Dr.", + "Drs.": "Drs." + }, + "language": { + "af_ZA": "Afrikaca", + "az_AZ": "Azeri Türkçesi", + "be_BY": "Rusça", + "bg_BG": "Bulgarca", + "bn_IN": "Bengalcw", + "bs_BA": "Boşnakça", + "ca_ES": "Katalanca", + "cs_CZ": "Çekce", + "cy_GB": "Galce", + "da_DK": "Danca", + "de_DE": "Almanca", + "el_GR": "Yunanca", + "en_GB":"English (UK)", + "en_US":"English (US)", + "es_ES":"Spanish (Spain)", + "et_EE": "Estonca", + "eu_ES": "Baskça", + "fa_IR": "Farsça", + "fi_FI": "Fince", + "fo_FO": "Faroese", + "fr_CA":"French (Canada)", + "fr_FR":"French (France)", + "ga_IE": "İrlandaca", + "gl_ES": "Galce", + "gn_PY": "Guarani", + "he_IL": "İbranice", + "hi_IN": "Hintçe", + "hr_HR": "Hırvatça", + "hu_HU": "Macarca", + "hy_AM": "Ermenice", + "id_ID": "Indonesian", + "is_IS": "İzlandaca", + "it_IT": "İtalyanca", + "ja_JP": "Japonca", + "ka_GE": "Gürcüce", + "km_KH": "Khmer", + "ko_KR": "Korece", + "ku_TR": "Kürtçe", + "lt_LT": "Litvanca", + "lv_LV": "Letonca", + "mk_MK": "Makedonca", + "ml_IN": "Malay", + "ms_MY": "Malay", + "nb_NO": "Norveç Bokmål", + "nn_NO": "Norwegian Nynorsk", + "ne_NP": "Nepalce", + "nl_NL": "Flemenkçe", + "pa_IN": "Punjabi", + "pl_PL": "Polca", + "ps_AF": "Pashto", + "pt_BR":"Portuguese (Brazil)", + "pt_PT":"Portuguese (Portugal)", + "ro_RO": "Rumence", + "ru_RU": "Rusça", + "sk_SK": "Slovakça", + "sl_SI": "Slovence", + "sq_AL": "Arnavutça", + "sr_RS": "Sırpça", + "sv_SE": "İsveççe", + "sw_KE": "Swahili", + "ta_IN": "Tamil", + "te_IN": "Telugu", + "th_TH": "Taicei", + "tl_PH": "Tagalog", + "tr_TR": "Türkçe", + "uk_UA": "Ukraynaca", + "ur_PK": "Urdu", + "vi_VN": "Vietnamca", + "zh_CN":"Simplified Chinese (China)", + "zh_HK":"Traditional Chinese (Hong Kong)", + "zh_TW":"Traditional Chinese (Taiwan)" + }, + "dateSearchRanges": { + "on": "Da", + "notOn": "NOT ON", + "after": "Sonra", + "before": "Önce", + "between": "Arasında" + }, + "intSearchRanges": { + "equals": "Eşit", + "notEquals": "Eşit Değil", + "greaterThan": "den Büyük", + "lessThan": "den Küçük", + "greaterThanOrEquals": "den Büyük ya da Eşit", + "lessThanOrEquals": "den Küçük ya da Eşit", + "between": "Arasında" + }, + "autorefreshInterval": { + "0": "Hiç", + "0.5": "30 saniye", + "1": "1 dakika", + "2": "2 dakika", + "5": "5 dakika", + "10": "10 dakika" + } + }, + "sets": { + "summernote": { + "NOTICE": "Çeviriyi bu adreste bulabilirsiniz: https://github.com/HackerWins/summernote/tree/master/lang", + "font":{ + "bold": "Kalın", + "italic": "İtalik", + "underline": "Altı Çizili", + "strike": "Üstü Çizili", + "clear": "Yazı Karakterini Kaldır", + "height": "Satır Yüksekliği", + "name": "Yazı Karakteri", + "size": "YazıKarakteri Boyutu" + }, + "image":{ + "image": "Resim", + "insert": "Resim Ekle", + "resizeFull": "Orjinal Boyut", + "resizeHalf": "1/2 Boyut", + "resizeQuarter": "1/4 Boyut", + "floatLeft": "Sola Hizala", + "floatRight": "Sağa Hizala", + "floatNone": "Hizalamayı Kaldır", + "dragImageHere": "Resmi buraya sürükle", + "selectFromFiles": "Dosya seç", + "url": "Resim URL", + "remove": "Resmi Kaldır" + }, + "link":{ + "link": "Bağlantı", + "insert": "Bağlantı Ekle", + "unlink": "Bağlantıyı Kes", + "edit": "Düzenle", + "textToDisplay": "Gösterilecek Metin", + "url":"To what URL should this link go?", + "openInNewWindow": "Yeni Pencerede Aç" + }, + "video":{ + "video": "Video", + "videoLink": "Video Bağlantısı", + "insert": "Video Ekle", + "url":"Video URL?", + "providers":"(YouTube, Vimeo, Vine, Instagram, or DailyMotion)" + }, + "table":{ + "table": "Tablo" + }, + "hr":{ + "insert": "Yatay Cetvel Ekle" + }, + "style":{ + "style": "Stil", + "normal": "Normal", + "blockquote": "QUOTE", + "pre": "Kod", + "h1": "Başlık 1", + "h2": "Başlık 2", + "h3": "Başlık 3", + "h4": "Başlık 4", + "h5": "Başlık 5", + "h6": "Başlık 6" + }, + "lists":{ + "unordered": "Düzenlenmemiş Liste", + "ordered": "Düzenlenmiş Liste" + }, + "options":{ + "help": "Yardım", + "fullscreen": "Tam Ekran", + "codeview": "Kod Görünümü" + }, + "paragraph":{ + "paragraph": "Paragraf", + "outdent": "Girintiyi arttır", + "indent": "Girintiyi azalt", + "left": "Sola hizala", + "center": "Ortaya hizala", + "right": "Sağa hizala", + "justify": "Tam Yasla" + }, + "color":{ + "recent": "Son Kullanılan Renk", + "more": "Daha Fazla Renk", + "background": "Arkaplan Rengi", + "foreground": "Yazı Karakteri Rengi", + "transparent": "Şeffaflık", + "setTransparent": "Şeffaflığı Ayarla", + "reset": "Sıfırla", + "resetToDefault": "Varsayılana Sıfırla" + }, + "shortcut":{ + "shortcuts": "Klavye Kısayolları", + "close": "Kapat", + "textFormatting": "Metin Biçimlendirme", + "action": "Eylem", + "paragraphFormatting": "Paragraf Biçimlendirme", + "documentStyle": "Döküman Stili" + }, + "history":{ + "undo": "Geri Al", + "redo": "Tekrrar Yap" + } + } + } } diff --git a/application/Espo/Resources/i18n/tr_TR/Note.json b/application/Espo/Resources/i18n/tr_TR/Note.json index 4c86ff95d3..cb3b7bc876 100644 --- a/application/Espo/Resources/i18n/tr_TR/Note.json +++ b/application/Espo/Resources/i18n/tr_TR/Note.json @@ -1,6 +1,6 @@ { - "fields": { - "post": "Yayınla", - "attachments": "Dosya Ekle" - } + "fields": { + "post": "Yayınla", + "attachments": "Dosya Ekle" + } } diff --git a/application/Espo/Resources/i18n/tr_TR/Preferences.json b/application/Espo/Resources/i18n/tr_TR/Preferences.json index a8e619c88e..9fc423649a 100644 --- a/application/Espo/Resources/i18n/tr_TR/Preferences.json +++ b/application/Espo/Resources/i18n/tr_TR/Preferences.json @@ -1,32 +1,32 @@ { - "fields": { - "dateFormat": "Tarih Biçimi", - "timeFormat": "Saat Biçimi", - "timeZone": "Zaman Dilimi", - "weekStart": "Hafta Başlangıç Günü", - "thousandSeparator": "Binlik Ayraç", - "decimalMark": "Ondalık Ayraç", - "defaultCurrency": "Varsayılan Para Birimi", - "currencyList": "para Birimi Listesi", - "language": "Dil", - - "smtpServer": "Sunucu", - "smtpPort": "Bağlantı Noktası", - "smtpAuth": "Auth", - "smtpSecurity": "Güvenlik", - "smtpUsername": "Kullanıcı Adı", - "emailAddress": "Eposta", - "smtpPassword": "Şifre", - "smtpEmailAddress": "Eposta Adresi", - - "exportDelimiter": "Export Delimiter" - }, - "links": { - }, - "options": { - "weekStart": { - "0": "Pazar", - "1": "Pazartesi" - } - } + "fields": { + "dateFormat": "Tarih Biçimi", + "timeFormat": "Saat Biçimi", + "timeZone": "Zaman Dilimi", + "weekStart": "Hafta Başlangıç Günü", + "thousandSeparator": "Binlik Ayraç", + "decimalMark": "Ondalık Ayraç", + "defaultCurrency": "Varsayılan Para Birimi", + "currencyList": "para Birimi Listesi", + "language": "Dil", + + "smtpServer": "Sunucu", + "smtpPort": "Bağlantı Noktası", + "smtpAuth": "Auth", + "smtpSecurity": "Güvenlik", + "smtpUsername": "Kullanıcı Adı", + "emailAddress": "Eposta", + "smtpPassword": "Şifre", + "smtpEmailAddress": "Eposta Adresi", + + "exportDelimiter": "Export Delimiter" + }, + "links": { + }, + "options": { + "weekStart": { + "0": "Pazar", + "1": "Pazartesi" + } + } } diff --git a/application/Espo/Resources/i18n/tr_TR/Role.json b/application/Espo/Resources/i18n/tr_TR/Role.json index 2985b643d5..186b8ad452 100644 --- a/application/Espo/Resources/i18n/tr_TR/Role.json +++ b/application/Espo/Resources/i18n/tr_TR/Role.json @@ -1,32 +1,32 @@ { - "fields": { - "name": "İsim", - "roles": "Görevler" - }, - "links": { - "users": "Kullanıcılar", - "teams": "Takımlar" - }, - "labels": { - "Access": "Giriş", - "Create Role": "Görev Oluştur" - }, - "options": { - "accessList": { - "not-set": "ayarlanmadı", - "enabled": "etkinleştirildi", - "disabled": "devre dışı bırakıldı" - }, - "levelList": { - "all": "tümü", - "team": "takım", - "own": "kendi", - "no": "NO" - } - }, - "actions": { - "read": "Oku", - "edit": "Düzenle", - "delete": "Sil" - } + "fields": { + "name": "İsim", + "roles": "Görevler" + }, + "links": { + "users": "Kullanıcılar", + "teams": "Takımlar" + }, + "labels": { + "Access": "Giriş", + "Create Role": "Görev Oluştur" + }, + "options": { + "accessList": { + "not-set": "ayarlanmadı", + "enabled": "etkinleştirildi", + "disabled": "devre dışı bırakıldı" + }, + "levelList": { + "all": "tümü", + "team": "takım", + "own": "kendi", + "no": "NO" + } + }, + "actions": { + "read": "Oku", + "edit": "Düzenle", + "delete": "Sil" + } } diff --git a/application/Espo/Resources/i18n/tr_TR/ScheduledJob.json b/application/Espo/Resources/i18n/tr_TR/ScheduledJob.json index 3ce984eda2..2cf6258c94 100644 --- a/application/Espo/Resources/i18n/tr_TR/ScheduledJob.json +++ b/application/Espo/Resources/i18n/tr_TR/ScheduledJob.json @@ -1,30 +1,30 @@ { - "fields": { - "name": "İsim", - "status": "Durum", - "job": "İş", - "scheduling": "Scheduling (crontab notation)" - }, - "links": { - "log": "Kayıt" - }, - "labels": { - "Create ScheduledJob": "Create Scheduled Job" - }, - "options": { - "job": { - "CheckInboundEmails": "Gelen Epostaları Kontrol T", - "Cleanup": "Temizle" - }, - "cronSetup": { - "linux": "Not: Espo Planlanmış İşleri çalıştırabilmek için şu kodları crontab dosyasına ekleyin:", - "mac": "Not: Espo Planlanmış İşleri çalıştırabilmek için şu kodları crontab dosyasına ekleyin:", - "windows": "Not: Espo Planlanmış İşleri Windows Scheduled Task ile kullanabilmek için şu kodlarla bir BATCH dosyası oluşturun: ", - "default": "Note: Add this command to Cron Job (Scheduled Task):" - }, - "status": { - "Active": "Aktif", - "Inactive": "Pasif" - } - } + "fields": { + "name": "İsim", + "status": "Durum", + "job": "İş", + "scheduling": "Scheduling (crontab notation)" + }, + "links": { + "log": "Kayıt" + }, + "labels": { + "Create ScheduledJob": "Create Scheduled Job" + }, + "options": { + "job": { + "CheckInboundEmails": "Gelen Epostaları Kontrol T", + "Cleanup": "Temizle" + }, + "cronSetup": { + "linux": "Not: Espo Planlanmış İşleri çalıştırabilmek için şu kodları crontab dosyasına ekleyin:", + "mac": "Not: Espo Planlanmış İşleri çalıştırabilmek için şu kodları crontab dosyasına ekleyin:", + "windows": "Not: Espo Planlanmış İşleri Windows Scheduled Task ile kullanabilmek için şu kodlarla bir BATCH dosyası oluşturun: ", + "default": "Note: Add this command to Cron Job (Scheduled Task):" + }, + "status": { + "Active": "Aktif", + "Inactive": "Pasif" + } + } } diff --git a/application/Espo/Resources/i18n/tr_TR/ScheduledJobLogRecord.json b/application/Espo/Resources/i18n/tr_TR/ScheduledJobLogRecord.json index 9421c2c2e0..2a79802fce 100644 --- a/application/Espo/Resources/i18n/tr_TR/ScheduledJobLogRecord.json +++ b/application/Espo/Resources/i18n/tr_TR/ScheduledJobLogRecord.json @@ -1,6 +1,6 @@ { - "fields": { - "status": "Durum", - "executionTime": "Çalışma Süresi" - } + "fields": { + "status": "Durum", + "executionTime": "Çalışma Süresi" + } } diff --git a/application/Espo/Resources/i18n/tr_TR/Settings.json b/application/Espo/Resources/i18n/tr_TR/Settings.json index e9fa0d2c9f..08926ad04b 100644 --- a/application/Espo/Resources/i18n/tr_TR/Settings.json +++ b/application/Espo/Resources/i18n/tr_TR/Settings.json @@ -1,46 +1,46 @@ { - "fields": { - "useCache": "Önbelleği Kullan", - "dateFormat": "Tarih Biçimi", - "timeFormat": "Saat Biçimi", - "timeZone": "Zaman Dilimi", - "weekStart": "Hafta Başlangıç Günü", - "thousandSeparator": "Binlik Ayraç", - "decimalMark": "Ondalık Ayraç", - "defaultCurrency": "Varsayılan Para Birimi", - "currencyList": "para Birimi Listesi", - "language": "Dil", - - "companyLogo": "Company Logo", - - "smtpServer": "Sunucu", - "smtpPort": "Bağlantı Noktası", - "smtpAuth": "Auth", - "smtpSecurity": "Güvenlik", - "smtpUsername": "Kullanıcı Adı", - "emailAddress": "Eposta", - "smtpPassword": "Şifre", - "outboundEmailFromName": "Kimden", - "outboundEmailFromAddress": "Gönderen Adresi", - "outboundEmailIsShared": "Paylaşıldı", - - "recordsPerPage": "Sayfa Başına Kayıtlar", - "recordsPerPageSmall": "Records Per Page (Small)", - "tabList": "Sekme Listesi", - "quickCreateList": "Çabuk Oluşturma Listesi", - - "exportDelimiter": "Export Delimiter" - }, - "options": { - "weekStart": { - "0": "Pazar", - "1": "Pazartesi" - } - }, - "labels": { - "System": "Sistem", - "Locale": "Yerel", - "SMTP": "SMTP", - "Configuration": "Yapılandırma" - } + "fields": { + "useCache": "Önbelleği Kullan", + "dateFormat": "Tarih Biçimi", + "timeFormat": "Saat Biçimi", + "timeZone": "Zaman Dilimi", + "weekStart": "Hafta Başlangıç Günü", + "thousandSeparator": "Binlik Ayraç", + "decimalMark": "Ondalık Ayraç", + "defaultCurrency": "Varsayılan Para Birimi", + "currencyList": "para Birimi Listesi", + "language": "Dil", + + "companyLogo": "Company Logo", + + "smtpServer": "Sunucu", + "smtpPort": "Bağlantı Noktası", + "smtpAuth": "Auth", + "smtpSecurity": "Güvenlik", + "smtpUsername": "Kullanıcı Adı", + "emailAddress": "Eposta", + "smtpPassword": "Şifre", + "outboundEmailFromName": "Kimden", + "outboundEmailFromAddress": "Gönderen Adresi", + "outboundEmailIsShared": "Paylaşıldı", + + "recordsPerPage": "Sayfa Başına Kayıtlar", + "recordsPerPageSmall": "Records Per Page (Small)", + "tabList": "Sekme Listesi", + "quickCreateList": "Çabuk Oluşturma Listesi", + + "exportDelimiter": "Export Delimiter" + }, + "options": { + "weekStart": { + "0": "Pazar", + "1": "Pazartesi" + } + }, + "labels": { + "System": "Sistem", + "Locale": "Yerel", + "SMTP": "SMTP", + "Configuration": "Yapılandırma" + } } diff --git a/application/Espo/Resources/i18n/tr_TR/Team.json b/application/Espo/Resources/i18n/tr_TR/Team.json index 9dafc99f9d..61eb1de415 100644 --- a/application/Espo/Resources/i18n/tr_TR/Team.json +++ b/application/Espo/Resources/i18n/tr_TR/Team.json @@ -1,12 +1,12 @@ { - "fields": { - "name": "İsim", - "roles": "Görevler" - }, - "links": { - "users": "Kullanıcılar" - }, - "labels": { - "Create Team": "Takım Oluştur" - } + "fields": { + "name": "İsim", + "roles": "Görevler" + }, + "links": { + "users": "Kullanıcılar" + }, + "labels": { + "Create Team": "Takım Oluştur" + } } diff --git a/application/Espo/Resources/i18n/tr_TR/User.json b/application/Espo/Resources/i18n/tr_TR/User.json index b292eb1421..5a8f592d7f 100644 --- a/application/Espo/Resources/i18n/tr_TR/User.json +++ b/application/Espo/Resources/i18n/tr_TR/User.json @@ -1,32 +1,32 @@ { - "fields": { - "name": "İsim", - "userName": "Kullanıcı Adı", - "title": "Başlık", - "isAdmin": "Yönetici", - "defaultTeam": "Varsayılan Takım", - "emailAddress": "Eposta", - "phone": "Telefon", - "roles": "Görevler", - "password": "Şifre", - "passwordConfirm": "Şifreyi Doğrulayın", - "newPassword": "New Password" - }, - "links": { - "teams": "Takımlar", - "roles": "Görevler" - }, - "labels": { - "Create User": "Kullanıcı Oluştur", - "Generate": "Generate", - "Access": "Giriş", - "Preferences": "Seçenekler", - "Change Password": "Change Password" - }, - "messages": { - "passwordWillBeSent": "Password will be sent to user's email address.", - "accountInfoEmailSubject": "Account info", - "accountInfoEmailBody": "Your account information:\n\nUsername: {userName}\nPassword: {password}\n\n{siteUrl}", - "passwordChanged": "Password has been changed" - } + "fields": { + "name": "İsim", + "userName": "Kullanıcı Adı", + "title": "Başlık", + "isAdmin": "Yönetici", + "defaultTeam": "Varsayılan Takım", + "emailAddress": "Eposta", + "phone": "Telefon", + "roles": "Görevler", + "password": "Şifre", + "passwordConfirm": "Şifreyi Doğrulayın", + "newPassword": "New Password" + }, + "links": { + "teams": "Takımlar", + "roles": "Görevler" + }, + "labels": { + "Create User": "Kullanıcı Oluştur", + "Generate": "Generate", + "Access": "Giriş", + "Preferences": "Seçenekler", + "Change Password": "Change Password" + }, + "messages": { + "passwordWillBeSent": "Password will be sent to user's email address.", + "accountInfoEmailSubject": "Account info", + "accountInfoEmailBody": "Your account information:\n\nUsername: {userName}\nPassword: {password}\n\n{siteUrl}", + "passwordChanged": "Password has been changed" + } } diff --git a/application/Espo/Resources/i18n/vi_VN/Admin.json b/application/Espo/Resources/i18n/vi_VN/Admin.json index 218e1fd134..fab2e5f7a7 100644 --- a/application/Espo/Resources/i18n/vi_VN/Admin.json +++ b/application/Espo/Resources/i18n/vi_VN/Admin.json @@ -1,126 +1,123 @@ { - "labels": { - "Enabled": "Bật", - "Disabled": "Tắt", - "System": "Hệ thống", - "Users": "Người dùng", - "Email": "Email", - "Data": "Dữ liệu", - "Customization": "Tùy chỉnh", - "Available Fields": "Trường hiện có", - "Layout": "Giao diện", - "Enabled": "Bật", - "Disabled": "Tắt", - "Add Panel": "Thêm bảng điều khiển", - "Add Field": "Thêm trường", - "Settings": "Cái đặt", - "Scheduled Jobs": "Công việc đã lên lịch", - "Upgrade": "Nâng cấp", - "Clear Cache": "Xóa Cache", - "Rebuild": "Dựng lại", - "Users": "Người dùng", - "Teams": "Nhóm", - "Roles": "Vai trò", - "Outbound Emails": "Email đã gửi", - "Inbound Emails": "Email đã nhận", - "Email Templates": "Mẫu email", - "Import": "Nhập", - "Layout Manager": "Quản lý giao diện", - "Field Manager": "Quản lý trường", - "User Interface": "Giao diện người dùng", - "Auth Tokens": "Auth Tokens", - "Authentication": "Xác thực" - }, - "layouts": { - "list": "Đanh sách", - "detail": "Chi tiết", - "listSmall": "List (Small)", - "detailSmall": "Detail (Small)", - "filters": "Bộ lọc tìm kiếm", - "massUpdate": "Cập nhật", - "relationships": "Quan hệ" - }, - "fieldTypes": { - "address": "Địa chỉ", - "array": "Mảng", - "foreign": "Nước ngoài", - "duration": "Thời gian", - "password": "Mật khẩu", - "parsonName": "Tên", - "autoincrement": "Tự động tăng", - "bool": "Bool", - "currency": "Tiền tệ", - "date": "Thời gian", - "datetime": "Thời gian", - "email": "Email", - "enum": "Enum", - "enumInt": "Enum Integer", - "enumFloat": "Enum Float", - "float": "Float", - "int": "Int", - "link": "Đường dẫn", - "linkMultiple": "Đa đường dẫn", - "linkParent": "Đường dẫn gốc", - "multienim": "Multienum", - "phone": "Điện thoại", - "text": "Text", - "url": "Đường dẫn", - "varchar": "Varchar", - "file": "File", - "image": "Ảnh" - }, - "fields": { - "type": "Loại", - "name": "Tên", - "label": "Thẻ", - "required": "Yêu cầu", - "default": "Mặc định", - "maxLength": "Chiều dài tối đa", - "options": "Options (raw values, not translated)", - "after": "After (field)", - "before": "Before (field)", - "link": "Đường dẫn", - "field": "Trường", - "min": "Tối thiểu", - "max": "Tối đa", - "translation": "Dịch", - "previewSize": "Kích thước cũ" - }, - "messages": { - "upgradeVersion": "Your EspoCRM will be upgraded to version {version}. This can take some time.", - "upgradeDone": "Your EspoCRM has been upgraded to version {version}. Refresh your browser window.", - "upgradeBackup": "We recommend you to make backup of your EspoCRM files and data before upgrade.", - "thousandSeparatorEqualsDecimalMark": "Dấu phân cách không thể giống nhau", - "userHasNoEmailAddress": "Người dùng chưa có địa chỉ email", - "selectEntityType": "Chọn loại ở menu bên trái", - "selectUpgradePackage": "Chọn gói nâng cấp", - "selectLayout": "Chọn giao diện cần sửa bên trái" - }, - "descriptions": { - "settings": "System settings of application.", - "scheduledJob": "Công việc tự động tiến hành", - "upgrade": "Nâng cấp hệ thống EspoCRM", - "clearCache": "Xóa dữ liệu cache.", - "rebuild": "Xóa dữ liệu và tải lại hệ thống", - "users": "Quản lý người dùng.", - "teams": "Quản lý nhóm.", - "roles": "Quản lý vai trò.", - "outboundEmails": "Tùy chỉnh SMTP để gửi email.", - "inboundEmails": "Nhóm tài khoản email IMAP. Nhập email và Email-to-Case.", - "emailTemplates": "Mẫu email gửi đi", - "import": "Nhập dữ liệu từ tệp CSV", - "layoutManager": "Customize layouts (list, detail, edit, search, mass update).", - "fieldManager": "Tạo trường mới hoặc sửa trường đã tồn tại", - "userInterface": "Chỉnh sửa giao diện.", - "authTokens": "Kích hoạt quản lý phiên làm việc. Địa chỉ IP và ngày truy cập.", - "authentication": "Cài đặt xác thực truy cập" - }, - "options": { - "previewSize": { - "x-small": "Cực nhỏ", - "small": "Nhỏ", - "medium": "Trung bình", - "large": "Lớn" - } - } + "labels": { + "Enabled": "Bật", + "Disabled": "Tắt", + "System": "Hệ thống", + "Users": "Người dùng", + "Email": "Email", + "Data": "Dữ liệu", + "Customization": "Tùy chỉnh", + "Available Fields": "Trường hiện có", + "Layout": "Giao diện", + "Add Panel": "Thêm bảng điều khiển", + "Add Field": "Thêm trường", + "Settings": "Cái đặt", + "Scheduled Jobs": "Công việc đã lên lịch", + "Upgrade": "Nâng cấp", + "Clear Cache": "Xóa Cache", + "Rebuild": "Dựng lại", + "Teams": "Nhóm", + "Roles": "Vai trò", + "Outbound Emails": "Email đã gửi", + "Inbound Emails": "Email đã nhận", + "Email Templates": "Mẫu email", + "Import": "Nhập", + "Layout Manager": "Quản lý giao diện", + "Field Manager": "Quản lý trường", + "User Interface": "Giao diện người dùng", + "Auth Tokens": "Auth Tokens", + "Authentication": "Xác thực" + }, + "layouts": { + "list": "Đanh sách", + "detail": "Chi tiết", + "listSmall": "List (Small)", + "detailSmall": "Detail (Small)", + "filters": "Bộ lọc tìm kiếm", + "massUpdate": "Cập nhật", + "relationships": "Quan hệ" + }, + "fieldTypes": { + "address": "Địa chỉ", + "array": "Mảng", + "foreign": "Nước ngoài", + "duration": "Thời gian", + "password": "Mật khẩu", + "parsonName": "Tên", + "autoincrement": "Tự động tăng", + "bool": "Bool", + "currency": "Tiền tệ", + "date": "Thời gian", + "datetime": "Thời gian", + "email": "Email", + "enum": "Enum", + "enumInt": "Enum Integer", + "enumFloat": "Enum Float", + "float": "Float", + "int": "Int", + "link": "Đường dẫn", + "linkMultiple": "Đa đường dẫn", + "linkParent": "Đường dẫn gốc", + "multienim": "Multienum", + "phone": "Điện thoại", + "text": "Text", + "url": "Đường dẫn", + "varchar": "Varchar", + "file": "File", + "image": "Ảnh" + }, + "fields": { + "type": "Loại", + "name": "Tên", + "label": "Thẻ", + "required": "Yêu cầu", + "default": "Mặc định", + "maxLength": "Chiều dài tối đa", + "options": "Options (raw values, not translated)", + "after": "After (field)", + "before": "Before (field)", + "link": "Đường dẫn", + "field": "Trường", + "min": "Tối thiểu", + "max": "Tối đa", + "translation": "Dịch", + "previewSize": "Kích thước cũ" + }, + "messages": { + "upgradeVersion": "Your EspoCRM will be upgraded to version {version}. This can take some time.", + "upgradeDone": "Your EspoCRM has been upgraded to version {version}. Refresh your browser window.", + "upgradeBackup": "We recommend you to make backup of your EspoCRM files and data before upgrade.", + "thousandSeparatorEqualsDecimalMark": "Dấu phân cách không thể giống nhau", + "userHasNoEmailAddress": "Người dùng chưa có địa chỉ email", + "selectEntityType": "Chọn loại ở menu bên trái", + "selectUpgradePackage": "Chọn gói nâng cấp", + "selectLayout": "Chọn giao diện cần sửa bên trái" + }, + "descriptions": { + "settings": "System settings of application.", + "scheduledJob": "Công việc tự động tiến hành", + "upgrade": "Nâng cấp hệ thống EspoCRM", + "clearCache": "Xóa dữ liệu cache.", + "rebuild": "Xóa dữ liệu và tải lại hệ thống", + "users": "Quản lý người dùng.", + "teams": "Quản lý nhóm.", + "roles": "Quản lý vai trò.", + "outboundEmails": "Tùy chỉnh SMTP để gửi email.", + "inboundEmails": "Nhóm tài khoản email IMAP. Nhập email và Email-to-Case.", + "emailTemplates": "Mẫu email gửi đi", + "import": "Nhập dữ liệu từ tệp CSV", + "layoutManager": "Customize layouts (list, detail, edit, search, mass update).", + "fieldManager": "Tạo trường mới hoặc sửa trường đã tồn tại", + "userInterface": "Chỉnh sửa giao diện.", + "authTokens": "Kích hoạt quản lý phiên làm việc. Địa chỉ IP và ngày truy cập.", + "authentication": "Cài đặt xác thực truy cập" + }, + "options": { + "previewSize": { + "x-small": "Cực nhỏ", + "small": "Nhỏ", + "medium": "Trung bình", + "large": "Lớn" + } + } } diff --git a/application/Espo/Resources/i18n/vi_VN/AuthToken.json b/application/Espo/Resources/i18n/vi_VN/AuthToken.json index f197c4336f..b1a00a830b 100644 --- a/application/Espo/Resources/i18n/vi_VN/AuthToken.json +++ b/application/Espo/Resources/i18n/vi_VN/AuthToken.json @@ -1,9 +1,9 @@ { - "fields": { - "user": "Người dùng", - "ipAddress": "Địa chỉ IP", - "lastAccess": "Thời gian truy cập cuối", - "createdAt": "Thời gian đăng nhập" + "fields": { + "user": "Người dùng", + "ipAddress": "Địa chỉ IP", + "lastAccess": "Thời gian truy cập cuối", + "createdAt": "Thời gian đăng nhập" - } + } } diff --git a/application/Espo/Resources/i18n/vi_VN/Email.json b/application/Espo/Resources/i18n/vi_VN/Email.json index e0af04c89b..00b987318d 100644 --- a/application/Espo/Resources/i18n/vi_VN/Email.json +++ b/application/Espo/Resources/i18n/vi_VN/Email.json @@ -1,36 +1,36 @@ { - "fields": { - "name": "Chủ đề", - "parent": "Chủ", - "status": "Trạng thái", - "dateSent": "Ngày gửi", - "from": "Từ", - "to": "Tới", - "cc": "CC", - "bcc": "BCC", - "isHtml": "Chỉ Html", - "body": "Nội dung", - "subject": "Chủ đề", - "attachments": "Đính kèm", - "selectTemplate": "Chọn mẫu", - "fromEmailAddress": "Địa chỉ gửi", - "toEmailAddresses": "Địa chỉ nhận", - "emailAddress": "Địa chỉ email" - }, - "links": { - }, - "options": { - "Draft": "Nháp", - "Sending": "Đang gửi", - "Sent": "Đã gửi", - "Archived": "Lưu trữ" - }, - "labels": { - "Create Email": "Email lưu trữ", - "Compose": "Soạn" - }, - "presetFilters": { - "sent": "Đã gửi", - "archived": "Lưu trữ" - } + "fields": { + "name": "Chủ đề", + "parent": "Chủ", + "status": "Trạng thái", + "dateSent": "Ngày gửi", + "from": "Từ", + "to": "Tới", + "cc": "CC", + "bcc": "BCC", + "isHtml": "Chỉ Html", + "body": "Nội dung", + "subject": "Chủ đề", + "attachments": "Đính kèm", + "selectTemplate": "Chọn mẫu", + "fromEmailAddress": "Địa chỉ gửi", + "toEmailAddresses": "Địa chỉ nhận", + "emailAddress": "Địa chỉ email" + }, + "links": { + }, + "options": { + "Draft": "Nháp", + "Sending": "Đang gửi", + "Sent": "Đã gửi", + "Archived": "Lưu trữ" + }, + "labels": { + "Create Email": "Email lưu trữ", + "Compose": "Soạn" + }, + "presetFilters": { + "sent": "Đã gửi", + "archived": "Lưu trữ" + } } diff --git a/application/Espo/Resources/i18n/vi_VN/EmailAddress.json b/application/Espo/Resources/i18n/vi_VN/EmailAddress.json index 10bbc55179..16a448b8b7 100644 --- a/application/Espo/Resources/i18n/vi_VN/EmailAddress.json +++ b/application/Espo/Resources/i18n/vi_VN/EmailAddress.json @@ -1,7 +1,7 @@ { - "labels": { - "Primary": "Chính", - "Opted Out": "Chọn ra", - "Invalid": "Không hợp lệ" - } + "labels": { + "Primary": "Chính", + "Opted Out": "Chọn ra", + "Invalid": "Không hợp lệ" + } } diff --git a/application/Espo/Resources/i18n/vi_VN/EmailTemplate.json b/application/Espo/Resources/i18n/vi_VN/EmailTemplate.json index aaa472515d..014f71ae2d 100644 --- a/application/Espo/Resources/i18n/vi_VN/EmailTemplate.json +++ b/application/Espo/Resources/i18n/vi_VN/EmailTemplate.json @@ -1,16 +1,16 @@ { - "fields": { - "name": "Tên", - "status": "Trạng thái", - "isHtml": "Chỉ Html", - "body": "Nội dung", - "subject": "Chủ đề", - "attachments": "Đính kèm", - "insertField": "" - }, - "links": { - }, - "labels": { - "Create EmailTemplate": "Tạo mẫu email" - } + "fields": { + "name": "Tên", + "status": "Trạng thái", + "isHtml": "Chỉ Html", + "body": "Nội dung", + "subject": "Chủ đề", + "attachments": "Đính kèm", + "insertField": "" + }, + "links": { + }, + "labels": { + "Create EmailTemplate": "Tạo mẫu email" + } } diff --git a/application/Espo/Resources/i18n/vi_VN/Global.json b/application/Espo/Resources/i18n/vi_VN/Global.json index 77ec510af2..520bf35810 100644 --- a/application/Espo/Resources/i18n/vi_VN/Global.json +++ b/application/Espo/Resources/i18n/vi_VN/Global.json @@ -1,412 +1,412 @@ { - "scopeNames": { - "Email": "Email", - "User": "Người dùng", - "Team": "Nhóm", - "Role": "Vai trò", - "EmailTemplate": "Mẫu email", - "OutboundEmail": "Email đã gửi", - "ScheduledJob": "Công việc đã lên lịch" - }, - "scopeNamesPlural": { - "Email": "Địa chỉ email", - "User": "Người dùng", - "Team": "Nhóm", - "Role": "Vai trò", - "EmailTemplate": "Mẫu email", - "OutboundEmail": "Email đã gửi", - "ScheduledJob": "Công việc đã lên lịch" - }, - "labels": { - "Misc": "Khác", - "Merge": "Gộp", - "None": "Trống", - "by": "bởi", - "Saved": "Đã lưu", - "Error": "Lỗi", - "Select": "Chọn", - "Not valid": "Không phù hợp", - "Please wait...": "Vui lòng đợi...", - "Please wait": "Vui lòng đợi", - "Loading...": "Đang tải...", - "Uploading...": "Đang tải lên...", - "Sending...": "Đang gửi...", - "Removed": "Đã xóa", - "Posted": "Đã đăng", - "Linked": "Đã liên kết", - "Unlinked": "Đã bỏ liên kết", - "Access denied": "Từ chối truy cập", - "Access": "Truy cập", - "Are you sure?": "Are you sure?", - "Record has been removed": "bản ghi đã được xóa", - "Wrong username/password": "Sai tên truy cập và mật khẩu", - "Post cannot be empty": "Nội dung không được để trống", - "Removing...": "Đang xóa...", - "Unlinking...": "Đang bỏ liên kết...", - "Posting...": "Đang gửi...", - "Username can not be empty!": "Tên đăng nhập không được để trống!", - "Cache is not enabled": "Cache không được bật", - "Cache has been cleared": "Cache đã được xóa", - "Rebuild has been done": "Tải lại thành công", - "Saving...": "Đang lưu...", - "Modified": "Đã sửa", - "Created": "Đã tạo", - "Create": "Tạo", - "create": "tạo", - "Overview": "Sơ lược", - "Details": "Chi tiết", - "Add Filter": "Thêm bộ lọc", - "Add Dashlet": "Thêm module", - "Add": "Thêm", - "Reset": "Reset", - "Menu": "Menu", - "More": "Thêm nữa", - "Search": "Tìm kiếm", - "Only My": "Chỉ", - "Open": "Mở", - "Admin": "Admin", - "About": "Thông tin", - "Refresh": "Tải lại", - "Remove": "Xóa", - "Options": "Tùy chọn", - "Username": "Tên đăng nhập", - "Password": "Mật khẩu", - "Login": "Đăng nhập", - "Log Out": "Đăng xuất", - "Preferences": "Tùy chỉnh", - "State": "Thành phố", - "Street": "Đường", - "Country": "Quốc gia", - "City": "Quận - huyện", - "PostalCode": "Mã bưu điện", - "Followed": "Đã theo dõi", - "Follow": "Theo dõi", - "Clear Local Cache": "Clear Local Cache", - "Actions": "Hoạt động", - "Delete": "Xóa", - "Update": "Cập nhật", - "Save": "Lưu", - "Edit": "Sửa", - "Cancel": "Bỏ qua", - "Unlink": "Xóa liên kết", - "Mass Update": "Cập nhật", - "Export": "Xuất", - "No Data": "Không có dữ liệu", - "All": "Tất cả", - "Active": "Đang hoạt động", - "Inactive": "Chưa hoạt động", - "Write your comment here": "Viết lời nhắn tại đây", - "Post": "Gửi", - "Stream": "Luồng", - "Show more": "Xem thêm", - "Dashlet Options": "Tùy chọn module", - "Full Form": "Đầy đủ", - "Insert": "Chèn", - "Person": "Cá nhân", - "First Name": "Tên", - "Last Name": "Họ", - "Original": "Gốc", - "You": "Bạn", - "you": "bạn", - "change": "thay đổi", - "Primary": "Chính", - "Save Filters": "Lưu bộ lọc", - "Administration": "Administration", - "Run Import": "Bắt đầu nhập", - "Duplicate": "Trùng", - "Notifications": "Thông báo" - }, - "messages": { - "notModified": "Bạn chưa sửa bản ghi", - "duplicate": "Bản ghi được tạo bị trùng", - "fieldIsRequired": "{field} là bắt buộc", - "fieldShouldBeEmail": "Kiểm tra lại {field}", - "fieldShouldBeFloat": "Kiểm tra lại {field}", - "fieldShouldBeInt": "Kiểm tra lại {field}", - "fieldShouldBeDate": "Kiểm tra lại {field}", - "fieldShouldBeDatetime": "Kiểm tra lại {field}", - "fieldShouldAfter": "{field} cần đặt sau {otherField}", - "fieldShouldBefore": "{field} cần đặt trước {otherField}", - "fieldShouldBeBetween": "{field} cần đặt giữa {min} và {max}", - "fieldShouldBeLess": "{field} cần nhỏ hơn {value}", - "fieldShouldBeGreater": "{field} cần lớn hơn {value}", - "fieldBadPasswordConfirm": "{field} không hợp lệ" - }, - "boolFilters": { - "onlyMy": "Chỉ", - "open": "Mở", - "active": "Đang hoạt động" - }, - "fields": { - "name": "Tên", - "firstName": "Tên", - "lastName": "Họ", - "salutationName": "Chào đón", - "assignedUser": "Phân công", - "emailAddress": "Email", - "assignedUserName": "Thành viên được phân công", - "teams": "Nhóm", - "createdAt": "Tạo lúc", - "modifiedAt": "Sửa lúc", - "createdBy": "Tạo bởi", - "modifiedBy": "Sửa bởi", - "title": "Tiêu đề", - "dateFrom": "Từ ngày", - "dateTo": "Tới ngày", - "autorefreshInterval": "Tự động tải lại sau", - "displayRecords": "Xem bản ghi" - }, - "links": { - "teams": "Nhóm", - "users": "Người dùng" - }, - "dashlets": { - "Stream": "Luồng" - }, - "streamMessages": { - "create": "{user} tạo {entityType} {entity}", - "createAssigned": "{user} tạo {entityType} {entity} phân công cho {assignee}", - "assign": "{user} phân công {entityType} {entity} cho {assignee}", - "post": "{user} đăng {entityType} {entity}", - "attach": "{user} đính kèm ở {entityType} {entity}", - "status": "{user} cập nhật {field} ở {entityType} {entity}", - "update": "{user} cập nhật {entityType} {entity}", - "createRelated": "{user} created {relatedEntityType} {relatedEntity} linked to {entityType} {entity}", - "emailReceived": "{entity} đã được nhận bởi {entityType} {entity}", - - "createThis": "{user} tạo {entityType}", - "createAssignedThis": "{user} tạo {entityType} phân công cho {assignee}", - "assignThis": "{user} phân công {entityType} cho {assignee}", - "postThis": "{user} đã đăng", - "attachThis": "{user} đã đính kèm", - "statusThis": "{user} đã cập nhật {field}", - "updateThis": "{user} cập nhật {entityType}", - "createRelatedThis": "{user} created {relatedEntityType} {relatedEntity} linked to this {entityType}", - "emailReceivedThis": "{entity} đã được nhận" - }, - "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"] - }, - "options": { - "salutationName": { - "Mr.": "Ông.", - "Mrs.": "Bà.", - "Dr.": "Ông.", - "Drs.": "Bà." - }, - "language": { - "af_ZA": "Afrikaans", - "az_AZ": "Azerbaijani", - "be_BY": "Belarusian", - "bg_BG": "Bulgarian", - "bn_IN": "Bengali", - "bs_BA": "Bosnian", - "ca_ES": "Catalan", - "cs_CZ": "Czech", - "cy_GB": "Welsh", - "da_DK": "Danish", - "de_DE": "German", - "el_GR": "Greek", - "en_GB":"English (UK)", - "en_US":"English (US)", - "es_ES":"Spanish (Spain)", - "et_EE": "Estonian", - "eu_ES": "Basque", - "fa_IR": "Persian", - "fi_FI": "Finnish", - "fo_FO": "Faroese", - "fr_CA":"French (Canada)", - "fr_FR":"French (France)", - "ga_IE": "Irish", - "gl_ES": "Galician", - "gn_PY": "Guarani", - "he_IL": "Hebrew", - "hi_IN": "Hindi", - "hr_HR": "Croatian", - "hu_HU": "Hungarian", - "hy_AM": "Armenian", - "id_ID": "Indonesian", - "is_IS": "Icelandic", - "it_IT": "Italian", - "ja_JP": "Japanese", - "ka_GE": "Georgian", - "km_KH": "Khmer", - "ko_KR": "Korean", - "ku_TR": "Kurdish", - "lt_LT": "Lithuanian", - "lv_LV": "Latvian", - "mk_MK": "Macedonian", - "ml_IN": "Malayalam", - "ms_MY": "Malay", - "nb_NO": "Norwegian Bokmål", - "nn_NO": "Norwegian Nynorsk", - "ne_NP": "Nepali", - "nl_NL": "Dutch", - "pa_IN": "Punjabi", - "pl_PL": "Polish", - "ps_AF": "Pashto", - "pt_BR":"Portuguese (Brazil)", - "pt_PT":"Portuguese (Portugal)", - "ro_RO": "Romanian", - "ru_RU": "Russian", - "sk_SK": "Slovak", - "sl_SI": "Slovene", - "sq_AL": "Albanian", - "sr_RS": "Serbian", - "sv_SE": "Swedish", - "sw_KE": "Swahili", - "ta_IN": "Tamil", - "te_IN": "Telugu", - "th_TH": "Thai", - "tl_PH": "Tagalog", - "tr_TR": "Turkish", - "uk_UA": "Ukrainian", - "ur_PK": "Urdu", - "vi_VN": "Vietnamese", - "zh_CN":"Simplified Chinese (China)", - "zh_HK":"Traditional Chinese (Hong Kong)", - "zh_TW":"Traditional Chinese (Taiwan)" - }, - "dateSearchRanges": { - "on": "On", - "notOn": "Not On", - "after": "After", - "before": "Before", - "between": "Between", - "today": "Today", - "past": "Past", - "future": "Future" - }, - "intSearchRanges": { - "equals": "Equals", - "notEquals": "Not Equals", - "greaterThan": "Greater Than", - "lessThan": "Less Than", - "greaterThanOrEquals": "Greater Than or Equals", - "lessThanOrEquals": "Less Than or Equals", - "between": "Between" - }, - "autorefreshInterval": { - "0": "Trống", - "0.5": "30 seconds", - "1": "1 minute", - "2": "2 minutes", - "5": "5 minutes", - "10": "10 minutes" - }, - "phoneNumber": { - "Mobile": "Mobile", - "Office": "Office", - "Fax": "Fax", - "Home": "Home", - "Other": "Khác" - } - }, - "sets": { - "summernote": { - "NOTICE": "You can find translation here: https://github.com/HackerWins/summernote/tree/master/lang", - "font":{ - "bold": "Đậm", - "italic": "Nghiêng", - "underline": "Gạch chân", - "strike": "Gạch giữa", - "clear": "Xóa định dạng", - "height": "Kích thước dòng", - "name": "Font chữ", - "size": "Kích thước" - }, - "image":{ - "image": "Ảnh", - "insert": "Chèn ảnh", - "resizeFull": "Ảnh đầy đủ", - "resizeHalf": "Giảm nửa kích thước", - "resizeQuarter": "Giảm 1/4 kích thước", - "floatLeft": "Căn trái", - "floatRight": "Căn phải", - "floatNone": "Không căn lề", - "dragImageHere": "Thả ảnh vào đây", - "selectFromFiles": "Chọn từ thư mục", - "url": "Đường dẫn ảnh", - "remove": "Xóa ảnh" - }, - "link":{ - "link": "Đường dẫn", - "insert": "Chèn đường dẫn", - "unlink": "Xóa liên kết", - "edit": "Sửa", - "textToDisplay": "Chữ hiển thị", - "url":"To what URL should this link go?", - "openInNewWindow": "Mở trong cửa sổ mới" - }, - "video":{ - "video": "Video", - "videoLink": "Đường dẫn video", - "insert": "Chèn Video", - "url":"Video URL?", - "providers":"(YouTube, Vimeo, Vine, Instagram, or DailyMotion)" - }, - "table":{ - "table": "Bảng" - }, - "hr":{ - "insert": "Thêm dòng ngang" - }, - "style":{ - "style": "Kiểu", - "normal": "Bình thường", - "blockquote": "Trích dẫn", - "pre": "Code", - "h1": "Tiêu đề 1", - "h2": "Tiêu đề 2", - "h3": "Tiêu đềTiêu đề 3", - "h4": "Tiêu đề 4", - "h5": "Tiêu đề 5", - "h6": "Tiêu đề 6" - }, - "lists":{ - "unordered": "Liệt kê", - "ordered": "Danh sách" - }, - "options":{ - "help": "Trợ giúp", - "fullscreen": "Đầy màn hình", - "codeview": "Hiển thị dạng code" - }, - "paragraph":{ - "paragraph": "Đoạn văn bản", - "outdent": "Bỏ lùi đầu dòng", - "indent": "Lùi đầu dòng", - "left": "Căn lề trái", - "center": "Căn lề giữa", - "right": "Căn lề phải", - "justify": "Căn lề 2 bên" - }, - "color":{ - "recent": "Màu đã dùng", - "more": "Thêm màu", - "background": "Màu nền", - "foreground": "Màu chữ", - "transparent": "Trong suốt", - "setTransparent": "Chỉnh độ trong suốt", - "reset": "Reset", - "resetToDefault": "Đặt lại mặc định" - }, - "shortcut":{ - "shortcuts": "Phím tắt", - "close": "Đóng", - "textFormatting": "Định dạng chữ", - "action": "Hành động", - "paragraphFormatting": "Định dạng đoạn văn bản", - "documentStyle": "Kiểu văn bản" - }, - "history":{ - "undo": "Quay lui", - "redo": "Tiến lên" - } - } - } + "scopeNames": { + "Email": "Email", + "User": "Người dùng", + "Team": "Nhóm", + "Role": "Vai trò", + "EmailTemplate": "Mẫu email", + "OutboundEmail": "Email đã gửi", + "ScheduledJob": "Công việc đã lên lịch" + }, + "scopeNamesPlural": { + "Email": "Địa chỉ email", + "User": "Người dùng", + "Team": "Nhóm", + "Role": "Vai trò", + "EmailTemplate": "Mẫu email", + "OutboundEmail": "Email đã gửi", + "ScheduledJob": "Công việc đã lên lịch" + }, + "labels": { + "Misc": "Khác", + "Merge": "Gộp", + "None": "Trống", + "by": "bởi", + "Saved": "Đã lưu", + "Error": "Lỗi", + "Select": "Chọn", + "Not valid": "Không phù hợp", + "Please wait...": "Vui lòng đợi...", + "Please wait": "Vui lòng đợi", + "Loading...": "Đang tải...", + "Uploading...": "Đang tải lên...", + "Sending...": "Đang gửi...", + "Removed": "Đã xóa", + "Posted": "Đã đăng", + "Linked": "Đã liên kết", + "Unlinked": "Đã bỏ liên kết", + "Access denied": "Từ chối truy cập", + "Access": "Truy cập", + "Are you sure?": "Are you sure?", + "Record has been removed": "bản ghi đã được xóa", + "Wrong username/password": "Sai tên truy cập và mật khẩu", + "Post cannot be empty": "Nội dung không được để trống", + "Removing...": "Đang xóa...", + "Unlinking...": "Đang bỏ liên kết...", + "Posting...": "Đang gửi...", + "Username can not be empty!": "Tên đăng nhập không được để trống!", + "Cache is not enabled": "Cache không được bật", + "Cache has been cleared": "Cache đã được xóa", + "Rebuild has been done": "Tải lại thành công", + "Saving...": "Đang lưu...", + "Modified": "Đã sửa", + "Created": "Đã tạo", + "Create": "Tạo", + "create": "tạo", + "Overview": "Sơ lược", + "Details": "Chi tiết", + "Add Filter": "Thêm bộ lọc", + "Add Dashlet": "Thêm module", + "Add": "Thêm", + "Reset": "Reset", + "Menu": "Menu", + "More": "Thêm nữa", + "Search": "Tìm kiếm", + "Only My": "Chỉ", + "Open": "Mở", + "Admin": "Admin", + "About": "Thông tin", + "Refresh": "Tải lại", + "Remove": "Xóa", + "Options": "Tùy chọn", + "Username": "Tên đăng nhập", + "Password": "Mật khẩu", + "Login": "Đăng nhập", + "Log Out": "Đăng xuất", + "Preferences": "Tùy chỉnh", + "State": "Thành phố", + "Street": "Đường", + "Country": "Quốc gia", + "City": "Quận - huyện", + "PostalCode": "Mã bưu điện", + "Followed": "Đã theo dõi", + "Follow": "Theo dõi", + "Clear Local Cache": "Clear Local Cache", + "Actions": "Hoạt động", + "Delete": "Xóa", + "Update": "Cập nhật", + "Save": "Lưu", + "Edit": "Sửa", + "Cancel": "Bỏ qua", + "Unlink": "Xóa liên kết", + "Mass Update": "Cập nhật", + "Export": "Xuất", + "No Data": "Không có dữ liệu", + "All": "Tất cả", + "Active": "Đang hoạt động", + "Inactive": "Chưa hoạt động", + "Write your comment here": "Viết lời nhắn tại đây", + "Post": "Gửi", + "Stream": "Luồng", + "Show more": "Xem thêm", + "Dashlet Options": "Tùy chọn module", + "Full Form": "Đầy đủ", + "Insert": "Chèn", + "Person": "Cá nhân", + "First Name": "Tên", + "Last Name": "Họ", + "Original": "Gốc", + "You": "Bạn", + "you": "bạn", + "change": "thay đổi", + "Primary": "Chính", + "Save Filters": "Lưu bộ lọc", + "Administration": "Administration", + "Run Import": "Bắt đầu nhập", + "Duplicate": "Trùng", + "Notifications": "Thông báo" + }, + "messages": { + "notModified": "Bạn chưa sửa bản ghi", + "duplicate": "Bản ghi được tạo bị trùng", + "fieldIsRequired": "{field} là bắt buộc", + "fieldShouldBeEmail": "Kiểm tra lại {field}", + "fieldShouldBeFloat": "Kiểm tra lại {field}", + "fieldShouldBeInt": "Kiểm tra lại {field}", + "fieldShouldBeDate": "Kiểm tra lại {field}", + "fieldShouldBeDatetime": "Kiểm tra lại {field}", + "fieldShouldAfter": "{field} cần đặt sau {otherField}", + "fieldShouldBefore": "{field} cần đặt trước {otherField}", + "fieldShouldBeBetween": "{field} cần đặt giữa {min} và {max}", + "fieldShouldBeLess": "{field} cần nhỏ hơn {value}", + "fieldShouldBeGreater": "{field} cần lớn hơn {value}", + "fieldBadPasswordConfirm": "{field} không hợp lệ" + }, + "boolFilters": { + "onlyMy": "Chỉ", + "open": "Mở", + "active": "Đang hoạt động" + }, + "fields": { + "name": "Tên", + "firstName": "Tên", + "lastName": "Họ", + "salutationName": "Chào đón", + "assignedUser": "Phân công", + "emailAddress": "Email", + "assignedUserName": "Thành viên được phân công", + "teams": "Nhóm", + "createdAt": "Tạo lúc", + "modifiedAt": "Sửa lúc", + "createdBy": "Tạo bởi", + "modifiedBy": "Sửa bởi", + "title": "Tiêu đề", + "dateFrom": "Từ ngày", + "dateTo": "Tới ngày", + "autorefreshInterval": "Tự động tải lại sau", + "displayRecords": "Xem bản ghi" + }, + "links": { + "teams": "Nhóm", + "users": "Người dùng" + }, + "dashlets": { + "Stream": "Luồng" + }, + "streamMessages": { + "create": "{user} tạo {entityType} {entity}", + "createAssigned": "{user} tạo {entityType} {entity} phân công cho {assignee}", + "assign": "{user} phân công {entityType} {entity} cho {assignee}", + "post": "{user} đăng {entityType} {entity}", + "attach": "{user} đính kèm ở {entityType} {entity}", + "status": "{user} cập nhật {field} ở {entityType} {entity}", + "update": "{user} cập nhật {entityType} {entity}", + "createRelated": "{user} created {relatedEntityType} {relatedEntity} linked to {entityType} {entity}", + "emailReceived": "{entity} đã được nhận bởi {entityType} {entity}", + + "createThis": "{user} tạo {entityType}", + "createAssignedThis": "{user} tạo {entityType} phân công cho {assignee}", + "assignThis": "{user} phân công {entityType} cho {assignee}", + "postThis": "{user} đã đăng", + "attachThis": "{user} đã đính kèm", + "statusThis": "{user} đã cập nhật {field}", + "updateThis": "{user} cập nhật {entityType}", + "createRelatedThis": "{user} created {relatedEntityType} {relatedEntity} linked to this {entityType}", + "emailReceivedThis": "{entity} đã được nhận" + }, + "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"] + }, + "options": { + "salutationName": { + "Mr.": "Ông.", + "Mrs.": "Bà.", + "Dr.": "Ông.", + "Drs.": "Bà." + }, + "language": { + "af_ZA": "Afrikaans", + "az_AZ": "Azerbaijani", + "be_BY": "Belarusian", + "bg_BG": "Bulgarian", + "bn_IN": "Bengali", + "bs_BA": "Bosnian", + "ca_ES": "Catalan", + "cs_CZ": "Czech", + "cy_GB": "Welsh", + "da_DK": "Danish", + "de_DE": "German", + "el_GR": "Greek", + "en_GB":"English (UK)", + "en_US":"English (US)", + "es_ES":"Spanish (Spain)", + "et_EE": "Estonian", + "eu_ES": "Basque", + "fa_IR": "Persian", + "fi_FI": "Finnish", + "fo_FO": "Faroese", + "fr_CA":"French (Canada)", + "fr_FR":"French (France)", + "ga_IE": "Irish", + "gl_ES": "Galician", + "gn_PY": "Guarani", + "he_IL": "Hebrew", + "hi_IN": "Hindi", + "hr_HR": "Croatian", + "hu_HU": "Hungarian", + "hy_AM": "Armenian", + "id_ID": "Indonesian", + "is_IS": "Icelandic", + "it_IT": "Italian", + "ja_JP": "Japanese", + "ka_GE": "Georgian", + "km_KH": "Khmer", + "ko_KR": "Korean", + "ku_TR": "Kurdish", + "lt_LT": "Lithuanian", + "lv_LV": "Latvian", + "mk_MK": "Macedonian", + "ml_IN": "Malayalam", + "ms_MY": "Malay", + "nb_NO": "Norwegian Bokmål", + "nn_NO": "Norwegian Nynorsk", + "ne_NP": "Nepali", + "nl_NL": "Dutch", + "pa_IN": "Punjabi", + "pl_PL": "Polish", + "ps_AF": "Pashto", + "pt_BR":"Portuguese (Brazil)", + "pt_PT":"Portuguese (Portugal)", + "ro_RO": "Romanian", + "ru_RU": "Russian", + "sk_SK": "Slovak", + "sl_SI": "Slovene", + "sq_AL": "Albanian", + "sr_RS": "Serbian", + "sv_SE": "Swedish", + "sw_KE": "Swahili", + "ta_IN": "Tamil", + "te_IN": "Telugu", + "th_TH": "Thai", + "tl_PH": "Tagalog", + "tr_TR": "Turkish", + "uk_UA": "Ukrainian", + "ur_PK": "Urdu", + "vi_VN": "Vietnamese", + "zh_CN":"Simplified Chinese (China)", + "zh_HK":"Traditional Chinese (Hong Kong)", + "zh_TW":"Traditional Chinese (Taiwan)" + }, + "dateSearchRanges": { + "on": "On", + "notOn": "Not On", + "after": "After", + "before": "Before", + "between": "Between", + "today": "Today", + "past": "Past", + "future": "Future" + }, + "intSearchRanges": { + "equals": "Equals", + "notEquals": "Not Equals", + "greaterThan": "Greater Than", + "lessThan": "Less Than", + "greaterThanOrEquals": "Greater Than or Equals", + "lessThanOrEquals": "Less Than or Equals", + "between": "Between" + }, + "autorefreshInterval": { + "0": "Trống", + "0.5": "30 seconds", + "1": "1 minute", + "2": "2 minutes", + "5": "5 minutes", + "10": "10 minutes" + }, + "phoneNumber": { + "Mobile": "Mobile", + "Office": "Office", + "Fax": "Fax", + "Home": "Home", + "Other": "Khác" + } + }, + "sets": { + "summernote": { + "NOTICE": "You can find translation here: https://github.com/HackerWins/summernote/tree/master/lang", + "font":{ + "bold": "Đậm", + "italic": "Nghiêng", + "underline": "Gạch chân", + "strike": "Gạch giữa", + "clear": "Xóa định dạng", + "height": "Kích thước dòng", + "name": "Font chữ", + "size": "Kích thước" + }, + "image":{ + "image": "Ảnh", + "insert": "Chèn ảnh", + "resizeFull": "Ảnh đầy đủ", + "resizeHalf": "Giảm nửa kích thước", + "resizeQuarter": "Giảm 1/4 kích thước", + "floatLeft": "Căn trái", + "floatRight": "Căn phải", + "floatNone": "Không căn lề", + "dragImageHere": "Thả ảnh vào đây", + "selectFromFiles": "Chọn từ thư mục", + "url": "Đường dẫn ảnh", + "remove": "Xóa ảnh" + }, + "link":{ + "link": "Đường dẫn", + "insert": "Chèn đường dẫn", + "unlink": "Xóa liên kết", + "edit": "Sửa", + "textToDisplay": "Chữ hiển thị", + "url":"To what URL should this link go?", + "openInNewWindow": "Mở trong cửa sổ mới" + }, + "video":{ + "video": "Video", + "videoLink": "Đường dẫn video", + "insert": "Chèn Video", + "url":"Video URL?", + "providers":"(YouTube, Vimeo, Vine, Instagram, or DailyMotion)" + }, + "table":{ + "table": "Bảng" + }, + "hr":{ + "insert": "Thêm dòng ngang" + }, + "style":{ + "style": "Kiểu", + "normal": "Bình thường", + "blockquote": "Trích dẫn", + "pre": "Code", + "h1": "Tiêu đề 1", + "h2": "Tiêu đề 2", + "h3": "Tiêu đềTiêu đề 3", + "h4": "Tiêu đề 4", + "h5": "Tiêu đề 5", + "h6": "Tiêu đề 6" + }, + "lists":{ + "unordered": "Liệt kê", + "ordered": "Danh sách" + }, + "options":{ + "help": "Trợ giúp", + "fullscreen": "Đầy màn hình", + "codeview": "Hiển thị dạng code" + }, + "paragraph":{ + "paragraph": "Đoạn văn bản", + "outdent": "Bỏ lùi đầu dòng", + "indent": "Lùi đầu dòng", + "left": "Căn lề trái", + "center": "Căn lề giữa", + "right": "Căn lề phải", + "justify": "Căn lề 2 bên" + }, + "color":{ + "recent": "Màu đã dùng", + "more": "Thêm màu", + "background": "Màu nền", + "foreground": "Màu chữ", + "transparent": "Trong suốt", + "setTransparent": "Chỉnh độ trong suốt", + "reset": "Reset", + "resetToDefault": "Đặt lại mặc định" + }, + "shortcut":{ + "shortcuts": "Phím tắt", + "close": "Đóng", + "textFormatting": "Định dạng chữ", + "action": "Hành động", + "paragraphFormatting": "Định dạng đoạn văn bản", + "documentStyle": "Kiểu văn bản" + }, + "history":{ + "undo": "Quay lui", + "redo": "Tiến lên" + } + } + } } diff --git a/application/Espo/Resources/i18n/vi_VN/Note.json b/application/Espo/Resources/i18n/vi_VN/Note.json index 58a8f5cb03..04ac101f63 100644 --- a/application/Espo/Resources/i18n/vi_VN/Note.json +++ b/application/Espo/Resources/i18n/vi_VN/Note.json @@ -1,6 +1,6 @@ { - "fields": { - "post": "Gửi", - "attachments": "Đính kèm" - } + "fields": { + "post": "Gửi", + "attachments": "Đính kèm" + } } diff --git a/application/Espo/Resources/i18n/vi_VN/Preferences.json b/application/Espo/Resources/i18n/vi_VN/Preferences.json index 6784cb8d94..a0fcf02ef3 100644 --- a/application/Espo/Resources/i18n/vi_VN/Preferences.json +++ b/application/Espo/Resources/i18n/vi_VN/Preferences.json @@ -1,32 +1,32 @@ { - "fields": { - "dateFormat": "Định dạng ngày", - "timeFormat": "Định dạng thời gian", - "timeZone": "Múi giờ", - "weekStart": "Ngày đầu tiên của tuần", - "thousandSeparator": "Dấu phân cách hàng nghìn", - "decimalMark": "Dấu phân cách thập phân", - "defaultCurrency": "Tiền tệ mặc định", - "currencyList": "Danh sách tiền tệ", - "language": "Ngôn ngữ", - - "smtpServer": "Máy chủ", - "smtpPort": "Cổng", - "smtpAuth": "Truy cập", - "smtpSecurity": "Bảo mật", - "smtpUsername": "Tên đăng nhập", - "emailAddress": "Email", - "smtpPassword": "Mật khẩu", - "smtpEmailAddress": "Địa chỉ email", - - "exportDelimiter": "Xuất dấu phân cách" - }, - "links": { - }, - "options": { - "weekStart": { - "0": "Chủ nhật", - "1": "Thứ 2" - } - } + "fields": { + "dateFormat": "Định dạng ngày", + "timeFormat": "Định dạng thời gian", + "timeZone": "Múi giờ", + "weekStart": "Ngày đầu tiên của tuần", + "thousandSeparator": "Dấu phân cách hàng nghìn", + "decimalMark": "Dấu phân cách thập phân", + "defaultCurrency": "Tiền tệ mặc định", + "currencyList": "Danh sách tiền tệ", + "language": "Ngôn ngữ", + + "smtpServer": "Máy chủ", + "smtpPort": "Cổng", + "smtpAuth": "Truy cập", + "smtpSecurity": "Bảo mật", + "smtpUsername": "Tên đăng nhập", + "emailAddress": "Email", + "smtpPassword": "Mật khẩu", + "smtpEmailAddress": "Địa chỉ email", + + "exportDelimiter": "Xuất dấu phân cách" + }, + "links": { + }, + "options": { + "weekStart": { + "0": "Chủ nhật", + "1": "Thứ 2" + } + } } diff --git a/application/Espo/Resources/i18n/vi_VN/Role.json b/application/Espo/Resources/i18n/vi_VN/Role.json index 3eecea4c34..0d54398cc5 100644 --- a/application/Espo/Resources/i18n/vi_VN/Role.json +++ b/application/Espo/Resources/i18n/vi_VN/Role.json @@ -1,32 +1,32 @@ { - "fields": { - "name": "Tên", - "roles": "Vai trò" - }, - "links": { - "users": "Người dùng", - "teams": "Nhóm" - }, - "labels": { - "Access": "Truy cập", - "Create Role": "Tạo vai trò" - }, - "options": { - "accessList": { - "not-set": "chưa đặt", - "enabled": "kích hoạt", - "disabled": "tắt" - }, - "levelList": { - "all": "tất cả", - "team": "nhóm", - "own": "sở hữu", - "no": "không" - } - }, - "actions": { - "read": "Đọc", - "edit": "Sửa", - "delete": "Xóa" - } + "fields": { + "name": "Tên", + "roles": "Vai trò" + }, + "links": { + "users": "Người dùng", + "teams": "Nhóm" + }, + "labels": { + "Access": "Truy cập", + "Create Role": "Tạo vai trò" + }, + "options": { + "accessList": { + "not-set": "chưa đặt", + "enabled": "kích hoạt", + "disabled": "tắt" + }, + "levelList": { + "all": "tất cả", + "team": "nhóm", + "own": "sở hữu", + "no": "không" + } + }, + "actions": { + "read": "Đọc", + "edit": "Sửa", + "delete": "Xóa" + } } diff --git a/application/Espo/Resources/i18n/vi_VN/ScheduledJob.json b/application/Espo/Resources/i18n/vi_VN/ScheduledJob.json index b1c40eb172..a3a5592754 100644 --- a/application/Espo/Resources/i18n/vi_VN/ScheduledJob.json +++ b/application/Espo/Resources/i18n/vi_VN/ScheduledJob.json @@ -1,30 +1,30 @@ { - "fields": { - "name": "Tên", - "status": "Trạng thái", - "job": "Công việc", - "scheduling": "Scheduling (crontab notation)" - }, - "links": { - "log": "Nhật ký" - }, - "labels": { - "Create ScheduledJob": "Lên lịch công việc" - }, - "options": { - "job": { - "CheckInboundEmails": "Kiểm tra hộp thư đến", - "Cleanup": "Dọn dẹp" - }, - "cronSetup": { - "linux": "Note: Add this line to the crontab file to run Espo Scheduled Jobs:", - "mac": "Note: Add this line to the crontab file to run Espo Scheduled Jobs:", - "windows": "Note: Create a batch file with the following commands to run Espo Scheduled Jobs using Windows Scheduled Tasks:", - "default": "Note: Add this command to Cron Job (Scheduled Task):" - }, - "status": { - "Active": "Đang hoạt động", - "Inactive": "Chưa hoạt động" - } - } + "fields": { + "name": "Tên", + "status": "Trạng thái", + "job": "Công việc", + "scheduling": "Scheduling (crontab notation)" + }, + "links": { + "log": "Nhật ký" + }, + "labels": { + "Create ScheduledJob": "Lên lịch công việc" + }, + "options": { + "job": { + "CheckInboundEmails": "Kiểm tra hộp thư đến", + "Cleanup": "Dọn dẹp" + }, + "cronSetup": { + "linux": "Note: Add this line to the crontab file to run Espo Scheduled Jobs:", + "mac": "Note: Add this line to the crontab file to run Espo Scheduled Jobs:", + "windows": "Note: Create a batch file with the following commands to run Espo Scheduled Jobs using Windows Scheduled Tasks:", + "default": "Note: Add this command to Cron Job (Scheduled Task):" + }, + "status": { + "Active": "Đang hoạt động", + "Inactive": "Chưa hoạt động" + } + } } diff --git a/application/Espo/Resources/i18n/vi_VN/ScheduledJobLogRecord.json b/application/Espo/Resources/i18n/vi_VN/ScheduledJobLogRecord.json index 92e3ef7c3e..be8e66c83a 100644 --- a/application/Espo/Resources/i18n/vi_VN/ScheduledJobLogRecord.json +++ b/application/Espo/Resources/i18n/vi_VN/ScheduledJobLogRecord.json @@ -1,6 +1,6 @@ { - "fields": { - "status": "Trạng thái", - "executionTime": "Thời gian hoạt động" - } + "fields": { + "status": "Trạng thái", + "executionTime": "Thời gian hoạt động" + } } diff --git a/application/Espo/Resources/i18n/vi_VN/Settings.json b/application/Espo/Resources/i18n/vi_VN/Settings.json index 63517c5703..5b39e4e29a 100644 --- a/application/Espo/Resources/i18n/vi_VN/Settings.json +++ b/application/Espo/Resources/i18n/vi_VN/Settings.json @@ -1,64 +1,64 @@ { - "fields": { - "useCache": "Dùng Cache", - "dateFormat": "Định dạng ngày", - "timeFormat": "Định dạng thời gian", - "timeZone": "Múi giờ", - "weekStart": "Ngày đầu tiên của tuần", - "thousandSeparator": "Dấu phân cách hàng nghìn", - "decimalMark": "Dấu phân cách thập phân", - "defaultCurrency": "Tiền tệ mặc định", - "currencyList": "Danh sách tiền tệ", - "language": "Ngôn ngữ", - - "companyLogo": "Logo công ty", - - "smtpServer": "Máy chủ", - "smtpPort": "Cổng", - "smtpAuth": "Truy cập", - "smtpSecurity": "Bảo mật", - "smtpUsername": "Tên đăng nhập", - "emailAddress": "Email", - "smtpPassword": "Mật khẩu", - "outboundEmailFromName": "tên người gửi", - "outboundEmailFromAddress": "Địa chỉ gửi", - "outboundEmailIsShared": "Được chia sẻ", - - "recordsPerPage": "Số bản ghi trên mỗi trang", - "recordsPerPageSmall": "Records Per Page (Small)", - "tabList": "Danh sách Tab", - "quickCreateList": "Tạo nhanh danh sách", - - "exportDelimiter": "Xuất dấu phân cách", - - "authenticationMethod": "Phương thức xác thực", - "ldapHost": "Máy chủ", - "ldapPort": "Cổng", - "ldapAuth": "Truy cập", - "ldapUsername": "Tên đăng nhập", - "ldapPassword": "Mật khẩu", - "ldapBindRequiresDn": "Yêu cầu Dn", - "ldapBaseDn": "Dn gốc", - "ldapAccountCanonicalForm": "Account Canonical Form", - "ldapAccountDomainName": "Tên miền tài khoản", - "ldapTryUsernameSplit": "Thử lại", - "ldapCreateEspoUser": "Tạo người dùng", - "ldapSecurity": "Bảo mật", - "ldapUserLoginFilter": "Bộ lọc đăng nhập", - "ldapAccountDomainNameShort": "Tên miền tài khoản", - "ldapOptReferrals": "Được giới thiệu", - "disableExport": "Disable Export (only admin is allowed)" - }, - "options": { - "weekStart": { - "0": "Chủ nhật", - "1": "Thứ 2" - } - }, - "labels": { - "System": "Hệ thống", - "Locale": "Bản địa hóa", - "SMTP": "SMTP", - "Configuration": "Tùy chỉnh" - } + "fields": { + "useCache": "Dùng Cache", + "dateFormat": "Định dạng ngày", + "timeFormat": "Định dạng thời gian", + "timeZone": "Múi giờ", + "weekStart": "Ngày đầu tiên của tuần", + "thousandSeparator": "Dấu phân cách hàng nghìn", + "decimalMark": "Dấu phân cách thập phân", + "defaultCurrency": "Tiền tệ mặc định", + "currencyList": "Danh sách tiền tệ", + "language": "Ngôn ngữ", + + "companyLogo": "Logo công ty", + + "smtpServer": "Máy chủ", + "smtpPort": "Cổng", + "smtpAuth": "Truy cập", + "smtpSecurity": "Bảo mật", + "smtpUsername": "Tên đăng nhập", + "emailAddress": "Email", + "smtpPassword": "Mật khẩu", + "outboundEmailFromName": "tên người gửi", + "outboundEmailFromAddress": "Địa chỉ gửi", + "outboundEmailIsShared": "Được chia sẻ", + + "recordsPerPage": "Số bản ghi trên mỗi trang", + "recordsPerPageSmall": "Records Per Page (Small)", + "tabList": "Danh sách Tab", + "quickCreateList": "Tạo nhanh danh sách", + + "exportDelimiter": "Xuất dấu phân cách", + + "authenticationMethod": "Phương thức xác thực", + "ldapHost": "Máy chủ", + "ldapPort": "Cổng", + "ldapAuth": "Truy cập", + "ldapUsername": "Tên đăng nhập", + "ldapPassword": "Mật khẩu", + "ldapBindRequiresDn": "Yêu cầu Dn", + "ldapBaseDn": "Dn gốc", + "ldapAccountCanonicalForm": "Account Canonical Form", + "ldapAccountDomainName": "Tên miền tài khoản", + "ldapTryUsernameSplit": "Thử lại", + "ldapCreateEspoUser": "Tạo người dùng", + "ldapSecurity": "Bảo mật", + "ldapUserLoginFilter": "Bộ lọc đăng nhập", + "ldapAccountDomainNameShort": "Tên miền tài khoản", + "ldapOptReferrals": "Được giới thiệu", + "disableExport": "Disable Export (only admin is allowed)" + }, + "options": { + "weekStart": { + "0": "Chủ nhật", + "1": "Thứ 2" + } + }, + "labels": { + "System": "Hệ thống", + "Locale": "Bản địa hóa", + "SMTP": "SMTP", + "Configuration": "Tùy chỉnh" + } } diff --git a/application/Espo/Resources/i18n/vi_VN/Team.json b/application/Espo/Resources/i18n/vi_VN/Team.json index 004d4c5967..be15ba1292 100644 --- a/application/Espo/Resources/i18n/vi_VN/Team.json +++ b/application/Espo/Resources/i18n/vi_VN/Team.json @@ -1,12 +1,12 @@ { - "fields": { - "name": "Tên", - "roles": "Vai trò" - }, - "links": { - "users": "Người dùng" - }, - "labels": { - "Create Team": "Tạo nhóm" - } + "fields": { + "name": "Tên", + "roles": "Vai trò" + }, + "links": { + "users": "Người dùng" + }, + "labels": { + "Create Team": "Tạo nhóm" + } } diff --git a/application/Espo/Resources/i18n/vi_VN/User.json b/application/Espo/Resources/i18n/vi_VN/User.json index bfb6d398ef..806fba857d 100644 --- a/application/Espo/Resources/i18n/vi_VN/User.json +++ b/application/Espo/Resources/i18n/vi_VN/User.json @@ -1,32 +1,32 @@ { - "fields": { - "name": "Tên", - "userName": "Tên người dùng", - "title": "Tiêu đề", - "isAdmin": "Tài khoản Admin", - "defaultTeam": "Nhóm mặc định", - "emailAddress": "Email", - "phoneNumber": "Điện thoại", - "roles": "Vai trò", - "password": "Mật khẩu", - "passwordConfirm": "Xác thực mật khẩu", - "newPassword": "Mật khẩu mới" - }, - "links": { - "teams": "Nhóm", - "roles": "Vai trò" - }, - "labels": { - "Create User": "Tạo người dùng", - "Generate": "Tạo", - "Access": "Truy cập", - "Preferences": "Tùy chỉnh", - "Change Password": "Đổi mật khẩu" - }, - "messages": { - "passwordWillBeSent": "Mật khẩu sẽ được gửi tới email tài khoản", - "accountInfoEmailSubject": "Thông tin tài khoản", - "accountInfoEmailBody": "Your account information:\n\nUsername: {userName}\nPassword: {password}\n\n{siteUrl}", - "passwordChanged": "Mật khẩu đã được đổi" - } + "fields": { + "name": "Tên", + "userName": "Tên người dùng", + "title": "Tiêu đề", + "isAdmin": "Tài khoản Admin", + "defaultTeam": "Nhóm mặc định", + "emailAddress": "Email", + "phoneNumber": "Điện thoại", + "roles": "Vai trò", + "password": "Mật khẩu", + "passwordConfirm": "Xác thực mật khẩu", + "newPassword": "Mật khẩu mới" + }, + "links": { + "teams": "Nhóm", + "roles": "Vai trò" + }, + "labels": { + "Create User": "Tạo người dùng", + "Generate": "Tạo", + "Access": "Truy cập", + "Preferences": "Tùy chỉnh", + "Change Password": "Đổi mật khẩu" + }, + "messages": { + "passwordWillBeSent": "Mật khẩu sẽ được gửi tới email tài khoản", + "accountInfoEmailSubject": "Thông tin tài khoản", + "accountInfoEmailBody": "Your account information:\n\nUsername: {userName}\nPassword: {password}\n\n{siteUrl}", + "passwordChanged": "Mật khẩu đã được đổi" + } } diff --git a/application/Espo/Resources/layouts/AuthToken/list.json b/application/Espo/Resources/layouts/AuthToken/list.json index e03be098be..ab0fa30608 100644 --- a/application/Espo/Resources/layouts/AuthToken/list.json +++ b/application/Espo/Resources/layouts/AuthToken/list.json @@ -1,6 +1,6 @@ [ - {"name":"user"}, - {"name":"ipAddress"}, - {"name":"lastAccess"}, - {"name":"createdAt"} + {"name":"user"}, + {"name":"ipAddress"}, + {"name":"lastAccess"}, + {"name":"createdAt"} ] diff --git a/application/Espo/Resources/layouts/Email/composeSmall.json b/application/Espo/Resources/layouts/Email/composeSmall.json index 2b979aea86..f4c75c7bac 100644 --- a/application/Espo/Resources/layouts/Email/composeSmall.json +++ b/application/Espo/Resources/layouts/Email/composeSmall.json @@ -1,30 +1,30 @@ [ - { - "label":"", - "rows":[ - [ - { - "name":"from", - "view": "Email.Fields.ComposeFromAddress" - }, - {"name":"cc"} - ], - [ - {"name":"to"}, - {"name":"bcc"} - ], - [ - { - "name": "parent" - }, - { - "name":"selectTemplate", - "view":"Email.Fields.SelectTemplate" - } - ], - [{"name":"name","fullWidth":true}], - [{"name":"body","fullWidth":true}], - [{"name":"attachments"},{"name":"isHtml"}] - ] - } + { + "label":"", + "rows":[ + [ + { + "name":"from", + "view": "Email.Fields.ComposeFromAddress" + }, + {"name":"cc"} + ], + [ + {"name":"to"}, + {"name":"bcc"} + ], + [ + { + "name": "parent" + }, + { + "name":"selectTemplate", + "view":"Email.Fields.SelectTemplate" + } + ], + [{"name":"name","fullWidth":true}], + [{"name":"body","fullWidth":true}], + [{"name":"attachments"},{"name":"isHtml"}] + ] + } ] diff --git a/application/Espo/Resources/layouts/Email/detail.json b/application/Espo/Resources/layouts/Email/detail.json index 2f3d222203..990fa7b368 100644 --- a/application/Espo/Resources/layouts/Email/detail.json +++ b/application/Espo/Resources/layouts/Email/detail.json @@ -1,13 +1,13 @@ [ - { - "label":"", - "rows":[ - [{"name":"status"},{"name":"from"}], - [{"name":"dateSent"}, {"name":"to"}], - [{"name":"parent"}, {"name":"cc"}], - [{"name":"name","fullWidth":true}], - [{"name":"body","fullWidth":true}], - [{"name":"attachments"},{"name":"isHtml"}] - ] - } + { + "label":"", + "rows":[ + [{"name":"status"},{"name":"from"}], + [{"name":"dateSent"}, {"name":"to"}], + [{"name":"parent"}, {"name":"cc"}], + [{"name":"name","fullWidth":true}], + [{"name":"body","fullWidth":true}], + [{"name":"attachments"},{"name":"isHtml"}] + ] + } ] diff --git a/application/Espo/Resources/layouts/Email/detailRestricted.json b/application/Espo/Resources/layouts/Email/detailRestricted.json index 8405f48eb5..1d761501a5 100644 --- a/application/Espo/Resources/layouts/Email/detailRestricted.json +++ b/application/Espo/Resources/layouts/Email/detailRestricted.json @@ -1,13 +1,13 @@ [ - { - "label":"", - "rows":[ - [{"name":"status"},{"name":"from", "readOnly": true}], - [{"name":"dateSent", "readOnly": true}, {"name":"to", "readOnly": true}], - [{"name":"parent"}, {"name":"cc", "readOnly": true}], - [{"name":"name","fullWidth":true, "readOnly": true}], - [{"name":"body","fullWidth":true, "readOnly": true}], - [{"name":"attachments", "readOnly": true}] - ] - } + { + "label":"", + "rows":[ + [{"name":"status"},{"name":"from", "readOnly": true}], + [{"name":"dateSent", "readOnly": true}, {"name":"to", "readOnly": true}], + [{"name":"parent"}, {"name":"cc", "readOnly": true}], + [{"name":"name","fullWidth":true, "readOnly": true}], + [{"name":"body","fullWidth":true, "readOnly": true}], + [{"name":"attachments", "readOnly": true}] + ] + } ] diff --git a/application/Espo/Resources/layouts/Email/detailSmall.json b/application/Espo/Resources/layouts/Email/detailSmall.json index 0fb4e49486..68c76118f8 100644 --- a/application/Espo/Resources/layouts/Email/detailSmall.json +++ b/application/Espo/Resources/layouts/Email/detailSmall.json @@ -1,14 +1,14 @@ [ - { - "label":"", - "rows":[ - [{"name":"dateSent"}], - [{"name":"parent"}], - [{"name":"from"}], - [{"name":"to"}], - [{"name":"name"}], - [{"name":"body"}], - [{"name":"attachments"}] - ] - } + { + "label":"", + "rows":[ + [{"name":"dateSent"}], + [{"name":"parent"}], + [{"name":"from"}], + [{"name":"to"}], + [{"name":"name"}], + [{"name":"body"}], + [{"name":"attachments"}] + ] + } ] diff --git a/application/Espo/Resources/layouts/Email/detailSmallRestricted.json b/application/Espo/Resources/layouts/Email/detailSmallRestricted.json index 15da8ba697..c93cda560b 100644 --- a/application/Espo/Resources/layouts/Email/detailSmallRestricted.json +++ b/application/Espo/Resources/layouts/Email/detailSmallRestricted.json @@ -1,14 +1,14 @@ [ - { - "label":"", - "rows":[ - [{"name":"dateSent", "readOnly": true}], - [{"name":"parent"}], - [{"name":"from", "readOnly": true}], - [{"name":"to", "readOnly": true}], - [{"name":"name", "readOnly": true}], - [{"name":"body", "readOnly": true}], - [{"name":"attachments", "readOnly": true}] - ] - } + { + "label":"", + "rows":[ + [{"name":"dateSent", "readOnly": true}], + [{"name":"parent"}], + [{"name":"from", "readOnly": true}], + [{"name":"to", "readOnly": true}], + [{"name":"name", "readOnly": true}], + [{"name":"body", "readOnly": true}], + [{"name":"attachments", "readOnly": true}] + ] + } ] diff --git a/application/Espo/Resources/layouts/Email/filters.json b/application/Espo/Resources/layouts/Email/filters.json index 86ea9458ea..b86290d5bd 100644 --- a/application/Espo/Resources/layouts/Email/filters.json +++ b/application/Espo/Resources/layouts/Email/filters.json @@ -1,8 +1,8 @@ [ - "emailAddress", - "dateSent", - "status", - "parent", - "body", - "teams" + "emailAddress", + "dateSent", + "status", + "parent", + "body", + "teams" ] diff --git a/application/Espo/Resources/layouts/Email/list.json b/application/Espo/Resources/layouts/Email/list.json index e6504f68f6..81a73d8090 100644 --- a/application/Espo/Resources/layouts/Email/list.json +++ b/application/Espo/Resources/layouts/Email/list.json @@ -1,7 +1,7 @@ [ - {"name":"name","width":30,"link":true,"notSortable": true}, - {"name":"fromEmailAddress","notSortable": true}, - {"name":"status","notSortable": true, "width":10}, - {"name":"parent","notSortable": true}, - {"name":"dateSent","view": "Fields.DatetimeShort", "notSortable": true, "width":10, "align": "right"} + {"name":"name","width":30,"link":true,"notSortable": true}, + {"name":"fromEmailAddress","notSortable": true}, + {"name":"status","notSortable": true, "width":10}, + {"name":"parent","notSortable": true}, + {"name":"dateSent","view": "Fields.DatetimeShort", "notSortable": true, "width":10, "align": "right"} ] diff --git a/application/Espo/Resources/layouts/EmailAccount/detail.json b/application/Espo/Resources/layouts/EmailAccount/detail.json index da91a57c8e..e83b3b23d8 100644 --- a/application/Espo/Resources/layouts/EmailAccount/detail.json +++ b/application/Espo/Resources/layouts/EmailAccount/detail.json @@ -1,28 +1,28 @@ [ - { - "label":"Main", - "rows":[ - [ - {"name":"name"}, - {"name":"status"} - ], - [ - {"name":"fetchSince"} - ] - ] - }, - { - "label":"IMAP", - "rows":[ - [ - {"name":"host"},{"name":"ssl"} - ], - [ - {"name":"port"},{"name":"username"} - ], - [ - {"name":"monitoredFolders"},{"name":"password"} - ] - ] - } + { + "label":"Main", + "rows":[ + [ + {"name":"name"}, + {"name":"status"} + ], + [ + {"name":"fetchSince"} + ] + ] + }, + { + "label":"IMAP", + "rows":[ + [ + {"name":"host"},{"name":"ssl"} + ], + [ + {"name":"port"},{"name":"username"} + ], + [ + {"name":"monitoredFolders"},{"name":"password"} + ] + ] + } ] diff --git a/application/Espo/Resources/layouts/EmailTemplate/detail.json b/application/Espo/Resources/layouts/EmailTemplate/detail.json index d0fd524418..2ca48b54d1 100644 --- a/application/Espo/Resources/layouts/EmailTemplate/detail.json +++ b/application/Espo/Resources/layouts/EmailTemplate/detail.json @@ -1,22 +1,22 @@ [ - { - "label":"", - "rows":[ - [ - { - "name":"name" - } - ], - [{"name":"subject","fullWidth":true}], - [ - { - "name":"insertField", - "view": "EmailTemplate.Fields.InsertField", - "fullWidth":true - } - ], - [{"name":"body","fullWidth":true}], - [{"name":"attachments"},{"name":"isHtml"}] - ] - } + { + "label":"", + "rows":[ + [ + { + "name":"name" + } + ], + [{"name":"subject","fullWidth":true}], + [ + { + "name":"insertField", + "view": "EmailTemplate.Fields.InsertField", + "fullWidth":true + } + ], + [{"name":"body","fullWidth":true}], + [{"name":"attachments"},{"name":"isHtml"}] + ] + } ] diff --git a/application/Espo/Resources/layouts/EmailTemplate/detailSmall.json b/application/Espo/Resources/layouts/EmailTemplate/detailSmall.json index f847938b99..fb73a9cb5e 100644 --- a/application/Espo/Resources/layouts/EmailTemplate/detailSmall.json +++ b/application/Espo/Resources/layouts/EmailTemplate/detailSmall.json @@ -1,11 +1,11 @@ [ - { - "label":"", - "rows":[ - [{"name":"name"}], - [{"name":"subject"}], - [{"name":"body","fullWidth":true}], - [{"name":"attachments"},{"name":"isHtml"}] - ] - } + { + "label":"", + "rows":[ + [{"name":"name"}], + [{"name":"subject"}], + [{"name":"body","fullWidth":true}], + [{"name":"attachments"},{"name":"isHtml"}] + ] + } ] diff --git a/application/Espo/Resources/layouts/Extension/list.json b/application/Espo/Resources/layouts/Extension/list.json index e75712b7ab..2d3189ac60 100644 --- a/application/Espo/Resources/layouts/Extension/list.json +++ b/application/Espo/Resources/layouts/Extension/list.json @@ -1,6 +1,6 @@ [ - {"name":"name","width":35,"notSortable": true}, - {"name":"version","notSortable": true, "width":15}, - {"name":"description","notSortable": true}, - {"name":"isInstalled","notSortable": true, "width":5} + {"name":"name","width":35,"notSortable": true}, + {"name":"version","notSortable": true, "width":15}, + {"name":"description","notSortable": true}, + {"name":"isInstalled","notSortable": true, "width":5} ] diff --git a/application/Espo/Resources/layouts/Note/detail.json b/application/Espo/Resources/layouts/Note/detail.json index 7199565cfd..b1a5577099 100644 --- a/application/Espo/Resources/layouts/Note/detail.json +++ b/application/Espo/Resources/layouts/Note/detail.json @@ -1,13 +1,18 @@ [ - { - "label":"", - "rows": [ - [ - {"name":"post"} - ], - [ - {"name":"attachments"} - ] - ] - } + { + "label":"", + "rows": [ + [ + { + "name":"post", + "params": { + "required": true + } + } + ], + [ + {"name":"attachments"} + ] + ] + } ] diff --git a/application/Espo/Resources/layouts/Note/detailSmall.json b/application/Espo/Resources/layouts/Note/detailSmall.json index 7199565cfd..b1a5577099 100644 --- a/application/Espo/Resources/layouts/Note/detailSmall.json +++ b/application/Espo/Resources/layouts/Note/detailSmall.json @@ -1,13 +1,18 @@ [ - { - "label":"", - "rows": [ - [ - {"name":"post"} - ], - [ - {"name":"attachments"} - ] - ] - } + { + "label":"", + "rows": [ + [ + { + "name":"post", + "params": { + "required": true + } + } + ], + [ + {"name":"attachments"} + ] + ] + } ] diff --git a/application/Espo/Resources/layouts/OutboundEmail/detail.json b/application/Espo/Resources/layouts/OutboundEmail/detail.json deleted file mode 100644 index bbdea10832..0000000000 --- a/application/Espo/Resources/layouts/OutboundEmail/detail.json +++ /dev/null @@ -1,17 +0,0 @@ -[ - { - "label": "SMTP", - "rows": [ - [{"name": "server"}, {"name": "port"}], - [{"name": "auth"}, {"name": "security"}], - [{"name": "username"}], - [{"name": "password"}] - ] - }, - { - "label": "Configuration", - "rows": [ - [{"name": "fromName"}, {"name": "fromAddress"}] - ] - } -] diff --git a/application/Espo/Resources/layouts/Preferences/detail.json b/application/Espo/Resources/layouts/Preferences/detail.json index 2caa3668b3..b6c78018aa 100644 --- a/application/Espo/Resources/layouts/Preferences/detail.json +++ b/application/Espo/Resources/layouts/Preferences/detail.json @@ -1,38 +1,38 @@ [ - { - "label": "Locale", - "rows": [ - [{"name": "dateFormat"}, {"name": "timeFormat"}], - [{"name": "timeZone"}, {"name": "weekStart"}], - [{"name": "defaultCurrency"}], - [{"name": "thousandSeparator"}, {"name": "decimalMark"}], - [{"name": "language"}] - ] - }, - { - "label": "SMTP", - "rows": [ - [ - { - "name": "smtpEmailAddress" - } - ], - [{"name": "smtpServer"}, {"name": "smtpPort"}], - [{"name": "smtpAuth"}, {"name": "smtpSecurity"}], - [{"name": "smtpUsername"}], - [{"name": "smtpPassword"}] - ] - }, - { - "label": "Misc", - "rows": [ - [{"name": "exportDelimiter"}] - ] - }, - { - "label": "Notifications", - "rows": [ - [{"name": "receiveAssignmentEmailNotifications"}] - ] - } + { + "label": "Locale", + "rows": [ + [{"name": "dateFormat"}, {"name": "timeFormat"}], + [{"name": "timeZone"}, {"name": "weekStart"}], + [{"name": "defaultCurrency"}], + [{"name": "thousandSeparator"}, {"name": "decimalMark"}], + [{"name": "language"}] + ] + }, + { + "label": "SMTP", + "rows": [ + [ + { + "name": "smtpEmailAddress" + } + ], + [{"name": "smtpServer"}, {"name": "smtpPort"}], + [{"name": "smtpAuth"}, {"name": "smtpSecurity"}], + [{"name": "smtpUsername"}, {"name": "testSend", "customLabel": null, "view": "Preferences.Fields.TestSend"}], + [{"name": "smtpPassword"}] + ] + }, + { + "label": "Misc", + "rows": [ + [{"name": "exportDelimiter"}] + ] + }, + { + "label": "Notifications", + "rows": [ + [{"name": "receiveAssignmentEmailNotifications"}] + ] + } ] diff --git a/application/Espo/Resources/layouts/Role/detail.json b/application/Espo/Resources/layouts/Role/detail.json new file mode 100644 index 0000000000..5add6d0621 --- /dev/null +++ b/application/Espo/Resources/layouts/Role/detail.json @@ -0,0 +1,9 @@ +[ + { + "rows": [ + [ + {"name": "name"} + ] + ] + } +] diff --git a/application/Espo/Resources/layouts/ScheduledJob/detail.json b/application/Espo/Resources/layouts/ScheduledJob/detail.json index fa1324a042..d3c6b566e7 100644 --- a/application/Espo/Resources/layouts/ScheduledJob/detail.json +++ b/application/Espo/Resources/layouts/ScheduledJob/detail.json @@ -1,9 +1,9 @@ [ - { - "rows": [ - [{"name": "name"}, {"name": "status"}], - [{"name": "job"}], - [{"name": "scheduling"}] - ] - } + { + "rows": [ + [{"name": "name"}, {"name": "status"}], + [{"name": "job"}], + [{"name": "scheduling"}] + ] + } ] diff --git a/application/Espo/Resources/layouts/Settings/authentication.json b/application/Espo/Resources/layouts/Settings/authentication.json index ee346e9cfd..3e5e8d295f 100644 --- a/application/Espo/Resources/layouts/Settings/authentication.json +++ b/application/Espo/Resources/layouts/Settings/authentication.json @@ -1,24 +1,24 @@ [ - { - "label": "Configuration", - "rows": [ - [{"name": "authenticationMethod"}] - ] - }, - { - "label": "LDAP", - "name": "LDAP", - "rows": [ - [{"name": "ldapHost"}, {"name": "ldapPort"}], - [{"name": "ldapAuth"}, {"name": "ldapSecurity"}], - [{"name": "ldapUsername"}, false], - [{"name": "ldapPassword"}, false], - [{"name": "ldapBindRequiresDn"}, {"name": "ldapUserLoginFilter"}], - [{"name": "ldapBaseDn"}, false], - [{"name": "ldapAccountCanonicalForm"}, false], - [{"name": "ldapAccountDomainName"}, {"name": "ldapAccountDomainNameShort"}], - [{"name": "ldapTryUsernameSplit"}, {"name": "ldapOptReferrals"}], - [{"name": "ldapCreateEspoUser"}, false] - ] - } + { + "label": "Configuration", + "rows": [ + [{"name": "authenticationMethod"}] + ] + }, + { + "label": "LDAP", + "name": "LDAP", + "rows": [ + [{"name": "ldapHost"}, {"name": "ldapPort"}], + [{"name": "ldapAuth"}, {"name": "ldapSecurity"}], + [{"name": "ldapUsername"}, false], + [{"name": "ldapPassword"}, false], + [{"name": "ldapBindRequiresDn"}, {"name": "ldapUserLoginFilter"}], + [{"name": "ldapBaseDn"}, false], + [{"name": "ldapAccountCanonicalForm"}, false], + [{"name": "ldapAccountDomainName"}, {"name": "ldapAccountDomainNameShort"}], + [{"name": "ldapTryUsernameSplit"}, {"name": "ldapOptReferrals"}], + [{"name": "ldapCreateEspoUser"}, false] + ] + } ] diff --git a/application/Espo/Resources/layouts/Settings/currency.json b/application/Espo/Resources/layouts/Settings/currency.json index 8db7204c0b..de72270c38 100644 --- a/application/Espo/Resources/layouts/Settings/currency.json +++ b/application/Espo/Resources/layouts/Settings/currency.json @@ -1,14 +1,14 @@ [ - { - "label": "Currency Settings", - "rows": [ - [{"name": "defaultCurrency"}, {"name": "currencyList"}] - ] - }, - { - "label": "Currency Rates", - "rows": [ - [{"name": "baseCurrency"}, {"name": "currencyRates"}] - ] - } + { + "label": "Currency Settings", + "rows": [ + [{"name": "defaultCurrency"}, {"name": "currencyList"}] + ] + }, + { + "label": "Currency Rates", + "rows": [ + [{"name": "baseCurrency"}, {"name": "currencyRates"}] + ] + } ] diff --git a/application/Espo/Resources/layouts/Settings/outboundEmail.json b/application/Espo/Resources/layouts/Settings/outboundEmail.json index 6c03e2a432..d3e76d802c 100644 --- a/application/Espo/Resources/layouts/Settings/outboundEmail.json +++ b/application/Espo/Resources/layouts/Settings/outboundEmail.json @@ -1,24 +1,24 @@ [ - { - "label": "SMTP", - "rows": [ - [{"name": "smtpServer"}, {"name": "smtpPort"}], - [{"name": "smtpAuth"}, {"name": "smtpSecurity"}], - [{"name": "smtpUsername"}], - [{"name": "smtpPassword"}] - ] - }, - { - "label": "Configuration", - "rows": [ - [{"name": "outboundEmailFromName"}, {"name": "outboundEmailFromAddress"}], - [{"name": "outboundEmailIsShared"}] - ] - }, - { - "label": "Notifications", - "rows": [ - [{"name": "assignmentEmailNotifications"}, {"name": "assignmentEmailNotificationsEntityList"}] - ] - } + { + "label": "SMTP", + "rows": [ + [{"name": "smtpServer"}, {"name": "smtpPort"}], + [{"name": "smtpAuth"}, {"name": "smtpSecurity"}], + [{"name": "smtpUsername"}, {"name": "testSend", "customLabel": null, "view": "OutboundEmail.Fields.TestSend"}], + [{"name": "smtpPassword"}] + ] + }, + { + "label": "Configuration", + "rows": [ + [{"name": "outboundEmailFromName"}, {"name": "outboundEmailFromAddress"}], + [{"name": "outboundEmailIsShared"}] + ] + }, + { + "label": "Notifications", + "rows": [ + [{"name": "assignmentEmailNotifications"}, {"name": "assignmentEmailNotificationsEntityList"}] + ] + } ] diff --git a/application/Espo/Resources/layouts/Settings/settings.json b/application/Espo/Resources/layouts/Settings/settings.json index 126b994740..182381aefb 100644 --- a/application/Espo/Resources/layouts/Settings/settings.json +++ b/application/Espo/Resources/layouts/Settings/settings.json @@ -1,18 +1,18 @@ [ - { - "label": "System", - "rows": [ - [{"name": "useCache"},{"name": "companyLogo"}], - [{"name": "disableExport"}] - ] - }, - { - "label": "Locale", - "rows": [ - [{"name": "dateFormat"}, {"name": "timeZone"}], - [{"name": "timeFormat"}, {"name": "weekStart"}], - [{"name": "thousandSeparator"}, {"name": "decimalMark"}], - [{"name": "language"}] - ] - } + { + "label": "System", + "rows": [ + [{"name": "useCache"},{"name": "companyLogo"}], + [{"name": "disableExport"}] + ] + }, + { + "label": "Locale", + "rows": [ + [{"name": "dateFormat"}, {"name": "timeZone"}], + [{"name": "timeFormat"}, {"name": "weekStart"}], + [{"name": "thousandSeparator"}, {"name": "decimalMark"}], + [{"name": "language"}] + ] + } ] diff --git a/application/Espo/Resources/layouts/Settings/userInterface.json b/application/Espo/Resources/layouts/Settings/userInterface.json index c70c581322..04b8fd29a3 100644 --- a/application/Espo/Resources/layouts/Settings/userInterface.json +++ b/application/Espo/Resources/layouts/Settings/userInterface.json @@ -1,9 +1,9 @@ [ - { - "label": "Configuration", - "rows": [ - [{"name": "recordsPerPage"},{"name": "recordsPerPageSmall"}], - [{"name": "tabList"},{"name": "quickCreateList"}] - ] - } + { + "label": "Configuration", + "rows": [ + [{"name": "recordsPerPage"},{"name": "recordsPerPageSmall"}], + [{"name": "tabList"},{"name": "quickCreateList"}] + ] + } ] diff --git a/application/Espo/Resources/layouts/Team/detail.json b/application/Espo/Resources/layouts/Team/detail.json new file mode 100644 index 0000000000..63675851e7 --- /dev/null +++ b/application/Espo/Resources/layouts/Team/detail.json @@ -0,0 +1,13 @@ +[ + { + "rows": [ + [ + {"name": "name"} + ], + [ + {"name": "roles"}, + {"name": "positionList"} + ] + ] + } +] diff --git a/application/Espo/Resources/layouts/User/detail.json b/application/Espo/Resources/layouts/User/detail.json index 1d48a149cb..4be7752a27 100644 --- a/application/Espo/Resources/layouts/User/detail.json +++ b/application/Espo/Resources/layouts/User/detail.json @@ -1,11 +1,17 @@ [ - { - "label":"Overview", - "rows":[ - [{"name":"userName"},{"name":"isAdmin"}], - [{"name":"name"},{"name":"title"}], - [{"name":"defaultTeam"}], - [{"name":"emailAddress"},{"name":"phoneNumber"}] - ] - } + { + "label": "Overview", + "rows": [ + [{"name":"userName"}], + [{"name": "name"}, {"name": "title"}], + [{"name": "emailAddress"}, {"name": "phoneNumber"}] + ] + }, + { + "label": "Teams and Access Control", + "rows": [ + [{"name":"defaultTeam"}, {"name":"isAdmin"}], + [{"name":"teams"}, {"name":"roles"}] + ] + } ] diff --git a/application/Espo/Resources/layouts/User/detailSmall.json b/application/Espo/Resources/layouts/User/detailSmall.json index cf1c7f2fd7..dc3320bad3 100644 --- a/application/Espo/Resources/layouts/User/detailSmall.json +++ b/application/Espo/Resources/layouts/User/detailSmall.json @@ -1,11 +1,11 @@ [ - { - "label":"", - "rows": [ - [{"name":"name"}], - [{"name":"userName"}], - [{"name":"isAdmin"}], - [{"name":"emailAddress"}] - ] - } + { + "label":"", + "rows": [ + [{"name":"name"}], + [{"name":"userName"}], + [{"name":"isAdmin"}], + [{"name":"emailAddress"}] + ] + } ] diff --git a/application/Espo/Resources/layouts/User/listForTeam.json b/application/Espo/Resources/layouts/User/listForTeam.json new file mode 100644 index 0000000000..e4ee77b32f --- /dev/null +++ b/application/Espo/Resources/layouts/User/listForTeam.json @@ -0,0 +1,5 @@ +[ + {"name":"name","width":40,"link":true}, + {"name":"userName"}, + {"name":"teamRole", "notSortable": true} +] diff --git a/application/Espo/Resources/metadata/app/acl.json b/application/Espo/Resources/metadata/app/acl.json index a031135533..1a5b1f9f23 100644 --- a/application/Espo/Resources/metadata/app/acl.json +++ b/application/Espo/Resources/metadata/app/acl.json @@ -1,30 +1,35 @@ { - "solid": { - "User": { - "read": "all", - "edit": "no", - "delete": "no" - }, - "Team": { - "read": "all", - "edit": "no", - "delete": "no" - }, - "Note": { - "read": "all", - "edit": "own", - "delete": "own" - }, - "EmailAddress": { - "read": "no", - "edit": "no", - "delete": "no" - }, - "EmailAccount": { - "read": "own", - "edit": "own", - "delete": "own" - }, - "Role": false - } + "solid": { + "User": { + "read": "all", + "edit": "no", + "delete": "no" + }, + "Team": { + "read": "all", + "edit": "no", + "delete": "no" + }, + "Note": { + "read": "all", + "edit": "own", + "delete": "own" + }, + "EmailAddress": { + "read": "no", + "edit": "no", + "delete": "no" + }, + "PhoneNumber": { + "read": "no", + "edit": "no", + "delete": "no" + }, + "EmailAccount": { + "read": "own", + "edit": "own", + "delete": "own" + }, + "Role": false + } } diff --git a/application/Espo/Resources/metadata/app/defaultDashboardLayout.json b/application/Espo/Resources/metadata/app/defaultDashboardLayout.json index cb7e1d91fe..f4c139490d 100644 --- a/application/Espo/Resources/metadata/app/defaultDashboardLayout.json +++ b/application/Espo/Resources/metadata/app/defaultDashboardLayout.json @@ -1,18 +1,22 @@ [ - [ - { - "name": "Stream", - "id": "d4" - }, - { - "name": "Calls", - "id": "d1" - } - ], - [ - { - "name": "Tasks", - "id": "d3" - } - ] + [ + { + "name": "Stream", + "id": "d4" + }, + { + "name": "Calls", + "id": "d1" + } + ], + [ + { + "name": "Tasks", + "id": "d3" + }, + { + "name": "Meetings", + "id": "d2" + } + ] ] diff --git a/application/Espo/Resources/metadata/app/jsLibs.json b/application/Espo/Resources/metadata/app/jsLibs.json index 478f6a178f..0661c35675 100644 --- a/application/Espo/Resources/metadata/app/jsLibs.json +++ b/application/Espo/Resources/metadata/app/jsLibs.json @@ -1,18 +1,22 @@ { - "Flotr": { - "path": "client/lib/flotr2.min.js", - "exportsTo": "window", - "exportsAs": "Flotr" - }, - "Summernote": { - "path": "client/lib/summernote.min.js", - "exportsTo": "$", - "exportsAs": "summernote" - }, - "Textcomplete": { - "path": "client/lib/jquery.textcomplete.js", - "exportsTo": "$", - "exportsAs": "textcomplete" - - } + "Flotr": { + "path": "client/lib/flotr2.min.js", + "exportsTo": "window", + "exportsAs": "Flotr" + }, + "Summernote": { + "path": "client/lib/summernote.min.js", + "exportsTo": "$", + "exportsAs": "summernote" + }, + "Textcomplete": { + "path": "client/lib/jquery.textcomplete.js", + "exportsTo": "$", + "exportsAs": "textcomplete" + }, + "Select2": { + "path": "client/lib/select2.min.js", + "exportsTo": "$", + "exportsAs": "select2" + } } diff --git a/application/Espo/Resources/metadata/clientDefs/Email.json b/application/Espo/Resources/metadata/clientDefs/Email.json index d333835bf4..32a01c118b 100644 --- a/application/Espo/Resources/metadata/clientDefs/Email.json +++ b/application/Espo/Resources/metadata/clientDefs/Email.json @@ -22,15 +22,11 @@ } ], "dropdown": [ - { + { "label": "Archive Email", "link": "#Email/create", "acl": "edit" - }, - { - "label": "Email Accounts", - "link": "#EmailAccount" - } + } ] }, "detail": { @@ -43,21 +39,21 @@ } ], "dropdown": [ - { + { "label": "Reply", "action": "reply", "acl": "read" - }, - { + }, + { "label": "Reply to All", "action": "replyToAll", "acl": "read" - }, - { + }, + { "label": "Forward", "action": "forward", "acl": "read" - } + } ] } }, diff --git a/application/Espo/Resources/metadata/clientDefs/EmailAccount.json b/application/Espo/Resources/metadata/clientDefs/EmailAccount.json index 6ca7c5cc1a..ba3d6553ae 100644 --- a/application/Espo/Resources/metadata/clientDefs/EmailAccount.json +++ b/application/Espo/Resources/metadata/clientDefs/EmailAccount.json @@ -1,9 +1,9 @@ { - "controller": "Controllers.Record", - "recordViews":{ - "list":"EmailAccount.Record.List", - "detail": "EmailAccount.Record.Detail", - "edit": "EmailAccount.Record.Edit" - }, - "disableSearchPanel": true + "controller": "Controllers.Record", + "recordViews":{ + "list":"EmailAccount.Record.List", + "detail": "EmailAccount.Record.Detail", + "edit": "EmailAccount.Record.Edit" + }, + "disableSearchPanel": true } diff --git a/application/Espo/Resources/metadata/clientDefs/Role.json b/application/Espo/Resources/metadata/clientDefs/Role.json index 5a5226bd2a..ee4f559172 100644 --- a/application/Espo/Resources/metadata/clientDefs/Role.json +++ b/application/Espo/Resources/metadata/clientDefs/Role.json @@ -16,6 +16,6 @@ } }, "views": { - "list": "Role.List" + "list": "Role.List" } } diff --git a/application/Espo/Resources/metadata/clientDefs/ScheduledJob.json b/application/Espo/Resources/metadata/clientDefs/ScheduledJob.json index 0a6c822afa..c7a9f06556 100644 --- a/application/Espo/Resources/metadata/clientDefs/ScheduledJob.json +++ b/application/Espo/Resources/metadata/clientDefs/ScheduledJob.json @@ -9,6 +9,6 @@ "list":"ScheduledJob.Record.List" }, "views": { - "list": "ScheduledJob.List" + "list": "ScheduledJob.List" } } diff --git a/application/Espo/Resources/metadata/clientDefs/Team.json b/application/Espo/Resources/metadata/clientDefs/Team.json index 1741c207c2..1708bf2bbc 100644 --- a/application/Espo/Resources/metadata/clientDefs/Team.json +++ b/application/Espo/Resources/metadata/clientDefs/Team.json @@ -2,12 +2,13 @@ "relationshipPanels":{ "users":{ "create":false, - "rowActionsView": "Record.RowActions.RelationshipUnlinkOnly" + "rowActionsView": "Record.RowActions.RelationshipUnlinkOnly", + "layout":"listForTeam" } }, "recordViews":{ "detail":"Team.Record.Detail", "edit":"Team.Record.Edit", "list":"Team.Record.List" - } + } } diff --git a/application/Espo/Resources/metadata/entityDefs/Attachment.json b/application/Espo/Resources/metadata/entityDefs/Attachment.json index 2461d1750b..7aacce7160 100644 --- a/application/Espo/Resources/metadata/entityDefs/Attachment.json +++ b/application/Espo/Resources/metadata/entityDefs/Attachment.json @@ -32,8 +32,8 @@ "maxLength": 36 }, "global": { - "type": "bool", - "default": false + "type": "bool", + "default": false } }, "links": { @@ -47,7 +47,7 @@ } }, "collection": { - "sortBy": "createdAt", - "asc": false + "sortBy": "createdAt", + "asc": false } } diff --git a/application/Espo/Resources/metadata/entityDefs/AuthToken.json b/application/Espo/Resources/metadata/entityDefs/AuthToken.json index 21e8f1a2e8..1cac4656e2 100644 --- a/application/Espo/Resources/metadata/entityDefs/AuthToken.json +++ b/application/Espo/Resources/metadata/entityDefs/AuthToken.json @@ -6,7 +6,7 @@ }, "hash": { "type": "varchar", - "maxLength": "36", + "maxLength": 150, "index": true }, "userId": { @@ -17,8 +17,8 @@ "type": "link" }, "ipAddress": { - "type": "varchar", - "maxLength": "36" + "type": "varchar", + "maxLength": "36" }, "lastAccess": { "type": "datetime" @@ -39,7 +39,7 @@ } }, "collection": { - "sortBy": "lastAccess", - "asc": false + "sortBy": "lastAccess", + "asc": false } } diff --git a/application/Espo/Resources/metadata/entityDefs/Email.json b/application/Espo/Resources/metadata/entityDefs/Email.json index bfc57a33c0..dc976a2692 100644 --- a/application/Espo/Resources/metadata/entityDefs/Email.json +++ b/application/Espo/Resources/metadata/entityDefs/Email.json @@ -35,37 +35,37 @@ "view": "Email.Fields.EmailAddressVarchar" }, "nameHash": { - "type": "text", - "notStorable": true, - "readOlny": true, - "disabled": true + "type": "text", + "notStorable": true, + "readOlny": true, + "disabled": true }, "typeHash": { - "type": "text", - "notStorable": true, - "readOlny": true, - "disabled": true + "type": "text", + "notStorable": true, + "readOlny": true, + "disabled": true }, "idHash": { - "type": "text", - "notStorable": true, - "readOlny": true, - "disabled": true + "type": "text", + "notStorable": true, + "readOlny": true, + "disabled": true }, "messageId": { - "type": "varchar", - "maxLength": 255, - "readOlny": true + "type": "varchar", + "maxLength": 255, + "readOlny": true }, "messageIdInternal": { - "type": "varchar", - "maxLength": 300, - "readOlny": true, - "index": true + "type": "varchar", + "maxLength": 300, + "readOlny": true, + "index": true }, "emailAddress": { - "type": "base", - "db": false + "type": "base", + "db": false }, "fromEmailAddress": { "type": "link", @@ -169,48 +169,48 @@ "type": "hasMany", "entity": "EmailAddress", "relationName": "EmailEmailAddress", - "conditions": { - "addressType": "to" - }, + "conditions": { + "addressType": "to" + }, "additionalColumns": { - "addressType": { - "type": "varchar", - "len": "4" - } + "addressType": { + "type": "varchar", + "len": "4" + } } }, "ccEmailAddresses": { "type": "hasMany", "entity": "EmailAddress", "relationName": "EmailEmailAddress", - "conditions": { - "addressType": "cc" - }, + "conditions": { + "addressType": "cc" + }, "additionalColumns": { - "addressType": { - "type": "varchar", - "len": "4" - } + "addressType": { + "type": "varchar", + "len": "4" + } } }, "bccEmailAddresses": { "type": "hasMany", "entity": "EmailAddress", "relationName": "EmailEmailAddress", - "conditions": { - "addressType": "bcc" - }, + "conditions": { + "addressType": "bcc" + }, "additionalColumns": { - "addressType": { - "type": "varchar", - "len": "4" - } + "addressType": { + "type": "varchar", + "len": "4" + } } } }, "collection": { - "sortBy": "dateSent", - "asc": false, - "textFilterFields": ["name", "body", "bodyPlain"] + "sortBy": "dateSent", + "asc": false, + "textFilterFields": ["name", "body", "bodyPlain"] } } diff --git a/application/Espo/Resources/metadata/entityDefs/EmailAccount.json b/application/Espo/Resources/metadata/entityDefs/EmailAccount.json index de747916c7..39e370d4ab 100644 --- a/application/Espo/Resources/metadata/entityDefs/EmailAccount.json +++ b/application/Espo/Resources/metadata/entityDefs/EmailAccount.json @@ -34,11 +34,11 @@ "view": "EmailAccount.Fields.Folders" }, "fetchSince": { - "type": "date", - "required": true + "type": "date", + "required": true }, "fetchData": { - "type": "text", + "type": "text", "readOnly": true }, "createdAt": { @@ -77,7 +77,7 @@ } }, "collection": { - "sortBy": "name", - "asc": true + "sortBy": "name", + "asc": true } } diff --git a/application/Espo/Resources/metadata/entityDefs/EmailAddress.json b/application/Espo/Resources/metadata/entityDefs/EmailAddress.json index 845d6fadcb..1404e27e9c 100644 --- a/application/Espo/Resources/metadata/entityDefs/EmailAddress.json +++ b/application/Espo/Resources/metadata/entityDefs/EmailAddress.json @@ -19,7 +19,7 @@ "links": { }, "collection": { - "sortBy": "name", - "asc": true + "sortBy": "name", + "asc": true } } diff --git a/application/Espo/Resources/metadata/entityDefs/EmailTemplate.json b/application/Espo/Resources/metadata/entityDefs/EmailTemplate.json index 491013f7c2..9bada69af1 100644 --- a/application/Espo/Resources/metadata/entityDefs/EmailTemplate.json +++ b/application/Espo/Resources/metadata/entityDefs/EmailTemplate.json @@ -68,7 +68,7 @@ } }, "collection": { - "sortBy": "name", - "asc": true + "sortBy": "name", + "asc": true } } diff --git a/application/Espo/Resources/metadata/entityDefs/Note.json b/application/Espo/Resources/metadata/entityDefs/Note.json index 008ab4275d..f8d5d3358a 100644 --- a/application/Espo/Resources/metadata/entityDefs/Note.json +++ b/application/Espo/Resources/metadata/entityDefs/Note.json @@ -54,35 +54,35 @@ } }, "collection": { - "sortBy": "createdAt", - "asc": false + "sortBy": "createdAt", + "asc": false }, "streamRelated": { - "Account": [ - "meetings", - "calls", - "tasks", - "opportunities" - ], - "Contact": [ - "meetings", - "calls", - "tasks" - ], - "Lead": [ - "meetings", - "calls", - "tasks" - ], - "Opportunity": [ - "meetings", - "calls", - "tasks" - ], - "Case": [ - "meetings", - "calls", - "tasks" - ] - } + "Account": [ + "meetings", + "calls", + "tasks", + "opportunities" + ], + "Contact": [ + "meetings", + "calls", + "tasks" + ], + "Lead": [ + "meetings", + "calls", + "tasks" + ], + "Opportunity": [ + "meetings", + "calls", + "tasks" + ], + "Case": [ + "meetings", + "calls", + "tasks" + ] + } } diff --git a/application/Espo/Resources/metadata/entityDefs/Notification.json b/application/Espo/Resources/metadata/entityDefs/Notification.json index f55f92bf47..38b81ff02d 100644 --- a/application/Espo/Resources/metadata/entityDefs/Notification.json +++ b/application/Espo/Resources/metadata/entityDefs/Notification.json @@ -14,7 +14,7 @@ "type": "bool" }, "user": { - "type": "link" + "type": "link" }, "createdAt": { "type": "datetime", @@ -22,13 +22,13 @@ } }, "links": { - "user": { - "type": "belongsTo", - "entity": "User" - } + "user": { + "type": "belongsTo", + "entity": "User" + } }, "collection": { - "sortBy": "createdAt", - "asc": false + "sortBy": "createdAt", + "asc": false } } diff --git a/application/Espo/Resources/metadata/entityDefs/OutboundEmail.json b/application/Espo/Resources/metadata/entityDefs/OutboundEmail.json deleted file mode 100644 index c5cf9a1f02..0000000000 --- a/application/Espo/Resources/metadata/entityDefs/OutboundEmail.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "fields": { - "name": { - "type": "varchar", - "required": true - }, - "server": { - "type": "varchar", - "required": true - }, - "port": { - "type": "int", - "required": true, - "min": 0, - "max": 9999, - "default": 25 - }, - "auth": { - "type": "bool", - "default": true - }, - "security": { - "type": "enum", - "options": ["", "SSL", "TLS"] - }, - "username": { - "type": "varchar", - "required": true - }, - "password": { - "type": "password" - }, - "fromName": { - "type": "varchar", - "required": true - }, - "fromAddress": { - "type": "varchar", - "required": true - }, - "user": { - "type": "link" - } - }, - "links": { - "user": { - "type": "belongsTo", - "entity": "User" - } - } -} diff --git a/application/Espo/Resources/metadata/entityDefs/PhoneNumber.json b/application/Espo/Resources/metadata/entityDefs/PhoneNumber.json index 61fcf70f05..31ba487935 100644 --- a/application/Espo/Resources/metadata/entityDefs/PhoneNumber.json +++ b/application/Espo/Resources/metadata/entityDefs/PhoneNumber.json @@ -13,7 +13,7 @@ "links": { }, "collection": { - "sortBy": "name", - "asc": true + "sortBy": "name", + "asc": true } } diff --git a/application/Espo/Resources/metadata/entityDefs/Preferences.json b/application/Espo/Resources/metadata/entityDefs/Preferences.json index c7bff38bf6..69a0eb7162 100644 --- a/application/Espo/Resources/metadata/entityDefs/Preferences.json +++ b/application/Espo/Resources/metadata/entityDefs/Preferences.json @@ -36,13 +36,13 @@ "default": "USD" }, "dashboardLayout": { - "type": "text" + "type": "text" }, "dashletOptions": { - "type": "text" + "type": "text" }, "presetFilters": { - "type": "text" + "type": "text" }, "smtpEmailAddress": { "type": "varchar", diff --git a/application/Espo/Resources/metadata/entityDefs/Role.json b/application/Espo/Resources/metadata/entityDefs/Role.json index 4383618a98..4740d442c5 100644 --- a/application/Espo/Resources/metadata/entityDefs/Role.json +++ b/application/Espo/Resources/metadata/entityDefs/Role.json @@ -6,7 +6,7 @@ "type": "varchar" }, "data": { - "type": "text" + "type": "text" } }, "links": { @@ -22,7 +22,7 @@ } }, "collection": { - "sortBy": "name", - "asc": true + "sortBy": "name", + "asc": true } } diff --git a/application/Espo/Resources/metadata/entityDefs/ScheduledJob.json b/application/Espo/Resources/metadata/entityDefs/ScheduledJob.json index e627ed7a79..22731ab17b 100644 --- a/application/Espo/Resources/metadata/entityDefs/ScheduledJob.json +++ b/application/Espo/Resources/metadata/entityDefs/ScheduledJob.json @@ -14,11 +14,11 @@ "options": ["Active", "Inactive"] }, "scheduling": { - "type": "varchar", + "type": "varchar", "required": true, "view": "ScheduledJob.Fields.Scheduling", - "default": "* * * * *" - }, + "default": "* * * * *" + }, "lastRun": { "type": "datetime", "readOnly": true @@ -50,13 +50,13 @@ "entity": "User" }, "log": { - "type": "hasMany", - "entity": "ScheduledJobLogRecord", - "foreign": "scheduledJob" + "type": "hasMany", + "entity": "ScheduledJobLogRecord", + "foreign": "scheduledJob" } }, "collection": { - "sortBy": "name", - "asc": true + "sortBy": "name", + "asc": true } } diff --git a/application/Espo/Resources/metadata/entityDefs/ScheduledJobLogRecord.json b/application/Espo/Resources/metadata/entityDefs/ScheduledJobLogRecord.json index 8a05c52979..24e406687e 100644 --- a/application/Espo/Resources/metadata/entityDefs/ScheduledJobLogRecord.json +++ b/application/Espo/Resources/metadata/entityDefs/ScheduledJobLogRecord.json @@ -18,8 +18,8 @@ "readOnly": true }, "scheduledJob": { - "type": "link" - } + "type": "link" + } }, "links": { "scheduledJob": { @@ -28,7 +28,7 @@ } }, "collection": { - "sortBy": "executionTime", - "asc": false + "sortBy": "executionTime", + "asc": false } } diff --git a/application/Espo/Resources/metadata/entityDefs/Settings.json b/application/Espo/Resources/metadata/entityDefs/Settings.json index fd0d5747fe..ae1112b058 100644 --- a/application/Espo/Resources/metadata/entityDefs/Settings.json +++ b/application/Espo/Resources/metadata/entityDefs/Settings.json @@ -52,7 +52,7 @@ "maxLength": 1 }, "currencyList": { - "type": "array", + "type": "multiEnum", "default": ["USD", "EUR"], "options": ["AED","ANG","ARS","AUD","BGN","BHD","BND","BOB","BRL","BWP","CAD","CHF","CLP","CNY","COP","CRC","CZK","DKK","DOP","DZD","EEK","EGP","EUR","FJD","GBP","HKD","HNL","HRK","HUF","IDR","ILS","INR","JMD","JOD","JPY","KES","KRW","KWD","KYD","KZT","LBP","LKR","LTL","LVL","MAD","MDL","MKD","MUR","MXN","MYR","NAD","NGN","NIO","NOK","NPR","NZD","OMR","PEN","PGK","PHP","PKR","PLN","PYG","QAR","RON","RSD","RUB","SAR","SCR","SEK","SGD","SKK","SLL","SVC","THB","TND","TRY","TTD","TWD","TZS","UAH","UGX","USD","UYU","UZS","VND","YER","ZAR","ZMK"], "required": true @@ -68,8 +68,8 @@ "required": true }, "currencyRates": { - "type": "base", - "view": "Settings.Fields.CurrencyRates" + "type": "base", + "view": "Settings.Fields.CurrencyRates" }, "outboundEmailIsShared": { "type": "bool", @@ -134,77 +134,81 @@ "type": "image" }, "authenticationMethod": { - "type": "enum", - "options": ["Espo", "LDAP"], - "default": "Espo" + "type": "enum", + "options": ["Espo", "LDAP"], + "default": "Espo" }, "ldapHost": { - "type": "varchar", - "required": true + "type": "varchar", + "required": true }, "ldapPort": { - "type": "int", - "max": 9999, - "min": 0, - "default": 389 + "type": "int", + "max": 9999, + "min": 0, + "default": 389 }, "ldapSecurity": { - "type": "enum", - "options": ["", "SSL", "TLS"] + "type": "enum", + "options": ["", "SSL", "TLS"] }, "ldapAuth": { - "type": "bool" + "type": "bool" }, "ldapUsername": { - "type": "varchar", - "required": true + "type": "varchar", + "required": true }, "ldapPassword": { - "type": "password" + "type": "password" }, "ldapBindRequiresDn": { - "type": "bool" + "type": "bool" }, "ldapBaseDn": { - "type": "varchar" + "type": "varchar" }, "ldapUserLoginFilter": { - "type": "varchar" + "type": "varchar" }, "ldapAccountCanonicalForm": { - "type": "enum", - "options": ["Dn", "Username", "Backslash", "Principal"] + "type": "enum", + "options": ["Dn", "Username", "Backslash", "Principal"] }, "ldapAccountDomainName": { - "type": "varchar" + "type": "varchar" }, "ldapAccountDomainNameShort": { - "type": "varchar" + "type": "varchar" }, "ldapAccountFilterFormat": { - "type": "varchar" + "type": "varchar" }, "ldapTryUsernameSplit": { - "type": "bool" + "type": "bool" }, "ldapOptReferrals": { - "type": "bool" + "type": "bool" }, "ldapCreateEspoUser": { - "type": "bool", - "default": true + "type": "bool", + "default": true }, "disableExport": { - "type": "bool", - "default": false - }, + "type": "bool", + "default": false + }, "assignmentEmailNotifications": { - "type": "bool", - "default": false - }, - "assignmentEmailNotificationsEntityList": { - "type": "array", - "translation": "Global.scopeNamesPlural" - } + "type": "bool", + "default": false + }, + "assignmentEmailNotificationsEntityList": { + "type": "multiEnum", + "translation": "Global.scopeNamesPlural" + }, + "b2cMode": { + "type": "bool", + "default": false + } } } diff --git a/application/Espo/Resources/metadata/entityDefs/Team.json b/application/Espo/Resources/metadata/entityDefs/Team.json index dd24fe86d7..6801285827 100644 --- a/application/Espo/Resources/metadata/entityDefs/Team.json +++ b/application/Espo/Resources/metadata/entityDefs/Team.json @@ -7,6 +7,15 @@ "roles": { "type": "linkMultiple", "tooltip": true + }, + "positionList": { + "type": "array", + "tooltip": true + }, + "userRole": { + "type": "varchar", + "notStorable": true, + "disabled": true } }, "links": { @@ -22,7 +31,7 @@ } }, "collection": { - "sortBy": "name", - "asc": true + "sortBy": "name", + "asc": true } } diff --git a/application/Espo/Resources/metadata/entityDefs/User.json b/application/Espo/Resources/metadata/entityDefs/User.json index 0c746f061e..0726068503 100644 --- a/application/Espo/Resources/metadata/entityDefs/User.json +++ b/application/Espo/Resources/metadata/entityDefs/User.json @@ -1,7 +1,8 @@ { "fields": { "isAdmin": { - "type": "bool" + "type": "bool", + "tooltip": true }, "userName": { "type": "varchar", @@ -13,8 +14,9 @@ "name": { "type": "personName" }, - "password": { + "password": { "type": "password", + "maxLength": 150, "internal": true }, "salutationName": { @@ -47,22 +49,34 @@ }, "token": { "type": "varchar", - "notStorable": true + "notStorable": true, + "disabled": true }, "defaultTeam": { "type": "link", "tooltip": true }, "acceptanceStatus": { - "type": "varchar", - "notStorable": true, - "disabled": true + "type": "varchar", + "notStorable": true, + "disabled": true + }, + "teamRole": { + "type": "varchar", + "notStorable": true, + "disabled": true }, "teams": { - "type": "linkMultiple" + "type": "linkMultiple", + "tooltip": true, + "columns": { + "role": "userRole" + }, + "view": "User.Fields.Teams" }, "roles": { - "type": "linkMultiple" + "type": "linkMultiple", + "tooltip": true } }, "links": { @@ -73,7 +87,13 @@ "teams": { "type": "hasMany", "entity": "Team", - "foreign": "users" + "foreign": "users", + "additionalColumns": { + "role": { + "type": "varchar", + "len": 100 + } + } }, "roles": { "type": "hasMany", @@ -84,20 +104,20 @@ "type": "hasOne", "entity": "Preferences" }, - "meetings": { + "meetings": { "type": "hasMany", "entity": "Meeting", "foreign": "users" }, - "calls": { + "calls": { "type": "hasMany", "entity": "Call", "foreign": "users" } }, "collection": { - "sortBy": "userName", - "asc": true, - "textFilterFields": ["name", "userName"] + "sortBy": "userName", + "asc": true, + "textFilterFields": ["name", "userName"] } } diff --git a/application/Espo/Resources/metadata/fields/address.json b/application/Espo/Resources/metadata/fields/address.json index 561875579d..832b8f3146 100644 --- a/application/Espo/Resources/metadata/fields/address.json +++ b/application/Espo/Resources/metadata/fields/address.json @@ -8,9 +8,9 @@ ], "fields":{ "street":{ - "type": "text", - "maxLength": 255, - "dbType": "varchar" + "type": "text", + "maxLength": 255, + "dbType": "varchar" }, "city":{ "type":"varchar" diff --git a/application/Espo/Resources/metadata/fields/enum.json b/application/Espo/Resources/metadata/fields/enum.json index 0c669276ba..b3236239eb 100644 --- a/application/Espo/Resources/metadata/fields/enum.json +++ b/application/Espo/Resources/metadata/fields/enum.json @@ -7,7 +7,8 @@ }, { "name":"options", - "type":"array" + "type":"array", + "view": "Admin.FieldManager.Fields.Options" }, { "name":"default", diff --git a/application/Espo/Resources/metadata/fields/multiEnum.json b/application/Espo/Resources/metadata/fields/multiEnum.json new file mode 100644 index 0000000000..f1bf6dcfdc --- /dev/null +++ b/application/Espo/Resources/metadata/fields/multiEnum.json @@ -0,0 +1,18 @@ +{ + "params":[ + { + "name": "required", + "type": "bool", + "default": false + }, + { + "name":"options", + "type":"array" + } + ], + "filter": false, + "notCreatable": false, + "fieldDefs":{ + "type":"jsonArray" + } +} diff --git a/application/Espo/Resources/metadata/fields/multienum.json b/application/Espo/Resources/metadata/fields/multienum.json deleted file mode 100644 index c25cc33a62..0000000000 --- a/application/Espo/Resources/metadata/fields/multienum.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "params":[ - { - "name":"required", - "type":"bool", - "default":false - }, - { - "name":"options", - "type":"array" - }, - { - "name":"translation", - "type":"varchar" - } - ], - "notCreatable": true, - "filter": false -} diff --git a/application/Espo/Resources/metadata/integrations/Google.json b/application/Espo/Resources/metadata/integrations/Google.json index 26b2502c36..e95bd623ac 100644 --- a/application/Espo/Resources/metadata/integrations/Google.json +++ b/application/Espo/Resources/metadata/integrations/Google.json @@ -1,22 +1,22 @@ { - "fields": { - "clientId": { - "type": "varchar", - "maxLength": 255, - "required": true - }, - "clientSecret": { - "type": "varchar", - "maxLength": 255, - "required": true - } - }, - "params": { - "endpoint": "https://accounts.google.com/o/oauth2/auth", - "tokenEndpoint": "https://accounts.google.com/o/oauth2/token", - "scope": "https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/calendar" - }, - "allowUserAccounts": true, - "authMethod": "OAuth2", - "clientClassName": "\\Espo\\Core\\ExternalAccount\\Clients\\Google" + "fields": { + "clientId": { + "type": "varchar", + "maxLength": 255, + "required": true + }, + "clientSecret": { + "type": "varchar", + "maxLength": 255, + "required": true + } + }, + "params": { + "endpoint": "https://accounts.google.com/o/oauth2/auth", + "tokenEndpoint": "https://accounts.google.com/o/oauth2/token", + "scope": "https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/calendar" + }, + "allowUserAccounts": true, + "authMethod": "OAuth2", + "clientClassName": "\\Espo\\Core\\ExternalAccount\\Clients\\Google" } diff --git a/application/Espo/Resources/metadata/scopes/AuthToken.json b/application/Espo/Resources/metadata/scopes/AuthToken.json index a64dc42037..e7970c2b06 100644 --- a/application/Espo/Resources/metadata/scopes/AuthToken.json +++ b/application/Espo/Resources/metadata/scopes/AuthToken.json @@ -1,7 +1,7 @@ { - "entity": true, - "layouts": false, - "tab": false, - "acl": false, - "customizable":false + "entity": true, + "layouts": false, + "tab": false, + "acl": false, + "customizable":false } diff --git a/application/Espo/Resources/metadata/scopes/Email.json b/application/Espo/Resources/metadata/scopes/Email.json index ce2ff4e148..6f6b169b19 100644 --- a/application/Espo/Resources/metadata/scopes/Email.json +++ b/application/Espo/Resources/metadata/scopes/Email.json @@ -1,6 +1,6 @@ { - "entity": true, - "layouts": false, - "tab": true, - "acl": true + "entity": true, + "layouts": false, + "tab": true, + "acl": true } diff --git a/application/Espo/Resources/metadata/scopes/EmailAccount.json b/application/Espo/Resources/metadata/scopes/EmailAccount.json index 62a7844e2b..7469fbdbdc 100644 --- a/application/Espo/Resources/metadata/scopes/EmailAccount.json +++ b/application/Espo/Resources/metadata/scopes/EmailAccount.json @@ -1,6 +1,6 @@ { - "entity": true, - "layouts": false, - "tab": false, - "acl": false + "entity": true, + "layouts": false, + "tab": false, + "acl": false } diff --git a/application/Espo/Resources/metadata/scopes/EmailAccountScope.json b/application/Espo/Resources/metadata/scopes/EmailAccountScope.json new file mode 100644 index 0000000000..40dba6312e --- /dev/null +++ b/application/Espo/Resources/metadata/scopes/EmailAccountScope.json @@ -0,0 +1,6 @@ +{ + "entity": false, + "layouts": false, + "tab": false, + "acl": "boolean" +} diff --git a/application/Espo/Resources/metadata/scopes/EmailAddress.json b/application/Espo/Resources/metadata/scopes/EmailAddress.json index a64dc42037..e7970c2b06 100644 --- a/application/Espo/Resources/metadata/scopes/EmailAddress.json +++ b/application/Espo/Resources/metadata/scopes/EmailAddress.json @@ -1,7 +1,7 @@ { - "entity": true, - "layouts": false, - "tab": false, - "acl": false, - "customizable":false + "entity": true, + "layouts": false, + "tab": false, + "acl": false, + "customizable":false } diff --git a/application/Espo/Resources/metadata/scopes/EmailTemplate.json b/application/Espo/Resources/metadata/scopes/EmailTemplate.json index 3a58f377f7..0f8a0bc591 100644 --- a/application/Espo/Resources/metadata/scopes/EmailTemplate.json +++ b/application/Espo/Resources/metadata/scopes/EmailTemplate.json @@ -1,7 +1,7 @@ { - "entity": true, - "layouts": false, - "tab": true, - "acl": true, - "customizable":false + "entity": true, + "layouts": false, + "tab": true, + "acl": true, + "customizable":false } diff --git a/application/Espo/Resources/metadata/scopes/Extension.json b/application/Espo/Resources/metadata/scopes/Extension.json index 55066c1a9f..a5280171da 100644 --- a/application/Espo/Resources/metadata/scopes/Extension.json +++ b/application/Espo/Resources/metadata/scopes/Extension.json @@ -1,7 +1,7 @@ { - "entity": true, - "layouts": false, - "tab": false, - "acl": false, - "customizable": false + "entity": true, + "layouts": false, + "tab": false, + "acl": false, + "customizable": false } diff --git a/application/Espo/Resources/metadata/scopes/ExternalAccount.json b/application/Espo/Resources/metadata/scopes/ExternalAccount.json index 6fb84e513f..432d5091d0 100644 --- a/application/Espo/Resources/metadata/scopes/ExternalAccount.json +++ b/application/Espo/Resources/metadata/scopes/ExternalAccount.json @@ -1,7 +1,7 @@ { - "entity":true, - "layouts":false, - "tab":false, - "acl":false, - "customizable":false + "entity":true, + "layouts":false, + "tab":false, + "acl":false, + "customizable":false } diff --git a/application/Espo/Resources/metadata/scopes/Integration.json b/application/Espo/Resources/metadata/scopes/Integration.json index 6fb84e513f..432d5091d0 100644 --- a/application/Espo/Resources/metadata/scopes/Integration.json +++ b/application/Espo/Resources/metadata/scopes/Integration.json @@ -1,7 +1,7 @@ { - "entity":true, - "layouts":false, - "tab":false, - "acl":false, - "customizable":false + "entity":true, + "layouts":false, + "tab":false, + "acl":false, + "customizable":false } diff --git a/application/Espo/Resources/metadata/scopes/Job.json b/application/Espo/Resources/metadata/scopes/Job.json index a64dc42037..e7970c2b06 100644 --- a/application/Espo/Resources/metadata/scopes/Job.json +++ b/application/Espo/Resources/metadata/scopes/Job.json @@ -1,7 +1,7 @@ { - "entity": true, - "layouts": false, - "tab": false, - "acl": false, - "customizable":false + "entity": true, + "layouts": false, + "tab": false, + "acl": false, + "customizable":false } diff --git a/application/Espo/Resources/metadata/scopes/Notification.json b/application/Espo/Resources/metadata/scopes/Notification.json index 6fb84e513f..432d5091d0 100644 --- a/application/Espo/Resources/metadata/scopes/Notification.json +++ b/application/Espo/Resources/metadata/scopes/Notification.json @@ -1,7 +1,7 @@ { - "entity":true, - "layouts":false, - "tab":false, - "acl":false, - "customizable":false + "entity":true, + "layouts":false, + "tab":false, + "acl":false, + "customizable":false } diff --git a/application/Espo/Resources/metadata/scopes/OutboundEmail.json b/application/Espo/Resources/metadata/scopes/OutboundEmail.json deleted file mode 100644 index a64dc42037..0000000000 --- a/application/Espo/Resources/metadata/scopes/OutboundEmail.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "entity": true, - "layouts": false, - "tab": false, - "acl": false, - "customizable":false -} diff --git a/application/Espo/Resources/metadata/scopes/PhoneNumber.json b/application/Espo/Resources/metadata/scopes/PhoneNumber.json index a64dc42037..e7970c2b06 100644 --- a/application/Espo/Resources/metadata/scopes/PhoneNumber.json +++ b/application/Espo/Resources/metadata/scopes/PhoneNumber.json @@ -1,7 +1,7 @@ { - "entity": true, - "layouts": false, - "tab": false, - "acl": false, - "customizable":false + "entity": true, + "layouts": false, + "tab": false, + "acl": false, + "customizable":false } diff --git a/application/Espo/Resources/metadata/scopes/ScheduledJob.json b/application/Espo/Resources/metadata/scopes/ScheduledJob.json index a64dc42037..e7970c2b06 100644 --- a/application/Espo/Resources/metadata/scopes/ScheduledJob.json +++ b/application/Espo/Resources/metadata/scopes/ScheduledJob.json @@ -1,7 +1,7 @@ { - "entity": true, - "layouts": false, - "tab": false, - "acl": false, - "customizable":false + "entity": true, + "layouts": false, + "tab": false, + "acl": false, + "customizable":false } diff --git a/application/Espo/Resources/metadata/scopes/ScheduledJobLogRecord.json b/application/Espo/Resources/metadata/scopes/ScheduledJobLogRecord.json index a64dc42037..e7970c2b06 100644 --- a/application/Espo/Resources/metadata/scopes/ScheduledJobLogRecord.json +++ b/application/Espo/Resources/metadata/scopes/ScheduledJobLogRecord.json @@ -1,7 +1,7 @@ { - "entity": true, - "layouts": false, - "tab": false, - "acl": false, - "customizable":false + "entity": true, + "layouts": false, + "tab": false, + "acl": false, + "customizable":false } diff --git a/application/Espo/Resources/metadata/scopes/Stream.json b/application/Espo/Resources/metadata/scopes/Stream.json index 36e0d2d257..d606885db7 100644 --- a/application/Espo/Resources/metadata/scopes/Stream.json +++ b/application/Espo/Resources/metadata/scopes/Stream.json @@ -1,7 +1,7 @@ { - "entity":false, - "layouts":false, - "tab":false, - "acl":false, - "customizable":false + "entity":false, + "layouts":false, + "tab":false, + "acl":false, + "customizable":false } diff --git a/application/Espo/Resources/metadata/scopes/UniqueId.json b/application/Espo/Resources/metadata/scopes/UniqueId.json index a64dc42037..e7970c2b06 100644 --- a/application/Espo/Resources/metadata/scopes/UniqueId.json +++ b/application/Espo/Resources/metadata/scopes/UniqueId.json @@ -1,7 +1,7 @@ { - "entity": true, - "layouts": false, - "tab": false, - "acl": false, - "customizable":false + "entity": true, + "layouts": false, + "tab": false, + "acl": false, + "customizable":false } diff --git a/application/Espo/Resources/routes.json b/application/Espo/Resources/routes.json index 41eb470ab4..7ff0690483 100644 --- a/application/Espo/Resources/routes.json +++ b/application/Espo/Resources/routes.json @@ -1,318 +1,318 @@ [ { - "route":"/", - "method":"get", - "params":"

EspoCRM REST API<\/h1>" + "route":"/", + "method":"get", + "params":"

EspoCRM REST API<\/h1>" }, { - "route":"/App/user", - "method":"get", - "params":{ - "controller":"App", - "action":"user" - } + "route":"/App/user", + "method":"get", + "params":{ + "controller":"App", + "action":"user" + } }, { - "route":"/Metadata", - "method":"get", - "params":{ - "controller":"Metadata" - } + "route":"/Metadata", + "method":"get", + "params":{ + "controller":"Metadata" + } }, { - "route":"I18n", - "method":"get", - "params":{ - "controller":"I18n" - } + "route":"I18n", + "method":"get", + "params":{ + "controller":"I18n" + } }, { - "route":"/Settings", - "method":"get", - "params":{ - "controller":"Settings" - }, - "conditions":{ - "auth":false - } + "route":"/Settings", + "method":"get", + "params":{ + "controller":"Settings" + }, + "conditions":{ + "auth":false + } }, { - "route":"/Settings", - "method":"patch", - "params":{ - "controller":"Settings" - } + "route":"/Settings", + "method":"patch", + "params":{ + "controller":"Settings" + } }, { - "route":"/Stream", - "method":"get", - "params":{ - "controller":"Stream", - "action":"list", - "scope": "User" - } + "route":"/Stream", + "method":"get", + "params":{ + "controller":"Stream", + "action":"list", + "scope": "User" + } }, { - "route":"/GlobalSearch/:query", - "method":"get", - "params":{ - "controller":"GlobalSearch", - "action":"search", - "query": ":query" - } + "route":"/GlobalSearch/:query", + "method":"get", + "params":{ + "controller":"GlobalSearch", + "action":"search", + "query": ":query" + } }, { - "route":"/:controller/action/:action", - "method":"post", - "params":{ - "controller":":controller", - "action":":action" - } + "route":"/:controller/action/:action", + "method":"post", + "params":{ + "controller":":controller", + "action":":action" + } }, { - "route":"/:controller/action/:action", - "method":"put", - "params":{ - "controller":":controller", - "action":":action" - } + "route":"/:controller/action/:action", + "method":"put", + "params":{ + "controller":":controller", + "action":":action" + } }, { - "route":"/:controller/action/:action", - "method":"get", - "params":{ - "controller":":controller", - "action":":action" - } + "route":"/:controller/action/:action", + "method":"get", + "params":{ + "controller":":controller", + "action":":action" + } }, { - "route":"/:controller/layout/:name", - "method":"get", - "params":{ - "controller":"Layout", - "scope":":controller" - } + "route":"/:controller/layout/:name", + "method":"get", + "params":{ + "controller":"Layout", + "scope":":controller" + } }, { - "route":"/:controller/layout/:name", - "method":"put", - "params":{ - "controller":"Layout", - "scope":":controller" - } + "route":"/:controller/layout/:name", + "method":"put", + "params":{ + "controller":"Layout", + "scope":":controller" + } }, { - "route":"/:controller/layout/:name", - "method":"patch", - "params":{ - "controller":"Layout", - "scope":":controller" - } + "route":"/:controller/layout/:name", + "method":"patch", + "params":{ + "controller":"Layout", + "scope":":controller" + } }, { - "route":"/Admin/rebuild", - "method":"get", - "params":{ - "controller":"Admin", - "action":"rebuild" - } + "route":"/Admin/rebuild", + "method":"get", + "params":{ + "controller":"Admin", + "action":"rebuild" + } }, { - "route":"/Admin/clearCache", - "method":"get", - "params":{ - "controller":"Admin", - "action":"clearCache" - } + "route":"/Admin/clearCache", + "method":"get", + "params":{ + "controller":"Admin", + "action":"clearCache" + } }, { - "route":"/Admin/jobs", - "method":"get", - "params":{ - "controller":"Admin", - "action":"jobs" - } + "route":"/Admin/jobs", + "method":"get", + "params":{ + "controller":"Admin", + "action":"jobs" + } }, { - "route":"/Admin/fieldManager/:scope/:name", - "method":"get", - "params":{ - "controller":"FieldManager", - "action":"read", - "scope":":scope", - "name":":name" - } + "route":"/Admin/fieldManager/:scope/:name", + "method":"get", + "params":{ + "controller":"FieldManager", + "action":"read", + "scope":":scope", + "name":":name" + } }, { - "route":"/Admin/fieldManager/:scope", - "method":"post", - "params":{ - "controller":"FieldManager", - "action":"create", - "scope":":scope" - } + "route":"/Admin/fieldManager/:scope", + "method":"post", + "params":{ + "controller":"FieldManager", + "action":"create", + "scope":":scope" + } }, { - "route":"/Admin/fieldManager/:scope/:name", - "method":"put", - "params":{ - "controller":"FieldManager", - "action":"update", - "scope":":scope", - "name":":name" - } + "route":"/Admin/fieldManager/:scope/:name", + "method":"put", + "params":{ + "controller":"FieldManager", + "action":"update", + "scope":":scope", + "name":":name" + } }, { - "route":"/Admin/fieldManager/:scope/:name", - "method":"delete", - "params":{ - "controller":"FieldManager", - "action":"delete", - "scope":":scope", - "name":":name" - } + "route":"/Admin/fieldManager/:scope/:name", + "method":"delete", + "params":{ + "controller":"FieldManager", + "action":"delete", + "scope":":scope", + "name":":name" + } }, { - "route":"/:controller/:id", - "method":"get", - "params":{ - "controller":":controller", - "action":"read", - "id":":id" - } + "route":"/:controller/:id", + "method":"get", + "params":{ + "controller":":controller", + "action":"read", + "id":":id" + } }, { - "route":"/:controller", - "method":"get", - "params":{ - "controller":":controller", - "action":"index" - } + "route":"/:controller", + "method":"get", + "params":{ + "controller":":controller", + "action":"index" + } }, { - "route":"/:controller", - "method":"post", - "params":{ - "controller":":controller", - "action":"create" - } + "route":"/:controller", + "method":"post", + "params":{ + "controller":":controller", + "action":"create" + } }, { - "route":"/:controller/:id", - "method":"put", - "params":{ - "controller":":controller", - "action":"update", - "id":":id" - } + "route":"/:controller/:id", + "method":"put", + "params":{ + "controller":":controller", + "action":"update", + "id":":id" + } }, { - "route":"/:controller/:id", - "method":"patch", - "params":{ - "controller":":controller", - "action":"patch", - "id":":id" - } + "route":"/:controller/:id", + "method":"patch", + "params":{ + "controller":":controller", + "action":"patch", + "id":":id" + } }, { - "route":"/:controller/:id", - "method":"delete", - "params":{ - "controller":":controller", - "action":"delete", - "id":":id" - } + "route":"/:controller/:id", + "method":"delete", + "params":{ + "controller":":controller", + "action":"delete", + "id":":id" + } }, { - "route":"/:controller/:id/stream", - "method":"get", - "params":{ - "controller":"Stream", - "action":"list", - "id":":id", - "scope":":controller" - } + "route":"/:controller/:id/stream", + "method":"get", + "params":{ + "controller":"Stream", + "action":"list", + "id":":id", + "scope":":controller" + } }, { - "route":"/:controller/:id/subscription", - "method":"put", - "params":{ - "controller":":controller", - "id":":id", - "action":"follow" - } + "route":"/:controller/:id/subscription", + "method":"put", + "params":{ + "controller":":controller", + "id":":id", + "action":"follow" + } }, { - "route":"/:controller/:id/subscription", - "method":"delete", - "params":{ - "controller":":controller", - "id":":id", - "action":"unfollow" - } + "route":"/:controller/:id/subscription", + "method":"delete", + "params":{ + "controller":":controller", + "id":":id", + "action":"unfollow" + } }, { - "route":"/:controller/:id/:link", - "method":"get", - "params":{ - "controller":":controller", - "action":"listLinked", - "id":":id", - "link":":link" - } + "route":"/:controller/:id/:link", + "method":"get", + "params":{ + "controller":":controller", + "action":"listLinked", + "id":":id", + "link":":link" + } }, { - "route":"/:controller/:id/:link", - "method":"post", - "params":{ - "controller":":controller", - "action":"createLink", - "id":":id", - "link":":link" - } + "route":"/:controller/:id/:link", + "method":"post", + "params":{ + "controller":":controller", + "action":"createLink", + "id":":id", + "link":":link" + } }, { - "route":"/:controller/:id/:link", - "method":"delete", - "params":{ - "controller":":controller", - "action":"removeLink", - "id":":id", - "link":":link" - } + "route":"/:controller/:id/:link", + "method":"delete", + "params":{ + "controller":":controller", + "action":"removeLink", + "id":":id", + "link":":link" + } } ] diff --git a/application/Espo/SelectManagers/EmailAccount.php b/application/Espo/SelectManagers/EmailAccount.php index 8e289b9294..c9f492b88c 100644 --- a/application/Espo/SelectManagers/EmailAccount.php +++ b/application/Espo/SelectManagers/EmailAccount.php @@ -23,13 +23,13 @@ namespace Espo\SelectManagers; class EmailAccount extends \Espo\Core\SelectManagers\Base -{ +{ protected function access(&$result) { - if (!array_key_exists('whereClause', $result)) { - $result['whereClause'] = array(); - } - $result['whereClause']['assignedUserId'] = $this->user->id; + if (!array_key_exists('whereClause', $result)) { + $result['whereClause'] = array(); + } + $result['whereClause']['assignedUserId'] = $this->user->id; } } diff --git a/application/Espo/Services/Attachment.php b/application/Espo/Services/Attachment.php index 7800a0bfdb..9e7b96eb37 100644 --- a/application/Espo/Services/Attachment.php +++ b/application/Espo/Services/Attachment.php @@ -18,26 +18,26 @@ * * 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\Services; class Attachment extends Record { - - protected $notFilteringFields = array('contents'); - - public function createEntity($data) - { - if (!empty($data['file'])) { - list($prefix, $contents) = explode(',', $data['file']); - $contents = base64_decode($contents); - $data['contents'] = $contents; - } - - $entity = parent::createEntity($data); - - return $entity; - } + + protected $notFilteringFields = array('contents'); + + public function createEntity($data) + { + if (!empty($data['file'])) { + list($prefix, $contents) = explode(',', $data['file']); + $contents = base64_decode($contents); + $data['contents'] = $contents; + } + + $entity = parent::createEntity($data); + + return $entity; + } } diff --git a/application/Espo/Services/AuthToken.php b/application/Espo/Services/AuthToken.php index e47ca45d65..f359daf71c 100644 --- a/application/Espo/Services/AuthToken.php +++ b/application/Espo/Services/AuthToken.php @@ -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\Services; @@ -27,7 +27,7 @@ use \Espo\Core\Exceptions\Error; use \Espo\Core\Exceptions\NotFound; class AuthToken extends Record -{ - protected $internalFields = array('hash', 'token'); +{ + protected $internalFields = array('hash', 'token'); } diff --git a/application/Espo/Services/Email.php b/application/Espo/Services/Email.php index 0b8895fa0d..36a7233a09 100644 --- a/application/Espo/Services/Email.php +++ b/application/Espo/Services/Email.php @@ -29,234 +29,275 @@ use \Espo\Core\Exceptions\Error; class Email extends Record { - protected function init() - { - $this->dependencies[] = 'mailSender'; - $this->dependencies[] = 'preferences'; - $this->dependencies[] = 'fileManager'; - } - - protected function getFileManager() - { - return $this->getInjection('fileManager'); - } + protected function init() + { + $this->dependencies[] = 'mailSender'; + $this->dependencies[] = 'preferences'; + $this->dependencies[] = 'fileManager'; + $this->dependencies[] = 'crypt'; + } + + protected function getFileManager() + { + return $this->getInjection('fileManager'); + } - protected function getMailSender() - { - return $this->injections['mailSender']; - } + protected function getMailSender() + { + return $this->injections['mailSender']; + } - protected function getPreferences() - { - return $this->injections['preferences']; - } + protected function getPreferences() + { + return $this->injections['preferences']; + } - public function createEntity($data) - { - $entity = parent::createEntity($data); + protected function getCrypt() + { + return $this->injections['crypt']; + } - if ($entity && $entity->get('status') == 'Sending') { - $emailSender = $this->getMailSender(); + public function createEntity($data) + { + $entity = parent::createEntity($data); - if (strtolower($this->getUser()->get('emailAddress')) == strtolower($entity->get('from'))) { - $smtpParams = $this->getPreferences()->getSmtpParams(); - if ($smtpParams) { - $smtpParams['fromName'] = $this->getUser()->get('name'); - $emailSender->useSmtp($smtpParams); - } - } else { - if (!$this->getConfig()->get('outboundEmailIsShared')) { - throw new Error('Can not use system smtp. outboundEmailIsShared is false.'); - } - } + if ($entity && $entity->get('status') == 'Sending') { + $emailSender = $this->getMailSender(); - $emailSender->send($entity); + if (strtolower($this->getUser()->get('emailAddress')) == strtolower($entity->get('from'))) { + $smtpParams = $this->getPreferences()->getSmtpParams(); + if (array_key_exists('password', $smtpParams)) { + $smtpParams['password'] = $this->getCrypt()->decrypt($smtpParams['password']); + } + + if ($smtpParams) { + $smtpParams['fromName'] = $this->getUser()->get('name'); + $emailSender->useSmtp($smtpParams); + } + } else { + if (!$this->getConfig()->get('outboundEmailIsShared')) { + throw new Error('Can not use system smtp. outboundEmailIsShared is false.'); + } + $emailSender->setParams(array( + 'fromName' => $this->getUser()->get('name') + )); + } - $this->getEntityManager()->saveEntity($entity); - } + $emailSender->send($entity); - return $entity; - } + $this->getEntityManager()->saveEntity($entity); + } - public function getEntity($id = null) - { - $entity = parent::getEntity($id); - if (!empty($id)) { + return $entity; + } - if ($entity->get('fromEmailAddressName')) { - $entity->set('from', $entity->get('fromEmailAddressName')); - } + public function getEntity($id = null) + { + $entity = parent::getEntity($id); + if (!empty($id)) { - $entity->loadLinkMultipleField('toEmailAddresses'); - $entity->loadLinkMultipleField('ccEmailAddresses'); - $entity->loadLinkMultipleField('bccEmailAddresses'); + if ($entity->get('fromEmailAddressName')) { + $entity->set('from', $entity->get('fromEmailAddressName')); + } - $names = $entity->get('toEmailAddressesNames'); - if (!empty($names)) { - $arr = array(); - foreach ($names as $id => $address) { - $arr[] = $address; - } - $entity->set('to', implode(';', $arr)); - } + $entity->loadLinkMultipleField('toEmailAddresses'); + $entity->loadLinkMultipleField('ccEmailAddresses'); + $entity->loadLinkMultipleField('bccEmailAddresses'); - $names = $entity->get('ccEmailAddressesNames'); - if (!empty($names)) { - $arr = array(); - foreach ($names as $id => $address) { - $arr[] = $address; - } - $entity->set('cc', implode(';', $arr)); - } + $names = $entity->get('toEmailAddressesNames'); + if (!empty($names)) { + $arr = array(); + foreach ($names as $id => $address) { + $arr[] = $address; + } + $entity->set('to', implode(';', $arr)); + } - $names = $entity->get('bccEmailAddressesNames'); - if (!empty($names)) { - $arr = array(); - foreach ($names as $id => $address) { - $arr[] = $address; - } - $entity->set('bcc', implode(';', $arr)); - } - - $this->loadNameHash($entity); + $names = $entity->get('ccEmailAddressesNames'); + if (!empty($names)) { + $arr = array(); + foreach ($names as $id => $address) { + $arr[] = $address; + } + $entity->set('cc', implode(';', $arr)); + } - } - return $entity; - } - - public function loadNameHash(Entity $entity) - { - $addressList = array(); - if ($entity->get('from')) { - $addressList[] = $entity->get('from'); - } - - $arr = explode(';', $entity->get('to')); - foreach ($arr as $address) { - if (!in_array($address, $addressList)) { - $addressList[] = $address; - } - } - - $arr = explode(';', $entity->get('cc')); - foreach ($arr as $address) { - if (!in_array($address, $addressList)) { - $addressList[] = $address; - } - } - - $nameHash = array(); - $typeHash = array(); - $idHash = array(); - foreach ($addressList as $address) { - $p = $this->getEntityManager()->getRepository('EmailAddress')->getEntityByAddress($address); - if ($p) { - $nameHash[$address] = $p->get('name'); - $typeHash[$address] = $p->getEntityName(); - $idHash[$address] = $p->id; - } - } - - $entity->set('nameHash', $nameHash); - $entity->set('typeHash', $typeHash); - $entity->set('idHash', $idHash); - } - - public function findEntities($params) - { - $searchByEmailAddress = false; - if (!empty($params['where']) && is_array($params['where'])) { - foreach ($params['where'] as $i => $p) { - if (!empty($p['field']) && $p['field'] == 'emailAddress') { - $searchByEmailAddress = true; - $emailAddress = $this->getEntityManager()->getRepository('EmailAddress')->where(array( - 'lower' => strtolower($p['value']) - ))->findOne(); - unset($params['where'][$i]); - $emailAddressId = null; - if ($emailAddress) { - $emailAddressId = $emailAddress->id; - } - } - - } - } - - $selectParams = $this->getSelectManager($this->entityName)->getSelectParams($params, true); - - if ($searchByEmailAddress) { - if ($emailAddressId) { - $pdo = $this->getEntityManager()->getPDO(); - - $selectParams['customJoin'] = " - LEFT JOIN email_email_address - ON - email_email_address.email_id = email.id AND - email_email_address.deleted = 0 - "; - $selectParams['customWhere'] = " - AND - ( - email.from_email_address_id = ".$pdo->quote($emailAddressId)." OR - email_email_address.email_address_id = ".$pdo->quote($emailAddressId)." - ) - "; - } else { - $selectParams['customWhere'] = ' AND 0'; - } - - } - - $collection = $this->getRepository()->find($selectParams); - - foreach ($collection as $e) { - $this->loadParentNameFields($e); - } - - return array( - 'total' => $this->getRepository()->count($selectParams), - 'collection' => $collection, - ); - } - - public function getCopiedAttachments($id) - { - $ids = array(); - $names = new \stdClass(); - - if (!empty($id)) { - $email = $this->getEntityManager()->getEntity('Email', $id); - if ($email && $this->getAcl()->check($email, 'read')) { - $email->loadLinkMultipleField('attachments'); - $attachmentsIds = $email->get('attachmentsIds'); - - foreach ($attachmentsIds as $attachmentId) { - $source = $this->getEntityManager()->getEntity('Attachment', $attachmentId); - if ($source) { - $attachment = $this->getEntityManager()->getEntity('Attachment'); - $attachment->set('role', 'Attachment'); - $attachment->set('type', $source->get('type')); - $attachment->set('size', $source->get('size')); - $attachment->set('global', $source->get('global')); - $attachment->set('name', $source->get('name')); - - $this->getEntityManager()->saveEntity($attachment); - - $contents = $this->getFileManager()->getContents('data/upload/' . $source->id); - if (!empty($contents)) { - $this->getFileManager()->putContents('data/upload/' . $attachment->id, $contents); - $ids[] = $attachment->id; - $names->{$attachment->id} = $attachment->get('name'); - } - } - } - } - } - - return array( - 'ids' => $ids, - 'names' => $names - ); - } + $names = $entity->get('bccEmailAddressesNames'); + if (!empty($names)) { + $arr = array(); + foreach ($names as $id => $address) { + $arr[] = $address; + } + $entity->set('bcc', implode(';', $arr)); + } + + $this->loadNameHash($entity); + + } + return $entity; + } + + public function loadNameHash(Entity $entity) + { + $addressList = array(); + if ($entity->get('from')) { + $addressList[] = $entity->get('from'); + } + + $arr = explode(';', $entity->get('to')); + foreach ($arr as $address) { + if (!in_array($address, $addressList)) { + $addressList[] = $address; + } + } + + $arr = explode(';', $entity->get('cc')); + foreach ($arr as $address) { + if (!in_array($address, $addressList)) { + $addressList[] = $address; + } + } + + $nameHash = array(); + $typeHash = array(); + $idHash = array(); + foreach ($addressList as $address) { + $p = $this->getEntityManager()->getRepository('EmailAddress')->getEntityByAddress($address); + if ($p) { + $nameHash[$address] = $p->get('name'); + $typeHash[$address] = $p->getEntityName(); + $idHash[$address] = $p->id; + } + } + + $entity->set('nameHash', $nameHash); + $entity->set('typeHash', $typeHash); + $entity->set('idHash', $idHash); + } + + public function findEntities($params) + { + $searchByEmailAddress = false; + if (!empty($params['where']) && is_array($params['where'])) { + foreach ($params['where'] as $i => $p) { + if (!empty($p['field']) && $p['field'] == 'emailAddress') { + $searchByEmailAddress = true; + $emailAddress = $this->getEntityManager()->getRepository('EmailAddress')->where(array( + 'lower' => strtolower($p['value']) + ))->findOne(); + unset($params['where'][$i]); + $emailAddressId = null; + if ($emailAddress) { + $emailAddressId = $emailAddress->id; + } + } + + } + } + + $selectParams = $this->getSelectManager($this->entityName)->getSelectParams($params, true); + + if ($searchByEmailAddress) { + if ($emailAddressId) { + $pdo = $this->getEntityManager()->getPDO(); + + $selectParams['distinct'] = true; + + $selectParams['customJoin'] = " + LEFT JOIN email_email_address + ON + email_email_address.email_id = email.id AND + email_email_address.deleted = 0 + "; + $selectParams['customWhere'] = " + AND + ( + email.from_email_address_id = ".$pdo->quote($emailAddressId)." OR + email_email_address.email_address_id = ".$pdo->quote($emailAddressId)." + ) + "; + } else { + $selectParams['customWhere'] = ' AND 0'; + } + + } + + $collection = $this->getRepository()->find($selectParams); + + foreach ($collection as $e) { + $this->loadParentNameFields($e); + } + + return array( + 'total' => $this->getRepository()->count($selectParams), + 'collection' => $collection, + ); + } + + public function copyAttachments($emailId, $parentType, $parentId) + { + return $this->getCopiedAttachments($emailId, $parentType, $parentId); + } + + public function getCopiedAttachments($id, $parentType = null, $parentId = null) + { + $ids = array(); + $names = new \stdClass(); + + if (!empty($id)) { + $email = $this->getEntityManager()->getEntity('Email', $id); + if ($email && $this->getAcl()->check($email, 'read')) { + $email->loadLinkMultipleField('attachments'); + $attachmentsIds = $email->get('attachmentsIds'); + + foreach ($attachmentsIds as $attachmentId) { + $source = $this->getEntityManager()->getEntity('Attachment', $attachmentId); + if ($source) { + $attachment = $this->getEntityManager()->getEntity('Attachment'); + $attachment->set('role', 'Attachment'); + $attachment->set('type', $source->get('type')); + $attachment->set('size', $source->get('size')); + $attachment->set('global', $source->get('global')); + $attachment->set('name', $source->get('name')); + + if (!empty($parentType) && !empty($parentId)) { + $attachment->set('parentType', $parentType); + $attachment->set('parentId', $parentId); + } + + $this->getEntityManager()->saveEntity($attachment); + + $contents = $this->getFileManager()->getContents('data/upload/' . $source->id); + if (!empty($contents)) { + $this->getFileManager()->putContents('data/upload/' . $attachment->id, $contents); + $ids[] = $attachment->id; + $names->{$attachment->id} = $attachment->get('name'); + } + } + } + } + } + + return array( + 'ids' => $ids, + 'names' => $names + ); + } + + public function sendTestEmail($data) + { + $email = $this->getEntityManager()->getEntity('Email'); + + $email->set(array( + 'subject' => 'EspoCRM: Test Email', + 'isHtml' => false, + 'to' => $data['emailAddress'] + )); + + $emailSender = $this->getMailSender(); + $emailSender->useSmtp($data)->send($email); + + return true; + } } diff --git a/application/Espo/Services/EmailAccount.php b/application/Espo/Services/EmailAccount.php index aa8ceffef8..59d73b02fb 100644 --- a/application/Espo/Services/EmailAccount.php +++ b/application/Espo/Services/EmailAccount.php @@ -28,189 +28,203 @@ use \Espo\Core\Exceptions\Error; use \Espo\Core\Exceptions\Forbidden; class EmailAccount extends Record -{ - protected $internalFields = array('password'); - - protected $readOnlyFields = array('assignedUserId', 'fetchData'); - - const PORTION_LIMIT = 10; - - protected function init() - { - $this->dependencies[] = 'fileManager'; - } - - protected function getFileManager() - { - return $this->injections['fileManager']; - } - - public function getFolders($params) - { - $password = $params['password']; - - if (!empty($params['id'])) { - $entity = $this->getEntityManager()->getEntity('EmailAccount', $params['id']); - if ($entity) { - $password = $entity->get('password'); - } - } - - $imapParams = array( - 'host' => $params['host'], - 'port' => $params['port'], - 'user' => $params['username'], - 'password' => $password, - ); - - if (!empty($params['ssl'])) { - $imapParams['ssl'] = 'SSL'; - } - - $foldersArr = array(); - - $storage = new \Zend\Mail\Storage\Imap($imapParams); - - $folders = new \RecursiveIteratorIterator($storage->getFolders(), \RecursiveIteratorIterator::SELF_FIRST); - foreach ($folders as $name => $folder) { - $foldersArr[] = $folder->getGlobalName(); - } - return $foldersArr; - } - - public function createEntity($data) - { - $entity = parent::createEntity($data); - if ($entity) { - $entity->set('assignedUserId', $this->getUser()->id); - $this->getEntityManager()->saveEntity($entity); - } - return $entity; - } - - public function fetchFromMailServer(Entity $emailAccount) - { - if ($emailAccount->get('status') != 'Active') { - throw new Error(); - } - - $importer = new \Espo\Core\Mail\Importer($this->getEntityManager(), $this->getFileManager()); - - $maxSize = $this->getConfig()->get('emailMessageMaxSize'); - - $user = $this->getEntityManager()->getEntity('User', $emailAccount->get('assignedUserId')); - - if (!$user) { - throw new Error(); - } - - $userId = $user->id; - $teamId = $user->get('defaultTeam'); - - $fetchData = json_decode($emailAccount->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' => $emailAccount->get('host'), - 'port' => $emailAccount->get('port'), - 'user' => $emailAccount->get('username'), - 'password' => $emailAccount->get('password'), - ); - - if ($emailAccount->get('ssl')) { - $imapParams['ssl'] = 'SSL'; - } - - $storage = new \Espo\Core\Mail\Storage\Imap($imapParams); - - $monitoredFolders = $emailAccount->get('monitoredFolders'); - if (empty($monitoredFolders)) { - throw new Error(); - } - - $monitoredFoldersArr = explode(',', $monitoredFolders); - foreach ($monitoredFoldersArr as $folder) { - $folder = trim($folder); - $storage->selectFolder($folder); - - $lastUID = 0; - $lastDate = 0; - if (!empty($fetchData['lastUID'][$folder])) { - $lastUID = $fetchData['lastUID'][$folder]; - } - if (!empty($fetchData['lastDate'][$folder])) { - $lastDate = $fetchData['lastDate'][$folder]; - } +{ + protected $internalFields = array('password'); + + protected $readOnlyFields = array('assignedUserId', 'fetchData'); + + const PORTION_LIMIT = 10; + + protected function init() + { + $this->dependencies[] = 'fileManager'; + $this->dependencies[] = 'crypt'; + } + + protected function getFileManager() + { + return $this->injections['fileManager']; + } + + protected function getCrypt() + { + return $this->injections['crypt']; + } + + protected function handleInput(&$data) + { + parent::handleInput($data); + if (array_key_exists('password', $data)) { + $data['password'] = $this->getCrypt()->encrypt($data['password']); + } + } + + public function getFolders($params) + { + $password = $params['password']; + + if (!empty($params['id'])) { + $entity = $this->getEntityManager()->getEntity('EmailAccount', $params['id']); + if ($entity) { + $password = $this->getCrypt()->decrypt($entity->get('password')); + } + } + + $imapParams = array( + 'host' => $params['host'], + 'port' => $params['port'], + 'user' => $params['username'], + 'password' => $password, + ); + + if (!empty($params['ssl'])) { + $imapParams['ssl'] = 'SSL'; + } + + $foldersArr = array(); + + $storage = new \Zend\Mail\Storage\Imap($imapParams); + + $folders = new \RecursiveIteratorIterator($storage->getFolders(), \RecursiveIteratorIterator::SELF_FIRST); + foreach ($folders as $name => $folder) { + $foldersArr[] = $folder->getGlobalName(); + } + return $foldersArr; + } + + public function createEntity($data) + { + $entity = parent::createEntity($data); + if ($entity) { + $entity->set('assignedUserId', $this->getUser()->id); + $this->getEntityManager()->saveEntity($entity); + } + return $entity; + } + + public function fetchFromMailServer(Entity $emailAccount) + { + if ($emailAccount->get('status') != 'Active') { + throw new Error(); + } + + $importer = new \Espo\Core\Mail\Importer($this->getEntityManager(), $this->getFileManager()); + + $maxSize = $this->getConfig()->get('emailMessageMaxSize'); + + $user = $this->getEntityManager()->getEntity('User', $emailAccount->get('assignedUserId')); + + if (!$user) { + throw new Error(); + } + + $userId = $user->id; + $teamId = $user->get('defaultTeam'); + + $fetchData = json_decode($emailAccount->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' => $emailAccount->get('host'), + 'port' => $emailAccount->get('port'), + 'user' => $emailAccount->get('username'), + 'password' => $this->getCrypt()->decrypt($emailAccount->get('password')), + ); + + if ($emailAccount->get('ssl')) { + $imapParams['ssl'] = 'SSL'; + } + + $storage = new \Espo\Core\Mail\Storage\Imap($imapParams); + + $monitoredFolders = $emailAccount->get('monitoredFolders'); + if (empty($monitoredFolders)) { + throw new Error(); + } + + $monitoredFoldersArr = explode(',', $monitoredFolders); + foreach ($monitoredFoldersArr as $folder) { + $folder = trim($folder); + $storage->selectFolder($folder); + + $lastUID = 0; + $lastDate = 0; + if (!empty($fetchData['lastUID'][$folder])) { + $lastUID = $fetchData['lastUID'][$folder]; + } + if (!empty($fetchData['lastDate'][$folder])) { + $lastDate = $fetchData['lastDate'][$folder]; + } - if (!empty($lastUID)) { - $ids = $storage->getIdsFromUID($lastUID); - } else { - $dt = new \DateTime($emailAccount->get('fetchSince')); - if ($dt) { - $ids = $storage->getIdsFromDate($dt->format('d-M-Y')); - } else { - return false; - } - } - - if ((count($ids) == 1) && !empty($lastUID)) { - if ($storage->getUniqueId($ids[0]) == $lastUID) { - continue; - } - } - - $k = 0; - foreach ($ids as $i => $id) { - if ($k == count($ids) - 1) { - $lastUID = $storage->getUniqueId($id); - } - - if ($maxSize) { - if ($storage->getSize($id) > $maxSize * 1024 * 1024) { - continue; - } - } - - $message = $storage->getMessage($id); - - $email = $importer->importMessage($message, $userId, array($teamId)); - - if ($k == count($ids) - 1) { - $lastUID = $storage->getUniqueId($id); - - 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++; - } - - $fetchData['lastUID'][$folder] = $lastUID; - $fetchData['lastDate'][$folder] = $lastDate; - - $emailAccount->set('fetchData', json_encode($fetchData)); - $this->getEntityManager()->saveEntity($emailAccount); - } - - return true; - } + if (!empty($lastUID)) { + $ids = $storage->getIdsFromUID($lastUID); + } else { + $dt = new \DateTime($emailAccount->get('fetchSince')); + if ($dt) { + $ids = $storage->getIdsFromDate($dt->format('d-M-Y')); + } else { + return false; + } + } + + if ((count($ids) == 1) && !empty($lastUID)) { + if ($storage->getUniqueId($ids[0]) == $lastUID) { + continue; + } + } + + $k = 0; + foreach ($ids as $i => $id) { + if ($k == count($ids) - 1) { + $lastUID = $storage->getUniqueId($id); + } + + if ($maxSize) { + if ($storage->getSize($id) > $maxSize * 1024 * 1024) { + continue; + } + } + + $message = $storage->getMessage($id); + + $email = $importer->importMessage($message, $userId, array($teamId)); + + if ($k == count($ids) - 1) { + $lastUID = $storage->getUniqueId($id); + + 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++; + } + + $fetchData['lastUID'][$folder] = $lastUID; + $fetchData['lastDate'][$folder] = $lastDate; + + $emailAccount->set('fetchData', json_encode($fetchData)); + $this->getEntityManager()->saveEntity($emailAccount); + } + + return true; + } } diff --git a/application/Espo/Services/EmailAddress.php b/application/Espo/Services/EmailAddress.php index ed509152d2..f03ae7cfea 100644 --- a/application/Espo/Services/EmailAddress.php +++ b/application/Espo/Services/EmailAddress.php @@ -28,89 +28,89 @@ use \Espo\Core\Exceptions\Error; class EmailAddress extends Record { - private function findInAddressBookByEntityType($where, $limit, $entityType, &$result) - { - $service = $this->getServiceFactory()->create($entityType); - - $r = $service->findEntities(array( - 'where' => $where, - 'maxSize' => $limit, - 'sortBy' => 'name' - )); - - foreach ($r['collection'] as $entity) { - $entity->loadLinkMultipleField('emailAddress'); - - $emailAddress = $entity->get('emailAddress'); - - $result[] = array( - 'emailAddress' => $emailAddress, - 'name' => $entity->get('name'), - 'entityType' => $entityType - ); - + private function findInAddressBookByEntityType($where, $limit, $entityType, &$result) + { + $service = $this->getServiceFactory()->create($entityType); + + $r = $service->findEntities(array( + 'where' => $where, + 'maxSize' => $limit, + 'sortBy' => 'name' + )); + + foreach ($r['collection'] as $entity) { + $entity->loadLinkMultipleField('emailAddress'); + + $emailAddress = $entity->get('emailAddress'); + + $result[] = array( + 'emailAddress' => $emailAddress, + 'name' => $entity->get('name'), + 'entityType' => $entityType + ); + + + $c = $service->getEntity($entity->id); + $emailAddressData = $c->get('emailAddressData'); + foreach ($emailAddressData as $d) { + if ($emailAddress != $d->emailAddress) { + $emailAddress = $d->emailAddress; + $result[] = array( + 'emailAddress' => $emailAddress, + 'name' => $entity->get('name'), + 'entityType' => $entityType + ); + break; + } + } + } + } + + + public function searchInAddressBook($query, $limit) + { + $result = array(); + + $where = array( + array( + 'type' => 'or', + 'value' => array( + array( + 'type' => 'like', + 'field' => 'name', + 'value' => $query . '%' + ), + array( + 'type' => 'like', + 'field' => 'emailAddress', + 'value' => $query . '%' + ) + ) + ), + array( + 'type' => 'notEquals', + 'field' => 'emailAddress', + 'value' => null + ) + ); + + $this->findInAddressBookByEntityType($where, $limit, 'Contact', $result); + $this->findInAddressBookByEntityType($where, $limit, 'Lead', $result); + $this->findInAddressBookByEntityType($where, $limit, 'User', $result); + + $final = array(); + + foreach ($result as $r) { + foreach ($final as $f) { + if ($f['emailAddress'] == $r['emailAddress'] && $f['name'] == $r['name']) { + continue 2; + } + } + $final[] = $r; + } + + return $final; + } - $c = $service->getEntity($entity->id); - $emailAddressData = $c->get('emailAddressData'); - foreach ($emailAddressData as $d) { - if ($emailAddress != $d->emailAddress) { - $emailAddress = $d->emailAddress; - $result[] = array( - 'emailAddress' => $emailAddress, - 'name' => $entity->get('name'), - 'entityType' => $entityType - ); - break; - } - } - } - } - - - public function searchInAddressBook($query, $limit) - { - $result = array(); - - $where = array( - array( - 'type' => 'or', - 'value' => array( - array( - 'type' => 'like', - 'field' => 'name', - 'value' => $query . '%' - ), - array( - 'type' => 'like', - 'field' => 'emailAddress', - 'value' => $query . '%' - ) - ) - ), - array( - 'type' => 'notEquals', - 'field' => 'emailAddress', - 'value' => null - ) - ); - - $this->findInAddressBookByEntityType($where, $limit, 'Contact', $result); - $this->findInAddressBookByEntityType($where, $limit, 'Lead', $result); - $this->findInAddressBookByEntityType($where, $limit, 'User', $result); - - $final = array(); - - foreach ($result as $r) { - foreach ($final as $f) { - if ($f['emailAddress'] == $r['emailAddress'] && $f['name'] == $r['name']) { - continue 2; - } - } - $final[] = $r; - } - - return $final; - } - } diff --git a/application/Espo/Services/EmailNotification.php b/application/Espo/Services/EmailNotification.php index a60d77cc6e..ef8fdac606 100644 --- a/application/Espo/Services/EmailNotification.php +++ b/application/Espo/Services/EmailNotification.php @@ -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\Services; @@ -28,91 +28,91 @@ use \Espo\Core\Exceptions\NotFound; use Espo\ORM\Entity; class EmailNotification extends \Espo\Core\Services\Base -{ - protected function init() - { - $this->dependencies[] = 'metadata'; - $this->dependencies[] = 'mailSender'; - $this->dependencies[] = 'language'; - } - - protected function getMailSender() - { - return $this->getInjection('mailSender'); - } - - protected function getMetadata() - { - return $this->getInjection('metadata'); - } - - protected function getLanguage() - { - return $this->getInjection('language'); - } - - protected function replaceMessageVariables($text, $entity, $user, $assignerUser) - { - $recordUrl = $this->getConfig()->get('siteUrl') . '#' . $entity->getEntityName() . '/view/' . $entity->id; - - $text = str_replace('{userName}', $user->get('name'), $text); - $text = str_replace('{assignerUserName}', $assignerUser->get('name'), $text); - $text = str_replace('{recordUrl}', $recordUrl, $text); - $text = str_replace('{entityType}', $this->getLanguage()->translate($entity->getEntityName(), 'scopeNames'), $text); - - $fields = $entity->getFields(); - foreach ($fields as $field => $d) { - $text = str_replace('{Entity.' . $field . '}', $entity->get($field), $text); - } - - return $text; - } - - public function notifyAboutAssignmentJob($data) - { - $userId = $data['userId']; - $assignerUserId = $data['assignerUserId']; - $entityId = $data['entityId']; - $entityType = $data['entityType']; - - $user = $this->getEntityManager()->getEntity('User', $userId); - - $prefs = $this->getEntityManager()->getEntity('Preferences', $userId); - - if (!$prefs) { - return true; - } - - if (!$prefs->get('receiveAssignmentEmailNotifications')) { - return true; - } - - $assignerUser = $this->getEntityManager()->getEntity('User', $assignerUserId); - $entity = $this->getEntityManager()->getEntity($entityType, $entityId); - - if ($user && $entity && $assignerUser && $entity->get('assignedUserId') == $userId) { - $emailAddress = $user->get('emailAddress'); - if (!empty($emailAddress)) { - $email = $this->getEntityManager()->getEntity('Email'); - - $subject = $this->getLanguage()->translate('assignmentEmailNotificationSubject', 'messages', $entity->getEntityName()); - $body = $this->getLanguage()->translate('assignmentEmailNotificationBody', 'messages', $entity->getEntityName()); - - $subject = $this->replaceMessageVariables($subject, $entity, $user, $assignerUser); - $body = $this->replaceMessageVariables($body, $entity, $user, $assignerUser); - - $email->set(array( - 'subject' => $subject, - 'body' => $body, - 'isHtml' => false, - 'to' => $emailAddress - )); - - $this->getMailSender()->send($email); - } - } - - return true; - } +{ + protected function init() + { + $this->dependencies[] = 'metadata'; + $this->dependencies[] = 'mailSender'; + $this->dependencies[] = 'language'; + } + + protected function getMailSender() + { + return $this->getInjection('mailSender'); + } + + protected function getMetadata() + { + return $this->getInjection('metadata'); + } + + protected function getLanguage() + { + return $this->getInjection('language'); + } + + protected function replaceMessageVariables($text, $entity, $user, $assignerUser) + { + $recordUrl = $this->getConfig()->get('siteUrl') . '#' . $entity->getEntityName() . '/view/' . $entity->id; + + $text = str_replace('{userName}', $user->get('name'), $text); + $text = str_replace('{assignerUserName}', $assignerUser->get('name'), $text); + $text = str_replace('{recordUrl}', $recordUrl, $text); + $text = str_replace('{entityType}', $this->getLanguage()->translate($entity->getEntityName(), 'scopeNames'), $text); + + $fields = $entity->getFields(); + foreach ($fields as $field => $d) { + $text = str_replace('{Entity.' . $field . '}', $entity->get($field), $text); + } + + return $text; + } + + public function notifyAboutAssignmentJob($data) + { + $userId = $data['userId']; + $assignerUserId = $data['assignerUserId']; + $entityId = $data['entityId']; + $entityType = $data['entityType']; + + $user = $this->getEntityManager()->getEntity('User', $userId); + + $prefs = $this->getEntityManager()->getEntity('Preferences', $userId); + + if (!$prefs) { + return true; + } + + if (!$prefs->get('receiveAssignmentEmailNotifications')) { + return true; + } + + $assignerUser = $this->getEntityManager()->getEntity('User', $assignerUserId); + $entity = $this->getEntityManager()->getEntity($entityType, $entityId); + + if ($user && $entity && $assignerUser && $entity->get('assignedUserId') == $userId) { + $emailAddress = $user->get('emailAddress'); + if (!empty($emailAddress)) { + $email = $this->getEntityManager()->getEntity('Email'); + + $subject = $this->getLanguage()->translate('assignmentEmailNotificationSubject', 'messages', $entity->getEntityName()); + $body = $this->getLanguage()->translate('assignmentEmailNotificationBody', 'messages', $entity->getEntityName()); + + $subject = $this->replaceMessageVariables($subject, $entity, $user, $assignerUser); + $body = $this->replaceMessageVariables($body, $entity, $user, $assignerUser); + + $email->set(array( + 'subject' => $subject, + 'body' => $body, + 'isHtml' => false, + 'to' => $emailAddress + )); + + $this->getMailSender()->send($email); + } + } + + return true; + } } diff --git a/application/Espo/Services/EmailTemplate.php b/application/Espo/Services/EmailTemplate.php index 1acfe1a153..34d2b15dca 100644 --- a/application/Espo/Services/EmailTemplate.php +++ b/application/Espo/Services/EmailTemplate.php @@ -30,138 +30,142 @@ use \Espo\Core\Exceptions\NotFound; class EmailTemplate extends Record { - protected function init() - { - $this->dependencies[] = 'fileManager'; - $this->dependencies[] = 'dateTime'; - } - - protected function getFileManager() - { - return $this->injections['fileManager']; - } - - protected function getDateTime() - { - return $this->injections['dateTime']; - } - - public function parse($id, array $params = array(), $copyAttachments = false) - { - $emailTemplate = $this->getEntity($id); - if (empty($emailTemplate)) { - throw new NotFound(); - } - - $entityList = array(); - if (!empty($params['entityHash']) && is_array($params['entityHash'])) { - $entityList = $params['entityHash']; - } + protected function init() + { + $this->dependencies[] = 'fileManager'; + $this->dependencies[] = 'dateTime'; + } + + protected function getFileManager() + { + return $this->injections['fileManager']; + } + + protected function getDateTime() + { + return $this->injections['dateTime']; + } + + public function parse($id, array $params = array(), $copyAttachments = false) + { + $emailTemplate = $this->getEntity($id); + if (empty($emailTemplate)) { + throw new NotFound(); + } + + + + $entityList = array(); + if (!empty($params['entityHash']) && is_array($params['entityHash'])) { + $entityList = $params['entityHash']; + } + + $entityList['User'] = $this->getUser(); - if (!empty($params['emailAddress'])) { - $emailAddress = $this->getEntityManager()->getRepository('EmailAddress')->where(array( - 'lower' => $params['emailAddress'] - ))->findOne(); - + if (!empty($params['emailAddress'])) { + $emailAddress = $this->getEntityManager()->getRepository('EmailAddress')->where(array( + 'lower' => $params['emailAddress'] + ))->findOne(); + - if (!empty($emailAddress)) { - $pdo = $this->getEntityManager()->getPDO(); - $sql = " - SELECT * FROM `entity_email_address` - WHERE - `primary` = 1 AND `deleted` = 0 AND `email_address_id` = " . $pdo->quote($emailAddress->id). " - "; - $sth = $pdo->prepare($sql); - $sth->execute(); - while ($row = $sth->fetch()) { - if (!empty($row['entity_id'])) { - $entity = $this->getEntityManager()->getEntity($row['entity_type'], $row['entity_id']); - if ($entity) { - if (!empty($entity::$person)) { - $entityList['Person'] = $entity; - } - if (empty($entityList[$entity->getEntityName()])) { - $entityList[$entity->getEntityName()] = $entity; - } - break; - } - - } - } - } - } - - if (!empty($params['parentId']) && !empty($params['parentType'])) { - $parent = $this->getEntityManager()->getEntity($params['parentType'], $params['parentId']); - if (!empty($parent)) { - $entityList[$params['parentType']] = $parent; - $entityList['Parent'] = $parent; - - if (empty($entityList['Person']) && !empty($parent::$person)) { - $entityList['Person'] = $parent; - } - } - } - - $subject = $emailTemplate->get('subject'); - $body = $emailTemplate->get('body'); - - foreach ($entityList as $type => $entity) { - $subject = $this->parseText($type, $entity, $subject); - } - foreach ($entityList as $type => $entity) { - $body = $this->parseText($type, $entity, $body); - } - - $attachmentsIds = array(); - $attachmentsNames = new \StdClass(); - - if ($copyAttachments) { - $attachmentList = $emailTemplate->get('attachments'); - if (!empty($attachmentList)) { - foreach ($attachmentList as $attachment) { - $clone = $this->getEntityManager()->getEntity('Attachment'); - $data = $attachment->toArray(); - unset($data['parentType']); - unset($data['parentId']); - unset($data['id']); - $clone->set($data); - $this->getEntityManager()->saveEntity($clone); - - $contents = $this->getFileManager()->getContents('data/upload/' . $attachment->id); - if (empty($contents)) { - continue; - } - $this->getFileManager()->putContents('data/upload/' . $clone->id, $contents); - - $attachmentsIds[] = $id = $clone->id; - $attachmentsNames->$id = $clone->get('name'); - } - } - } - - return array( - 'subject' => $subject, - 'body' => $body, - 'attachmentsIds' => $attachmentsIds, - 'attachmentsNames' => $attachmentsNames, - 'isHtml' => $emailTemplate->get('isHtml') - ); - } - - protected function parseText($type, Entity $entity, $text) - { - $fields = array_keys($entity->getFields()); - foreach ($fields as $field) { - $value = $entity->get($field); - if ($entity->fields[$field]['type'] == 'date') { - $value = $this->getDateTime()->convertSystemDateToGlobal($value); - } else if ($entity->fields[$field]['type'] == 'datetime') { - $value = $this->getDateTime()->convertSystemDateTimeToGlobal($value); - } - $text = str_replace('{' . $type . '.' . $field . '}', $value, $text); - } - return $text; - } + if (!empty($emailAddress)) { + $pdo = $this->getEntityManager()->getPDO(); + $sql = " + SELECT * FROM `entity_email_address` + WHERE + `primary` = 1 AND `deleted` = 0 AND `email_address_id` = " . $pdo->quote($emailAddress->id). " + "; + $sth = $pdo->prepare($sql); + $sth->execute(); + while ($row = $sth->fetch()) { + if (!empty($row['entity_id'])) { + $entity = $this->getEntityManager()->getEntity($row['entity_type'], $row['entity_id']); + if ($entity) { + if (!empty($entity::$person)) { + $entityList['Person'] = $entity; + } + if (empty($entityList[$entity->getEntityName()])) { + $entityList[$entity->getEntityName()] = $entity; + } + break; + } + + } + } + } + } + + if (!empty($params['parentId']) && !empty($params['parentType'])) { + $parent = $this->getEntityManager()->getEntity($params['parentType'], $params['parentId']); + if (!empty($parent)) { + $entityList[$params['parentType']] = $parent; + $entityList['Parent'] = $parent; + + if (empty($entityList['Person']) && !empty($parent::$person)) { + $entityList['Person'] = $parent; + } + } + } + + $subject = $emailTemplate->get('subject'); + $body = $emailTemplate->get('body'); + + foreach ($entityList as $type => $entity) { + $subject = $this->parseText($type, $entity, $subject); + } + foreach ($entityList as $type => $entity) { + $body = $this->parseText($type, $entity, $body); + } + + $attachmentsIds = array(); + $attachmentsNames = new \StdClass(); + + if ($copyAttachments) { + $attachmentList = $emailTemplate->get('attachments'); + if (!empty($attachmentList)) { + foreach ($attachmentList as $attachment) { + $clone = $this->getEntityManager()->getEntity('Attachment'); + $data = $attachment->toArray(); + unset($data['parentType']); + unset($data['parentId']); + unset($data['id']); + $clone->set($data); + $this->getEntityManager()->saveEntity($clone); + + $contents = $this->getFileManager()->getContents('data/upload/' . $attachment->id); + if (empty($contents)) { + continue; + } + $this->getFileManager()->putContents('data/upload/' . $clone->id, $contents); + + $attachmentsIds[] = $id = $clone->id; + $attachmentsNames->$id = $clone->get('name'); + } + } + } + + return array( + 'subject' => $subject, + 'body' => $body, + 'attachmentsIds' => $attachmentsIds, + 'attachmentsNames' => $attachmentsNames, + 'isHtml' => $emailTemplate->get('isHtml') + ); + } + + protected function parseText($type, Entity $entity, $text) + { + $fields = array_keys($entity->getFields()); + foreach ($fields as $field) { + $value = $entity->get($field); + if ($entity->fields[$field]['type'] == 'date') { + $value = $this->getDateTime()->convertSystemDateToGlobal($value); + } else if ($entity->fields[$field]['type'] == 'datetime') { + $value = $this->getDateTime()->convertSystemDateTimeToGlobal($value); + } + $text = str_replace('{' . $type . '.' . $field . '}', $value, $text); + } + return $text; + } } diff --git a/application/Espo/Services/ExternalAccount.php b/application/Espo/Services/ExternalAccount.php index 4c1b446fb4..cefa91a2af 100644 --- a/application/Espo/Services/ExternalAccount.php +++ b/application/Espo/Services/ExternalAccount.php @@ -29,67 +29,67 @@ use \Espo\Core\Exceptions\Forbidden; use \Espo\Core\Exceptions\NotFound; class ExternalAccount extends Record -{ - protected function getClient($integration, $id) - { - $integrationEntity = $this->getEntityManager()->getEntity('Integration', $integration); - - if (!$integrationEntity) { - throw new NotFound(); - } - $d = $integrationEntity->toArray(); - - if (!$integrationEntity->get('enabled')) { - throw new Error("{$integration} is disabled."); - } - - $factory = new \Espo\Core\ExternalAccount\ClientManager($this->getEntityManager(), $this->getMetadata(), $this->getConfig()); - return $factory->create($integration, $id); - } - - public function getExternalAccountEntity($integration, $userId) - { - return $this->getEntityManager()->getEntity('ExternalAccount', $integration . '__' . $userId); - } - - public function ping($integration, $userId) - { - $entity = $this->getExternalAccountEntity($integration, $userId); - try { - $client = $this->getClient($integration, $userId); - if ($client) { - return $client->ping(); - } - } catch (\Exception $e) {} - } - - public function authorizationCode($integration, $userId, $code) - { - $entity = $this->getExternalAccountEntity($integration, $userId); - if (!$entity) { - throw new NotFound(); - } - $entity->set('enabled', true); - $this->getEntityManager()->saveEntity($entity); - - $client = $this->getClient($integration, $userId); - if ($client instanceof \Espo\Core\ExternalAccount\Clients\OAuth2Abstract) { - $result = $client->getAccessTokenFromAuthorizationCode($code); - if (!empty($result) && !empty($result['accessToken'])) { - $entity->clear('accessToken'); - $entity->clear('refreshToken'); - $entity->clear('tokenType'); - foreach ($result as $name => $value) { - $entity->set($name, $value); - } - $this->getEntityManager()->saveEntity($entity); - return true; - } else { - throw new Error("Could not get access token for {$integration}."); - } - } else { - throw new Error("Could not load client for {$integration}."); - } - } +{ + protected function getClient($integration, $id) + { + $integrationEntity = $this->getEntityManager()->getEntity('Integration', $integration); + + if (!$integrationEntity) { + throw new NotFound(); + } + $d = $integrationEntity->toArray(); + + if (!$integrationEntity->get('enabled')) { + throw new Error("{$integration} is disabled."); + } + + $factory = new \Espo\Core\ExternalAccount\ClientManager($this->getEntityManager(), $this->getMetadata(), $this->getConfig()); + return $factory->create($integration, $id); + } + + public function getExternalAccountEntity($integration, $userId) + { + return $this->getEntityManager()->getEntity('ExternalAccount', $integration . '__' . $userId); + } + + public function ping($integration, $userId) + { + $entity = $this->getExternalAccountEntity($integration, $userId); + try { + $client = $this->getClient($integration, $userId); + if ($client) { + return $client->ping(); + } + } catch (\Exception $e) {} + } + + public function authorizationCode($integration, $userId, $code) + { + $entity = $this->getExternalAccountEntity($integration, $userId); + if (!$entity) { + throw new NotFound(); + } + $entity->set('enabled', true); + $this->getEntityManager()->saveEntity($entity); + + $client = $this->getClient($integration, $userId); + if ($client instanceof \Espo\Core\ExternalAccount\Clients\OAuth2Abstract) { + $result = $client->getAccessTokenFromAuthorizationCode($code); + if (!empty($result) && !empty($result['accessToken'])) { + $entity->clear('accessToken'); + $entity->clear('refreshToken'); + $entity->clear('tokenType'); + foreach ($result as $name => $value) { + $entity->set($name, $value); + } + $this->getEntityManager()->saveEntity($entity); + return true; + } else { + throw new Error("Could not get access token for {$integration}."); + } + } else { + throw new Error("Could not load client for {$integration}."); + } + } } diff --git a/application/Espo/Services/GlobalSearch.php b/application/Espo/Services/GlobalSearch.php index f39e83a488..10e0f21d84 100644 --- a/application/Espo/Services/GlobalSearch.php +++ b/application/Espo/Services/GlobalSearch.php @@ -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\Services; @@ -28,79 +28,79 @@ use \Espo\Core\Exceptions\NotFound; use Espo\ORM\Entity; class GlobalSearch extends \Espo\Core\Services\Base -{ - protected $dependencies = array( - 'entityManager', - 'user', - 'metadata', - 'acl', - 'selectManagerFactory', - 'config', - ); - - protected function getSelectManagerFactory() - { - return $this->injections['selectManagerFactory']; - } +{ + protected $dependencies = array( + 'entityManager', + 'user', + 'metadata', + 'acl', + 'selectManagerFactory', + 'config', + ); - protected function getEntityManager() - { - return $this->injections['entityManager']; - } - - protected function getAcl() - { - return $this->injections['acl']; - } - - protected function getMetadata() - { - return $this->injections['metadata']; - } - - public function find($query, $offset, $maxSize) - { - $entityNameList = $this->getConfig()->get('globalSearchEntityList'); - - $entityTypeCount = count($entityNameList); - - $list = array(); - $count = 0; - $total = 0; - foreach ($entityNameList as $entityName) { - - if (!$this->getAcl()->check($entityName, 'read')) { - continue; - } - $selectManager = $this->getSelectManagerFactory()->create($entityName); - - $searchParams = array( - 'whereClause' => array( - 'OR' => array( - 'name*' => '%' . $query . '%', - ) - ), - 'offset' => round($offset / $entityTypeCount), - 'limit' => round($maxSize / $entityTypeCount), - 'orderBy' => 'createdAt', - 'order' => 'DESC', - ); - $selectParams = array_merge_recursive($searchParams, $selectManager->getAclParams()); - - $collection = $this->getEntityManager()->getRepository($entityName)->find($selectParams); - $count += count($collection); - $total += $this->getEntityManager()->getRepository($entityName)->count($selectParams); - foreach ($collection as $entity) { - $data = $entity->toArray(); - $data['_scope'] = $entityName; - $list[] = $data; - } - } - - return array( - 'total' => $total, - 'list' => $list, - ); - } + protected function getSelectManagerFactory() + { + return $this->injections['selectManagerFactory']; + } + + protected function getEntityManager() + { + return $this->injections['entityManager']; + } + + protected function getAcl() + { + return $this->injections['acl']; + } + + protected function getMetadata() + { + return $this->injections['metadata']; + } + + public function find($query, $offset, $maxSize) + { + $entityNameList = $this->getConfig()->get('globalSearchEntityList'); + + $entityTypeCount = count($entityNameList); + + $list = array(); + $count = 0; + $total = 0; + foreach ($entityNameList as $entityName) { + + if (!$this->getAcl()->check($entityName, 'read')) { + continue; + } + $selectManager = $this->getSelectManagerFactory()->create($entityName); + + $searchParams = array( + 'whereClause' => array( + 'OR' => array( + 'name*' => '%' . $query . '%', + ) + ), + 'offset' => round($offset / $entityTypeCount), + 'limit' => round($maxSize / $entityTypeCount), + 'orderBy' => 'createdAt', + 'order' => 'DESC', + ); + $selectParams = array_merge_recursive($searchParams, $selectManager->getAclParams()); + + $collection = $this->getEntityManager()->getRepository($entityName)->find($selectParams); + $count += count($collection); + $total += $this->getEntityManager()->getRepository($entityName)->count($selectParams); + foreach ($collection as $entity) { + $data = $entity->toArray(); + $data['_scope'] = $entityName; + $list[] = $data; + } + } + + return array( + 'total' => $total, + 'list' => $list, + ); + } } diff --git a/application/Espo/Services/Import.php b/application/Espo/Services/Import.php index 31b9908e99..7805a1bac0 100644 --- a/application/Espo/Services/Import.php +++ b/application/Espo/Services/Import.php @@ -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\Services; @@ -29,381 +29,381 @@ use \Espo\Core\Exceptions\Error; use Espo\ORM\Entity; class Import extends \Espo\Core\Services\Base -{ - protected $dependencies = array( - 'entityManager', - 'user', - 'metadata', - 'acl', - 'selectManagerFactory', - 'config', - 'serviceFactory', - 'fileManager', - ); - - protected $dateFormatsMap = array( - 'YYYY-MM-DD' => 'Y-m-d', - 'DD-MM-YYYY' => 'd-m-Y', - 'MM-DD-YYYY' => 'm-d-Y', - 'MM/DD/YYYY' => 'm/d/Y', - 'DD/MM/YYYY' => 'd/m/Y', - 'DD.MM.YYYY' => 'd.m.Y', - 'MM.DD.YYYY' => 'm.d.Y', - 'YYYY.MM.DD' => 'Y.m.d', - ); - - protected $timeFormatsMap = array( - 'HH:mm' => 'H:i', - 'hh:mm a' => 'h:i a', - 'hh:mma' => 'h:ia', - 'hh:mm A' => 'h:iA', - 'hh:mmA' => 'h:iA', - ); - - protected function getSelectManagerFactory() - { - return $this->injections['selectManagerFactory']; - } - - protected function getFileManager() - { - return $this->injections['fileManager']; - } - - protected function getAcl() - { - return $this->injections['acl']; - } - - protected function getMetadata() - { - return $this->injections['metadata']; - } - - protected function getServiceFactory() - { - return $this->injections['serviceFactory']; - } - - - protected function readCsvString(&$string, $CSV_SEPARATOR = ';', $CSV_ENCLOSURE = '"', $CSV_LINEBREAK = "\n") - { - $o = array(); - $cnt = strlen($string); - $esc = false; - $escesc = false; - $num = 0; - $i = 0; - while ($i < $cnt) { - $s = $string[$i]; - if ($s == $CSV_LINEBREAK) { - if ($esc) { - $o[$num].= $s; - } - else { - $i++; - break; - } - } - elseif ($s == $CSV_SEPARATOR) { - if ($esc) { - $o[$num].= $s; - } - else { - $num++; - $esc = false; - $escesc = false; - } - } - elseif ($s == $CSV_ENCLOSURE) { - if ($escesc) { - $o[$num].= $CSV_ENCLOSURE; - $escesc = false; - } +{ + protected $dependencies = array( + 'entityManager', + 'user', + 'metadata', + 'acl', + 'selectManagerFactory', + 'config', + 'serviceFactory', + 'fileManager', + ); - if ($esc) { - $esc = false; - $escesc = true; - } - else { - $esc = true; - $escesc = false; - } - } - else { - if ($escesc) { - $o[$num].= $CSV_ENCLOSURE; - $escesc = false; - } + protected $dateFormatsMap = array( + 'YYYY-MM-DD' => 'Y-m-d', + 'DD-MM-YYYY' => 'd-m-Y', + 'MM-DD-YYYY' => 'm-d-Y', + 'MM/DD/YYYY' => 'm/d/Y', + 'DD/MM/YYYY' => 'd/m/Y', + 'DD.MM.YYYY' => 'd.m.Y', + 'MM.DD.YYYY' => 'm.d.Y', + 'YYYY.MM.DD' => 'Y.m.d', + ); - $o[$num].= $s; - } + protected $timeFormatsMap = array( + 'HH:mm' => 'H:i', + 'hh:mm a' => 'h:i a', + 'hh:mma' => 'h:ia', + 'hh:mm A' => 'h:iA', + 'hh:mmA' => 'h:iA', + ); - $i++; - } - $string = substr($string, $i); - return $o; - } - - public function revert($scope, array $idsToRemove) - { - $ids = array(); - if (!empty($scope) && !empty($idsToRemove)) { - foreach ($idsToRemove as $id) { - $entity = $this->getEntityManager()->getEntity($scope, $id); - if ($entity) { - if ($this->getEntityManager()->removeEntity($entity)) { - $ids[] = $id; - } - } - $this->getEntityManager()->getRepository($scope)->deleteFromDb($id); - } - } - return $ids; - } - - public function import($scope, array $fields, $attachmentId, array $params = array()) - { - $delimiter = ','; - if (!empty($params['fieldDelimiter'])) { - $delimiter = $params['fieldDelimiter']; - } - $enclosure = '"'; - if (!empty($params['textQualifier'])) { - $enclosure = $params['textQualifier']; - } - - $contents = $this->getFileManager()->getContents('data/upload/' . $attachmentId); - - if (empty($contents)) { - throw new Error('Import error'); - } - - $result = array( - 'importedIds' => array(), - 'updatedIds' => array(), - 'duplicateIds' => array(), - ); - $i = -1; - while ($arr = $this->readCsvString($contents, $delimiter, $enclosure)) { - $i++; - if ($i == 0 && !empty($params['headerRow'])) { - continue; - } - if (count($arr) == 1 && empty($arr[0])) { - continue; - } - $r = $this->importRow($scope, $fields, $arr, $params); - if (!empty($r['imported'])) { - $result['importedIds'][] = $r['id']; - } - if (!empty($r['updated'])) { - $result['updatedIds'][] = $r['id']; - } - if (!empty($r['duplicate'])) { - $result['duplicateIds'][] = $r['id']; - } - - } - return array( - 'countCreated' => count($result['importedIds']), - 'countUpdated' => count($result['updatedIds']), - 'importedIds' => $result['importedIds'], - 'duplicateIds' => $result['duplicateIds'], - ); - } - - public function importRow($scope, array $fields, array $row, array $params = array()) - { - // TODO create related records or related if exists, e.g. Account from accountName (skip users) - // Duplicate check - - $id = null; - if (!empty($params['action'])) { - if ($params['action'] == 'createAndUpdate' && in_array('id', $fields)) { - $i = array_search('id', $fields); - $id = $row[$i]; - if (empty($id)) { - $id = null; - } - } - } - - - $entity = $this->getEntityManager()->getEntity($scope, $id); - - $entity->set('assignedUserId', $this->getUser()->id); - - if (!empty($params['defaultValues'])) { - $entity->set(get_object_vars($params['defaultValues'])); - } - - $fieldsDefs = $entity->getFields(); - $relDefs = $entity->getRelations(); + protected function getSelectManagerFactory() + { + return $this->injections['selectManagerFactory']; + } - foreach ($fields as $i => $field) { - if (!empty($field)) { - $value = $row[$i]; - if ($field == 'id') { - if ($params['action'] == 'create') { - $entity->id = $value; - } - continue; - } - if (array_key_exists($field, $fieldsDefs)) { - if ($value !== '') { - $type = $this->getMetadata()->get("entityDefs.{$scope}.fields.{$field}.type"); - if ($type == 'personName') { - $lastNameField = 'last' . ucfirst($field); - $firstNameField = 'first' . ucfirst($field); - - $firstName = ''; - $lastName = $value; - switch ($params['personNameFormat']) { + protected function getFileManager() + { + return $this->injections['fileManager']; + } - case 'f l': - $pos = strpos($value, ' '); - if ($pos) { - $firstName = trim(substr($value, 0, $pos)); - $lastName = trim(substr($value, $pos + 1)); - } - break; - case 'l f': - $pos = strpos($value, ' '); - if ($pos) { - $lastName = trim(substr($value, 0, $pos)); - $firstName = trim(substr($value, $pos + 1)); - } - break; - case 'l, f': - $pos = strpos($value, ','); - if ($pos) { - $lastName = trim(substr($value, 0, $pos)); - $firstName = trim(substr($value, $pos + 1)); - } - break; - } - - if (!$entity->get($firstNameField)) { - $entity->set($firstNameField, $firstName); - } - if (!$entity->get($lastNameField)) { - $entity->set($lastNameField, $lastName); - } - continue; - } - $entity->set($field, $this->parseValue($entity, $field, $value, $params)); - } - } - } - } - - - - foreach ($fields as $i => $field) { - if (array_key_exists($field, $fieldsDefs) && $fieldsDefs[$field]['type'] == Entity::FOREIGN) { - if ($entity->has($field)) { - $relation = $fieldsDefs[$field]['relation']; - if ($field == $relation . 'Name' && !$entity->has($relation . 'Id') && array_key_exists($relation, $relDefs)) { - if ($relDefs[$relation]['type'] == Entity::BELONGS_TO) { - $name = $entity->get($field); - $scope = $relDefs[$relation]['entity']; - $found = $this->getEntityManager()->getRepository($scope)->where(array('name' => $name))->findOne(); - - if ($found) { - $entity->set($relation . 'Id', $found->id); - } else { - if (!in_array($scope, 'User', 'Team')) { - - // TODO create related record with name $name and relate - } - } - } - } - } - } - - } + protected function getAcl() + { + return $this->injections['acl']; + } - $result = array(); - - $a = $entity->toArray(); - - try { - if ($this->getEntityManager()->saveEntity($entity)) { - $result['id'] = $entity->id; - if (empty($id)) { - $result['imported'] = true; - } else { - $result['updated'] = true; - } - } - } catch (\Exception $e) {} - - return $result; - } - - protected function parseValue(Entity $entity, $field, $value, $params = array()) - { - $decimalMark = '.'; - if (!empty($params['decimalMark'])) { - $decimalMark = $params['decimalMark']; - } - - $defaultCurrency = 'USD'; - if (!empty($params['defaultCurrency'])) { - $dateFormat = $params['defaultCurrency']; - } - - $dateFormat = 'Y-m-d'; - if (!empty($params['dateFormat'])) { - $dateFormat = $params['dateFormat']; - } - - $timeFormat = 'H:i'; - if (!empty($params['timeFormat'])) { - $timeFormat = $params['timeFormat']; - } - - $fieldDefs = $entity->getFields(); - - if (!empty($fieldDefs[$field])) { - $type = $fieldDefs[$field]['type']; - - switch ($type) { - case Entity::DATE: - $dt = \DateTime::createFromFormat($dateFormat, $value); - if ($dt) { - return $dt->format('Y-m-d'); - } - break; - case Entity::DATETIME: - $dt = \DateTime::createFromFormat($dateFormat . ' ' . $timeFormat, $value); - if ($dt) { - return $dt->format('Y-m-d H:i'); - } - break; - case Entity::FLOAT: - $currencyField = $field . 'Currency'; - if ($entity->hasField($currencyField)) { - if (!$entity->has($currencyField)) { - $entity->set($currencyField, $defaultCurrency); - } - } - - $a = explode($decimalMark, $value); - $a[0] = preg_replace('/[^A-Za-z0-9\-]/', '', $a[0]); - - if (count($a) > 1) { - return $a[0] . '.' . $a[1]; - } else { - return $a[0]; - } - break; - } - - } - return $value; - } + protected function getMetadata() + { + return $this->injections['metadata']; + } + + protected function getServiceFactory() + { + return $this->injections['serviceFactory']; + } + + + protected function readCsvString(&$string, $CSV_SEPARATOR = ';', $CSV_ENCLOSURE = '"', $CSV_LINEBREAK = "\n") + { + $o = array(); + $cnt = strlen($string); + $esc = false; + $escesc = false; + $num = 0; + $i = 0; + while ($i < $cnt) { + $s = $string[$i]; + if ($s == $CSV_LINEBREAK) { + if ($esc) { + $o[$num].= $s; + } + else { + $i++; + break; + } + } + elseif ($s == $CSV_SEPARATOR) { + if ($esc) { + $o[$num].= $s; + } + else { + $num++; + $esc = false; + $escesc = false; + } + } + elseif ($s == $CSV_ENCLOSURE) { + if ($escesc) { + $o[$num].= $CSV_ENCLOSURE; + $escesc = false; + } + + if ($esc) { + $esc = false; + $escesc = true; + } + else { + $esc = true; + $escesc = false; + } + } + else { + if ($escesc) { + $o[$num].= $CSV_ENCLOSURE; + $escesc = false; + } + + $o[$num].= $s; + } + + $i++; + } + $string = substr($string, $i); + return $o; + } + + public function revert($scope, array $idsToRemove) + { + $ids = array(); + if (!empty($scope) && !empty($idsToRemove)) { + foreach ($idsToRemove as $id) { + $entity = $this->getEntityManager()->getEntity($scope, $id); + if ($entity) { + if ($this->getEntityManager()->removeEntity($entity)) { + $ids[] = $id; + } + } + $this->getEntityManager()->getRepository($scope)->deleteFromDb($id); + } + } + return $ids; + } + + public function import($scope, array $fields, $attachmentId, array $params = array()) + { + $delimiter = ','; + if (!empty($params['fieldDelimiter'])) { + $delimiter = $params['fieldDelimiter']; + } + $enclosure = '"'; + if (!empty($params['textQualifier'])) { + $enclosure = $params['textQualifier']; + } + + $contents = $this->getFileManager()->getContents('data/upload/' . $attachmentId); + + if (empty($contents)) { + throw new Error('Import error'); + } + + $result = array( + 'importedIds' => array(), + 'updatedIds' => array(), + 'duplicateIds' => array(), + ); + $i = -1; + while ($arr = $this->readCsvString($contents, $delimiter, $enclosure)) { + $i++; + if ($i == 0 && !empty($params['headerRow'])) { + continue; + } + if (count($arr) == 1 && empty($arr[0])) { + continue; + } + $r = $this->importRow($scope, $fields, $arr, $params); + if (!empty($r['imported'])) { + $result['importedIds'][] = $r['id']; + } + if (!empty($r['updated'])) { + $result['updatedIds'][] = $r['id']; + } + if (!empty($r['duplicate'])) { + $result['duplicateIds'][] = $r['id']; + } + + } + return array( + 'countCreated' => count($result['importedIds']), + 'countUpdated' => count($result['updatedIds']), + 'importedIds' => $result['importedIds'], + 'duplicateIds' => $result['duplicateIds'], + ); + } + + public function importRow($scope, array $fields, array $row, array $params = array()) + { + // TODO create related records or related if exists, e.g. Account from accountName (skip users) + // Duplicate check + + $id = null; + if (!empty($params['action'])) { + if ($params['action'] == 'createAndUpdate' && in_array('id', $fields)) { + $i = array_search('id', $fields); + $id = $row[$i]; + if (empty($id)) { + $id = null; + } + } + } + + + $entity = $this->getEntityManager()->getEntity($scope, $id); + + $entity->set('assignedUserId', $this->getUser()->id); + + if (!empty($params['defaultValues'])) { + $entity->set(get_object_vars($params['defaultValues'])); + } + + $fieldsDefs = $entity->getFields(); + $relDefs = $entity->getRelations(); + + foreach ($fields as $i => $field) { + if (!empty($field)) { + $value = $row[$i]; + if ($field == 'id') { + if ($params['action'] == 'create') { + $entity->id = $value; + } + continue; + } + if (array_key_exists($field, $fieldsDefs)) { + if ($value !== '') { + $type = $this->getMetadata()->get("entityDefs.{$scope}.fields.{$field}.type"); + if ($type == 'personName') { + $lastNameField = 'last' . ucfirst($field); + $firstNameField = 'first' . ucfirst($field); + + $firstName = ''; + $lastName = $value; + switch ($params['personNameFormat']) { + + case 'f l': + $pos = strpos($value, ' '); + if ($pos) { + $firstName = trim(substr($value, 0, $pos)); + $lastName = trim(substr($value, $pos + 1)); + } + break; + case 'l f': + $pos = strpos($value, ' '); + if ($pos) { + $lastName = trim(substr($value, 0, $pos)); + $firstName = trim(substr($value, $pos + 1)); + } + break; + case 'l, f': + $pos = strpos($value, ','); + if ($pos) { + $lastName = trim(substr($value, 0, $pos)); + $firstName = trim(substr($value, $pos + 1)); + } + break; + } + + if (!$entity->get($firstNameField)) { + $entity->set($firstNameField, $firstName); + } + if (!$entity->get($lastNameField)) { + $entity->set($lastNameField, $lastName); + } + continue; + } + $entity->set($field, $this->parseValue($entity, $field, $value, $params)); + } + } + } + } + + + + foreach ($fields as $i => $field) { + if (array_key_exists($field, $fieldsDefs) && $fieldsDefs[$field]['type'] == Entity::FOREIGN) { + if ($entity->has($field)) { + $relation = $fieldsDefs[$field]['relation']; + if ($field == $relation . 'Name' && !$entity->has($relation . 'Id') && array_key_exists($relation, $relDefs)) { + if ($relDefs[$relation]['type'] == Entity::BELONGS_TO) { + $name = $entity->get($field); + $scope = $relDefs[$relation]['entity']; + $found = $this->getEntityManager()->getRepository($scope)->where(array('name' => $name))->findOne(); + + if ($found) { + $entity->set($relation . 'Id', $found->id); + } else { + if (!in_array($scope, 'User', 'Team')) { + + // TODO create related record with name $name and relate + } + } + } + } + } + } + + } + + $result = array(); + + $a = $entity->toArray(); + + try { + if ($this->getEntityManager()->saveEntity($entity)) { + $result['id'] = $entity->id; + if (empty($id)) { + $result['imported'] = true; + } else { + $result['updated'] = true; + } + } + } catch (\Exception $e) {} + + return $result; + } + + protected function parseValue(Entity $entity, $field, $value, $params = array()) + { + $decimalMark = '.'; + if (!empty($params['decimalMark'])) { + $decimalMark = $params['decimalMark']; + } + + $defaultCurrency = 'USD'; + if (!empty($params['defaultCurrency'])) { + $dateFormat = $params['defaultCurrency']; + } + + $dateFormat = 'Y-m-d'; + if (!empty($params['dateFormat'])) { + $dateFormat = $params['dateFormat']; + } + + $timeFormat = 'H:i'; + if (!empty($params['timeFormat'])) { + $timeFormat = $params['timeFormat']; + } + + $fieldDefs = $entity->getFields(); + + if (!empty($fieldDefs[$field])) { + $type = $fieldDefs[$field]['type']; + + switch ($type) { + case Entity::DATE: + $dt = \DateTime::createFromFormat($dateFormat, $value); + if ($dt) { + return $dt->format('Y-m-d'); + } + break; + case Entity::DATETIME: + $dt = \DateTime::createFromFormat($dateFormat . ' ' . $timeFormat, $value); + if ($dt) { + return $dt->format('Y-m-d H:i'); + } + break; + case Entity::FLOAT: + $currencyField = $field . 'Currency'; + if ($entity->hasField($currencyField)) { + if (!$entity->has($currencyField)) { + $entity->set($currencyField, $defaultCurrency); + } + } + + $a = explode($decimalMark, $value); + $a[0] = preg_replace('/[^A-Za-z0-9\-]/', '', $a[0]); + + if (count($a) > 1) { + return $a[0] . '.' . $a[1]; + } else { + return $a[0]; + } + break; + } + + } + return $value; + } } diff --git a/application/Espo/Services/Job.php b/application/Espo/Services/Job.php index bb15b5bc64..dff54a12f5 100644 --- a/application/Espo/Services/Job.php +++ b/application/Espo/Services/Job.php @@ -27,125 +27,125 @@ use \Espo\Core\CronManager; class Job extends Record { - public function getPendingJobs() - { - /** Mark Failed old jobs and remove pending duplicates */ - $this->markFailedJobs(); - $this->removePendingJobDuplicates(); + public function getPendingJobs() + { + /** Mark Failed old jobs and remove pending duplicates */ + $this->markFailedJobs(); + $this->removePendingJobDuplicates(); - $jobList = $this->getActiveJobs(); + $jobList = $this->getActiveJobs(); - $runningScheduledJobs = $this->getActiveJobs('scheduled_job_id', CronManager::RUNNING, PDO::FETCH_COLUMN); + $runningScheduledJobs = $this->getActiveJobs('scheduled_job_id', CronManager::RUNNING, PDO::FETCH_COLUMN); - $list = array(); - foreach ($jobList as $row) { - if (!in_array($row['scheduled_job_id'], $runningScheduledJobs)) { - $list[] = $row; - } - } + $list = array(); + foreach ($jobList as $row) { + if (!in_array($row['scheduled_job_id'], $runningScheduledJobs)) { + $list[] = $row; + } + } - return $list; - } + return $list; + } - /** - * Get active Jobs, which execution date in jobPeriod time - * - * @param string $displayColumns - * @param string $status - * @return array - */ - protected function getActiveJobs($displayColumns = '*', $status = CronManager::PENDING, $fetchMode = PDO::FETCH_ASSOC) - { - $jobConfigs = $this->getConfig()->get('cron'); + /** + * Get active Jobs, which execution date in jobPeriod time + * + * @param string $displayColumns + * @param string $status + * @return array + */ + protected function getActiveJobs($displayColumns = '*', $status = CronManager::PENDING, $fetchMode = PDO::FETCH_ASSOC) + { + $jobConfigs = $this->getConfig()->get('cron'); - $currentTime = time(); - $periodTime = $currentTime - intval($jobConfigs['jobPeriod']); - $limit = empty($jobConfigs['maxJobNumber']) ? '' : 'LIMIT '.$jobConfigs['maxJobNumber']; + $currentTime = time(); + $periodTime = $currentTime - intval($jobConfigs['jobPeriod']); + $limit = empty($jobConfigs['maxJobNumber']) ? '' : 'LIMIT '.$jobConfigs['maxJobNumber']; - $query = "SELECT " . $displayColumns . " FROM job WHERE - `status` = '" . $status . "' - AND execute_time BETWEEN '".date('Y-m-d H:i:s', $periodTime)."' AND '".date('Y-m-d H:i:s', $currentTime)."' - AND deleted = 0 - ORDER BY execute_time DESC ".$limit; + $query = "SELECT " . $displayColumns . " FROM job WHERE + `status` = '" . $status . "' + AND execute_time BETWEEN '".date('Y-m-d H:i:s', $periodTime)."' AND '".date('Y-m-d H:i:s', $currentTime)."' + AND deleted = 0 + ORDER BY execute_time DESC ".$limit; - $pdo = $this->getEntityManager()->getPDO(); - $sth = $pdo->prepare($query); - $sth->execute(); + $pdo = $this->getEntityManager()->getPDO(); + $sth = $pdo->prepare($query); + $sth->execute(); - $rows = $sth->fetchAll($fetchMode); + $rows = $sth->fetchAll($fetchMode); - return $rows; - } + return $rows; + } - public function getJobByScheduledJob($scheduledJobId, $date) - { - $query = "SELECT * FROM job WHERE - scheduled_job_id = '".$scheduledJobId."' - AND execute_time = '".$date."' - AND deleted = 0 - LIMIT 1"; + public function getJobByScheduledJob($scheduledJobId, $date) + { + $query = "SELECT * FROM job WHERE + scheduled_job_id = '".$scheduledJobId."' + AND execute_time = '".$date."' + AND deleted = 0 + LIMIT 1"; - $pdo = $this->getEntityManager()->getPDO(); - $sth = $pdo->prepare($query); - $sth->execute(); + $pdo = $this->getEntityManager()->getPDO(); + $sth = $pdo->prepare($query); + $sth->execute(); - $scheduledJob = $sth->fetchAll(PDO::FETCH_ASSOC); + $scheduledJob = $sth->fetchAll(PDO::FETCH_ASSOC); - return $scheduledJob; - } + return $scheduledJob; + } - /** - * Mark pending jobs (all jobs that exceeded jobPeriod) - * - * @return void - */ - protected function markFailedJobs() - { - $jobConfigs = $this->getConfig()->get('cron'); + /** + * Mark pending jobs (all jobs that exceeded jobPeriod) + * + * @return void + */ + protected function markFailedJobs() + { + $jobConfigs = $this->getConfig()->get('cron'); - $currentTime = time(); - $periodTime = $currentTime - intval($jobConfigs['jobPeriod']); + $currentTime = time(); + $periodTime = $currentTime - intval($jobConfigs['jobPeriod']); - $update = "UPDATE job SET `status` = '" . CronManager::FAILED ."' WHERE - (`status` = '" . CronManager::PENDING ."' OR `status` = '" . CronManager::RUNNING ."') - AND execute_time < '".date('Y-m-d H:i:s', $periodTime)."' "; + $update = "UPDATE job SET `status` = '" . CronManager::FAILED ."' WHERE + (`status` = '" . CronManager::PENDING ."' OR `status` = '" . CronManager::RUNNING ."') + AND execute_time < '".date('Y-m-d H:i:s', $periodTime)."' "; - $pdo = $this->getEntityManager()->getPDO(); - $sth = $pdo->prepare($update); - $sth->execute(); - } + $pdo = $this->getEntityManager()->getPDO(); + $sth = $pdo->prepare($update); + $sth->execute(); + } - /** - * Remove pending duplicate jobs, no need to run twice the same job - * - * @return void - */ - protected function removePendingJobDuplicates() - { - $duplicateJobs = $this->getActiveJobs('DISTINCT scheduled_job_id'); + /** + * Remove pending duplicate jobs, no need to run twice the same job + * + * @return void + */ + protected function removePendingJobDuplicates() + { + $duplicateJobs = $this->getActiveJobs('DISTINCT scheduled_job_id'); - $pdo = $this->getEntityManager()->getPDO(); + $pdo = $this->getEntityManager()->getPDO(); - foreach ($duplicateJobs as $row) { - if (!empty($row['scheduled_job_id'])) { + foreach ($duplicateJobs as $row) { + if (!empty($row['scheduled_job_id'])) { - /* no possibility to use limit in update or subqueries */ - $query = "SELECT id FROM `job` WHERE scheduled_job_id = '" . $row['scheduled_job_id'] . "' - AND `status` = '" . CronManager::PENDING ."' - ORDER BY execute_time - DESC LIMIT 1, 100000 "; - $sth = $pdo->prepare($query); - $sth->execute(); - $jobIds = $sth->fetchAll(PDO::FETCH_COLUMN); + /* no possibility to use limit in update or subqueries */ + $query = "SELECT id FROM `job` WHERE scheduled_job_id = '" . $row['scheduled_job_id'] . "' + AND `status` = '" . CronManager::PENDING ."' + ORDER BY execute_time + DESC LIMIT 1, 100000 "; + $sth = $pdo->prepare($query); + $sth->execute(); + $jobIds = $sth->fetchAll(PDO::FETCH_COLUMN); - $update = "UPDATE job SET deleted = 1 WHERE - id IN ('". implode("', '", $jobIds)."') "; + $update = "UPDATE job SET deleted = 1 WHERE + id IN ('". implode("', '", $jobIds)."') "; - $sth = $pdo->prepare($update); - $sth->execute(); - } - } - } + $sth = $pdo->prepare($update); + $sth->execute(); + } + } + } } diff --git a/application/Espo/Services/Note.php b/application/Espo/Services/Note.php index bcae8b4dd4..b39fcfbb1d 100644 --- a/application/Espo/Services/Note.php +++ b/application/Espo/Services/Note.php @@ -28,30 +28,30 @@ use \Espo\Core\Exceptions\NotFound; use Espo\ORM\Entity; class Note extends Record -{ - public function getEntity($id = null) - { - $entity = parent::getEntity($id); - if (!empty($id)) { - $entity->loadAttachments(); - } - return $entity; - } - - public function createEntity($data) - { - if (!empty($data['parentType']) && !empty($data['parentId'])) { - $entity = $this->getEntityManager()->getEntity($data['parentType'], $data['parentId']); - if ($entity) { - if (!$this->getAcl()->check($entity, 'read')) { - throw new Forbidden(); - } - } - } - - - return parent::createEntity($data); - } +{ + public function getEntity($id = null) + { + $entity = parent::getEntity($id); + if (!empty($id)) { + $entity->loadAttachments(); + } + return $entity; + } + + public function createEntity($data) + { + if (!empty($data['parentType']) && !empty($data['parentId'])) { + $entity = $this->getEntityManager()->getEntity($data['parentType'], $data['parentId']); + if ($entity) { + if (!$this->getAcl()->check($entity, 'read')) { + throw new Forbidden(); + } + } + } + + + return parent::createEntity($data); + } } diff --git a/application/Espo/Services/Notification.php b/application/Espo/Services/Notification.php index 2a1394a0af..73b86ddc64 100644 --- a/application/Espo/Services/Notification.php +++ b/application/Espo/Services/Notification.php @@ -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\Services; @@ -28,140 +28,140 @@ use \Espo\Core\Exceptions\NotFound; use Espo\ORM\Entity; class Notification extends \Espo\Core\Services\Base -{ - protected $dependencies = array( - 'entityManager', - 'user', - 'metadata', - ); +{ + protected $dependencies = array( + 'entityManager', + 'user', + 'metadata', + ); - protected function getEntityManager() - { - return $this->injections['entityManager']; - } + protected function getEntityManager() + { + return $this->injections['entityManager']; + } - protected function getUser() - { - return $this->injections['user']; - } - - protected function getMetadata() - { - return $this->injections['metadata']; - } - - public function notifyAboutMentionInPost($userId, $noteId) - { - $notification = $this->getEntityManager()->getEntity('Notification'); - $notification->set(array( - 'type' => 'MentionInPost', - 'data' => array('noteId' => $noteId), - 'userId' => $userId - )); - $this->getEntityManager()->saveEntity($notification); - } - - public function notifyAboutNote($userId, $noteId) - { - $notification = $this->getEntityManager()->getEntity('Notification'); - $notification->set(array( - 'type' => 'Note', - 'data' => array('noteId' => $noteId), - 'userId' => $userId - )); - $this->getEntityManager()->saveEntity($notification); - } - - public function notifyAboutNoteFromJob($data) - { - $userIdList = $data['userIdList']; - $noteId = $data['noteId']; - - foreach ($userIdList as $userId) { - $this->notifyAboutNote($userId, $noteId); - } - return true; - } - - public function getNotReadCount($userId) - { - $searchParams = array(); - $searchParams['whereClause'] = array( - 'userId' => $userId - ); - return $this->getEntityManager()->getRepository('Notification')->where(array( - 'userId' => $userId, - 'read' => 0, - ))->count(); - } - - public function markAllRead($userId) - { - $pdo = $this->getEntityManager()->getPDO(); - $sql = "UPDATE notification SET `read` = 1 WHERE user_id = ".$pdo->quote($userId)." AND `read` = 0"; - $pdo->prepare($sql)->execute(); - return true; - } - - public function getList($userId, array $params = array()) - { - $searchParams = array(); - $searchParams['whereClause'] = array( - 'userId' => $userId - ); - if (array_key_exists('offset', $params)) { - $searchParams['offset'] = $params['offset']; - } - if (array_key_exists('maxSize', $params)) { - $searchParams['limit'] = $params['maxSize']; - } - $searchParams['orderBy'] = 'createdAt'; - $searchParams['order'] = 'DESC'; - - $collection = $this->getEntityManager()->getRepository('Notification')->find($searchParams); - $count = $this->getEntityManager()->getRepository('Notification')->count($searchParams); - - $ids = array(); - foreach ($collection as $k => $entity) { - $ids[] = $entity->id; - $data = $entity->get('data'); - if (empty($data)) { - continue; - } - switch ($entity->get('type')) { - case 'Note': - case 'MentionInPost': - $note = $this->getEntityManager()->getEntity('Note', $data->noteId); - if ($note) { - if ($note->get('parentId') && $note->get('parentType')) { - $parent = $this->getEntityManager()->getEntity($note->get('parentType'), $note->get('parentId')); - if ($parent) { - $note->set('parentName', $parent->get('name')); - } - } - $entity->set('noteData', $note->toArray()); - } else { - unset($collection[$k]); - $count--; - $this->getEntityManager()->removeEntity($entity); - } - break; - } - } - - if (!empty($ids)) { - $pdo = $this->getEntityManager()->getPDO(); - $sql = "UPDATE notification SET `read` = 1 WHERE id IN ('" . implode("', '", $ids) ."')"; + protected function getUser() + { + return $this->injections['user']; + } - $s = $pdo->prepare($sql); - $s->execute(); - } - - - return array( - 'total' => $count, - 'collection' => $collection - ); - } + protected function getMetadata() + { + return $this->injections['metadata']; + } + + public function notifyAboutMentionInPost($userId, $noteId) + { + $notification = $this->getEntityManager()->getEntity('Notification'); + $notification->set(array( + 'type' => 'MentionInPost', + 'data' => array('noteId' => $noteId), + 'userId' => $userId + )); + $this->getEntityManager()->saveEntity($notification); + } + + public function notifyAboutNote($userId, $noteId) + { + $notification = $this->getEntityManager()->getEntity('Notification'); + $notification->set(array( + 'type' => 'Note', + 'data' => array('noteId' => $noteId), + 'userId' => $userId + )); + $this->getEntityManager()->saveEntity($notification); + } + + public function notifyAboutNoteFromJob($data) + { + $userIdList = $data['userIdList']; + $noteId = $data['noteId']; + + foreach ($userIdList as $userId) { + $this->notifyAboutNote($userId, $noteId); + } + return true; + } + + public function getNotReadCount($userId) + { + $searchParams = array(); + $searchParams['whereClause'] = array( + 'userId' => $userId + ); + return $this->getEntityManager()->getRepository('Notification')->where(array( + 'userId' => $userId, + 'read' => 0, + ))->count(); + } + + public function markAllRead($userId) + { + $pdo = $this->getEntityManager()->getPDO(); + $sql = "UPDATE notification SET `read` = 1 WHERE user_id = ".$pdo->quote($userId)." AND `read` = 0"; + $pdo->prepare($sql)->execute(); + return true; + } + + public function getList($userId, array $params = array()) + { + $searchParams = array(); + $searchParams['whereClause'] = array( + 'userId' => $userId + ); + if (array_key_exists('offset', $params)) { + $searchParams['offset'] = $params['offset']; + } + if (array_key_exists('maxSize', $params)) { + $searchParams['limit'] = $params['maxSize']; + } + $searchParams['orderBy'] = 'createdAt'; + $searchParams['order'] = 'DESC'; + + $collection = $this->getEntityManager()->getRepository('Notification')->find($searchParams); + $count = $this->getEntityManager()->getRepository('Notification')->count($searchParams); + + $ids = array(); + foreach ($collection as $k => $entity) { + $ids[] = $entity->id; + $data = $entity->get('data'); + if (empty($data)) { + continue; + } + switch ($entity->get('type')) { + case 'Note': + case 'MentionInPost': + $note = $this->getEntityManager()->getEntity('Note', $data->noteId); + if ($note) { + if ($note->get('parentId') && $note->get('parentType')) { + $parent = $this->getEntityManager()->getEntity($note->get('parentType'), $note->get('parentId')); + if ($parent) { + $note->set('parentName', $parent->get('name')); + } + } + $entity->set('noteData', $note->toArray()); + } else { + unset($collection[$k]); + $count--; + $this->getEntityManager()->removeEntity($entity); + } + break; + } + } + + if (!empty($ids)) { + $pdo = $this->getEntityManager()->getPDO(); + $sql = "UPDATE notification SET `read` = 1 WHERE id IN ('" . implode("', '", $ids) ."')"; + + $s = $pdo->prepare($sql); + $s->execute(); + } + + + return array( + 'total' => $count, + 'collection' => $collection + ); + } } diff --git a/application/Espo/Services/Record.php b/application/Espo/Services/Record.php index 66786ad659..a4bf4c3ee4 100644 --- a/application/Espo/Services/Record.php +++ b/application/Espo/Services/Record.php @@ -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\Services; @@ -33,591 +33,621 @@ use \Espo\Core\Utils\Util; class Record extends \Espo\Core\Services\Base { - protected $dependencies = array( - 'entityManager', - 'user', - 'metadata', - 'acl', - 'config', - 'serviceFactory', - 'fileManager', - 'selectManagerFactory', - 'preferences' - ); - - protected $entityName; - - private $streamService; - - protected $notFilteringFields = array(); // TODO maybe remove it - - protected $internalFields = array(); - - protected $readOnlyFields = array(); - - protected $linkSelectParams = array(); - - public function __construct() - { - parent::__construct(); - if (empty($this->entityName)) { - $name = get_class($this); - if (preg_match('@\\\\([\w]+)$@', $name, $matches)) { - $name = $matches[1]; - } - if ($name != 'Record') { - $this->entityName = $name; - } - } - } + protected $dependencies = array( + 'entityManager', + 'user', + 'metadata', + 'acl', + 'config', + 'serviceFactory', + 'fileManager', + 'selectManagerFactory', + 'preferences' + ); - public function setEntityName($entityName) - { - $this->entityName = $entityName; - } - - protected function getServiceFactory() - { - return $this->injections['serviceFactory']; - } - - protected function getSelectManagerFactory() - { - return $this->injections['selectManagerFactory']; - } - - protected function getAcl() - { - return $this->injections['acl']; - } - - protected function getFileManager() - { - return $this->injections['fileManager']; - } - - protected function getPreferences() - { - return $this->injections['preferences']; - } - - protected function getMetadata() - { - return $this->injections['metadata']; - } - - protected function getRepository() - { - return $this->getEntityManager()->getRepository($this->entityName); - } - - protected function getRecordService($name) - { - if ($this->getServiceFactory()->checkExists($name)) { - $service = $this->getServiceFactory()->create($name); - } else { - $service = $this->getServiceFactory()->create('Record'); - $service->setEntityName($name); - } - - return $service; - } - - protected function prepareEntity($entity) - { - - } + protected $entityName; + + private $streamService; + + protected $notFilteringFields = array(); // TODO maybe remove it + + protected $internalFields = array(); + + protected $readOnlyFields = array(); + + protected $linkSelectParams = array(); + + public function __construct() + { + parent::__construct(); + if (empty($this->entityName)) { + $name = get_class($this); + if (preg_match('@\\\\([\w]+)$@', $name, $matches)) { + $name = $matches[1]; + } + if ($name != 'Record') { + $this->entityName = $name; + } + } + } + + public function setEntityName($entityName) + { + $this->entityName = $entityName; + } + + protected function getServiceFactory() + { + return $this->injections['serviceFactory']; + } + + protected function getSelectManagerFactory() + { + return $this->injections['selectManagerFactory']; + } + + protected function getAcl() + { + return $this->injections['acl']; + } + + protected function getFileManager() + { + return $this->injections['fileManager']; + } + + protected function getPreferences() + { + return $this->injections['preferences']; + } + + protected function getMetadata() + { + return $this->injections['metadata']; + } + + protected function getRepository() + { + return $this->getEntityManager()->getRepository($this->entityName); + } + + protected function getRecordService($name) + { + if ($this->getServiceFactory()->checkExists($name)) { + $service = $this->getServiceFactory()->create($name); + } else { + $service = $this->getServiceFactory()->create('Record'); + $service->setEntityName($name); + } + + return $service; + } + + protected function prepareEntity($entity) + { + + } + + public function getEntity($id = null) + { + $entity = $this->getRepository()->get($id); + if (!empty($entity) && !empty($id)) { + $this->loadAdditionalFields($entity); + + if ($entity->getEntityName() == 'Opportunity') { + $contactsColumns = $entity->get('contactsColumns'); + } + + if (!$this->getAcl()->check($entity, 'read')) { + throw new Forbidden(); + } + } + if (!empty($entity)) { + $this->prepareEntityForOutput($entity); + } + return $entity; + } - public function getEntity($id = null) - { - $entity = $this->getRepository()->get($id); - if (!empty($entity) && !empty($id)) { - $this->loadAdditionalFields($entity); - - if ($entity->getEntityName() == 'Opportunity') { - $contactsColumns = $entity->get('contactsColumns'); - } - - if (!$this->getAcl()->check($entity, 'read')) { - throw new Forbidden(); - } - } - if (!empty($entity)) { - $this->prepareEntityForOutput($entity); - } - return $entity; - } - protected function getStreamService() { - if (empty($this->streamService)) { - $this->streamService = $this->getServiceFactory()->create('Stream'); - } - return $this->streamService; + if (empty($this->streamService)) { + $this->streamService = $this->getServiceFactory()->create('Stream'); + } + return $this->streamService; } - - protected function loadIsFollowed(Entity $entity) - { - if ($this->getStreamService()->checkIsFollowed($entity)) { - $entity->set('isFollowed', true); - } else { - $entity->set('isFollowed', false); - } - } - - protected function loadLinkMultipleFields(Entity $entity) - { - $fieldDefs = $this->getMetadata()->get('entityDefs.' . $entity->getEntityName() . '.fields', array()); - foreach ($fieldDefs as $field => $defs) { - if (isset($defs['type']) && $defs['type'] == 'linkMultiple') { - $columns = null; - if (!empty($defs['columns'])) { - $columns = $defs['columns']; - } - $entity->loadLinkMultipleField($field, $columns); - } - } - } - - protected function loadParentNameFields(Entity $entity) - { - $fieldDefs = $this->getMetadata()->get('entityDefs.' . $entity->getEntityName() . '.fields', array()); - foreach ($fieldDefs as $field => $defs) { - if (isset($defs['type']) && $defs['type'] == 'linkParent') { - $id = $entity->get($field . 'Id'); - $scope = $entity->get($field . 'Type'); - - if ($scope) { - if ($foreignEntity = $this->getEntityManager()->getEntity($scope, $id)) { - $entity->set($field . 'Name', $foreignEntity->get('name')); - } - } - } - } - } - - protected function loadAdditionalFields($entity) - { - $this->loadLinkMultipleFields($entity); - $this->loadParentNameFields($entity); - $this->loadIsFollowed($entity); - $this->loadEmailAddressField($entity); - $this->loadPhoneNumberField($entity); - } - - protected function loadEmailAddressField(Entity $entity) - { - $fieldDefs = $this->getMetadata()->get('entityDefs.' . $entity->getEntityName() . '.fields', array()); - if (!empty($fieldDefs['emailAddress']) && $fieldDefs['emailAddress']['type'] == 'email') { - $dataFieldName = 'emailAddressData'; - $entity->set($dataFieldName, $this->getEntityManager()->getRepository('EmailAddress')->getEmailAddressData($entity)); - } - } - - protected function loadPhoneNumberField(Entity $entity) - { - $fieldDefs = $this->getMetadata()->get('entityDefs.' . $entity->getEntityName() . '.fields', array()); - if (!empty($fieldDefs['phoneNumber']) && $fieldDefs['phoneNumber']['type'] == 'phone') { - $dataFieldName = 'phoneNumberData'; - $entity->set($dataFieldName, $this->getEntityManager()->getRepository('PhoneNumber')->getPhoneNumberData($entity)); - } - } - - protected function getSelectManager($entityName) - { - return $this->getSelectManagerFactory()->create($entityName); - } - - protected function storeEntity(Entity $entity) - { - return $this->getRepository()->save($entity); - } - - protected function isValid($entity) - { - $fieldDefs = $entity->getFields(); - if ($entity->hasField('name') && !empty($fieldDefs['name']['required'])) { - if (!$entity->get('name')) { - return false; - } - } - return true; - } - - protected function stripTags($string) - { - return strip_tags($string, '


'); - } - - protected function filterInputField($field, $value) - { - if (in_array($field, $this->notFilteringFields)) { - return $value; - } - $methodName = 'filterInputField' . ucfirst($field); - if (method_exists($this, $methodName)) { - $value = $this->$methodName($value); - } - return $value; - } - - protected function filterInput(&$data) - { - foreach ($this->readOnlyFields as $field) { - unset($data[$field]); - } - - foreach ($data as $key => $value) { - if (is_array($data[$key])) { - foreach ($data[$key] as $i => $v) { - $data[$key][$i] = $this->filterInputField($i, $data[$key][$i]); - } - } else if ($data[$key] instanceof \stdClass) { - $propertyList = get_object_vars($data[$key]); - foreach ($propertyList as $property => $value) { - $data[$key]->$property = $this->filterInputField($property, $data[$key]->$property); - } - } else { - $data[$key] = $this->filterInputField($key, $data[$key]); - } - } - } - public function createEntity($data) - { - $entity = $this->getEntity(); - - $this->filterInput($data); - - $entity->set($data); - - if (!$this->isValid($entity)) { - throw new BadRequest(); - } - - if (empty($data['forceDuplicate'])) { - $duplicates = $this->checkEntityForDuplicate($entity); - if (!empty($duplicates)) { - $reason = array( - 'reason' => 'Duplicate', - 'data' => $duplicates - ); - throw new Conflict(json_encode($reason)); - } - } - - if ($this->storeEntity($entity)) { - return $entity; - } - - throw new Error(); - } - - - public function updateEntity($id, $data) - { - unset($data['deleted']); - - $this->filterInput($data); - - $entity = $this->getEntity($id); - - if (!$this->getAcl()->check($entity, 'edit')) { - throw new Forbidden(); - } - - $entity->set($data); - - if (!$this->isValid($entity)) { - throw new BadRequest(); - } - - if ($this->storeEntity($entity)) { - return $entity; - } + protected function loadIsFollowed(Entity $entity) + { + if ($this->getStreamService()->checkIsFollowed($entity)) { + $entity->set('isFollowed', true); + } else { + $entity->set('isFollowed', false); + } + } - throw new Error(); - } + protected function loadLinkMultipleFields(Entity $entity) + { + $fieldDefs = $this->getMetadata()->get('entityDefs.' . $entity->getEntityName() . '.fields', array()); + foreach ($fieldDefs as $field => $defs) { + if (isset($defs['type']) && $defs['type'] == 'linkMultiple') { + $columns = null; + if (!empty($defs['columns'])) { + $columns = $defs['columns']; + } + $entity->loadLinkMultipleField($field, $columns); + } + } + } - public function deleteEntity($id) - { - $entity = $this->getEntity($id); + protected function loadParentNameFields(Entity $entity) + { + $fieldDefs = $this->getMetadata()->get('entityDefs.' . $entity->getEntityName() . '.fields', array()); + foreach ($fieldDefs as $field => $defs) { + if (isset($defs['type']) && $defs['type'] == 'linkParent') { + $id = $entity->get($field . 'Id'); + $scope = $entity->get($field . 'Type'); - if (!$this->getAcl()->check($entity, 'delete')) { - throw new Forbidden(); - } - - return $this->getRepository()->remove($entity); - } - - public function findEntities($params) - { - $selectParams = $this->getSelectManager($this->entityName)->getSelectParams($params, true); - $collection = $this->getRepository()->find($selectParams); - - foreach ($collection as $e) { - $this->loadParentNameFields($e); - $this->prepareEntityForOutput($e); - } - - return array( - 'total' => $this->getRepository()->count($selectParams), - 'collection' => $collection, - ); - } + if ($scope) { + if ($foreignEntity = $this->getEntityManager()->getEntity($scope, $id)) { + $entity->set($field . 'Name', $foreignEntity->get('name')); + } + } + } + } + } + + protected function loadAdditionalFields($entity) + { + $this->loadLinkMultipleFields($entity); + $this->loadParentNameFields($entity); + $this->loadIsFollowed($entity); + $this->loadEmailAddressField($entity); + $this->loadPhoneNumberField($entity); + } + + protected function loadEmailAddressField(Entity $entity) + { + $fieldDefs = $this->getMetadata()->get('entityDefs.' . $entity->getEntityName() . '.fields', array()); + if (!empty($fieldDefs['emailAddress']) && $fieldDefs['emailAddress']['type'] == 'email') { + $dataFieldName = 'emailAddressData'; + $entity->set($dataFieldName, $this->getEntityManager()->getRepository('EmailAddress')->getEmailAddressData($entity)); + } + } + + protected function loadPhoneNumberField(Entity $entity) + { + $fieldDefs = $this->getMetadata()->get('entityDefs.' . $entity->getEntityName() . '.fields', array()); + if (!empty($fieldDefs['phoneNumber']) && $fieldDefs['phoneNumber']['type'] == 'phone') { + $dataFieldName = 'phoneNumberData'; + $entity->set($dataFieldName, $this->getEntityManager()->getRepository('PhoneNumber')->getPhoneNumberData($entity)); + } + } + + protected function getSelectManager($entityName) + { + return $this->getSelectManagerFactory()->create($entityName); + } + + protected function storeEntity(Entity $entity) + { + return $this->getRepository()->save($entity); + } + + protected function isValid($entity) + { + $fieldDefs = $entity->getFields(); + if ($entity->hasField('name') && !empty($fieldDefs['name']['required'])) { + if (!$entity->get('name')) { + return false; + } + } + return true; + } + + protected function stripTags($string) + { + return strip_tags($string, '


'); + } + + protected function filterInputField($field, $value) + { + if (in_array($field, $this->notFilteringFields)) { + return $value; + } + $methodName = 'filterInputField' . ucfirst($field); + if (method_exists($this, $methodName)) { + $value = $this->$methodName($value); + } + return $value; + } + + protected function filterInput(&$data) + { + foreach ($this->readOnlyFields as $field) { + unset($data[$field]); + } + + foreach ($data as $key => $value) { + if (is_array($data[$key])) { + foreach ($data[$key] as $i => $v) { + $data[$key][$i] = $this->filterInputField($i, $data[$key][$i]); + } + } else if ($data[$key] instanceof \stdClass) { + $propertyList = get_object_vars($data[$key]); + foreach ($propertyList as $property => $value) { + $data[$key]->$property = $this->filterInputField($property, $data[$key]->$property); + } + } else { + $data[$key] = $this->filterInputField($key, $data[$key]); + } + } + } + + protected function handleInput(&$data) + { + + } + + public function createEntity($data) + { + $entity = $this->getEntity(); + + $this->filterInput($data); + $this->handleInput($data); + + $entity->set($data); + + if (!$this->isValid($entity)) { + throw new BadRequest(); + } + + if (empty($data['forceDuplicate'])) { + $duplicates = $this->checkEntityForDuplicate($entity); + if (!empty($duplicates)) { + $reason = array( + 'reason' => 'Duplicate', + 'data' => $duplicates + ); + throw new Conflict(json_encode($reason)); + } + } + + if ($this->storeEntity($entity)) { + $this->prepareEntityForOutput($entity); + return $entity; + } + + throw new Error(); + } + + + public function updateEntity($id, $data) + { + unset($data['deleted']); + + $this->filterInput($data); + $this->handleInput($data); + + $entity = $this->getEntity($id); + + if (!$this->getAcl()->check($entity, 'edit')) { + throw new Forbidden(); + } + + $entity->set($data); + + if (!$this->isValid($entity)) { + throw new BadRequest(); + } + + if ($this->storeEntity($entity)) { + $this->prepareEntityForOutput($entity); + return $entity; + } + + throw new Error(); + } + + public function deleteEntity($id) + { + $entity = $this->getEntity($id); + + if (!$this->getAcl()->check($entity, 'delete')) { + throw new Forbidden(); + } + + return $this->getRepository()->remove($entity); + } + + public function findEntities($params) + { + $selectParams = $this->getSelectManager($this->entityName)->getSelectParams($params, true); + $collection = $this->getRepository()->find($selectParams); + + foreach ($collection as $e) { + $this->loadParentNameFields($e); + $this->prepareEntityForOutput($e); + } + + return array( + 'total' => $this->getRepository()->count($selectParams), + 'collection' => $collection, + ); + } public function findLinkedEntities($id, $link, $params) - { - $entity = $this->getEntity($id); - $foreignEntityName = $entity->relations[$link]['entity']; - - if (!$this->getAcl()->check($entity, 'read')) { - throw new Forbidden(); - } - if (!$this->getAcl()->check($foreignEntityName, 'read')) { - throw new Forbidden(); - } - - $selectParams = $this->getSelectManager($foreignEntityName)->getSelectParams($params, true); - - if (array_key_exists($link, $this->linkSelectParams)) { - $selectParams = array_merge($selectParams, $this->linkSelectParams[$link]); - } - - $collection = $this->getRepository()->findRelated($entity, $link, $selectParams); - - $recordService = $this->getRecordService($foreignEntityName); - - foreach ($collection as $e) { - $this->loadParentNameFields($e); - $recordService->prepareEntityForOutput($e); - } - - return array( - 'total' => $this->getRepository()->countRelated($entity, $link, $selectParams), - 'collection' => $collection, - ); + { + $entity = $this->getEntity($id); + $foreignEntityName = $entity->relations[$link]['entity']; + + if (!$this->getAcl()->check($entity, 'read')) { + throw new Forbidden(); + } + if (!$this->getAcl()->check($foreignEntityName, 'read')) { + throw new Forbidden(); + } + + $selectParams = $this->getSelectManager($foreignEntityName)->getSelectParams($params, true); + + if (array_key_exists($link, $this->linkSelectParams)) { + $selectParams = array_merge($selectParams, $this->linkSelectParams[$link]); + } + + $collection = $this->getRepository()->findRelated($entity, $link, $selectParams); + + $recordService = $this->getRecordService($foreignEntityName); + + foreach ($collection as $e) { + $this->loadParentNameFields($e); + $recordService->prepareEntityForOutput($e); + } + + return array( + 'total' => $this->getRepository()->countRelated($entity, $link, $selectParams), + 'collection' => $collection, + ); } - + public function linkEntity($id, $link, $foreignId) - { - $entity = $this->getEntity($id); - - $entityName = $entity->getEntityName($entity); - $foreignEntityName = $entity->relations[$link]['entity']; - - if (!$this->getAcl()->check($entity, 'edit')) { - throw new Forbidden(); - } - - if (empty($foreignEntityName)) { - throw new Error(); - } - - $foreignEntity = $this->getEntityManager()->getEntity($foreignEntityName, $foreignId); - - if (!$this->getAcl()->check($foreignEntity, 'edit')) { - throw new Forbidden(); - } - - if (!empty($foreignEntity)) { - $this->getRepository()->relate($entity, $link, $foreignEntity); - return true; - } + { + $entity = $this->getEntity($id); + + $entityName = $entity->getEntityName($entity); + $foreignEntityName = $entity->relations[$link]['entity']; + + if (!$this->getAcl()->check($entity, 'edit')) { + throw new Forbidden(); + } + + if (empty($foreignEntityName)) { + throw new Error(); + } + + $foreignEntity = $this->getEntityManager()->getEntity($foreignEntityName, $foreignId); + + if (!$this->getAcl()->check($foreignEntity, 'edit')) { + throw new Forbidden(); + } + + if (!empty($foreignEntity)) { + $this->getRepository()->relate($entity, $link, $foreignEntity); + return true; + } } - + public function unlinkEntity($id, $link, $foreignId) { - $entity = $this->getEntity($id); - - $entityName = $entity->getEntityName($entity); - $foreignEntityName = $entity->relations[$link]['entity']; - - if (!$this->getAcl()->check($entity, 'edit')) { - throw new Forbidden(); - } - - if (empty($foreignEntityName)) { - throw new Error(); - } - - $foreignEntity = $this->getEntityManager()->getEntity($foreignEntityName, $foreignId); - - if (!$this->getAcl()->check($foreignEntity, 'edit')) { - throw new Forbidden(); - } - - if (!empty($foreignEntity)) { - $this->getRepository()->unrelate($entity, $link, $foreignEntity); - return true; - } + $entity = $this->getEntity($id); + + $entityName = $entity->getEntityName($entity); + $foreignEntityName = $entity->relations[$link]['entity']; + + if (!$this->getAcl()->check($entity, 'edit')) { + throw new Forbidden(); + } + + if (empty($foreignEntityName)) { + throw new Error(); + } + + $foreignEntity = $this->getEntityManager()->getEntity($foreignEntityName, $foreignId); + + if (!$this->getAcl()->check($foreignEntity, 'edit')) { + throw new Forbidden(); + } + + if (!empty($foreignEntity)) { + $this->getRepository()->unrelate($entity, $link, $foreignEntity); + return true; + } } - + public function massUpdate($attributes = array(), $ids = array(), $where = array()) { - $idsUpdated = array(); - $repository = $this->getRepository(); - - if (!empty($ids)) { - foreach ($ids as $id) { - $entity = $this->getEntity($id); - if ($this->getAcl()->check($entity, 'edit')) { - $entity->set(get_object_vars($attributes)); - if ($repository->save($entity)) { - $idsUpdated[] = $id; - } - } - } - } - - return $idsUpdated; - - // TODO update $where + $idsUpdated = array(); + $repository = $this->getRepository(); + + if (!empty($ids)) { + foreach ($ids as $id) { + $entity = $this->getEntity($id); + if ($this->getAcl()->check($entity, 'edit')) { + $entity->set(get_object_vars($attributes)); + if ($repository->save($entity)) { + $idsUpdated[] = $id; + } + } + } + } + + return $idsUpdated; + + // TODO update $where } - + + public function massRemove($ids = array(), $where = array()) + { + $idsRemoved = array(); + $repository = $this->getRepository(); + + if (!empty($ids)) { + foreach ($ids as $id) { + $entity = $this->getEntity($id); + if ($this->getAcl()->check($entity, 'remove')) { + if ($repository->remove($entity)) { + $idsRemoved[] = $id; + } + } + } + } + + return $idsRemoved; + + // TODO update $where + } + public function follow($id, $userId = null) { - $entity = $this->getEntity($id); - if (!$this->getAcl()->check($entity, 'read')) { - throw new Forbidden(); - } - - if (empty($userId)) { - $userId = $this->getUser()->id; - } + $entity = $this->getEntity($id); + if (!$this->getAcl()->check($entity, 'read')) { + throw new Forbidden(); + } - return $this->getStreamService()->followEntity($entity, $userId); + if (empty($userId)) { + $userId = $this->getUser()->id; + } + + return $this->getStreamService()->followEntity($entity, $userId); } - + public function unfollow($id, $userId = null) { - $entity = $this->getEntity($id); - if (!$this->getAcl()->check($entity, 'read')) { - throw new Forbidden(); - } - - if (empty($userId)) { - $userId = $this->getUser()->id; - } - - return $this->getStreamService()->unfollowEntity($entity, $userId); + $entity = $this->getEntity($id); + if (!$this->getAcl()->check($entity, 'read')) { + throw new Forbidden(); + } + + if (empty($userId)) { + $userId = $this->getUser()->id; + } + + return $this->getStreamService()->unfollowEntity($entity, $userId); } - + protected function getDuplicateWhereClause(Entity $entity) { - return false; + return false; } - + public function checkEntityForDuplicate(Entity $entity) - { - $where = $this->getDuplicateWhereClause($entity); - - if ($where) { - $duplicates = $this->getRepository()->where($where)->find(); - if (count($duplicates)) { - $result = array(); - foreach ($duplicates as $e) { - $result[$e->id] = $e->get('name'); - } - return $result; - } - } - return false; - } - - public function export($ids, $where) - { - if (!empty($ids)) { - $where = array( - array( - 'type' => 'in', - 'field' => 'id', - 'value' => $ids - ) - ); - } - - $selectParams = $this->getSelectManager($this->entityName)->getSelectParams(array('where' => $where), true); - $collection = $this->getRepository()->find($selectParams); - - $arr = array(); - - $collection->toArray(); - - $fieldsToSkip = array( - 'modifiedByName', - 'createdByName', - 'modifiedById', - 'createdById', - 'modifiedAt', - 'createdAt', - 'deleted', - ); - - $fields = null; - foreach ($collection as $entity) { - if (empty($fields)) { - $fields = array(); - foreach ($entity->getFields() as $field => $defs) { - if (in_array($field, $fieldsToSkip)) { - continue; - } - - if (empty($defs['notStorable'])) { - $fields[] = $field; - } else { - if (in_array($defs['type'], array('email', 'phone'))) { - $fields[] = $field; - } else if ($defs['name'] == 'name') { - $fields[] = $field; - } - } - } - } - - $row = array(); - foreach ($fields as $field) { - $row[$field] = $entity->get($field); - } - $arr[] = $row; - } - - $delimiter = $this->getPreferences()->get('exportDelimiter'); - if (empty($delimiter)) { - $delimiter = ','; - } - - $fp = fopen('php://temp', 'w'); - fputcsv($fp, array_keys($arr[0]), $delimiter); - foreach ($arr as $row) { - fputcsv($fp, $row, $delimiter); - } - rewind($fp); - $csv = stream_get_contents($fp); - fclose($fp); - - $fileName = "Export_{$this->entityName}.csv"; - - $attachment = $this->getEntityManager()->getEntity('Attachment'); - $attachment->set('name', $fileName); - $attachment->set('role', 'Export File'); - $attachment->set('type', 'text/csv'); - - $this->getEntityManager()->saveEntity($attachment); - - if (!empty($attachment->id)) { - $this->getInjection('fileManager')->putContents('data/upload/' . $attachment->id, $csv); - // TODO cron job to remove file - return $attachment->id; - } - throw new Error(); - } - - public function prepareEntityForOutput($entity) { - foreach ($this->internalFields as $field) { - $entity->clear($field); - } + $where = $this->getDuplicateWhereClause($entity); + + if ($where) { + $duplicates = $this->getRepository()->where($where)->find(); + if (count($duplicates)) { + $result = array(); + foreach ($duplicates as $e) { + $result[$e->id] = $e->get('name'); + } + return $result; + } + } + return false; + } + + public function export($ids, $where) + { + if (!empty($ids)) { + $where = array( + array( + 'type' => 'in', + 'field' => 'id', + 'value' => $ids + ) + ); + } + + $selectParams = $this->getSelectManager($this->entityName)->getSelectParams(array('where' => $where), true); + $collection = $this->getRepository()->find($selectParams); + + $arr = array(); + + $collection->toArray(); + + $fieldsToSkip = array( + 'modifiedByName', + 'createdByName', + 'modifiedById', + 'createdById', + 'modifiedAt', + 'createdAt', + 'deleted', + ); + + $fields = null; + foreach ($collection as $entity) { + if (empty($fields)) { + $fields = array(); + foreach ($entity->getFields() as $field => $defs) { + if (in_array($field, $fieldsToSkip)) { + continue; + } + + if (empty($defs['notStorable'])) { + $fields[] = $field; + } else { + if (in_array($defs['type'], array('email', 'phone'))) { + $fields[] = $field; + } else if ($defs['name'] == 'name') { + $fields[] = $field; + } + } + } + } + + $row = array(); + foreach ($fields as $field) { + $row[$field] = $entity->get($field); + } + $arr[] = $row; + } + + $delimiter = $this->getPreferences()->get('exportDelimiter'); + if (empty($delimiter)) { + $delimiter = ','; + } + + $fp = fopen('php://temp', 'w'); + fputcsv($fp, array_keys($arr[0]), $delimiter); + foreach ($arr as $row) { + fputcsv($fp, $row, $delimiter); + } + rewind($fp); + $csv = stream_get_contents($fp); + fclose($fp); + + $fileName = "Export_{$this->entityName}.csv"; + + $attachment = $this->getEntityManager()->getEntity('Attachment'); + $attachment->set('name', $fileName); + $attachment->set('role', 'Export File'); + $attachment->set('type', 'text/csv'); + + $this->getEntityManager()->saveEntity($attachment); + + if (!empty($attachment->id)) { + $this->getInjection('fileManager')->putContents('data/upload/' . $attachment->id, $csv); + // TODO cron job to remove file + return $attachment->id; + } + throw new Error(); + } + + public function prepareEntityForOutput(Entity $entity) + { + foreach ($this->internalFields as $field) { + $entity->clear($field); + } } } diff --git a/application/Espo/Services/ScheduledJob.php b/application/Espo/Services/ScheduledJob.php index c8dfd83a7a..a92eb0f3ed 100644 --- a/application/Espo/Services/ScheduledJob.php +++ b/application/Espo/Services/ScheduledJob.php @@ -25,59 +25,59 @@ namespace Espo\Services; use \PDO; class ScheduledJob extends \Espo\Services\Record -{ +{ - public function getActiveJobs() - { - $query = "SELECT * FROM scheduled_job WHERE - `status` = 'Active' - AND deleted = 0"; + public function getActiveJobs() + { + $query = "SELECT * FROM scheduled_job WHERE + `status` = 'Active' + AND deleted = 0"; - $pdo = $this->getEntityManager()->getPDO(); - $sth = $pdo->prepare($query); - $sth->execute(); + $pdo = $this->getEntityManager()->getPDO(); + $sth = $pdo->prepare($query); + $sth->execute(); - $rows = $sth->fetchAll(PDO::FETCH_ASSOC); - - $list = array(); - foreach ($rows as $row) { - $list[] = $row; - } + $rows = $sth->fetchAll(PDO::FETCH_ASSOC); + + $list = array(); + foreach ($rows as $row) { + $list[] = $row; + } - return $list; - } + return $list; + } - /** - * Add record to ScheduledJobLogRecord about executed job - * @param string $scheduledJobId - * @param string $status - * - * @return string Id of created ScheduledJobLogRecord - */ - public function addLogRecord($scheduledJobId, $status) - { - $lastRun = date('Y-m-d H:i:s'); + /** + * Add record to ScheduledJobLogRecord about executed job + * @param string $scheduledJobId + * @param string $status + * + * @return string Id of created ScheduledJobLogRecord + */ + public function addLogRecord($scheduledJobId, $status) + { + $lastRun = date('Y-m-d H:i:s'); - $entityManager = $this->getEntityManager(); + $entityManager = $this->getEntityManager(); - $scheduledJob = $entityManager->getEntity('ScheduledJob', $scheduledJobId); - $scheduledJob->set('lastRun', $lastRun); - $entityManager->saveEntity($scheduledJob); + $scheduledJob = $entityManager->getEntity('ScheduledJob', $scheduledJobId); + $scheduledJob->set('lastRun', $lastRun); + $entityManager->saveEntity($scheduledJob); - $scheduledJobLog = $entityManager->getEntity('ScheduledJobLogRecord'); - $scheduledJobLog->set(array( - 'scheduledJobId' => $scheduledJobId, - 'name' => $scheduledJob->get('name'), - 'status' => $status, - 'executionTime' => $lastRun, - )); - $scheduledJobLogId = $entityManager->saveEntity($scheduledJobLog); - //$entityManager->getRepository('ScheduledJobLogRecord')->relate($scheduledJobLog, 'scheduledJob', $scheduledJob); + $scheduledJobLog = $entityManager->getEntity('ScheduledJobLogRecord'); + $scheduledJobLog->set(array( + 'scheduledJobId' => $scheduledJobId, + 'name' => $scheduledJob->get('name'), + 'status' => $status, + 'executionTime' => $lastRun, + )); + $scheduledJobLogId = $entityManager->saveEntity($scheduledJobLog); + //$entityManager->getRepository('ScheduledJobLogRecord')->relate($scheduledJobLog, 'scheduledJob', $scheduledJob); - return $scheduledJobLogId; - } - - - + return $scheduledJobLogId; + } + + + } diff --git a/application/Espo/Services/Stream.php b/application/Espo/Services/Stream.php index 081ceb834c..1002b2fb70 100644 --- a/application/Espo/Services/Stream.php +++ b/application/Espo/Services/Stream.php @@ -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\Services; @@ -29,436 +29,450 @@ use Espo\ORM\Entity; class Stream extends \Espo\Core\Services\Base { - protected $statusDefs = array( - 'Lead' => array( - 'field' => 'status', - 'style' => array( - 'New' => 'primary', - 'Assigned' => 'primary', - 'In Process' => 'primary', - 'Converted' => 'success', - 'Recycled' => 'danger', - 'Dead' => 'danger', - ), - ), - 'Case' => array( - 'field' => 'status', - 'style' => array( - 'New' => 'primary', - 'Assigned' => 'primary', - 'Pending' => 'default', - 'Closed' => 'success', - 'Rejected' => 'danger', - 'Duplicate' => 'danger', - ), - ), - 'Opportunity' => array( - 'field' => 'stage', - 'style' => array( - 'Closed Won' => 'success', - 'Closed Lost' => 'danger', - ), - ), - ); - - protected $dependencies = array( - 'entityManager', - 'config', - 'user', - 'metadata', - 'acl' - ); - - protected function getAcl() - { - return $this->injections['acl']; - } - - protected function getMetadata() - { - return $this->injections['metadata']; - } - - public function checkIsFollowed(Entity $entity, $userId = null) - { - if (empty($userId)) { - $userId = $this->getUser()->id; - } - - $pdo = $this->getEntityManager()->getPDO(); - $sql = " - SELECT id FROM subscription - WHERE - entity_id = " . $pdo->quote($entity->id) . " AND entity_type = " . $pdo->quote($entity->getEntityName()) . " AND - user_id = " . $pdo->quote($userId) . " - "; - - $sth = $pdo->prepare($sql); - $sth->execute(); - if ($sth->fetchAll()) { - return true; - } - return false; - } - - public function followEntity(Entity $entity, $userId) - { - if ($userId == 'system') { - return; - } - if (!$this->getMetadata()->get('scopes.' . $entity->getEntityName() . '.stream')) { - throw new Error(); - } - - $pdo = $this->getEntityManager()->getPDO(); - - if (!$this->checkIsFollowed($entity, $userId)) { - $sql = " - INSERT INTO subscription - (entity_id, entity_type, user_id) - VALUES - (".$pdo->quote($entity->id) . ", " . $pdo->quote($entity->getEntityName()) . ", " . $pdo->quote($userId).") - "; - $sth = $pdo->prepare($sql)->execute(); - } - return true; - } - - public function unfollowEntity(Entity $entity, $userId) - { - if (!$this->getMetadata()->get('scopes.' . $entity->getEntityName() . '.stream')) { - throw new Error(); - } - - $pdo = $this->getEntityManager()->getPDO(); + protected $statusDefs = array( + 'Lead' => array( + 'field' => 'status', + 'style' => array( + 'New' => 'primary', + 'Assigned' => 'primary', + 'In Process' => 'primary', + 'Converted' => 'success', + 'Recycled' => 'danger', + 'Dead' => 'danger', + ), + ), + 'Case' => array( + 'field' => 'status', + 'style' => array( + 'New' => 'primary', + 'Assigned' => 'primary', + 'Pending' => 'default', + 'Closed' => 'success', + 'Rejected' => 'danger', + 'Duplicate' => 'danger', + ), + ), + 'Opportunity' => array( + 'field' => 'stage', + 'style' => array( + 'Closed Won' => 'success', + 'Closed Lost' => 'danger', + ), + ), + ); - $sql = " - DELETE FROM subscription - WHERE - entity_id = " . $pdo->quote($entity->id) . " AND entity_type = " . $pdo->quote($entity->getEntityName()) . " AND - user_id = " . $pdo->quote($userId) . " - "; - $sth = $pdo->prepare($sql)->execute(); - - return true; - } - - - public function unfollowAllUsersFromEntity(Entity $entity) - { - if (empty($entity->id)) { - return; - } - - $pdo = $this->getEntityManager()->getPDO(); - $sql = " - DELETE FROM subscription - WHERE - entity_id = " . $pdo->quote($entity->id) . " AND entity_type = " . $pdo->quote($entity->getEntityName()) . " - "; - $sth = $pdo->prepare($sql)->execute(); - } - - public function findUserStream($params = array()) - { - $selectParams = array( - 'offset' => $params['offset'], - 'limit' => $params['maxSize'], - 'orderBy' => 'createdAt', - 'order' => 'DESC', - 'customJoin' => " - JOIN subscription ON - note.parent_type = subscription.entity_type AND - note.parent_id = subscription.entity_id AND - subscription.user_id = '" . $this->getUser()->id . "' - " - ); - - if (!empty($params['after'])) { - $where = array(); - $where['createdAt>'] = $params['after']; - $selectParams['whereClause'] = $where; - } - - $collection = $this->getEntityManager()->getRepository('Note')->find($selectParams); - - foreach ($collection as $e) { - if ($e->get('type') == 'Post') { - $e->loadAttachments(); - } - } - - foreach ($collection as $e) { - if ($e->get('parentId') && $e->get('parentType')) { - $entity = $this->getEntityManager()->getEntity($e->get('parentType'), $e->get('parentId')); - if ($entity) { - $e->set('parentName', $entity->get('name')); - } - } - } - - unset($selectParams['whereClause']['createdAt>']); - $count = $this->getEntityManager()->getRepository('Note')->count($selectParams); - - return array( - 'total' => $count, - 'collection' => $collection, - ); - } - - public function find($scope, $id, $params = array()) - { - if ($scope == 'User') { - return $this->findUserStream($params); - } - $entity = $this->getEntityManager()->getEntity($scope, $id); - - if (empty($entity)) { - throw new NotFound(); - } - - if (!$this->getAcl($entity, 'read')) { - throw new Forbidden(); - } - - $where = array( - 'parentType' => $scope, - 'parentId' => $id - ); - - if (!empty($params['after'])) { - $where['createdAt>'] = $params['after']; - } - - $collection = $this->getEntityManager()->getRepository('Note')->find(array( - 'whereClause' => $where, - 'offset' => $params['offset'], - 'limit' => $params['maxSize'], - 'orderBy' => 'createdAt', - 'order' => 'DESC' - )); - - foreach ($collection as $e) { - if ($e->get('type') == 'Post') { - $e->loadAttachments(); - } - } - - unset($where['createdAt>']); - $count = $this->getEntityManager()->getRepository('Note')->count(array( - 'whereClause' => $where, - )); - - return array( - 'total' => $count, - 'collection' => $collection, - ); - } - - protected function loadAssignedUserName(Entity $entity) - { - $user = $this->getEntityManager()->getEntity('User', $entity->get('assignedUserId')); - if ($user) { - $entity->set('assignedUserName', $user->get('name')); - } - } - - public function noteEmailReceived(Entity $entity, Entity $email) - { - $entityName = $entity->getEntityName(); - - $note = $this->getEntityManager()->getEntity('Note'); - - $note->set('type', 'EmailReceived'); - $note->set('parentId', $entity->id); - $note->set('parentType', $entityName); - - $data = array(); - - $data['emailId'] = $email->id; - $data['emailName'] = $email->get('name'); - - $note->set('data', $data); - - $this->getEntityManager()->saveEntity($note); - } - - public function noteCreate(Entity $entity) - { - $entityName = $entity->getEntityName(); - - $note = $this->getEntityManager()->getEntity('Note'); - - $note->set('type', 'Create'); - $note->set('parentId', $entity->id); - $note->set('parentType', $entityName); + protected $dependencies = array( + 'entityManager', + 'config', + 'user', + 'metadata', + 'acl', + 'container', + ); - $data = array(); + protected function getServiceFactory() + { + return $this->injections['container']->get('serviceFactory'); + } - if ($entity->get('assignedUserId') != $entity->get('createdById')) { - if (!$entity->has('assignedUserName')) { - $this->loadAssignedUserName($entity); - } - $data['assignedUserId'] = $entity->get('assignedUserId'); - $data['assignedUserName'] = $entity->get('assignedUserName'); - } - - if (array_key_exists($entityName, $this->statusDefs)) { - $field = $this->statusDefs[$entityName]['field']; - $value = $entity->get($field); - if (!empty($value)) { - $style = 'default'; - if (!empty($this->statusDefs[$entityName]['style'][$value])) { - $style = $this->statusDefs[$entityName]['style'][$value]; - } - $data['statusValue'] = $value; - $data['statusField'] = $field; - $data['statusStyle'] = $style; - } - } - - $note->set('data', $data); - - $this->getEntityManager()->saveEntity($note); - } - - public function noteCreateRelated(Entity $entity, $entityType, $id, $action = 'created') - { - $note = $this->getEntityManager()->getEntity('Note'); - - $note->set('type', 'CreateRelated'); - $note->set('parentId', $id); - $note->set('parentType', $entityType); + protected function getAcl() + { + return $this->injections['acl']; + } - $note->set('data', array( - 'action' => $action, - 'entityType' => $entity->getEntityName(), - 'entityId' => $entity->id, - 'entityName' => $entity->get('name') - )); + protected function getMetadata() + { + return $this->injections['metadata']; + } - $this->getEntityManager()->saveEntity($note); - } - - public function noteAssign(Entity $entity) - { - $note = $this->getEntityManager()->getEntity('Note'); - - $note->set('type', 'Assign'); - $note->set('parentId', $entity->id); - $note->set('parentType', $entity->getEntityName()); + public function checkIsFollowed(Entity $entity, $userId = null) + { + if (empty($userId)) { + $userId = $this->getUser()->id; + } - if (!$entity->has('assignedUserName')) { - $this->loadAssignedUserName($entity); - } - $note->set('data', array( - 'assignedUserId' => $entity->get('assignedUserId'), - 'assignedUserName' => $entity->get('assignedUserName'), - )); + $pdo = $this->getEntityManager()->getPDO(); + $sql = " + SELECT id FROM subscription + WHERE + entity_id = " . $pdo->quote($entity->id) . " AND entity_type = " . $pdo->quote($entity->getEntityName()) . " AND + user_id = " . $pdo->quote($userId) . " + "; - $this->getEntityManager()->saveEntity($note); - } - - public function noteStatus(Entity $entity, $field) - { - $note = $this->getEntityManager()->getEntity('Note'); - - $note->set('type', 'Status'); - $note->set('parentId', $entity->id); - $note->set('parentType', $entity->getEntityName()); - - $style = 'default'; - $entityName = $entity->getEntityName(); - $value = $entity->get($field); - - if (!empty($this->statusDefs[$entityName]) && !empty($this->statusDefs[$entityName]['style'][$value])) { - $style = $this->statusDefs[$entityName]['style'][$value]; - } - - $note->set('data', array( - 'field' => $field, - 'value' => $value, - 'style' => $style, - )); - - $this->getEntityManager()->saveEntity($note); - } - - protected function getAuditedFields(Entity $entity) - { - $entityName = $entity->getEntityName(); - - if (!array_key_exists($entityName, $this->auditedFieldsCache)) { - $fields = $this->getMetadata()->get('entityDefs.' . $entityName . '.fields'); - $auditedFields = array(); - foreach ($fields as $field => $d) { - if (!empty($d['audited'])) { - $attributes = array(); - $fieldsDefs = $this->getMetadata()->get('fields.' . $d['type']); - - if (empty($fieldsDefs['actualFields'])) { - $attributes[] = $field; - } else { - foreach ($fieldsDefs['actualFields'] as $part) { - if (!empty($fieldsDefs['naming']) && $fieldsDefs['naming'] == 'prefix') { - $attributes[] = $part . ucfirst($field); - } else { - $attributes[] = $field . ucfirst($part); - } - } - } - - $auditedFields[$field] = $attributes; - } - } - $this->auditedFieldsCache[$entityName] = $auditedFields; - } - - return $this->auditedFieldsCache[$entityName]; - } - - public function handleAudited($entity) - { - $auditedFields = $this->getAuditedFields($entity); - - $updatedFields = array(); - $was = array(); - $became = array(); - - foreach ($auditedFields as $field => $attrs) { - $updated = false; - foreach ($attrs as $attr) { - if ($entity->get($attr) != $entity->getFetched($attr)) { + $sth = $pdo->prepare($sql); + $sth->execute(); + if ($sth->fetchAll()) { + return true; + } + return false; + } - $updated = true; - } - } - if ($updated) { - $updatedFields[] = $field; - foreach ($attrs as $attr) { - $was[$attr] = $entity->getFetched($attr); - $became[$attr] = $entity->get($attr); - } - } - } - - if (!empty($updatedFields)) { - $note = $this->getEntityManager()->getEntity('Note'); - - $note->set('type', 'Update'); - $note->set('parentId', $entity->id); - $note->set('parentType', $entity->getEntityName()); + public function followEntity(Entity $entity, $userId) + { + if ($userId == 'system') { + return; + } + if (!$this->getMetadata()->get('scopes.' . $entity->getEntityName() . '.stream')) { + throw new Error(); + } - $note->set('data', array( - 'fields' => $updatedFields, - 'attributes' => array( - 'was' => $was, - 'became' => $became, - ) - )); + $pdo = $this->getEntityManager()->getPDO(); - $this->getEntityManager()->saveEntity($note); - } - } + if (!$this->checkIsFollowed($entity, $userId)) { + $sql = " + INSERT INTO subscription + (entity_id, entity_type, user_id) + VALUES + (".$pdo->quote($entity->id) . ", " . $pdo->quote($entity->getEntityName()) . ", " . $pdo->quote($userId).") + "; + $sth = $pdo->prepare($sql)->execute(); + } + return true; + } + + public function unfollowEntity(Entity $entity, $userId) + { + if (!$this->getMetadata()->get('scopes.' . $entity->getEntityName() . '.stream')) { + throw new Error(); + } + + $pdo = $this->getEntityManager()->getPDO(); + + $sql = " + DELETE FROM subscription + WHERE + entity_id = " . $pdo->quote($entity->id) . " AND entity_type = " . $pdo->quote($entity->getEntityName()) . " AND + user_id = " . $pdo->quote($userId) . " + "; + $sth = $pdo->prepare($sql)->execute(); + + return true; + } + + + public function unfollowAllUsersFromEntity(Entity $entity) + { + if (empty($entity->id)) { + return; + } + + $pdo = $this->getEntityManager()->getPDO(); + $sql = " + DELETE FROM subscription + WHERE + entity_id = " . $pdo->quote($entity->id) . " AND entity_type = " . $pdo->quote($entity->getEntityName()) . " + "; + $sth = $pdo->prepare($sql)->execute(); + } + + public function findUserStream($params = array()) + { + $selectParams = array( + 'offset' => $params['offset'], + 'limit' => $params['maxSize'], + 'orderBy' => 'createdAt', + 'order' => 'DESC', + 'customJoin' => " + JOIN subscription ON + note.parent_type = subscription.entity_type AND + note.parent_id = subscription.entity_id AND + subscription.user_id = '" . $this->getUser()->id . "' + " + ); + + if (!empty($params['after'])) { + $where = array(); + $where['createdAt>'] = $params['after']; + $selectParams['whereClause'] = $where; + } + + $collection = $this->getEntityManager()->getRepository('Note')->find($selectParams); + + foreach ($collection as $e) { + if ($e->get('type') == 'Post' || $e->get('type') == 'EmailReceived') { + $e->loadAttachments(); + } + } + + foreach ($collection as $e) { + if ($e->get('parentId') && $e->get('parentType')) { + $entity = $this->getEntityManager()->getEntity($e->get('parentType'), $e->get('parentId')); + if ($entity) { + $e->set('parentName', $entity->get('name')); + } + } + } + + unset($selectParams['whereClause']['createdAt>']); + $count = $this->getEntityManager()->getRepository('Note')->count($selectParams); + + return array( + 'total' => $count, + 'collection' => $collection, + ); + } + + public function find($scope, $id, $params = array()) + { + if ($scope == 'User') { + return $this->findUserStream($params); + } + $entity = $this->getEntityManager()->getEntity($scope, $id); + + if (empty($entity)) { + throw new NotFound(); + } + + if (!$this->getAcl($entity, 'read')) { + throw new Forbidden(); + } + + $where = array( + 'parentType' => $scope, + 'parentId' => $id + ); + + if (!empty($params['after'])) { + $where['createdAt>'] = $params['after']; + } + + $collection = $this->getEntityManager()->getRepository('Note')->find(array( + 'whereClause' => $where, + 'offset' => $params['offset'], + 'limit' => $params['maxSize'], + 'orderBy' => 'createdAt', + 'order' => 'DESC' + )); + + foreach ($collection as $e) { + if ($e->get('type') == 'Post' || $e->get('type') == 'EmailReceived') { + $e->loadAttachments(); + } + } + + unset($where['createdAt>']); + $count = $this->getEntityManager()->getRepository('Note')->count(array( + 'whereClause' => $where, + )); + + return array( + 'total' => $count, + 'collection' => $collection, + ); + } + + protected function loadAssignedUserName(Entity $entity) + { + $user = $this->getEntityManager()->getEntity('User', $entity->get('assignedUserId')); + if ($user) { + $entity->set('assignedUserName', $user->get('name')); + } + } + + public function noteEmailReceived(Entity $entity, Entity $email, $isInitial = false) + { + $entityName = $entity->getEntityName(); + + $note = $this->getEntityManager()->getEntity('Note'); + + $note->set('type', 'EmailReceived'); + $note->set('parentId', $entity->id); + $note->set('parentType', $entityName); + + $note->set('post', $email->getBodyPlain()); + + $data = array(); + + $data['emailId'] = $email->id; + $data['emailName'] = $email->get('name'); + $data['isInitial'] = $isInitial; + + $note->set('data', $data); + + $this->getEntityManager()->saveEntity($note); + + $attachmentsIds = $email->get('attachmentsIds'); + if (!empty($attachmentsIds)) { + $attachmentsData = $this->getServiceFactory()->create('Email')->copyAttachments($email->id, 'Note', $note->id); + } + } + + public function noteCreate(Entity $entity) + { + $entityName = $entity->getEntityName(); + + $note = $this->getEntityManager()->getEntity('Note'); + + $note->set('type', 'Create'); + $note->set('parentId', $entity->id); + $note->set('parentType', $entityName); + + $data = array(); + + if ($entity->get('assignedUserId') != $entity->get('createdById')) { + if (!$entity->has('assignedUserName')) { + $this->loadAssignedUserName($entity); + } + $data['assignedUserId'] = $entity->get('assignedUserId'); + $data['assignedUserName'] = $entity->get('assignedUserName'); + } + + if (array_key_exists($entityName, $this->statusDefs)) { + $field = $this->statusDefs[$entityName]['field']; + $value = $entity->get($field); + if (!empty($value)) { + $style = 'default'; + if (!empty($this->statusDefs[$entityName]['style'][$value])) { + $style = $this->statusDefs[$entityName]['style'][$value]; + } + $data['statusValue'] = $value; + $data['statusField'] = $field; + $data['statusStyle'] = $style; + } + } + + $note->set('data', $data); + + $this->getEntityManager()->saveEntity($note); + } + + public function noteCreateRelated(Entity $entity, $entityType, $id, $action = 'created') + { + $note = $this->getEntityManager()->getEntity('Note'); + + $note->set('type', 'CreateRelated'); + $note->set('parentId', $id); + $note->set('parentType', $entityType); + + $note->set('data', array( + 'action' => $action, + 'entityType' => $entity->getEntityName(), + 'entityId' => $entity->id, + 'entityName' => $entity->get('name') + )); + + $this->getEntityManager()->saveEntity($note); + } + + public function noteAssign(Entity $entity) + { + $note = $this->getEntityManager()->getEntity('Note'); + + $note->set('type', 'Assign'); + $note->set('parentId', $entity->id); + $note->set('parentType', $entity->getEntityName()); + + if (!$entity->has('assignedUserName')) { + $this->loadAssignedUserName($entity); + } + $note->set('data', array( + 'assignedUserId' => $entity->get('assignedUserId'), + 'assignedUserName' => $entity->get('assignedUserName'), + )); + + $this->getEntityManager()->saveEntity($note); + } + + public function noteStatus(Entity $entity, $field) + { + $note = $this->getEntityManager()->getEntity('Note'); + + $note->set('type', 'Status'); + $note->set('parentId', $entity->id); + $note->set('parentType', $entity->getEntityName()); + + $style = 'default'; + $entityName = $entity->getEntityName(); + $value = $entity->get($field); + + if (!empty($this->statusDefs[$entityName]) && !empty($this->statusDefs[$entityName]['style'][$value])) { + $style = $this->statusDefs[$entityName]['style'][$value]; + } + + $note->set('data', array( + 'field' => $field, + 'value' => $value, + 'style' => $style, + )); + + $this->getEntityManager()->saveEntity($note); + } + + protected function getAuditedFields(Entity $entity) + { + $entityName = $entity->getEntityName(); + + if (!array_key_exists($entityName, $this->auditedFieldsCache)) { + $fields = $this->getMetadata()->get('entityDefs.' . $entityName . '.fields'); + $auditedFields = array(); + foreach ($fields as $field => $d) { + if (!empty($d['audited'])) { + $attributes = array(); + $fieldsDefs = $this->getMetadata()->get('fields.' . $d['type']); + + if (empty($fieldsDefs['actualFields'])) { + $attributes[] = $field; + } else { + foreach ($fieldsDefs['actualFields'] as $part) { + if (!empty($fieldsDefs['naming']) && $fieldsDefs['naming'] == 'prefix') { + $attributes[] = $part . ucfirst($field); + } else { + $attributes[] = $field . ucfirst($part); + } + } + } + + $auditedFields[$field] = $attributes; + } + } + $this->auditedFieldsCache[$entityName] = $auditedFields; + } + + return $this->auditedFieldsCache[$entityName]; + } + + public function handleAudited($entity) + { + $auditedFields = $this->getAuditedFields($entity); + + $updatedFields = array(); + $was = array(); + $became = array(); + + foreach ($auditedFields as $field => $attrs) { + $updated = false; + foreach ($attrs as $attr) { + if ($entity->get($attr) != $entity->getFetched($attr)) { + + $updated = true; + } + } + if ($updated) { + $updatedFields[] = $field; + foreach ($attrs as $attr) { + $was[$attr] = $entity->getFetched($attr); + $became[$attr] = $entity->get($attr); + } + } + } + + if (!empty($updatedFields)) { + $note = $this->getEntityManager()->getEntity('Note'); + + $note->set('type', 'Update'); + $note->set('parentId', $entity->id); + $note->set('parentType', $entity->getEntityName()); + + $note->set('data', array( + 'fields' => $updatedFields, + 'attributes' => array( + 'was' => $was, + 'became' => $became, + ) + )); + + $this->getEntityManager()->saveEntity($note); + } + } } diff --git a/application/Espo/Services/Team.php b/application/Espo/Services/Team.php new file mode 100644 index 0000000000..79e2451223 --- /dev/null +++ b/application/Espo/Services/Team.php @@ -0,0 +1,35 @@ + array( + 'additionalColumns' => array( + 'role' => 'teamRole' + ) + ) + ); +} + diff --git a/application/Espo/Services/User.php b/application/Espo/Services/User.php index 5556e6551c..f4b89905fa 100644 --- a/application/Espo/Services/User.php +++ b/application/Espo/Services/User.php @@ -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\Services; @@ -29,148 +29,151 @@ use \Espo\Core\Exceptions\NotFound; use \Espo\ORM\Entity; class User extends Record -{ - protected function init() - { - $this->dependencies[] = 'mailSender'; - $this->dependencies[] = 'language'; - } - - protected $internalFields = array('password'); - - protected function getMailSender() - { - return $this->injections['mailSender']; - } - - protected function getLanguage() - { - return $this->injections['language']; - } - - public function getEntity($id) - { - if ($id == 'system') { - throw new Forbidden(); - } - - $entity = parent::getEntity($id); - return $entity; - } - - public function findEntities($params) - { - if (empty($params['where'])) { - $params['where'] = array(); - } - $params['where'][] = array( - 'type' => 'notEquals', - 'field' => 'id', - 'value' => 'system' - ); - - $result = parent::findEntities($params); - return $result; - } - - public function changePassword($userId, $password) - { - $user = $this->getEntityManager()->getEntity('User', $userId); - if (!$user) { - throw new NotFound(); - } - - if (empty($password)) { - throw new Error('Password can\'t be empty.'); - } - - $user->set('password', $this->hashPassword($password)); - - $this->getEntityManager()->saveEntity($user); - - return true; - } - - protected function hashPassword($password) - { - return md5($password); - } - - public function createEntity($data) - { - $newPassword = null; - if (array_key_exists('password', $data)) { - $newPassword = $data['password']; - $data['password'] = $this->hashPassword($data['password']); - } - $user = parent::createEntity($data); - - if (!is_null($newPassword)) { - $this->sendPassword($user, $newPassword); - } - - return $user; - } - - public function updateEntity($id, $data) - { - if ($id == 'system') { - throw new Forbidden(); - } - $newPassword = null; - if (array_key_exists('password', $data)) { - $newPassword = $data['password']; - $data['password'] = $this->hashPassword($data['password']); - } - $user = parent::updateEntity($id, $data); - - if (!is_null($newPassword)) { - try { - $this->sendPassword($user, $newPassword); - } catch (\Exception $e) {} - } - - return $user; - } - - protected function sendPassword(Entity $user, $password) - { - $emailAddress = $user->get('emailAddress'); - - if (empty($emailAddress)) { - return; - } - - $email = $this->getEntityManager()->getEntity('Email'); - - if (!$this->getConfig()->get('smtpServer')) { - return; - } - - - $subject = $this->getLanguage()->translate('accountInfoEmailSubject', 'messages', 'User'); - $body = $this->getLanguage()->translate('accountInfoEmailBody', 'messages', 'User'); - - $body = str_replace('{userName}', $user->get('userName'), $body); - $body = str_replace('{password}', $password, $body); - $body = str_replace('{siteUrl}', $this->getConfig()->get('siteUrl'), $body); - - $email->set(array( - 'subject' => $subject, - 'body' => $body, - 'isHtml' => false, - 'to' => $emailAddress - )); - - $this->getMailSender()->send($email); - } - - public function deleteEntity($id) - { - if ($id == 'system') { - throw new Forbidden(); - } - return parent::deleteEntity($id); - } +{ + protected function init() + { + $this->dependencies[] = 'mailSender'; + $this->dependencies[] = 'language'; + } + + protected $internalFields = array('password'); + + protected function getMailSender() + { + return $this->injections['mailSender']; + } + + protected function getLanguage() + { + return $this->injections['language']; + } + + public function getEntity($id) + { + if ($id == 'system') { + throw new Forbidden(); + } + + $entity = parent::getEntity($id); + return $entity; + } + + public function findEntities($params) + { + if (empty($params['where'])) { + $params['where'] = array(); + } + $params['where'][] = array( + 'type' => 'notEquals', + 'field' => 'id', + 'value' => 'system' + ); + + $result = parent::findEntities($params); + return $result; + } + + public function changePassword($userId, $password) + { + $user = $this->getEntityManager()->getEntity('User', $userId); + if (!$user) { + throw new NotFound(); + } + + if (empty($password)) { + throw new Error('Password can\'t be empty.'); + } + + $user->set('password', $this->hashPassword($password)); + + $this->getEntityManager()->saveEntity($user); + + return true; + } + + protected function hashPassword($password) + { + $config = $this->getConfig(); + $passwordHash = new \Espo\Core\Utils\PasswordHash($config); + + return $passwordHash->hash($password); + } + + public function createEntity($data) + { + $newPassword = null; + if (array_key_exists('password', $data)) { + $newPassword = $data['password']; + $data['password'] = $this->hashPassword($data['password']); + } + $user = parent::createEntity($data); + + if (!is_null($newPassword)) { + $this->sendPassword($user, $newPassword); + } + + return $user; + } + + public function updateEntity($id, $data) + { + if ($id == 'system') { + throw new Forbidden(); + } + $newPassword = null; + if (array_key_exists('password', $data)) { + $newPassword = $data['password']; + $data['password'] = $this->hashPassword($data['password']); + } + $user = parent::updateEntity($id, $data); + + if (!is_null($newPassword)) { + try { + $this->sendPassword($user, $newPassword); + } catch (\Exception $e) {} + } + + return $user; + } + + protected function sendPassword(Entity $user, $password) + { + $emailAddress = $user->get('emailAddress'); + + if (empty($emailAddress)) { + return; + } + + $email = $this->getEntityManager()->getEntity('Email'); + + if (!$this->getConfig()->get('smtpServer')) { + return; + } + + + $subject = $this->getLanguage()->translate('accountInfoEmailSubject', 'messages', 'User'); + $body = $this->getLanguage()->translate('accountInfoEmailBody', 'messages', 'User'); + + $body = str_replace('{userName}', $user->get('userName'), $body); + $body = str_replace('{password}', $password, $body); + $body = str_replace('{siteUrl}', $this->getConfig()->get('siteUrl'), $body); + + $email->set(array( + 'subject' => $subject, + 'body' => $body, + 'isHtml' => false, + 'to' => $emailAddress + )); + + $this->getMailSender()->send($email); + } + + public function deleteEntity($id) + { + if ($id == 'system') { + throw new Forbidden(); + } + return parent::deleteEntity($id); + } } diff --git a/cron.php b/cron.php index f437f2df28..4ccec0bca2 100644 --- a/cron.php +++ b/cron.php @@ -7,7 +7,7 @@ if (substr($sapiName, 0, 3) != 'cli') { } include "bootstrap.php"; - + $app = new \Espo\Core\Application(); $app->runCron(); diff --git a/diff.js b/diff.js index 012871bc22..a5ec995833 100644 --- a/diff.js +++ b/diff.js @@ -1,7 +1,7 @@ var versionFrom = process.argv[2]; if (process.argv.length < 3) { - throw new Error("No 'version from' passed"); + throw new Error("No 'version from' passed"); } var acceptedVersionName = process.argv[3] || versionFrom; @@ -24,93 +24,94 @@ var upgradePath = currentPath + '/build/EspoCRM-upgrade-' + acceptedVersionName var exec = require('child_process').exec; function execute(command, callback) { - exec(command, function(error, stdout, stderr) { - callback(stdout); + exec(command, function(error, stdout, stderr) { + callback(stdout); }); }; execute('git diff --name-only ' + versionFrom, function (stdout) { - if (!fs.existsSync(upgradePath)) { - fs.mkdirSync(upgradePath); - } - if (!fs.existsSync(upgradePath + '/files')) { - fs.mkdirSync(upgradePath + '/files'); - } - process.chdir(buildPath); - - var fileList = []; - - (stdout || '').split('\n').forEach(function (file) { - if (file == '') { - return; - } - fileList.push(file.replace('frontend/', '')); - }); - - fileList.push('client/espo.min.js'); - - fileList.push('client/css/espo.min.css'); - - fs.writeFileSync(diffFilePath, fileList.join('\n')); - - execute('git diff --name-only --diff-filter=D ' + versionFrom, function (stdout) { - var deletedFileList = []; - - (stdout || '').split('\n').forEach(function (file) { - if (file == '') { - return; - } - deletedFileList.push(file.replace('frontend/', '')); - }); - - - execute('xargs -a ' + diffFilePath + ' cp --parents -t ' + upgradePath + '/files ' , function (stdout) { - - }); - - var d = new Date(); - - var monthN = ((d.getMonth() + 1).toString()); - monthN = monthN.length == 1 ? '0' + monthN : monthN; - - var dateN = d.getDate().toString(); - dateN = dateN.length == 1 ? '0' + dateN : dateN; - - var date = d.getFullYear().toString() + '-' + monthN + '-' + dateN.toString(); - - execute('git tag', function (stdout) { - var versionList = []; - var occured = false; - tagList = stdout.split('\n').forEach(function (tag) { - if (tag == versionFrom) { - occured = true; - } - if (!tag || tag == version) { - return; - } - if (occured) { - versionList.push(tag); - } - }); - - var manifest = { - "name": "EspoCRM Upgrade "+acceptedVersionName+" to "+version, - "type": "upgrade", - "version": version, - "acceptableVersions": versionList, - "releaseDate": date, - "author": "EspoCRM", - "description": "", - "delete": deletedFileList - } - - fs.writeFileSync(upgradePath + '/manifest.json', JSON.stringify(manifest, null, ' ')); - - }); - - fs.unlinkSync(diffFilePath) - - }); - + if (!fs.existsSync(upgradePath)) { + fs.mkdirSync(upgradePath); + } + if (!fs.existsSync(upgradePath + '/files')) { + fs.mkdirSync(upgradePath + '/files'); + } + process.chdir(buildPath); + + var fileList = []; + + (stdout || '').split('\n').forEach(function (file) { + if (file == '') { + return; + } + fileList.push(file.replace('frontend/', '')); + }); + + fileList.push('client/espo.min.js'); + + fileList.push('client/css/espo.min.css'); + fileList.push('client/css/bootstrap.css'); + + fs.writeFileSync(diffFilePath, fileList.join('\n')); + + execute('git diff --name-only --diff-filter=D ' + versionFrom, function (stdout) { + var deletedFileList = []; + + (stdout || '').split('\n').forEach(function (file) { + if (file == '') { + return; + } + deletedFileList.push(file.replace('frontend/', '')); + }); + + + execute('xargs -a ' + diffFilePath + ' cp --parents -t ' + upgradePath + '/files ' , function (stdout) { + + }); + + var d = new Date(); + + var monthN = ((d.getMonth() + 1).toString()); + monthN = monthN.length == 1 ? '0' + monthN : monthN; + + var dateN = d.getDate().toString(); + dateN = dateN.length == 1 ? '0' + dateN : dateN; + + var date = d.getFullYear().toString() + '-' + monthN + '-' + dateN.toString(); + + execute('git tag', function (stdout) { + var versionList = []; + var occured = false; + tagList = stdout.split('\n').forEach(function (tag) { + if (tag == versionFrom) { + occured = true; + } + if (!tag || tag == version) { + return; + } + if (occured) { + versionList.push(tag); + } + }); + + var manifest = { + "name": "EspoCRM Upgrade "+acceptedVersionName+" to "+version, + "type": "upgrade", + "version": version, + "acceptableVersions": versionList, + "releaseDate": date, + "author": "EspoCRM", + "description": "", + "delete": deletedFileList + } + + fs.writeFileSync(upgradePath + '/manifest.json', JSON.stringify(manifest, null, ' ')); + + }); + + fs.unlinkSync(diffFilePath) + + }); + }); diff --git a/frontend/client/css/bootstrap.css b/frontend/client/css/bootstrap.css deleted file mode 100644 index 97e5557387..0000000000 --- a/frontend/client/css/bootstrap.css +++ /dev/null @@ -1 +0,0 @@ -/*! normalize.css v3.0.1 | MIT License | git.io/normalize */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}@media print{*{text-shadow:none!important;color:#000!important;background:transparent!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}select{background:#fff!important}.navbar{display:none}.table td,.table th{background-color:#fff!important}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table-bordered th,.table-bordered td{border:1px solid #ddd!important}}@font-face{font-family:'Glyphicons Halflings';src:url('../fonts/glyphicons-halflings-regular.eot');src:url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'),url('../fonts/glyphicons-halflings-regular.woff') format('woff'),url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'),url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:normal;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}*:before,*:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:'Open Sans',sans-serif;font-size:14px;line-height:1.36;color:#333;background-color:#fefefe}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#5184b0;text-decoration:none}a:hover,a:focus{color:#385d7c;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.img-responsive,.thumbnail>img,.thumbnail a>img,.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;width:100% \9;max-width:100%;height:auto}.img-rounded{border-radius:0}.img-thumbnail{padding:4px;line-height:1.36;background-color:#fefefe;border:1px solid #e8eced;border-radius:0;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out;display:inline-block;width:100% \9;max-width:100%;height:auto}.img-circle{border-radius:50%}hr{margin-top:19px;margin-bottom:19px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:'Open Sans',sans-serif;font-weight:500;line-height:1;color:inherit}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small,.h1 small,.h2 small,.h3 small,.h4 small,.h5 small,.h6 small,h1 .small,h2 .small,h3 .small,h4 .small,h5 .small,h6 .small,.h1 .small,.h2 .small,.h3 .small,.h4 .small,.h5 .small,.h6 .small{font-weight:normal;line-height:1;color:#999}h1,.h1,h2,.h2,h3,.h3{margin-top:19px;margin-bottom:9.5px}h1 small,.h1 small,h2 small,.h2 small,h3 small,.h3 small,h1 .small,.h1 .small,h2 .small,.h2 .small,h3 .small,.h3 .small{font-size:65%}h4,.h4,h5,.h5,h6,.h6{margin-top:9.5px;margin-bottom:9.5px}h4 small,.h4 small,h5 small,.h5 small,h6 small,.h6 small,h4 .small,.h4 .small,h5 .small,.h5 .small,h6 .small,.h6 .small{font-size:75%}h1,.h1{font-size:36px}h2,.h2{font-size:30px}h3,.h3{font-size:24px}h4,.h4{font-size:18px}h5,.h5{font-size:14px}h6,.h6{font-size:12px}p{margin:0 0 9.5px}.lead{margin-bottom:19px;font-size:16px;font-weight:300;line-height:1.4}@media(min-width:768px){.lead{font-size:21px}}small,.small{font-size:85%}cite{font-style:normal}mark,.mark{background-color:#fcf8e3;padding:.2em}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#999}.text-primary{color:#5184b0}a.text-primary:hover{color:#406a8e}.text-success{color:#3c763d}a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:hover{color:#245269}.text-warning{color:#9e7328}a.text-warning:hover{color:#75551e}.text-danger{color:#a94442}a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#5184b0}a.bg-primary:hover{background-color:#406a8e}.bg-success{background-color:#dff0d8}a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#cee6ed}a.bg-info:hover{background-color:#a9d3df}.bg-warning{background-color:#fcf8e3}a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:8.5px;margin:38px 0 19px;border-bottom:1px solid #eee}ul,ol{margin-top:0;margin-bottom:9.5px}ul ul,ol ul,ul ol,ol ol{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none;margin-left:-5px}.list-inline>li{display:inline-block;padding-left:5px;padding-right:5px}dl{margin-top:0;margin-bottom:19px}dt,dd{line-height:1.36}dt{font-weight:bold}dd{margin-left:0}@media(min-width:768px){.dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:9.5px 19px;margin:0 0 19px;font-size:17.5px;border-left:5px solid #eee}blockquote p:last-child,blockquote ul:last-child,blockquote ol:last-child{margin-bottom:0}blockquote footer,blockquote small,blockquote .small{display:block;font-size:80%;line-height:1.36;color:#999}blockquote footer:before,blockquote small:before,blockquote .small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0;text-align:right}.blockquote-reverse footer:before,blockquote.pull-right footer:before,.blockquote-reverse small:before,blockquote.pull-right small:before,.blockquote-reverse .small:before,blockquote.pull-right .small:before{content:''}.blockquote-reverse footer:after,blockquote.pull-right footer:after,.blockquote-reverse small:after,blockquote.pull-right small:after,.blockquote-reverse .small:after,blockquote.pull-right .small:after{content:'\00A0 \2014'}blockquote:before,blockquote:after{content:""}address{margin-bottom:19px;font-style:normal;line-height:1.36}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:0}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:0;box-shadow:inset 0 -1px 0 rgba(0,0,0,0.25)}kbd kbd{padding:0;font-size:100%;box-shadow:none}pre{display:block;padding:9px;margin:0 0 9.5px;font-size:13px;line-height:1.36;word-break:break-all;word-wrap:break-word;color:#333;background-color:#e8eced;border:1px solid #ccc;border-radius:0}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-left:8px;padding-right:8px;margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}.container:before,.container:after{content:" ";display:table}.container:after{clear:both}.container:before,.container:after{content:" ";display:table}.container:after{clear:both}@media(min-width:768px){.container{width:none}}@media(min-width:992px){.container{width:none}}@media(min-width:1200px){.container{width:none}}.container-fluid{padding-left:8px;padding-right:8px;margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}.container-fluid:before,.container-fluid:after{content:" ";display:table}.container-fluid:after{clear:both}.container-fluid:before,.container-fluid:after{content:" ";display:table}.container-fluid:after{clear:both}.row{margin-left:-8px;margin-right:-8px}.col-xs-1,.col-sm-1,.col-md-1,.col-lg-1,.col-xs-2,.col-sm-2,.col-md-2,.col-lg-2,.col-xs-3,.col-sm-3,.col-md-3,.col-lg-3,.col-xs-4,.col-sm-4,.col-md-4,.col-lg-4,.col-xs-5,.col-sm-5,.col-md-5,.col-lg-5,.col-xs-6,.col-sm-6,.col-md-6,.col-lg-6,.col-xs-7,.col-sm-7,.col-md-7,.col-lg-7,.col-xs-8,.col-sm-8,.col-md-8,.col-lg-8,.col-xs-9,.col-sm-9,.col-md-9,.col-lg-9,.col-xs-10,.col-sm-10,.col-md-10,.col-lg-10,.col-xs-11,.col-sm-11,.col-md-11,.col-lg-11,.col-xs-12,.col-sm-12,.col-md-12,.col-lg-12{position:relative;min-height:1px;padding-left:8px;padding-right:8px}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11,.col-xs-12{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666666666666%}.col-xs-10{width:83.33333333333334%}.col-xs-9{width:75%}.col-xs-8{width:66.66666666666666%}.col-xs-7{width:58.333333333333336%}.col-xs-6{width:50%}.col-xs-5{width:41.66666666666667%}.col-xs-4{width:33.33333333333333%}.col-xs-3{width:25%}.col-xs-2{width:16.666666666666664%}.col-xs-1{width:8.333333333333332%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666666666666%}.col-xs-pull-10{right:83.33333333333334%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666666666666%}.col-xs-pull-7{right:58.333333333333336%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666666666667%}.col-xs-pull-4{right:33.33333333333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.666666666666664%}.col-xs-pull-1{right:8.333333333333332%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666666666666%}.col-xs-push-10{left:83.33333333333334%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666666666666%}.col-xs-push-7{left:58.333333333333336%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666666666667%}.col-xs-push-4{left:33.33333333333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.666666666666664%}.col-xs-push-1{left:8.333333333333332%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666666666666%}.col-xs-offset-10{margin-left:83.33333333333334%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666666666666%}.col-xs-offset-7{margin-left:58.333333333333336%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666666666667%}.col-xs-offset-4{margin-left:33.33333333333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.666666666666664%}.col-xs-offset-1{margin-left:8.333333333333332%}.col-xs-offset-0{margin-left:0}@media(min-width:768px){.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666666666666%}.col-sm-10{width:83.33333333333334%}.col-sm-9{width:75%}.col-sm-8{width:66.66666666666666%}.col-sm-7{width:58.333333333333336%}.col-sm-6{width:50%}.col-sm-5{width:41.66666666666667%}.col-sm-4{width:33.33333333333333%}.col-sm-3{width:25%}.col-sm-2{width:16.666666666666664%}.col-sm-1{width:8.333333333333332%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666666666666%}.col-sm-pull-10{right:83.33333333333334%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666666666666%}.col-sm-pull-7{right:58.333333333333336%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666666666667%}.col-sm-pull-4{right:33.33333333333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.666666666666664%}.col-sm-pull-1{right:8.333333333333332%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666666666666%}.col-sm-push-10{left:83.33333333333334%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666666666666%}.col-sm-push-7{left:58.333333333333336%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666666666667%}.col-sm-push-4{left:33.33333333333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.666666666666664%}.col-sm-push-1{left:8.333333333333332%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666666666666%}.col-sm-offset-10{margin-left:83.33333333333334%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666666666666%}.col-sm-offset-7{margin-left:58.333333333333336%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666666666667%}.col-sm-offset-4{margin-left:33.33333333333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.666666666666664%}.col-sm-offset-1{margin-left:8.333333333333332%}.col-sm-offset-0{margin-left:0}}@media(min-width:992px){.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666666666666%}.col-md-10{width:83.33333333333334%}.col-md-9{width:75%}.col-md-8{width:66.66666666666666%}.col-md-7{width:58.333333333333336%}.col-md-6{width:50%}.col-md-5{width:41.66666666666667%}.col-md-4{width:33.33333333333333%}.col-md-3{width:25%}.col-md-2{width:16.666666666666664%}.col-md-1{width:8.333333333333332%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666666666666%}.col-md-pull-10{right:83.33333333333334%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666666666666%}.col-md-pull-7{right:58.333333333333336%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666666666667%}.col-md-pull-4{right:33.33333333333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.666666666666664%}.col-md-pull-1{right:8.333333333333332%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666666666666%}.col-md-push-10{left:83.33333333333334%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666666666666%}.col-md-push-7{left:58.333333333333336%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666666666667%}.col-md-push-4{left:33.33333333333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.666666666666664%}.col-md-push-1{left:8.333333333333332%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666666666666%}.col-md-offset-10{margin-left:83.33333333333334%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666666666666%}.col-md-offset-7{margin-left:58.333333333333336%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666666666667%}.col-md-offset-4{margin-left:33.33333333333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.666666666666664%}.col-md-offset-1{margin-left:8.333333333333332%}.col-md-offset-0{margin-left:0}}@media(min-width:1200px){.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666666666666%}.col-lg-10{width:83.33333333333334%}.col-lg-9{width:75%}.col-lg-8{width:66.66666666666666%}.col-lg-7{width:58.333333333333336%}.col-lg-6{width:50%}.col-lg-5{width:41.66666666666667%}.col-lg-4{width:33.33333333333333%}.col-lg-3{width:25%}.col-lg-2{width:16.666666666666664%}.col-lg-1{width:8.333333333333332%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666666666666%}.col-lg-pull-10{right:83.33333333333334%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666666666666%}.col-lg-pull-7{right:58.333333333333336%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666666666667%}.col-lg-pull-4{right:33.33333333333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.666666666666664%}.col-lg-pull-1{right:8.333333333333332%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666666666666%}.col-lg-push-10{left:83.33333333333334%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666666666666%}.col-lg-push-7{left:58.333333333333336%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666666666667%}.col-lg-push-4{left:33.33333333333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.666666666666664%}.col-lg-push-1{left:8.333333333333332%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666666666666%}.col-lg-offset-10{margin-left:83.33333333333334%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666666666666%}.col-lg-offset-7{margin-left:58.333333333333336%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666666666667%}.col-lg-offset-4{margin-left:33.33333333333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.666666666666664%}.col-lg-offset-1{margin-left:8.333333333333332%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:19px}.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td{padding:8px;line-height:1.36;vertical-align:top;border-top:1px solid #e8eced}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #e8eced}.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>th,.table>caption+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>td,.table>thead:first-child>tr:first-child>td{border-top:0}.table>tbody+tbody{border-top:2px solid #e8eced}.table .table{background-color:#fefefe}.table-condensed>thead>tr>th,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>tbody>tr>td,.table-condensed>tfoot>tr>td{padding:5px}.table-bordered{border:1px solid #e8eced}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #e8eced}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table-striped>tbody>tr:nth-child(odd)>td,.table-striped>tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover>tbody>tr:hover>td,.table-hover>tbody>tr:hover>th{background-color:#e8eced}table col[class*="col-"]{position:static;float:none;display:table-column}table td[class*="col-"],table th[class*="col-"]{position:static;float:none;display:table-cell}.table>thead>tr>td.active,.table>tbody>tr>td.active,.table>tfoot>tr>td.active,.table>thead>tr>th.active,.table>tbody>tr>th.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>tbody>tr.active>td,.table>tfoot>tr.active>td,.table>thead>tr.active>th,.table>tbody>tr.active>th,.table>tfoot>tr.active>th{background-color:#e8eced}.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover,.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr.active:hover>th{background-color:#dae0e2}.table>thead>tr>td.success,.table>tbody>tr>td.success,.table>tfoot>tr>td.success,.table>thead>tr>th.success,.table>tbody>tr>th.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>tbody>tr.success>td,.table>tfoot>tr.success>td,.table>thead>tr.success>th,.table>tbody>tr.success>th,.table>tfoot>tr.success>th{background-color:#dff0d8}.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover,.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr.success:hover>th{background-color:#d0e9c6}.table>thead>tr>td.info,.table>tbody>tr>td.info,.table>tfoot>tr>td.info,.table>thead>tr>th.info,.table>tbody>tr>th.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>tbody>tr.info>td,.table>tfoot>tr.info>td,.table>thead>tr.info>th,.table>tbody>tr.info>th,.table>tfoot>tr.info>th{background-color:#cee6ed}.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover,.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr.info:hover>th{background-color:#bbdce6}.table>thead>tr>td.warning,.table>tbody>tr>td.warning,.table>tfoot>tr>td.warning,.table>thead>tr>th.warning,.table>tbody>tr>th.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>tbody>tr.warning>td,.table>tfoot>tr.warning>td,.table>thead>tr.warning>th,.table>tbody>tr.warning>th,.table>tfoot>tr.warning>th{background-color:#fcf8e3}.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover,.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr.warning:hover>th{background-color:#faf2cc}.table>thead>tr>td.danger,.table>tbody>tr>td.danger,.table>tfoot>tr>td.danger,.table>thead>tr>th.danger,.table>tbody>tr>th.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>tbody>tr.danger>td,.table>tfoot>tr.danger>td,.table>thead>tr.danger>th,.table>tbody>tr.danger>th,.table>tfoot>tr.danger>th{background-color:#f2dede}.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover,.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr.danger:hover>th{background-color:#ebcccc}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:14.25px;overflow-y:hidden;overflow-x:auto;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #e8eced;-webkit-overflow-scrolling:touch}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>thead>tr>th,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tfoot>tr>td{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>thead>tr>th:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.table-responsive>.table-bordered>thead>tr>th:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>th,.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}}fieldset{padding:0;margin:0;border:0;min-width:0}legend{display:block;width:100%;padding:0;margin-bottom:19px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:bold}input[type="search"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type="radio"],input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;line-height:normal}input[type="file"]{display:block}input[type="range"]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.36;color:#555}.form-control{display:block;width:100%;height:33px;padding:6px 10px;font-size:14px;line-height:1.36;color:#555;background-color:#fff;background-image:none;border:1px solid #d1d5d6;border-radius:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,0.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#eee;opacity:1}textarea.form-control{height:auto}input[type="search"]{-webkit-appearance:none}input[type="date"],input[type="time"],input[type="datetime-local"],input[type="month"]{line-height:33px;line-height:1.36 \0}input[type="date"].input-sm,input[type="time"].input-sm,input[type="datetime-local"].input-sm,input[type="month"].input-sm{line-height:30px}input[type="date"].input-lg,input[type="time"].input-lg,input[type="datetime-local"].input-lg,input[type="month"].input-lg{line-height:46px}.form-group{margin-bottom:15px}.radio,.checkbox{position:relative;display:block;min-height:19px;margin-top:10px;margin-bottom:10px}.radio label,.checkbox label{padding-left:20px;margin-bottom:0;font-weight:normal;cursor:pointer}.radio input[type="radio"],.radio-inline input[type="radio"],.checkbox input[type="checkbox"],.checkbox-inline input[type="checkbox"]{position:absolute;margin-left:-20px;margin-top:4px \9}.radio+.radio,.checkbox+.checkbox{margin-top:-5px}.radio-inline,.checkbox-inline{display:inline-block;padding-left:20px;margin-bottom:0;vertical-align:middle;font-weight:normal;cursor:pointer}.radio-inline+.radio-inline,.checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px}input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"].disabled,input[type="checkbox"].disabled,fieldset[disabled] input[type="radio"],fieldset[disabled] input[type="checkbox"]{cursor:not-allowed}.radio-inline.disabled,.checkbox-inline.disabled,fieldset[disabled] .radio-inline,fieldset[disabled] .checkbox-inline{cursor:not-allowed}.radio.disabled label,.checkbox.disabled label,fieldset[disabled] .radio label,fieldset[disabled] .checkbox label{cursor:not-allowed}.form-control-static{padding-top:7px;padding-bottom:7px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-left:0;padding-right:0}.input-sm,.form-horizontal .form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:0}select.input-sm{height:30px;line-height:30px}textarea.input-sm,select[multiple].input-sm{height:auto}.input-lg,.form-horizontal .form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:0}select.input-lg{height:46px;line-height:46px}textarea.input-lg,select[multiple].input-lg{height:auto}.has-feedback{position:relative}.has-feedback .form-control{padding-right:41.25px}.form-control-feedback{position:absolute;top:24px;right:0;z-index:2;display:block;width:33px;height:33px;line-height:33px;text-align:center}.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .help-block,.has-success .control-label,.has-success .radio,.has-success .checkbox,.has-success .radio-inline,.has-success .checkbox-inline{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;border-color:#3c763d;background-color:#dff0d8}.has-success .form-control-feedback{color:#3c763d}.has-warning .help-block,.has-warning .control-label,.has-warning .radio,.has-warning .checkbox,.has-warning .radio-inline,.has-warning .checkbox-inline{color:#9e7328}.has-warning .form-control{border-color:#9e7328;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-warning .form-control:focus{border-color:#75551e;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d5a757;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d5a757}.has-warning .input-group-addon{color:#9e7328;border-color:#9e7328;background-color:#fcf8e3}.has-warning .form-control-feedback{color:#9e7328}.has-error .help-block,.has-error .control-label,.has-error .radio,.has-error .checkbox,.has-error .radio-inline,.has-error .checkbox-inline{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;border-color:#a94442;background-color:#f2dede}.has-error .form-control-feedback{color:#a94442}.has-feedback label.sr-only ~ .form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media(min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn,.form-inline .input-group .form-control{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .radio,.form-inline .checkbox{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .radio label,.form-inline .checkbox label{padding-left:0}.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .radio,.form-horizontal .checkbox,.form-horizontal .radio-inline,.form-horizontal .checkbox-inline{margin-top:0;margin-bottom:0;padding-top:7px}.form-horizontal .radio,.form-horizontal .checkbox{min-height:26px}.form-horizontal .form-group{margin-left:-8px;margin-right:-8px}@media(min-width:768px){.form-horizontal .control-label{text-align:right;margin-bottom:0;padding-top:7px}}.form-horizontal .has-feedback .form-control-feedback{top:0;right:8px}@media(min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:14.3px}}@media(min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px}}.btn{display:inline-block;margin-bottom:0;font-weight:normal;text-align:center;vertical-align:middle;cursor:pointer;background-image:none;border:1px solid transparent;white-space:nowrap;padding:6px 10px;font-size:14px;line-height:1.36;border-radius:0;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.btn:focus,.btn:active:focus,.btn.active:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:hover,.btn:focus{color:#333;text-decoration:none}.btn:active,.btn.active{outline:0;background-image:none;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;pointer-events:none;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none}.btn-default{color:#333;background-color:#e8eced;border-color:#e8eced}.btn-default:hover,.btn-default:focus,.btn-default:active,.btn-default.active,.open>.dropdown-toggle.btn-default{color:#333;background-color:#cbd4d7;border-color:#c6d0d2}.btn-default:active,.btn-default.active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default[disabled],fieldset[disabled] .btn-default,.btn-default.disabled:hover,.btn-default[disabled]:hover,fieldset[disabled] .btn-default:hover,.btn-default.disabled:focus,.btn-default[disabled]:focus,fieldset[disabled] .btn-default:focus,.btn-default.disabled:active,.btn-default[disabled]:active,fieldset[disabled] .btn-default:active,.btn-default.disabled.active,.btn-default[disabled].active,fieldset[disabled] .btn-default.active{background-color:#e8eced;border-color:#e8eced}.btn-default .badge{color:#e8eced;background-color:#333}.btn-primary{color:#fff;background-color:#5184b0;border-color:#5184b0}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#406a8e;border-color:#3d6587}.btn-primary:active,.btn-primary.active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary[disabled],fieldset[disabled] .btn-primary,.btn-primary.disabled:hover,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary:hover,.btn-primary.disabled:focus,.btn-primary[disabled]:focus,fieldset[disabled] .btn-primary:focus,.btn-primary.disabled:active,.btn-primary[disabled]:active,fieldset[disabled] .btn-primary:active,.btn-primary.disabled.active,.btn-primary[disabled].active,fieldset[disabled] .btn-primary.active{background-color:#5184b0;border-color:#5184b0}.btn-primary .badge{color:#5184b0;background-color:#fff}.btn-success{color:#fff;background-color:#87c956;border-color:#87c956}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#6db339;border-color:#68ab37}.btn-success:active,.btn-success.active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success[disabled],fieldset[disabled] .btn-success,.btn-success.disabled:hover,.btn-success[disabled]:hover,fieldset[disabled] .btn-success:hover,.btn-success.disabled:focus,.btn-success[disabled]:focus,fieldset[disabled] .btn-success:focus,.btn-success.disabled:active,.btn-success[disabled]:active,fieldset[disabled] .btn-success:active,.btn-success.disabled.active,.btn-success[disabled].active,fieldset[disabled] .btn-success.active{background-color:#87c956;border-color:#87c956}.btn-success .badge{color:#87c956;background-color:#fff}.btn-info{color:#fff;background-color:#cee6ed;border-color:#cee6ed}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#a9d3df;border-color:#a1cfdd}.btn-info:active,.btn-info.active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info[disabled],fieldset[disabled] .btn-info,.btn-info.disabled:hover,.btn-info[disabled]:hover,fieldset[disabled] .btn-info:hover,.btn-info.disabled:focus,.btn-info[disabled]:focus,fieldset[disabled] .btn-info:focus,.btn-info.disabled:active,.btn-info[disabled]:active,fieldset[disabled] .btn-info:active,.btn-info.disabled.active,.btn-info[disabled].active,fieldset[disabled] .btn-info.active{background-color:#cee6ed;border-color:#cee6ed}.btn-info .badge{color:#cee6ed;background-color:#fff}.btn-warning{color:#fff;background-color:#f59c0c;border-color:#f59c0c}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#c67d08;border-color:#bc7708}.btn-warning:active,.btn-warning.active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-warning,.btn-warning.disabled:hover,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning:hover,.btn-warning.disabled:focus,.btn-warning[disabled]:focus,fieldset[disabled] .btn-warning:focus,.btn-warning.disabled:active,.btn-warning[disabled]:active,fieldset[disabled] .btn-warning:active,.btn-warning.disabled.active,.btn-warning[disabled].active,fieldset[disabled] .btn-warning.active{background-color:#f59c0c;border-color:#f59c0c}.btn-warning .badge{color:#f59c0c;background-color:#fff}.btn-danger{color:#fff;background-color:#cf605d;border-color:#cf605d}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c03c39;border-color:#b83a37}.btn-danger:active,.btn-danger.active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger[disabled],fieldset[disabled] .btn-danger,.btn-danger.disabled:hover,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger:hover,.btn-danger.disabled:focus,.btn-danger[disabled]:focus,fieldset[disabled] .btn-danger:focus,.btn-danger.disabled:active,.btn-danger[disabled]:active,fieldset[disabled] .btn-danger:active,.btn-danger.disabled.active,.btn-danger[disabled].active,fieldset[disabled] .btn-danger.active{background-color:#cf605d;border-color:#cf605d}.btn-danger .badge{color:#cf605d;background-color:#fff}.btn-link{color:#5184b0;font-weight:normal;cursor:pointer;border-radius:0}.btn-link,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:hover,.btn-link:focus,.btn-link:active{border-color:transparent}.btn-link:hover,.btn-link:focus{color:#385d7c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,fieldset[disabled] .btn-link:hover,.btn-link[disabled]:focus,fieldset[disabled] .btn-link:focus{color:#999;text-decoration:none}.btn-lg,.btn-group-lg>.btn{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:0}.btn-sm,.btn-group-sm>.btn{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:0}.btn-xs,.btn-group-xs>.btn{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:0}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;-o-transition:height .35s ease;transition:height .35s ease}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px solid;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;font-size:14px;text-align:left;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);border-radius:0;-webkit-box-shadow:0 6px 12px rgba(0,0,0,0.175);box-shadow:0 6px 12px rgba(0,0,0,0.175);background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:8.5px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:1.36;color:#333;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{text-decoration:none;color:#262626;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;outline:0;background-color:#5184b0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);cursor:not-allowed}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{left:auto;right:0}.dropdown-menu-left{left:0;right:auto}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.36;color:#999;white-space:nowrap}.dropdown-backdrop{position:fixed;left:0;right:0;bottom:0;top:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}@media(min-width:768px){.navbar-right .dropdown-menu{left:auto;right:0}.navbar-right .dropdown-menu-left{left:0;right:auto}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;float:left}.btn-group>.btn:hover,.btn-group-vertical>.btn:hover,.btn-group>.btn:focus,.btn-group-vertical>.btn:focus,.btn-group>.btn:active,.btn-group-vertical>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn.active{z-index:2}.btn-group>.btn:focus,.btn-group-vertical>.btn:focus{outline:0}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child>.btn:last-child,.btn-group>.btn-group:first-child>.dropdown-toggle{border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn-group:last-child>.btn:first-child{border-bottom-left-radius:0;border-top-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-left:8px;padding-right:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-left:12px;padding-right:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-bottom-left-radius:0;border-top-right-radius:0;border-top-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-right-radius:0;border-top-left-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{float:none;display:table-cell;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle="buttons"]>.btn>input[type="radio"],[data-toggle="buttons"]>.btn>input[type="checkbox"]{position:absolute;z-index:-1;opacity:0;filter:alpha(opacity=0)}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*="col-"]{float:none;padding-left:0;padding-right:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:0}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn,select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:0}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn,select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn{height:auto}.input-group-addon,.input-group-btn,.input-group .form-control{display:table-cell}.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child),.input-group .form-control:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 10px;font-size:14px;font-weight:normal;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #d1d5d6;border-radius:0}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:0}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:0}.input-group-addon input[type="radio"],.input-group-addon input[type="checkbox"]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group-btn:last-child>.btn-group:not(:last-child)>.btn{border-bottom-right-radius:0;border-top-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:first-child>.btn-group:not(:first-child)>.btn{border-bottom-left-radius:0;border-top-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:hover,.input-group-btn>.btn:focus,.input-group-btn>.btn:active{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{margin-left:-1px}.nav{margin-bottom:0;padding-left:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#999}.nav>li.disabled>a:hover,.nav>li.disabled>a:focus{color:#999;text-decoration:none;background-color:transparent;cursor:not-allowed}.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{background-color:#eee;border-color:#5184b0}.nav .nav-divider{height:1px;margin:8.5px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #e8eced}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.36;border:1px solid transparent;border-radius:0}.nav-tabs>li>a:hover{border-color:#eee #eee #e8eced}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{color:#555;background-color:#fefefe;border:1px solid #e8eced;border-bottom-color:transparent;cursor:default}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{text-align:center;margin-bottom:5px}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media(min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border:1px solid #e8eced}@media(min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #e8eced;border-radius:0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border-bottom-color:#fefefe}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:0}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{color:#fff;background-color:#5184b0}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{text-align:center;margin-bottom:5px}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media(min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border:1px solid #e8eced}@media(min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #e8eced;border-radius:0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border-bottom-color:#fefefe}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-right-radius:0;border-top-left-radius:0}.navbar{position:relative;min-height:44px;margin-bottom:19px;border:1px solid transparent}@media(min-width:768px){.navbar{border-radius:0}}@media(min-width:768px){.navbar-header{float:left}}.navbar-collapse{overflow-x:visible;padding-right:8px;padding-left:8px;border-top:1px solid transparent;box-shadow:inset 0 1px 0 rgba(255,255,255,0.1);-webkit-overflow-scrolling:touch}.navbar-collapse.in{overflow-y:auto}@media(min-width:768px){.navbar-collapse{width:auto;border-top:0;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{padding-left:0;padding-right:0}}.navbar-fixed-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{max-height:none}@media(max-width:480px) and (orientation:landscape){.navbar-fixed-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{max-height:200px}}.container>.navbar-header,.container-fluid>.navbar-header,.container>.navbar-collapse,.container-fluid>.navbar-collapse{margin-right:-8px;margin-left:-8px}@media(min-width:768px){.container>.navbar-header,.container-fluid>.navbar-header,.container>.navbar-collapse,.container-fluid>.navbar-collapse{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media(min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}@media(min-width:768px){.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;padding:12.5px 8px;font-size:18px;line-height:19px;height:44px}.navbar-brand:hover,.navbar-brand:focus{text-decoration:none}@media(min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-8px}}.navbar-toggle{position:relative;float:right;margin-right:8px;padding:9px 10px;margin-top:5px;margin-bottom:5px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:0}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media(min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:6.25px -8px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:19px}@media(max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;box-shadow:none}.navbar-nav .open .dropdown-menu>li>a,.navbar-nav .open .dropdown-menu .dropdown-header{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:19px}.navbar-nav .open .dropdown-menu>li>a:hover,.navbar-nav .open .dropdown-menu>li>a:focus{background-image:none}}@media(min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:12.5px;padding-bottom:12.5px}.navbar-nav.navbar-right:last-child{margin-right:-8px}}@media(min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important}}.navbar-form{margin-left:-8px;margin-right:-8px;padding:10px 8px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);margin-top:5.5px;margin-bottom:5.5px}@media(min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn,.navbar-form .input-group .form-control{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .radio,.navbar-form .checkbox{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .radio label,.navbar-form .checkbox label{padding-left:0}.navbar-form .radio input[type="radio"],.navbar-form .checkbox input[type="checkbox"]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media(max-width:767px){.navbar-form .form-group{margin-bottom:5px}}@media(min-width:768px){.navbar-form{width:auto;border:0;margin-left:0;margin-right:0;padding-top:0;padding-bottom:0;-webkit-box-shadow:none;box-shadow:none}.navbar-form.navbar-right:last-child{margin-right:-8px}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-right-radius:0;border-top-left-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:5.5px;margin-bottom:5.5px}.navbar-btn.btn-sm{margin-top:7px;margin-bottom:7px}.navbar-btn.btn-xs{margin-top:11px;margin-bottom:11px}.navbar-text{margin-top:12.5px;margin-bottom:12.5px}@media(min-width:768px){.navbar-text{float:left;margin-left:8px;margin-right:8px}.navbar-text.navbar-right:last-child{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:hover,.navbar-default .navbar-brand:focus{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:hover,.navbar-default .navbar-nav>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:hover,.navbar-default .navbar-nav>.disabled>a:focus{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#e8eced}.navbar-default .navbar-toggle:hover,.navbar-default .navbar-toggle:focus{background-color:#e8eced}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:hover,.navbar-default .navbar-nav>.open>a:focus{background-color:#e7e7e7;color:#555}@media(max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:hover,.navbar-default .btn-link:focus{color:#333}.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:hover,.navbar-default .btn-link[disabled]:focus,fieldset[disabled] .navbar-default .btn-link:focus{color:#ccc}.navbar-inverse{background-color:#4a6492;border-color:transparent}.navbar-inverse .navbar-brand{color:#dfdfdf}.navbar-inverse .navbar-brand:hover,.navbar-inverse .navbar-brand:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#999}.navbar-inverse .navbar-nav>li>a{color:#dfdfdf}.navbar-inverse .navbar-nav>li>a:hover,.navbar-inverse .navbar-nav>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:hover,.navbar-inverse .navbar-nav>.active>a:focus{color:#fff;background-color:#394d70}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:hover,.navbar-inverse .navbar-nav>.disabled>a:focus{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:hover,.navbar-inverse .navbar-toggle:focus{background-color:#394d70}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#3e547a}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:hover,.navbar-inverse .navbar-nav>.open>a:focus{background-color:#394d70;color:#fff}@media(max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#dfdfdf}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus{color:#fff;background-color:#394d70}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#dfdfdf}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#dfdfdf}.navbar-inverse .btn-link:hover,.navbar-inverse .btn-link:focus{color:#fff}.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:hover,.navbar-inverse .btn-link[disabled]:focus,fieldset[disabled] .navbar-inverse .btn-link:focus{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:19px;list-style:none;background-color:#e8eced;border-radius:0}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{content:"/\00a0";padding:0 5px;color:#ccc}.breadcrumb>.active{color:#999}.pagination{display:inline-block;padding-left:0;margin:19px 0;border-radius:0}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 10px;line-height:1.36;text-decoration:none;color:#5184b0;background-color:#fff;border:1px solid #e8eced;margin-left:-1px}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-bottom-left-radius:0;border-top-left-radius:0}.pagination>li:last-child>a,.pagination>li:last-child>span{border-bottom-right-radius:0;border-top-right-radius:0}.pagination>li>a:hover,.pagination>li>span:hover,.pagination>li>a:focus,.pagination>li>span:focus{color:#385d7c;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>span,.pagination>.active>a:hover,.pagination>.active>span:hover,.pagination>.active>a:focus,.pagination>.active>span:focus{z-index:2;color:#fff;background-color:#5184b0;border-color:#5184b0;cursor:default}.pagination>.disabled>span,.pagination>.disabled>span:hover,.pagination>.disabled>span:focus,.pagination>.disabled>a,.pagination>.disabled>a:hover,.pagination>.disabled>a:focus{color:#999;background-color:#fff;border-color:#ddd;cursor:not-allowed}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-bottom-left-radius:0;border-top-left-radius:0}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-bottom-right-radius:0;border-top-right-radius:0}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-bottom-left-radius:0;border-top-left-radius:0}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-bottom-right-radius:0;border-top-right-radius:0}.pager{padding-left:0;margin:19px 0;list-style:none;text-align:center}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #e8eced;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#999;background-color:#fff;cursor:not-allowed}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:bold;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:hover,a.label:focus{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#999}.label-default[href]:hover,.label-default[href]:focus{background-color:#808080}.label-primary{background-color:#5184b0}.label-primary[href]:hover,.label-primary[href]:focus{background-color:#406a8e}.label-success{background-color:#87c956}.label-success[href]:hover,.label-success[href]:focus{background-color:#6db339}.label-info{background-color:#cee6ed}.label-info[href]:hover,.label-info[href]:focus{background-color:#a9d3df}.label-warning{background-color:#f59c0c}.label-warning[href]:hover,.label-warning[href]:focus{background-color:#c67d08}.label-danger{background-color:#cf605d}.label-danger[href]:hover,.label-danger[href]:focus{background-color:#c03c39}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:bold;color:#fff;line-height:1;vertical-align:baseline;white-space:nowrap;text-align:center;background-color:#999;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-xs .badge{top:0;padding:1px 5px}a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}a.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#5184b0;background-color:#fff}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding:30px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron h1,.jumbotron .h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron{border-radius:0}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron{padding-left:60px;padding-right:60px}.jumbotron h1,.jumbotron .h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:19px;line-height:1.36;background-color:#fefefe;border:1px solid #e8eced;border-radius:0;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.thumbnail>img,.thumbnail a>img{margin-left:auto;margin-right:auto}a.thumbnail:hover,a.thumbnail:focus,a.thumbnail.active{border-color:#5184b0}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:19px;border:1px solid transparent;border-radius:0}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:bold}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{background-color:#dff0d8;border-color:#d6e9c6;color:#3c763d}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{background-color:#cee6ed;border-color:#b4e1e3;color:#31708f}.alert-info hr{border-top-color:#a1d9dd}.alert-info .alert-link{color:#245269}.alert-warning{background-color:#fcf8e3;border-color:#faebcc;color:#9e7328}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#75551e}.alert-danger{background-color:#f2dede;border-color:#ebccd1;color:#a94442}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{overflow:hidden;height:19px;margin-bottom:19px;background-color:#e8eced;border-radius:0;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:19px;color:#fff;text-align:center;background-color:#5184b0;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-striped .progress-bar,.progress-bar-striped{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-size:40px 40px}.progress.active .progress-bar,.progress-bar.active{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar[aria-valuenow="1"],.progress-bar[aria-valuenow="2"]{min-width:30px}.progress-bar[aria-valuenow="0"]{color:#999;min-width:30px;background-color:transparent;background-image:none;box-shadow:none}.progress-bar-success{background-color:#87c956}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#cee6ed}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f59c0c}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#cf605d}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.media,.media-body{overflow:hidden;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media>.pull-left{margin-right:10px}.media>.pull-right{margin-left:10px}.media-list{padding-left:0;list-style:none}.list-group{margin-bottom:20px;padding-left:0}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #e8eced}.list-group-item:first-child{border-top-right-radius:0;border-top-left-radius:0}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:0;border-bottom-left-radius:0}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}a.list-group-item{color:#555}a.list-group-item .list-group-item-heading{color:#333}a.list-group-item:hover,a.list-group-item:focus{text-decoration:none;color:#555;background-color:#e8eced}.list-group-item.disabled,.list-group-item.disabled:hover,.list-group-item.disabled:focus{background-color:#eee;color:#999}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text{color:#999}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{z-index:2;color:#fff;background-color:#5184b0;border-color:#5184b0}.list-group-item.active .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>.small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:hover .list-group-item-text,.list-group-item.active:focus .list-group-item-text{color:#dde7f0}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:hover,a.list-group-item-success:focus{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:hover,a.list-group-item-success.active:focus{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#cee6ed}a.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:hover,a.list-group-item-info:focus{color:#31708f;background-color:#bbdce6}a.list-group-item-info.active,a.list-group-item-info.active:hover,a.list-group-item-info.active:focus{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#9e7328;background-color:#fcf8e3}a.list-group-item-warning{color:#9e7328}a.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:hover,a.list-group-item-warning:focus{color:#9e7328;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:hover,a.list-group-item-warning.active:focus{color:#fff;background-color:#9e7328;border-color:#9e7328}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:hover,a.list-group-item-danger:focus{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:hover,a.list-group-item-danger.active:focus{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:19px;background-color:#fff;border:1px solid transparent;border-radius:0;-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.05);box-shadow:0 1px 1px rgba(0,0,0,0.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-right-radius:-1;border-top-left-radius:-1}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#e8eced;border-top:1px solid #e8eced;border-bottom-right-radius:-1;border-bottom-left-radius:-1}.panel>.list-group{margin-bottom:0}.panel>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-right-radius:-1;border-top-left-radius:-1}.panel>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:-1;border-bottom-left-radius:-1}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.table,.panel>.table-responsive>.table,.panel>.panel-collapse>.table{margin-bottom:0}.panel>.table:first-child,.panel>.table-responsive:first-child>.table:first-child{border-top-right-radius:-1;border-top-left-radius:-1}.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child{border-top-left-radius:-1}.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child{border-top-right-radius:-1}.panel>.table:last-child,.panel>.table-responsive:last-child>.table:last-child{border-bottom-right-radius:-1;border-bottom-left-radius:-1}.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:-1}.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:-1}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive{border-top:1px solid #e8eced}.panel>.table>tbody:first-child>tr:first-child th,.panel>.table>tbody:first-child>tr:first-child td{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{border:0;margin-bottom:0}.panel-group{margin-bottom:19px}.panel-group .panel{margin-bottom:0;border-radius:0}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.panel-body{border-top:1px solid #e8eced}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #e8eced}.panel-default{border-color:#e8eced}.panel-default>.panel-heading{color:#333;background-color:#e8eced;border-color:#e8eced}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#e8eced}.panel-default>.panel-heading .badge{color:#e8eced;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#e8eced}.panel-primary{border-color:#5184b0}.panel-primary>.panel-heading{color:#fff;background-color:#5184b0;border-color:#5184b0}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#5184b0}.panel-primary>.panel-heading .badge{color:#5184b0;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#5184b0}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#b4e1e3}.panel-info>.panel-heading{color:#31708f;background-color:#cee6ed;border-color:#b4e1e3}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#b4e1e3}.panel-info>.panel-heading .badge{color:#cee6ed;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#b4e1e3}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#9e7328;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#9e7328}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive iframe,.embed-responsive embed,.embed-responsive object{position:absolute;top:0;left:0;bottom:0;height:100%;width:100%;border:0}.embed-responsive.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#e8eced;border:1px solid #d4dbdd;border-radius:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}.well-lg{padding:24px;border-radius:0}.well-sm{padding:9px;border-radius:0}.close{float:right;font-size:21px;font-weight:bold;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.5;filter:alpha(opacity=50)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}.modal{display:none;overflow:hidden;position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transform:translate3d(0,-25%,0);transform:translate3d(0,-25%,0);-webkit-transition:-webkit-transform .3s ease-out;-moz-transition:-moz-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out}.modal.in .modal-dialog{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.2);border-radius:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,0.5);box-shadow:0 3px 9px rgba(0,0,0,0.5);background-clip:padding-box;outline:0}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#dbdbdb}.modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.modal-backdrop.in{opacity:.5;filter:alpha(opacity=50)}.modal-header{padding:10px;border-bottom:1px solid #e5e5e5;min-height:11.36px}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.36}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-left:5px;margin-bottom:0}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media(min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,0.5);box-shadow:0 5px 15px rgba(0,0,0,0.5)}.modal-sm{width:300px}}@media(min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1600;display:block;visibility:visible;font-size:12px;line-height:1.4;opacity:0;filter:alpha(opacity=0)}.tooltip.in{opacity:.9;filter:alpha(opacity=90)}.tooltip.top{margin-top:-3px;padding:5px 0}.tooltip.right{margin-left:3px;padding:0 5px}.tooltip.bottom{margin-top:3px;padding:5px 0}.tooltip.left{margin-left:-3px;padding:0 5px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;border-radius:0}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{bottom:0;left:5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;right:5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;left:5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;right:5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1600;display:none;max-width:276px;padding:1px;text-align:left;background-color:#fff;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);border-radius:0;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);white-space:normal}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{margin:0;padding:8px 14px;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:-1 -1 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{border-width:10px;content:""}.popover.top>.arrow{left:50%;margin-left:-11px;border-bottom-width:0;border-top-color:#999;border-top-color:rgba(0,0,0,0.25);bottom:-11px}.popover.top>.arrow:after{content:" ";bottom:1px;margin-left:-10px;border-bottom-width:0;border-top-color:#fff}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-left-width:0;border-right-color:#999;border-right-color:rgba(0,0,0,0.25)}.popover.right>.arrow:after{content:" ";left:1px;bottom:-10px;border-left-width:0;border-right-color:#fff}.popover.bottom>.arrow{left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,0.25);top:-11px}.popover.bottom>.arrow:after{content:" ";top:1px;margin-left:-10px;border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,0.25)}.popover.left>.arrow:after{content:" ";right:1px;border-right-width:0;border-left-color:#fff;bottom:-10px}.carousel{position:relative}.carousel-inner{position:relative;overflow:hidden;width:100%}.carousel-inner>.item{display:none;position:relative;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{line-height:1}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;left:0;bottom:0;width:15%;opacity:.5;filter:alpha(opacity=50);font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6)}.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,0.5) 0,rgba(0,0,0,0.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,0.5) 0,rgba(0,0,0,0.0001) 100%);background-image:linear-gradient(to right,rgba(0,0,0,0.5) 0,rgba(0,0,0,0.0001) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000',endColorstr='#00000000',GradientType=1)}.carousel-control.right{left:auto;right:0;background-image:-webkit-linear-gradient(left,rgba(0,0,0,0.0001) 0,rgba(0,0,0,0.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,0.0001) 0,rgba(0,0,0,0.5) 100%);background-image:linear-gradient(to right,rgba(0,0,0,0.0001) 0,rgba(0,0,0,0.5) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000',endColorstr='#80000000',GradientType=1)}.carousel-control:hover,.carousel-control:focus{outline:0;color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-control .icon-prev,.carousel-control .icon-next,.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right{position:absolute;top:50%;z-index:5;display:inline-block}.carousel-control .icon-prev,.carousel-control .glyphicon-chevron-left{left:50%;margin-left:-10px}.carousel-control .icon-next,.carousel-control .glyphicon-chevron-right{right:50%;margin-right:-10px}.carousel-control .icon-prev,.carousel-control .icon-next{width:20px;height:20px;margin-top:-10px;font-family:serif}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;margin-left:-30%;padding-left:0;list-style:none;text-align:center}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;border:1px solid #fff;border-radius:10px;cursor:pointer;background-color:#000 \9;background-color:rgba(0,0,0,0)}.carousel-indicators .active{margin:0;width:12px;height:12px;background-color:#fff}.carousel-caption{position:absolute;left:15%;right:15%;bottom:20px;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-prev,.carousel-control .icon-next{width:30px;height:30px;margin-top:-15px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-15px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-15px}.carousel-caption{left:20%;right:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}@-ms-viewport{width:device-width}.visible-xs,.visible-sm,.visible-md,.visible-lg{display:none!important}.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block{display:none!important}@media(max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table}tr.visible-xs{display:table-row!important}th.visible-xs,td.visible-xs{display:table-cell!important}}@media(max-width:767px){.visible-xs-block{display:block!important}}@media(max-width:767px){.visible-xs-inline{display:inline!important}}@media(max-width:767px){.visible-xs-inline-block{display:inline-block!important}}@media(min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table}tr.visible-sm{display:table-row!important}th.visible-sm,td.visible-sm{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-sm-block{display:block!important}}@media(min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline!important}}@media(min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block!important}}@media(min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table}tr.visible-md{display:table-row!important}th.visible-md,td.visible-md{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-md-block{display:block!important}}@media(min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline!important}}@media(min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block!important}}@media(min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table}tr.visible-lg{display:table-row!important}th.visible-lg,td.visible-lg{display:table-cell!important}}@media(min-width:1200px){.visible-lg-block{display:block!important}}@media(min-width:1200px){.visible-lg-inline{display:inline!important}}@media(min-width:1200px){.visible-lg-inline-block{display:inline-block!important}}@media(max-width:767px){.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table}tr.visible-print{display:table-row!important}th.visible-print,td.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}}.btn{border-radius:0}.panel-heading{padding:6px 10px}.panel-body{padding:14px}.panel-body:before,.panel-body:after{content:" ";display:table}.panel-body:after{clear:both}.panel-body:before,.panel-body:after{content:" ";display:table}.panel-body:after{clear:both}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-bottom-left-radius:0;border-top-left-radius:0}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-bottom-right-radius:0;border-top-right-radius:0}.pagination-sm>li>a{line-height:1.5}.modal-header{padding:10px 14px;border-bottom:1px solid #e5e5e5;min-height:11.36px}.modal-footer{margin-top:10px;padding:15px 15px 15px}.table thead>tr>th{border-bottom:1px solid #e8eced;font-weight:normal}.form-group{margin-bottom:12px}.panel-group .panel+.panel{margin-top:4px}.alert{padding:5px 18px}label{margin-bottom:3px}.table{margin-bottom:10px}.page-header{margin:10px 0;border-bottom:0;padding-bottom:2px}.modal-header{background-color:#e8eced}div.list-expanded>ul>li>div.expanded-row>.cell{padding-left:6px;padding-right:3px;border-left:1px solid #e8eced}div.list-expanded>ul>li>div.expanded-row>.cell:first-child{padding-left:0;border-left:0}table.table>thead th a{color:#999}table.table>thead th{color:#999}.cell>label,.filter label{color:#999;font-weight:normal;margin-bottom:2px}.btn.active{box-shadow:none}.navbar-inverse{border-bottom-width:0!important}@media(min-width:1200px){.container{max-width:1366px}}body{padding-top:55px}.navbar-brand{padding:3px 8px}#global-search-input{width:165px;margin-top:1px}.progress.pre-loading{margin-top:-50px;margin-bottom:31px}.edit form{margin:0}.button-container{padding:0 0 10px}.margin{margin:8px 0}ul.dropdown-menu>li.checkbox{margin-left:20px}.page-header h3{margin-top:0;margin-bottom:8px}.list-buttons-container>div{float:left;margin-right:15px}.list-container .pagination{margin:0}.floated-row>div{float:left;margin-right:15px}.search-row{margin-left:-3px!important;margin-right:-3px!important}.search-row>div{padding-left:2px!important;padding-right:2px!important}.btn-icon>span{margin:0 20px}.field>.row{margin-left:-5px!important;margin-right:-5px!important}.field .row>div{padding-left:5px!important;padding-right:5px!important;float:left}.field .form-control,.field .btn{margin-bottom:3px}.field .input-group .form-control,.field .input-group .btn{margin-bottom:0}.field .input-group{margin-bottom:3px}.field .link-container{margin-bottom:-1px}.field .link-container .list-group-item>div{margin:-3px 0 -3px}.field .link-container .list-group-item>div>div{margin:6px 0}.field .link-container .list-group-item .form-control,.field .link-container .list-group-item .btn{margin-top:1px;margin-bottom:1px}.field .link-container .list-group-item .form-control{width:140px!important}.filter .field .link-container .list-group-item a{margin-top:1px}.field .link-container .list-group-item a{margin-top:1px}.field .link-container .list-group-item.link-with-role a{margin-top:6px}#login.panel>.panel-heading{background-color:#4a6492;padding:3px 10px}@media screen and (min-width:768px){.modal-dialog{width:740px!important}}@media screen and (min-width:1024px){.modal-dialog{width:900px!important}}@media screen and (max-width:768px){.navbar-fixed-top{position:static}body{padding-top:0}}.list-row-buttons span.caret{border-top-color:#999}.list>table{margin-bottom:0}.list>ul{margin-bottom:0}.list>table td input[type="checkbox"]{margin:0;position:relative;top:3px}.list>table th span.caret{border-top-color:#999}.list>table th span.caret-up{border-bottom-color:#999}.filter a.remove-filter{display:none}.filter:hover a.remove-filter{display:block}select[multiple].input-sm{height:90px!important}.input-group-btn>select.form-control{position:relative;display:inline-block;width:auto;vertical-align:middle;margin-right:-1px}.input-group-btn:last-child>select.form-control{margin-right:0;margin-left:-1px}.input-group .form-control:focus{z-index:3}.panel-body>.list-container>.list-expanded{margin-left:-15px;margin-right:-15px}.panel-body>.list-container>.list{margin-left:-15px;margin-right:-15px}.panel-body>.list-container>.list>table td:first-child,.panel-body>.list-container>.list>table th:first-child{padding-left:15px}.panel-body>.list-container>.list>table td:last-child,.panel-body>.list-container>.list>table th:last-child{padding-right:15px}.list-expanded>.show-more{padding:0;margin-top:-1px}.list-expanded>li.show-more>.btn{margin-left:-1px;margin-right:-4px}.list-expanded>ul>li .list-row-buttons{margin-right:-12px;margin-top:-10px}.show-more>.btn{border-radius:0;border-color:#e0e0e0}.panel-body>.list-container:first-child>.list-expanded:first-child{margin-top:-15px}.panel-body>.list-container:last-child>.list-expanded:last-child{margin-bottom:-15px}.panel-body>.list-container:first-child>.list:first-child{margin-top:-15px}.panel-body>.list-container:last-child>.list:last-child{margin-bottom:-15px}.expanded-row{white-space:nowrap;text-overflow:ellipsis;overflow:hidden}#notifications-panel .expanded-row{white-space:normal;overflow:hidden}#notifications-panel .right{padding-top:5px}.expanded-row .cell{display:inline-block}.caret-up{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-bottom:4px solid #000;border-right:4px solid transparent;border-top:0 dotted;border-left:4px solid transparent;content:""}.list>table{table-layout:fixed}.list>table td,table.list th{white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.list>table td.cell-buttons{overflow:visible}.panel.dashlet>.panel-heading>.menu-container{margin-top:-8px;right:-10px}.panel.dashlet>.panel-body{height:295px;overflow-y:auto;overflow-x:hidden}.panel.dashlet.double-height>.panel-body{height:642px}.panel-heading>.btn-group{top:-7px;right:-11px}.list-container+.button-container{margin-top:6px;padding-bottom:0}td.cell-buttons>.btn-group{margin-top:-8px;margin-bottom:-8px;margin-right:-10px}.list-expanded>li>.right>.btn-group{top:-7px;right:-11px}.panel{border-width:2px}.panel-heading>.btn-group>.btn{border-radius:0!important}.list>table thead>th{border-top-width:1px!important}.show-more>.btn-block{text-align:left;padding-left:15px}.autocomplete-suggestions{border:1px solid #999;background:#FFF;cursor:default;overflow:auto;-webkit-box-shadow:1px 4px 3px rgba(50,50,50,0.64);-moz-box-shadow:1px 4px 3px rgba(50,50,50,0.64);box-shadow:1px 4px 3px rgba(50,50,50,0.64)}.autocomplete-suggestion{padding:2px 5px;white-space:nowrap;overflow:hidden}.autocomplete-selected{background:#f0f0f0}.autocomplete-suggestions strong{font-weight:normal;color:#39f}.gray-box{background-color:#eee;margin:0 5px 3px 0;padding:3px 3px 3px 5px}.gray-box .preview{overflow:hidden;display:inline-block}.attachment-preview{display:inline-block;margin:3px 6px 3px 0}.field>.attachment-preview{display:block;overflow:hidden}.stick-sub{position:fixed;top:0;margin:44px 0 0;z-index:4}.stick-sub.button-container{background-color:#fefefe;padding:3px 3px 3px 0;width:100%}@media screen and (max-width:768px){.stick-sub{margin-top:0}}@font-face{font-family:Open Sans;src:url('../fonts/open-sans-regular.eot?') format('eot'),url('../fonts/open-sans-regular.woff') format('woff'),url('../fonts/open-sans-regular.ttf') format('truetype'),url('../fonts/open-sans-regular.svg#svgFontName') format('svg')}.badge-circle{width:8px;height:8px;border-radius:4px;display:table-cell;font-size:5px;line-height:8px;text-align:center;background-color:#e8eced}.badge-circle.badge-circle-danger{background-color:#cf605d}.badge-circle.badge-circle-warning{background-color:#f59c0c}.danger.glyphicon{color:#cf605d}.warning.glyphicon{color:#f59c0c}html,body{height:100%}body>.content{height:auto;min-height:100%;padding-bottom:35px}body>footer{clear:both;position:relative;height:26px;margin-top:-28px;background-color:#eee}body>footer>p{padding:6px 15px}body>footer>p.credit{margin:0}body>footer>p,body>footer>p a,body>footer>p a:hover,body>footer>p a:active,body>footer>p a:visited{color:#555}.navbar-collapse{overflow-x:hidden!important}#global-search-panel>.panel>.panel-body{max-height:294px;overflow-y:auto;overflow-x:hidden}#notifications-panel>.panel>.panel-body{max-height:294px;overflow-y:auto;overflow-x:hidden}@media screen and (max-width:768px){.list{width:auto;overflow-y:hidden;overflow-x:scroll}.list.list-expanded{width:auto;overflow-x:hidden}.list>table{min-width:768px}}.modal.in .modal.in{overflow:visible!important;overflow-y:visible!important}.record>.panel:first-child{margin-top:0}.record>.panel{margin-top:-21px}.detail .bottom>.panel-stream:first-child{margin-top:-21px}.stream-post-container,.stream-attachments-container{padding:5px 0}.link-container .list-group-item{padding:6px 10px}.note-editable blockquote{font-size:14px}.legend-container table td{padding:2px 2px;line-height:1em}.textcomplete-item a{cursor:default}.clearfix:before,.clearfix:after,.dl-horizontal dd:before,.dl-horizontal dd:after,.container:before,.container:after,.container-fluid:before,.container-fluid:after,.row:before,.row:after,.form-horizontal .form-group:before,.form-horizontal .form-group:after,.btn-toolbar:before,.btn-toolbar:after,.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after,.nav:before,.nav:after,.navbar:before,.navbar:after,.navbar-header:before,.navbar-header:after,.navbar-collapse:before,.navbar-collapse:after,.pager:before,.pager:after,.panel-body:before,.panel-body:after,.modal-footer:before,.modal-footer:after{content:" ";display:table}.clearfix:after,.dl-horizontal dd:after,.container:after,.container-fluid:after,.row:after,.form-horizontal .form-group:after,.btn-toolbar:after,.btn-group-vertical>.btn-group:after,.nav:after,.navbar:after,.navbar-header:after,.navbar-collapse:after,.pager:after,.panel-body:after,.modal-footer:after{clear:both}.center-block{display:block;margin-left:auto;margin-right:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important;visibility:hidden!important}.affix{position:fixed;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)} \ No newline at end of file diff --git a/frontend/client/css/select2-bootstrap.css b/frontend/client/css/select2-bootstrap.css new file mode 100644 index 0000000000..494d7c3cd9 --- /dev/null +++ b/frontend/client/css/select2-bootstrap.css @@ -0,0 +1,379 @@ + + +.select2-container-multi .select2-choices .select2-search-choice { + margin: 3px 2px 3px 5px +} + + +.select2-container.form-control { + background: transparent; + border: none; + display: block; + /* 1 */ + margin: 0; + padding: 0; +} + +div.select2-container { + width: 100%; +} + +.select2-container .select2-choices .select2-search-field input, +.select2-container .select2-choice, +.select2-container .select2-choices { + background: none; + padding: 0; + border-color: #cccccc; + border-radius: 0; + color: #555555; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + background-color: white; + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.select2-search input { + border-color: #cccccc; + border-radius: 0; + color: #555555; + + + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + background-color: white; + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.select2-container .select2-choices .select2-search-field input { + -webkit-box-shadow: none; + box-shadow: none; +} + + +.select2-container .select2-choice { + height: 34px; + line-height: 1.42857; +} + +.select2-container.select2-container-multi.form-control { + height: auto; +} + +.select2-container.input-sm .select2-choice, +.input-group-sm .select2-container .select2-choice { + height: 30px; + line-height: 1.5; + border-radius: 0px; +} + +.select2-container.input-lg .select2-choice, +.input-group-lg .select2-container .select2-choice { + height: 46px; + line-height: 1.33; + border-radius: 6px; +} + +.select2-container-multi .select2-choices .select2-search-field input { + height: 32px; +} + +.select2-container-multi.input-sm .select2-choices .select2-search-field input, +.input-group-sm .select2-container-multi .select2-choices .select2-search-field input { + height: 28px; +} + +.select2-container-multi.input-lg .select2-choices .select2-search-field input, +.input-group-lg .select2-container-multi .select2-choices .select2-search-field input { + height: 44px; +} + +.select2-container-multi .select2-choices .select2-search-field input { + margin: 0; +} + +.select2-chosen, +.select2-choice > span:first-child, +.select2-container .select2-choices .select2-search-field input { + padding: 6px 12px; +} + +.input-sm .select2-chosen, +.input-group-sm .select2-chosen, +.input-sm .select2-choice > span:first-child, +.input-group-sm .select2-choice > span:first-child, +.input-sm .select2-choices .select2-search-field input, +.input-group-sm .select2-choices .select2-search-field input { + padding: 5px 10px; +} + +.input-lg .select2-chosen, +.input-group-lg .select2-chosen, +.input-lg .select2-choice > span:first-child, +.input-group-lg .select2-choice > span:first-child, +.input-lg .select2-choices .select2-search-field input, +.input-group-lg .select2-choices .select2-search-field input { + padding: 10px 16px; +} + +.select2-container-multi .select2-choices .select2-search-choice { + margin-top: 5px; + margin-bottom: 3px; +} + +.select2-container-multi.input-sm .select2-choices .select2-search-choice, +.input-group-sm .select2-container-multi .select2-choices .select2-search-choice { + margin-top: 3px; + margin-bottom: 2px; +} + +.select2-container-multi.input-lg .select2-choices .select2-search-choice, +.input-group-lg .select2-container-multi .select2-choices .select2-search-choice { + line-height: 24px; +} + +.select2-container .select2-choice .select2-arrow, +.select2-container .select2-choice div { + border-left: 1px solid #cccccc; + background: none; + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} + +.select2-dropdown-open .select2-choice .select2-arrow, +.select2-dropdown-open .select2-choice div { + border-left-color: transparent; + background: none; + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} + +.select2-container .select2-choice .select2-arrow b, +.select2-container .select2-choice div b { + background-position: 0 3px; +} + +.select2-dropdown-open .select2-choice .select2-arrow b, +.select2-dropdown-open .select2-choice div b { + background-position: -18px 3px; +} + +.select2-container.input-sm .select2-choice .select2-arrow b, +.input-group-sm .select2-container .select2-choice .select2-arrow b, +.select2-container.input-sm .select2-choice div b, +.input-group-sm .select2-container .select2-choice div b { + background-position: 0 1px; +} + +.select2-dropdown-open.input-sm .select2-choice .select2-arrow b, +.input-group-sm .select2-dropdown-open .select2-choice .select2-arrow b, +.select2-dropdown-open.input-sm .select2-choice div b, +.input-group-sm .select2-dropdown-open .select2-choice div b { + background-position: -18px 1px; +} + +.select2-container.input-lg .select2-choice .select2-arrow b, +.input-group-lg .select2-container .select2-choice .select2-arrow b, +.select2-container.input-lg .select2-choice div b, +.input-group-lg .select2-container .select2-choice div b { + background-position: 0 9px; +} + +.select2-dropdown-open.input-lg .select2-choice .select2-arrow b, +.input-group-lg .select2-dropdown-open .select2-choice .select2-arrow b, +.select2-dropdown-open.input-lg .select2-choice div b, +.input-group-lg .select2-dropdown-open .select2-choice div b { + background-position: -18px 9px; +} + + +.has-warning .select2-choice, +.has-warning .select2-choices { + border-color: #8a6d3b; +} +.has-warning .select2-container-active .select2-choice, +.has-warning .select2-container-multi.select2-container-active .select2-choices { + border-color: #66512c; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b; +} +.has-warning.select2-drop-active { + border-color: #66512c; +} +.has-warning.select2-drop-active.select2-drop.select2-drop-above { + border-top-color: #66512c; +} + +.has-error .select2-choice, +.has-error .select2-choices { + border-color: #a94442; +} +.has-error .select2-container-active .select2-choice, +.has-error .select2-container-multi.select2-container-active .select2-choices { + border-color: #843534; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483; +} +.has-error.select2-drop-active { + border-color: #843534; +} +.has-error.select2-drop-active.select2-drop.select2-drop-above { + border-top-color: #843534; +} + +.has-success .select2-choice, +.has-success .select2-choices { + border-color: #3c763d; +} +.has-success .select2-container-active .select2-choice, +.has-success .select2-container-multi.select2-container-active .select2-choices { + border-color: #2b542c; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168; +} +.has-success.select2-drop-active { + border-color: #2b542c; +} +.has-success.select2-drop-active.select2-drop.select2-drop-above { + border-top-color: #2b542c; +} + +.select2-container-active .select2-choice, +.select2-container-multi.select2-container-active .select2-choices { + border-color: #66afe9; + outline: none; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + -webkit-transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s; + -o-transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s; + transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s; +} + +.select2-drop-active { + border-color: #66afe9; +} + +.select2-drop-auto-width, +.select2-drop.select2-drop-above.select2-drop-active { + border-top-color: #66afe9; +} + +.input-group.select2-bootstrap-prepend [class^="select2-choice"] { + border-bottom-left-radius: 0 !important; + border-top-left-radius: 0 !important; +} + +.input-group.select2-bootstrap-append [class^="select2-choice"] { + border-bottom-right-radius: 0 !important; + border-top-right-radius: 0 !important; +} + +.select2-dropdown-open [class^="select2-choice"] { + border-bottom-right-radius: 0 !important; + border-bottom-left-radius: 0 !important; +} + +.select2-dropdown-open.select2-drop-above [class^="select2-choice"] { + border-top-right-radius: 0 !important; + border-top-left-radius: 0 !important; + border-bottom-right-radius: 0px !important; + border-bottom-left-radius: 0px !important; +} +.input-group.select2-bootstrap-prepend .select2-dropdown-open.select2-drop-above [class^="select2-choice"] { + border-bottom-left-radius: 0 !important; + border-top-left-radius: 0 !important; +} +.input-group.select2-bootstrap-append .select2-dropdown-open.select2-drop-above [class^="select2-choice"] { + border-bottom-right-radius: 0 !important; + border-top-right-radius: 0 !important; +} +.input-group.input-group-sm.select2-bootstrap-prepend .select2-dropdown-open.select2-drop-above [class^="select2-choice"] { + border-bottom-right-radius: 3px !important; +} +.input-group.input-group-lg.select2-bootstrap-prepend .select2-dropdown-open.select2-drop-above [class^="select2-choice"] { + border-bottom-right-radius: 6px !important; +} +.input-group.input-group-sm.select2-bootstrap-append .select2-dropdown-open.select2-drop-above [class^="select2-choice"] { + border-bottom-left-radius: 3px !important; +} +.input-group.input-group-lg.select2-bootstrap-append .select2-dropdown-open.select2-drop-above [class^="select2-choice"] { + border-bottom-left-radius: 0px !important; +} + +.select2-results .select2-highlighted { + color: white; + background-color: #428bca; +} + +.select2-bootstrap-append .select2-container-multiple, +.select2-bootstrap-append .input-group-btn, +.select2-bootstrap-append .input-group-btn .btn, +.select2-bootstrap-prepend .select2-container-multiple, +.select2-bootstrap-prepend .input-group-btn, +.select2-bootstrap-prepend .input-group-btn .btn { + vertical-align: top; +} + +.select2-container-multi .select2-choices .select2-search-choice { + color: #555555; + background: #eee; + border-color: #cccccc; + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + -webkit-box-shadow: none; + box-shadow: none; +} + +.select2-container-multi .select2-choices .select2-search-choice-focus { + background: #ebebeb; + border-color: #adadad; + color: #333333; + -webkit-box-shadow: none; + box-shadow: none; +} + +.select2-search-choice-close { + margin-top: -7px; + top: 50%; +} + +.select2-container .select2-choice abbr { + top: 50%; +} + +.select2-results .select2-no-results, +.select2-results .select2-searching, +.select2-results .select2-selection-limit { + background-color: #fcf8e3; + color: #8a6d3b; +} + +.select2-container.select2-container-disabled .select2-choice, +.select2-container.select2-container-disabled .select2-choices { + cursor: not-allowed; + background-color: #eeeeee; + border-color: #cccccc; +} +.select2-container.select2-container-disabled .select2-choice .select2-arrow, +.select2-container.select2-container-disabled .select2-choice div, +.select2-container.select2-container-disabled .select2-choices .select2-arrow, +.select2-container.select2-container-disabled .select2-choices div { + background-color: transparent; + border-left: 1px solid transparent; + /* 2 */ +} + + +.select2-search input.select2-active, +.select2-container-multi .select2-choices .select2-search-field input.select2-active, +.select2-more-results.select2-active { + background-position: 99%; + /* 4 */ + background-position: right 4px center; + /* 5 */ +} + +.select2-offscreen, +.select2-offscreen:focus { + width: 1px !important; + height: 1px !important; + position: absolute !important; +} diff --git a/frontend/client/css/select2.css b/frontend/client/css/select2.css new file mode 100644 index 0000000000..770694c9f6 --- /dev/null +++ b/frontend/client/css/select2.css @@ -0,0 +1,698 @@ +/* +Version: 3.5.1 Timestamp: Tue Jul 22 18:58:56 EDT 2014 +*/ +.select2-container { + margin: 0; + position: relative; + display: inline-block; + /* inline-block for ie7 */ + zoom: 1; + *display: inline; + vertical-align: middle; +} + +.select2-container, +.select2-drop, +.select2-search, +.select2-search input { + /* + Force border-box so that % widths fit the parent + container without overlap because of margin/padding. + More Info : http://www.quirksmode.org/css/box.html + */ + -webkit-box-sizing: border-box; /* webkit */ + -moz-box-sizing: border-box; /* firefox */ + box-sizing: border-box; /* css3 */ +} + +.select2-container .select2-choice { + display: block; + height: 26px; + padding: 0 0 0 8px; + overflow: hidden; + position: relative; + + border: 1px solid #d1d5d6; + white-space: nowrap; + line-height: 26px; + color: #444; + text-decoration: none; + + border-radius: 0px; + + background-clip: padding-box; + + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + + background-color: #fff; + background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(0.5, #fff)); + background-image: -webkit-linear-gradient(center bottom, #eee 0%, #fff 50%); + background-image: -moz-linear-gradient(center bottom, #eee 0%, #fff 50%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr = '#ffffff', endColorstr = '#eeeeee', GradientType = 0); + background-image: linear-gradient(to top, #eee 0%, #fff 50%); +} + +html[dir="rtl"] .select2-container .select2-choice { + padding: 0 8px 0 0; +} + +.select2-container.select2-drop-above .select2-choice { + border-bottom-color: #d1d5d6; + + border-radius: 0 0 0px 0px; + + background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(0.9, #fff)); + background-image: -webkit-linear-gradient(center bottom, #eee 0%, #fff 90%); + background-image: -moz-linear-gradient(center bottom, #eee 0%, #fff 90%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0); + background-image: linear-gradient(to bottom, #eee 0%, #fff 90%); +} + +.select2-container.select2-allowclear .select2-choice .select2-chosen { + margin-right: 42px; +} + +.select2-container .select2-choice > .select2-chosen { + margin-right: 26px; + display: block; + overflow: hidden; + + white-space: nowrap; + + text-overflow: ellipsis; + float: none; + width: auto; +} + +html[dir="rtl"] .select2-container .select2-choice > .select2-chosen { + margin-left: 26px; + margin-right: 0; +} + +.select2-container .select2-choice abbr { + display: none; + width: 12px; + height: 12px; + position: absolute; + right: 24px; + top: 8px; + + font-size: 1px; + text-decoration: none; + + border: 0; + background: url('../img/select2.png') right top no-repeat; + cursor: pointer; + outline: 0; +} + +.select2-container.select2-allowclear .select2-choice abbr { + display: inline-block; +} + +.select2-container .select2-choice abbr:hover { + background-position: right -11px; + cursor: pointer; +} + +.select2-drop-mask { + border: 0; + margin: 0; + padding: 0; + position: fixed; + left: 0; + top: 0; + min-height: 100%; + min-width: 100%; + height: auto; + width: auto; + opacity: 0; + z-index: 9998; + /* styles required for IE to work */ + background-color: #fff; + filter: alpha(opacity=0); +} + +.select2-drop { + width: 100%; + margin-top: -1px; + position: absolute; + z-index: 9999; + top: 100%; + + background: #fff; + color: #000; + border: 1px solid #d1d5d6; + border-top: 0; + + border-radius: 0 0 0px 0px; + + +} + +.select2-drop.select2-drop-above { + margin-top: 1px; + border-top: 1px solid #d1d5d6; + border-bottom: 0; + + border-radius: 0px 0px 0 0; + + +} + +.select2-drop-active { + border: 1px solid ; + border-top: none; +} + +.select2-drop.select2-drop-above.select2-drop-active { + border-top: 1px solid ; +} + +.select2-drop-auto-width { + border-top: 1px solid #d1d5d6; + width: auto; +} + +.select2-drop-auto-width .select2-search { + padding-top: 4px; +} + +.select2-container .select2-choice .select2-arrow { + display: inline-block; + width: 18px; + height: 100%; + position: absolute; + right: 0; + top: 0; + + border-left: 1px solid #d1d5d6; + border-radius: 0 4px 4px 0; + + background-clip: padding-box; + + background: #ccc; + background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #ccc), color-stop(0.6, #eee)); + background-image: -webkit-linear-gradient(center bottom, #ccc 0%, #eee 60%); + background-image: -moz-linear-gradient(center bottom, #ccc 0%, #eee 60%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr = '#eeeeee', endColorstr = '#cccccc', GradientType = 0); + background-image: linear-gradient(to top, #ccc 0%, #eee 60%); +} + +html[dir="rtl"] .select2-container .select2-choice .select2-arrow { + left: 0; + right: auto; + + border-left: none; + border-right: 1px solid #d1d5d6; + border-radius: 4px 0 0 4px; +} + +.select2-container .select2-choice .select2-arrow b { + display: block; + width: 100%; + height: 100%; + background: url('../img/select2.png') no-repeat 0 1px; +} + +html[dir="rtl"] .select2-container .select2-choice .select2-arrow b { + background-position: 2px 1px; +} + +.select2-search { + display: inline-block; + width: 100%; + min-height: 26px; + margin: 0; + padding-left: 4px; + padding-right: 4px; + + position: relative; + z-index: 10000; + + white-space: nowrap; +} + +.select2-search input { + width: 100%; + height: auto !important; + min-height: 26px; + padding: 4px 20px 4px 5px; + margin: 0; + + outline: 0; + font-family: sans-serif; + font-size: 1em; + + border: 1px solid #d1d5d6; + border-radius: 0; + + -webkit-box-shadow: none; + box-shadow: none; + + background: #fff url('../img/select2.png') no-repeat 100% -22px; + background: url('../img/select2.png') no-repeat 100% -22px, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, #fff), color-stop(0.99, #eee)); + background: url('../img/select2.png') no-repeat 100% -22px, -webkit-linear-gradient(center bottom, #fff 85%, #eee 99%); + background: url('../img/select2.png') no-repeat 100% -22px, -moz-linear-gradient(center bottom, #fff 85%, #eee 99%); + background: url('../img/select2.png') no-repeat 100% -22px, linear-gradient(to bottom, #fff 85%, #eee 99%) 0 0; +} + +html[dir="rtl"] .select2-search input { + padding: 4px 5px 4px 20px; + + background: #fff url('../img/select2.png') no-repeat -37px -22px; + background: url('../img/select2.png') no-repeat -37px -22px, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, #fff), color-stop(0.99, #eee)); + background: url('../img/select2.png') no-repeat -37px -22px, -webkit-linear-gradient(center bottom, #fff 85%, #eee 99%); + background: url('../img/select2.png') no-repeat -37px -22px, -moz-linear-gradient(center bottom, #fff 85%, #eee 99%); + background: url('../img/select2.png') no-repeat -37px -22px, linear-gradient(to bottom, #fff 85%, #eee 99%) 0 0; +} + +.select2-drop.select2-drop-above .select2-search input { + margin-top: 4px; +} + +.select2-search input.select2-active { + background: #fff no-repeat 100%; +} + +.select2-container-active .select2-choice, +.select2-container-active .select2-choices { + border: 1px solid ; + outline: none; + + -webkit-box-shadow: 0 0 5px rgba(0, 0, 0, .3); + box-shadow: 0 0 5px rgba(0, 0, 0, .3); +} + +.select2-dropdown-open .select2-choice { + border-bottom-color: transparent; + -webkit-box-shadow: 0 1px 0 #fff inset; + box-shadow: 0 1px 0 #fff inset; + + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + + background-color: #eee; + background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #fff), color-stop(0.5, #eee)); + background-image: -webkit-linear-gradient(center bottom, #fff 0%, #eee 50%); + background-image: -moz-linear-gradient(center bottom, #fff 0%, #eee 50%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#ffffff', GradientType=0); + background-image: linear-gradient(to top, #fff 0%, #eee 50%); +} + +.select2-dropdown-open.select2-drop-above .select2-choice, +.select2-dropdown-open.select2-drop-above .select2-choices { + border: 1px solid ; + border-top-color: transparent; + + background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #fff), color-stop(0.5, #eee)); + background-image: -webkit-linear-gradient(center top, #fff 0%, #eee 50%); + background-image: -moz-linear-gradient(center top, #fff 0%, #eee 50%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#ffffff', GradientType=0); + background-image: linear-gradient(to bottom, #fff 0%, #eee 50%); +} + +.select2-dropdown-open .select2-choice .select2-arrow { + background: transparent; + border-left: none; + filter: none; +} +html[dir="rtl"] .select2-dropdown-open .select2-choice .select2-arrow { + border-right: none; +} + +.select2-dropdown-open .select2-choice .select2-arrow b { + background-position: -18px 1px; +} + +html[dir="rtl"] .select2-dropdown-open .select2-choice .select2-arrow b { + background-position: -16px 1px; +} + +.select2-hidden-accessible { + border: 0; + clip: rect(0 0 0 0); + height: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; +} + +/* results */ +.select2-results { + max-height: 200px; + padding: 0 0 0 4px; + margin: 4px 4px 4px 0; + position: relative; + overflow-x: hidden; + overflow-y: auto; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} + +html[dir="rtl"] .select2-results { + padding: 0 4px 0 0; + margin: 4px 0 4px 4px; +} + +.select2-results ul.select2-result-sub { + margin: 0; + padding-left: 0; +} + +.select2-results li { + list-style: none; + display: list-item; + background-image: none; +} + +.select2-results li.select2-result-with-children > .select2-result-label { + font-weight: bold; +} + +.select2-results .select2-result-label { + padding: 3px 7px 4px; + margin: 0; + cursor: pointer; + + min-height: 1em; + + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.select2-results-dept-1 .select2-result-label { padding-left: 20px } +.select2-results-dept-2 .select2-result-label { padding-left: 40px } +.select2-results-dept-3 .select2-result-label { padding-left: 60px } +.select2-results-dept-4 .select2-result-label { padding-left: 80px } +.select2-results-dept-5 .select2-result-label { padding-left: 100px } +.select2-results-dept-6 .select2-result-label { padding-left: 110px } +.select2-results-dept-7 .select2-result-label { padding-left: 120px } + +.select2-results .select2-highlighted { + background: #3875d7; + color: #fff; +} + +.select2-results li em { + background: #feffde; + font-style: normal; +} + +.select2-results .select2-highlighted em { + background: transparent; +} + +.select2-results .select2-highlighted ul { + background: #fff; + color: #000; +} + +.select2-results .select2-no-results, +.select2-results .select2-searching, +.select2-results .select2-ajax-error, +.select2-results .select2-selection-limit { + background: #f4f4f4; + display: list-item; + padding-left: 5px; +} + +/* +disabled look for disabled choices in the results dropdown +*/ +.select2-results .select2-disabled.select2-highlighted { + color: #666; + background: #f4f4f4; + display: list-item; + cursor: default; +} +.select2-results .select2-disabled { + background: #f4f4f4; + display: list-item; + cursor: default; +} + +.select2-results .select2-selected { + display: none; +} + +.select2-more-results.select2-active { + background: #f4f4f4 no-repeat 100%; +} + +.select2-results .select2-ajax-error { + background: rgba(255, 50, 50, .2); +} + +.select2-more-results { + background: #f4f4f4; + display: list-item; +} + +/* disabled styles */ + +.select2-container.select2-container-disabled .select2-choice { + background-color: #f4f4f4; + background-image: none; + border: 1px solid #ddd; + cursor: default; +} + +.select2-container.select2-container-disabled .select2-choice .select2-arrow { + background-color: #f4f4f4; + background-image: none; + border-left: 0; +} + +.select2-container.select2-container-disabled .select2-choice abbr { + display: none; +} + + +/* multiselect */ + +.select2-container-multi .select2-choices { + height: auto !important; + height: 1%; + margin: 0; + padding: 0 5px 0 0; + position: relative; + + border: 1px solid #d1d5d6; + cursor: text; + overflow: hidden; + + background-color: #fff; + background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(1%, #eee), color-stop(15%, #fff)); + background-image: -webkit-linear-gradient(top, #eee 1%, #fff 15%); + background-image: -moz-linear-gradient(top, #eee 1%, #fff 15%); + background-image: linear-gradient(to bottom, #eee 1%, #fff 15%); +} + +html[dir="rtl"] .select2-container-multi .select2-choices { + padding: 0 0 0 5px; +} + +.select2-locked { + padding: 3px 5px 3px 5px !important; +} + +.select2-container-multi .select2-choices { + min-height: 26px; +} + +.select2-container-multi.select2-container-active .select2-choices { + border: 1px solid ; + outline: none; + + -webkit-box-shadow: 0 0 5px rgba(0, 0, 0, .3); + box-shadow: 0 0 5px rgba(0, 0, 0, .3); +} +.select2-container-multi .select2-choices li { + float: left; + list-style: none; +} +html[dir="rtl"] .select2-container-multi .select2-choices li +{ + float: right; +} +.select2-container-multi .select2-choices .select2-search-field { + margin: 0; + padding: 0; + white-space: nowrap; +} + +.select2-container-multi .select2-choices .select2-search-field input { + padding: 5px; + margin: 1px 0; + + font-family: sans-serif; + font-size: 100%; + color: #666; + outline: 0; + border: 0; + -webkit-box-shadow: none; + box-shadow: none; + background: transparent !important; +} + +.select2-container-multi .select2-choices .select2-search-field input.select2-active { + background: #fff no-repeat 100% !important; +} + +.select2-default { + color: #999 !important; +} + +.select2-container-multi .select2-choices .select2-search-choice { + padding: 3px 5px 3px 18px; + margin: 3px 0 3px 5px; + position: relative; + + line-height: 13px; + color: #333; + cursor: default; + border: 1px solid #d1d5d6; + + border-radius: 3px; + + -webkit-box-shadow: 0 0 2px #fff inset, 0 1px 0 rgba(0, 0, 0, 0.05); + box-shadow: 0 0 2px #fff inset, 0 1px 0 rgba(0, 0, 0, 0.05); + + background-clip: padding-box; + + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + + background-color: #e4e4e4; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#f4f4f4', GradientType=0); + background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(20%, #f4f4f4), color-stop(50%, #f0f0f0), color-stop(52%, #e8e8e8), color-stop(100%, #eee)); + background-image: -webkit-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eee 100%); + background-image: -moz-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eee 100%); + background-image: linear-gradient(to top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eee 100%); +} +html[dir="rtl"] .select2-container-multi .select2-choices .select2-search-choice +{ + margin: 3px 5px 3px 0; + padding: 3px 18px 3px 5px; +} +.select2-container-multi .select2-choices .select2-search-choice .select2-chosen { + cursor: default; +} +.select2-container-multi .select2-choices .select2-search-choice-focus { + background: #d4d4d4; +} + +.select2-search-choice-close { + display: block; + width: 12px; + height: 13px; + position: absolute; + right: 3px; + top: 4px; + + font-size: 1px; + outline: none; + background: url('../img/select2.png') right top no-repeat; +} +html[dir="rtl"] .select2-search-choice-close { + right: auto; + left: 3px; +} + +.select2-container-multi .select2-search-choice-close { + left: 3px; +} + +html[dir="rtl"] .select2-container-multi .select2-search-choice-close { + left: auto; + right: 2px; +} + +.select2-container-multi .select2-choices .select2-search-choice .select2-search-choice-close:hover { + background-position: right -11px; +} +.select2-container-multi .select2-choices .select2-search-choice-focus .select2-search-choice-close { + background-position: right -11px; +} + +/* disabled styles */ +.select2-container-multi.select2-container-disabled .select2-choices { + background-color: #f4f4f4; + background-image: none; + border: 1px solid #ddd; + cursor: default; +} + +.select2-container-multi.select2-container-disabled .select2-choices .select2-search-choice { + padding: 3px 5px 3px 5px; + border: 1px solid #ddd; + background-image: none; + background-color: #f4f4f4; +} + +.select2-container-multi.select2-container-disabled .select2-choices .select2-search-choice .select2-search-choice-close { display: none; + background: none; +} +/* end multiselect */ + + +.select2-result-selectable .select2-match, +.select2-result-unselectable .select2-match { + text-decoration: underline; +} + +.select2-offscreen, .select2-offscreen:focus { + clip: rect(0 0 0 0) !important; + width: 1px !important; + height: 1px !important; + border: 0 !important; + margin: 0 !important; + padding: 0 !important; + overflow: hidden !important; + position: absolute !important; + outline: 0 !important; + left: 0px !important; + top: 0px !important; +} + +.select2-display-none { + display: none; +} + +.select2-measure-scrollbar { + position: absolute; + top: -10000px; + left: -10000px; + width: 100px; + height: 100px; + overflow: scroll; +} + +/* Retina-ize icons */ + +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-resolution: 2dppx) { + .select2-search input, + .select2-search-choice-close, + .select2-container .select2-choice abbr, + .select2-container .select2-choice .select2-arrow b { + background-image: url('select2x2.png') !important; + background-repeat: no-repeat !important; + background-size: 60px 40px !important; + } + + .select2-search input { + background-position: 100% -21px !important; + } +} diff --git a/frontend/client/img/select2.png b/frontend/client/img/select2.png new file mode 100644 index 0000000000..1d804ffb99 Binary files /dev/null and b/frontend/client/img/select2.png differ diff --git a/frontend/client/lib/select2.min.js b/frontend/client/lib/select2.min.js new file mode 100644 index 0000000000..1d3ee49f34 --- /dev/null +++ b/frontend/client/lib/select2.min.js @@ -0,0 +1,23 @@ +/* +Copyright 2014 Igor Vaynberg + +Version: 3.5.1 Timestamp: Tue Jul 22 18:58:56 EDT 2014 + +This software is licensed under the Apache License, Version 2.0 (the "Apache License") or the GNU +General Public License version 2 (the "GPL License"). You may choose either license to govern your +use of this software only upon the condition that you accept all of the terms of either the Apache +License or the GPL License. + +You may obtain a copy of the Apache License and the GPL License at: + +http://www.apache.org/licenses/LICENSE-2.0 +http://www.gnu.org/licenses/gpl-2.0.html + +Unless required by applicable law or agreed to in writing, software distributed under the Apache License +or the GPL Licesnse is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +either express or implied. See the Apache License and the GPL License for the specific language governing +permissions and limitations under the Apache License and the GPL License. +*/ +!function(a){"undefined"==typeof a.fn.each2&&a.extend(a.fn,{each2:function(b){for(var c=a([0]),d=-1,e=this.length;++dc;c+=1)if(r(a,b[c]))return c;return-1}function q(){var b=a(l);b.appendTo("body");var c={width:b.width()-b[0].clientWidth,height:b.height()-b[0].clientHeight};return b.remove(),c}function r(a,c){return a===c?!0:a===b||c===b?!1:null===a||null===c?!1:a.constructor===String?a+""==c+"":c.constructor===String?c+""==a+"":!1}function s(b,c){var d,e,f;if(null===b||b.length<1)return[];for(d=b.split(c),e=0,f=d.length;f>e;e+=1)d[e]=a.trim(d[e]);return d}function t(a){return a.outerWidth(!1)-a.width()}function u(c){var d="keyup-change-value";c.on("keydown",function(){a.data(c,d)===b&&a.data(c,d,c.val())}),c.on("keyup",function(){var e=a.data(c,d);e!==b&&c.val()!==e&&(a.removeData(c,d),c.trigger("keyup-change"))})}function v(c){c.on("mousemove",function(c){var d=i;(d===b||d.x!==c.pageX||d.y!==c.pageY)&&a(c.target).trigger("mousemove-filtered",c)})}function w(a,c,d){d=d||b;var e;return function(){var b=arguments;window.clearTimeout(e),e=window.setTimeout(function(){c.apply(d,b)},a)}}function x(a,b){var c=w(a,function(a){b.trigger("scroll-debounced",a)});b.on("scroll",function(a){p(a.target,b.get())>=0&&c(a)})}function y(a){a[0]!==document.activeElement&&window.setTimeout(function(){var d,b=a[0],c=a.val().length;a.focus();var e=b.offsetWidth>0||b.offsetHeight>0;e&&b===document.activeElement&&(b.setSelectionRange?b.setSelectionRange(c,c):b.createTextRange&&(d=b.createTextRange(),d.collapse(!1),d.select()))},0)}function z(b){b=a(b)[0];var c=0,d=0;if("selectionStart"in b)c=b.selectionStart,d=b.selectionEnd-c;else if("selection"in document){b.focus();var e=document.selection.createRange();d=document.selection.createRange().text.length,e.moveStart("character",-b.value.length),c=e.text.length-d}return{offset:c,length:d}}function A(a){a.preventDefault(),a.stopPropagation()}function B(a){a.preventDefault(),a.stopImmediatePropagation()}function C(b){if(!h){var c=b[0].currentStyle||window.getComputedStyle(b[0],null);h=a(document.createElement("div")).css({position:"absolute",left:"-10000px",top:"-10000px",display:"none",fontSize:c.fontSize,fontFamily:c.fontFamily,fontStyle:c.fontStyle,fontWeight:c.fontWeight,letterSpacing:c.letterSpacing,textTransform:c.textTransform,whiteSpace:"nowrap"}),h.attr("class","select2-sizer"),a("body").append(h)}return h.text(b.val()),h.width()}function D(b,c,d){var e,g,f=[];e=a.trim(b.attr("class")),e&&(e=""+e,a(e.split(/\s+/)).each2(function(){0===this.indexOf("select2-")&&f.push(this)})),e=a.trim(c.attr("class")),e&&(e=""+e,a(e.split(/\s+/)).each2(function(){0!==this.indexOf("select2-")&&(g=d(this),g&&f.push(g))})),b.attr("class",f.join(" "))}function E(a,b,c,d){var e=o(a.toUpperCase()).indexOf(o(b.toUpperCase())),f=b.length;return 0>e?(c.push(d(a)),void 0):(c.push(d(a.substring(0,e))),c.push(""),c.push(d(a.substring(e,e+f))),c.push(""),c.push(d(a.substring(e+f,a.length))),void 0)}function F(a){var b={"\\":"\","&":"&","<":"<",">":">",'"':""","'":"'","/":"/"};return String(a).replace(/[&<>"'\/\\]/g,function(a){return b[a]})}function G(c){var d,e=null,f=c.quietMillis||100,g=c.url,h=this;return function(i){window.clearTimeout(d),d=window.setTimeout(function(){var d=c.data,f=g,j=c.transport||a.fn.select2.ajaxDefaults.transport,k={type:c.type||"GET",cache:c.cache||!1,jsonpCallback:c.jsonpCallback||b,dataType:c.dataType||"json"},l=a.extend({},a.fn.select2.ajaxDefaults.params,k);d=d?d.call(h,i.term,i.page,i.context):null,f="function"==typeof f?f.call(h,i.term,i.page,i.context):f,e&&"function"==typeof e.abort&&e.abort(),c.params&&(a.isFunction(c.params)?a.extend(l,c.params.call(h)):a.extend(l,c.params)),a.extend(l,{url:f,dataType:c.dataType,data:d,success:function(a){var b=c.results(a,i.page,i);i.callback(b)},error:function(a,b,c){var d={hasError:!0,jqXHR:a,textStatus:b,errorThrown:c};i.callback(d)}}),e=j.call(h,l)},f)}}function H(b){var d,e,c=b,f=function(a){return""+a.text};a.isArray(c)&&(e=c,c={results:e}),a.isFunction(c)===!1&&(e=c,c=function(){return e});var g=c();return g.text&&(f=g.text,a.isFunction(f)||(d=g.text,f=function(a){return a[d]})),function(b){var g,d=b.term,e={results:[]};return""===d?(b.callback(c()),void 0):(g=function(c,e){var h,i;if(c=c[0],c.children){h={};for(i in c)c.hasOwnProperty(i)&&(h[i]=c[i]);h.children=[],a(c.children).each2(function(a,b){g(b,h.children)}),(h.children.length||b.matcher(d,f(h),c))&&e.push(h)}else b.matcher(d,f(c),c)&&e.push(c)},a(c().results).each2(function(a,b){g(b,e.results)}),b.callback(e),void 0)}}function I(c){var d=a.isFunction(c);return function(e){var f=e.term,g={results:[]},h=d?c(e):c;a.isArray(h)&&(a(h).each(function(){var a=this.text!==b,c=a?this.text:this;(""===f||e.matcher(f,c))&&g.results.push(a?this:{id:this,text:this})}),e.callback(g))}}function J(b,c){if(a.isFunction(b))return!0;if(!b)return!1;if("string"==typeof b)return!0;throw new Error(c+" must be a string, function, or falsy value")}function K(b,c){if(a.isFunction(b)){var d=Array.prototype.slice.call(arguments,2);return b.apply(c,d)}return b}function L(b){var c=0;return a.each(b,function(a,b){b.children?c+=L(b.children):c++}),c}function M(a,c,d,e){var h,i,j,k,l,f=a,g=!1;if(!e.createSearchChoice||!e.tokenSeparators||e.tokenSeparators.length<1)return b;for(;;){for(i=-1,j=0,k=e.tokenSeparators.length;k>j&&(l=e.tokenSeparators[j],i=a.indexOf(l),!(i>=0));j++);if(0>i)break;if(h=a.substring(0,i),a=a.substring(i+l.length),h.length>0&&(h=e.createSearchChoice.call(this,h,c),h!==b&&null!==h&&e.id(h)!==b&&null!==e.id(h))){for(g=!1,j=0,k=c.length;k>j;j++)if(r(e.id(h),e.id(c[j]))){g=!0;break}g||d(h)}}return f!==a?a:void 0}function N(){var b=this;a.each(arguments,function(a,c){b[c].remove(),b[c]=null})}function O(b,c){var d=function(){};return d.prototype=new b,d.prototype.constructor=d,d.prototype.parent=b.prototype,d.prototype=a.extend(d.prototype,c),d}if(window.Select2===b){var c,d,e,f,g,h,j,k,i={x:0,y:0},c={TAB:9,ENTER:13,ESC:27,SPACE:32,LEFT:37,UP:38,RIGHT:39,DOWN:40,SHIFT:16,CTRL:17,ALT:18,PAGE_UP:33,PAGE_DOWN:34,HOME:36,END:35,BACKSPACE:8,DELETE:46,isArrow:function(a){switch(a=a.which?a.which:a){case c.LEFT:case c.RIGHT:case c.UP:case c.DOWN:return!0}return!1},isControl:function(a){var b=a.which;switch(b){case c.SHIFT:case c.CTRL:case c.ALT:return!0}return a.metaKey?!0:!1},isFunctionKey:function(a){return a=a.which?a.which:a,a>=112&&123>=a}},l="
",m={"\u24b6":"A","\uff21":"A","\xc0":"A","\xc1":"A","\xc2":"A","\u1ea6":"A","\u1ea4":"A","\u1eaa":"A","\u1ea8":"A","\xc3":"A","\u0100":"A","\u0102":"A","\u1eb0":"A","\u1eae":"A","\u1eb4":"A","\u1eb2":"A","\u0226":"A","\u01e0":"A","\xc4":"A","\u01de":"A","\u1ea2":"A","\xc5":"A","\u01fa":"A","\u01cd":"A","\u0200":"A","\u0202":"A","\u1ea0":"A","\u1eac":"A","\u1eb6":"A","\u1e00":"A","\u0104":"A","\u023a":"A","\u2c6f":"A","\ua732":"AA","\xc6":"AE","\u01fc":"AE","\u01e2":"AE","\ua734":"AO","\ua736":"AU","\ua738":"AV","\ua73a":"AV","\ua73c":"AY","\u24b7":"B","\uff22":"B","\u1e02":"B","\u1e04":"B","\u1e06":"B","\u0243":"B","\u0182":"B","\u0181":"B","\u24b8":"C","\uff23":"C","\u0106":"C","\u0108":"C","\u010a":"C","\u010c":"C","\xc7":"C","\u1e08":"C","\u0187":"C","\u023b":"C","\ua73e":"C","\u24b9":"D","\uff24":"D","\u1e0a":"D","\u010e":"D","\u1e0c":"D","\u1e10":"D","\u1e12":"D","\u1e0e":"D","\u0110":"D","\u018b":"D","\u018a":"D","\u0189":"D","\ua779":"D","\u01f1":"DZ","\u01c4":"DZ","\u01f2":"Dz","\u01c5":"Dz","\u24ba":"E","\uff25":"E","\xc8":"E","\xc9":"E","\xca":"E","\u1ec0":"E","\u1ebe":"E","\u1ec4":"E","\u1ec2":"E","\u1ebc":"E","\u0112":"E","\u1e14":"E","\u1e16":"E","\u0114":"E","\u0116":"E","\xcb":"E","\u1eba":"E","\u011a":"E","\u0204":"E","\u0206":"E","\u1eb8":"E","\u1ec6":"E","\u0228":"E","\u1e1c":"E","\u0118":"E","\u1e18":"E","\u1e1a":"E","\u0190":"E","\u018e":"E","\u24bb":"F","\uff26":"F","\u1e1e":"F","\u0191":"F","\ua77b":"F","\u24bc":"G","\uff27":"G","\u01f4":"G","\u011c":"G","\u1e20":"G","\u011e":"G","\u0120":"G","\u01e6":"G","\u0122":"G","\u01e4":"G","\u0193":"G","\ua7a0":"G","\ua77d":"G","\ua77e":"G","\u24bd":"H","\uff28":"H","\u0124":"H","\u1e22":"H","\u1e26":"H","\u021e":"H","\u1e24":"H","\u1e28":"H","\u1e2a":"H","\u0126":"H","\u2c67":"H","\u2c75":"H","\ua78d":"H","\u24be":"I","\uff29":"I","\xcc":"I","\xcd":"I","\xce":"I","\u0128":"I","\u012a":"I","\u012c":"I","\u0130":"I","\xcf":"I","\u1e2e":"I","\u1ec8":"I","\u01cf":"I","\u0208":"I","\u020a":"I","\u1eca":"I","\u012e":"I","\u1e2c":"I","\u0197":"I","\u24bf":"J","\uff2a":"J","\u0134":"J","\u0248":"J","\u24c0":"K","\uff2b":"K","\u1e30":"K","\u01e8":"K","\u1e32":"K","\u0136":"K","\u1e34":"K","\u0198":"K","\u2c69":"K","\ua740":"K","\ua742":"K","\ua744":"K","\ua7a2":"K","\u24c1":"L","\uff2c":"L","\u013f":"L","\u0139":"L","\u013d":"L","\u1e36":"L","\u1e38":"L","\u013b":"L","\u1e3c":"L","\u1e3a":"L","\u0141":"L","\u023d":"L","\u2c62":"L","\u2c60":"L","\ua748":"L","\ua746":"L","\ua780":"L","\u01c7":"LJ","\u01c8":"Lj","\u24c2":"M","\uff2d":"M","\u1e3e":"M","\u1e40":"M","\u1e42":"M","\u2c6e":"M","\u019c":"M","\u24c3":"N","\uff2e":"N","\u01f8":"N","\u0143":"N","\xd1":"N","\u1e44":"N","\u0147":"N","\u1e46":"N","\u0145":"N","\u1e4a":"N","\u1e48":"N","\u0220":"N","\u019d":"N","\ua790":"N","\ua7a4":"N","\u01ca":"NJ","\u01cb":"Nj","\u24c4":"O","\uff2f":"O","\xd2":"O","\xd3":"O","\xd4":"O","\u1ed2":"O","\u1ed0":"O","\u1ed6":"O","\u1ed4":"O","\xd5":"O","\u1e4c":"O","\u022c":"O","\u1e4e":"O","\u014c":"O","\u1e50":"O","\u1e52":"O","\u014e":"O","\u022e":"O","\u0230":"O","\xd6":"O","\u022a":"O","\u1ece":"O","\u0150":"O","\u01d1":"O","\u020c":"O","\u020e":"O","\u01a0":"O","\u1edc":"O","\u1eda":"O","\u1ee0":"O","\u1ede":"O","\u1ee2":"O","\u1ecc":"O","\u1ed8":"O","\u01ea":"O","\u01ec":"O","\xd8":"O","\u01fe":"O","\u0186":"O","\u019f":"O","\ua74a":"O","\ua74c":"O","\u01a2":"OI","\ua74e":"OO","\u0222":"OU","\u24c5":"P","\uff30":"P","\u1e54":"P","\u1e56":"P","\u01a4":"P","\u2c63":"P","\ua750":"P","\ua752":"P","\ua754":"P","\u24c6":"Q","\uff31":"Q","\ua756":"Q","\ua758":"Q","\u024a":"Q","\u24c7":"R","\uff32":"R","\u0154":"R","\u1e58":"R","\u0158":"R","\u0210":"R","\u0212":"R","\u1e5a":"R","\u1e5c":"R","\u0156":"R","\u1e5e":"R","\u024c":"R","\u2c64":"R","\ua75a":"R","\ua7a6":"R","\ua782":"R","\u24c8":"S","\uff33":"S","\u1e9e":"S","\u015a":"S","\u1e64":"S","\u015c":"S","\u1e60":"S","\u0160":"S","\u1e66":"S","\u1e62":"S","\u1e68":"S","\u0218":"S","\u015e":"S","\u2c7e":"S","\ua7a8":"S","\ua784":"S","\u24c9":"T","\uff34":"T","\u1e6a":"T","\u0164":"T","\u1e6c":"T","\u021a":"T","\u0162":"T","\u1e70":"T","\u1e6e":"T","\u0166":"T","\u01ac":"T","\u01ae":"T","\u023e":"T","\ua786":"T","\ua728":"TZ","\u24ca":"U","\uff35":"U","\xd9":"U","\xda":"U","\xdb":"U","\u0168":"U","\u1e78":"U","\u016a":"U","\u1e7a":"U","\u016c":"U","\xdc":"U","\u01db":"U","\u01d7":"U","\u01d5":"U","\u01d9":"U","\u1ee6":"U","\u016e":"U","\u0170":"U","\u01d3":"U","\u0214":"U","\u0216":"U","\u01af":"U","\u1eea":"U","\u1ee8":"U","\u1eee":"U","\u1eec":"U","\u1ef0":"U","\u1ee4":"U","\u1e72":"U","\u0172":"U","\u1e76":"U","\u1e74":"U","\u0244":"U","\u24cb":"V","\uff36":"V","\u1e7c":"V","\u1e7e":"V","\u01b2":"V","\ua75e":"V","\u0245":"V","\ua760":"VY","\u24cc":"W","\uff37":"W","\u1e80":"W","\u1e82":"W","\u0174":"W","\u1e86":"W","\u1e84":"W","\u1e88":"W","\u2c72":"W","\u24cd":"X","\uff38":"X","\u1e8a":"X","\u1e8c":"X","\u24ce":"Y","\uff39":"Y","\u1ef2":"Y","\xdd":"Y","\u0176":"Y","\u1ef8":"Y","\u0232":"Y","\u1e8e":"Y","\u0178":"Y","\u1ef6":"Y","\u1ef4":"Y","\u01b3":"Y","\u024e":"Y","\u1efe":"Y","\u24cf":"Z","\uff3a":"Z","\u0179":"Z","\u1e90":"Z","\u017b":"Z","\u017d":"Z","\u1e92":"Z","\u1e94":"Z","\u01b5":"Z","\u0224":"Z","\u2c7f":"Z","\u2c6b":"Z","\ua762":"Z","\u24d0":"a","\uff41":"a","\u1e9a":"a","\xe0":"a","\xe1":"a","\xe2":"a","\u1ea7":"a","\u1ea5":"a","\u1eab":"a","\u1ea9":"a","\xe3":"a","\u0101":"a","\u0103":"a","\u1eb1":"a","\u1eaf":"a","\u1eb5":"a","\u1eb3":"a","\u0227":"a","\u01e1":"a","\xe4":"a","\u01df":"a","\u1ea3":"a","\xe5":"a","\u01fb":"a","\u01ce":"a","\u0201":"a","\u0203":"a","\u1ea1":"a","\u1ead":"a","\u1eb7":"a","\u1e01":"a","\u0105":"a","\u2c65":"a","\u0250":"a","\ua733":"aa","\xe6":"ae","\u01fd":"ae","\u01e3":"ae","\ua735":"ao","\ua737":"au","\ua739":"av","\ua73b":"av","\ua73d":"ay","\u24d1":"b","\uff42":"b","\u1e03":"b","\u1e05":"b","\u1e07":"b","\u0180":"b","\u0183":"b","\u0253":"b","\u24d2":"c","\uff43":"c","\u0107":"c","\u0109":"c","\u010b":"c","\u010d":"c","\xe7":"c","\u1e09":"c","\u0188":"c","\u023c":"c","\ua73f":"c","\u2184":"c","\u24d3":"d","\uff44":"d","\u1e0b":"d","\u010f":"d","\u1e0d":"d","\u1e11":"d","\u1e13":"d","\u1e0f":"d","\u0111":"d","\u018c":"d","\u0256":"d","\u0257":"d","\ua77a":"d","\u01f3":"dz","\u01c6":"dz","\u24d4":"e","\uff45":"e","\xe8":"e","\xe9":"e","\xea":"e","\u1ec1":"e","\u1ebf":"e","\u1ec5":"e","\u1ec3":"e","\u1ebd":"e","\u0113":"e","\u1e15":"e","\u1e17":"e","\u0115":"e","\u0117":"e","\xeb":"e","\u1ebb":"e","\u011b":"e","\u0205":"e","\u0207":"e","\u1eb9":"e","\u1ec7":"e","\u0229":"e","\u1e1d":"e","\u0119":"e","\u1e19":"e","\u1e1b":"e","\u0247":"e","\u025b":"e","\u01dd":"e","\u24d5":"f","\uff46":"f","\u1e1f":"f","\u0192":"f","\ua77c":"f","\u24d6":"g","\uff47":"g","\u01f5":"g","\u011d":"g","\u1e21":"g","\u011f":"g","\u0121":"g","\u01e7":"g","\u0123":"g","\u01e5":"g","\u0260":"g","\ua7a1":"g","\u1d79":"g","\ua77f":"g","\u24d7":"h","\uff48":"h","\u0125":"h","\u1e23":"h","\u1e27":"h","\u021f":"h","\u1e25":"h","\u1e29":"h","\u1e2b":"h","\u1e96":"h","\u0127":"h","\u2c68":"h","\u2c76":"h","\u0265":"h","\u0195":"hv","\u24d8":"i","\uff49":"i","\xec":"i","\xed":"i","\xee":"i","\u0129":"i","\u012b":"i","\u012d":"i","\xef":"i","\u1e2f":"i","\u1ec9":"i","\u01d0":"i","\u0209":"i","\u020b":"i","\u1ecb":"i","\u012f":"i","\u1e2d":"i","\u0268":"i","\u0131":"i","\u24d9":"j","\uff4a":"j","\u0135":"j","\u01f0":"j","\u0249":"j","\u24da":"k","\uff4b":"k","\u1e31":"k","\u01e9":"k","\u1e33":"k","\u0137":"k","\u1e35":"k","\u0199":"k","\u2c6a":"k","\ua741":"k","\ua743":"k","\ua745":"k","\ua7a3":"k","\u24db":"l","\uff4c":"l","\u0140":"l","\u013a":"l","\u013e":"l","\u1e37":"l","\u1e39":"l","\u013c":"l","\u1e3d":"l","\u1e3b":"l","\u017f":"l","\u0142":"l","\u019a":"l","\u026b":"l","\u2c61":"l","\ua749":"l","\ua781":"l","\ua747":"l","\u01c9":"lj","\u24dc":"m","\uff4d":"m","\u1e3f":"m","\u1e41":"m","\u1e43":"m","\u0271":"m","\u026f":"m","\u24dd":"n","\uff4e":"n","\u01f9":"n","\u0144":"n","\xf1":"n","\u1e45":"n","\u0148":"n","\u1e47":"n","\u0146":"n","\u1e4b":"n","\u1e49":"n","\u019e":"n","\u0272":"n","\u0149":"n","\ua791":"n","\ua7a5":"n","\u01cc":"nj","\u24de":"o","\uff4f":"o","\xf2":"o","\xf3":"o","\xf4":"o","\u1ed3":"o","\u1ed1":"o","\u1ed7":"o","\u1ed5":"o","\xf5":"o","\u1e4d":"o","\u022d":"o","\u1e4f":"o","\u014d":"o","\u1e51":"o","\u1e53":"o","\u014f":"o","\u022f":"o","\u0231":"o","\xf6":"o","\u022b":"o","\u1ecf":"o","\u0151":"o","\u01d2":"o","\u020d":"o","\u020f":"o","\u01a1":"o","\u1edd":"o","\u1edb":"o","\u1ee1":"o","\u1edf":"o","\u1ee3":"o","\u1ecd":"o","\u1ed9":"o","\u01eb":"o","\u01ed":"o","\xf8":"o","\u01ff":"o","\u0254":"o","\ua74b":"o","\ua74d":"o","\u0275":"o","\u01a3":"oi","\u0223":"ou","\ua74f":"oo","\u24df":"p","\uff50":"p","\u1e55":"p","\u1e57":"p","\u01a5":"p","\u1d7d":"p","\ua751":"p","\ua753":"p","\ua755":"p","\u24e0":"q","\uff51":"q","\u024b":"q","\ua757":"q","\ua759":"q","\u24e1":"r","\uff52":"r","\u0155":"r","\u1e59":"r","\u0159":"r","\u0211":"r","\u0213":"r","\u1e5b":"r","\u1e5d":"r","\u0157":"r","\u1e5f":"r","\u024d":"r","\u027d":"r","\ua75b":"r","\ua7a7":"r","\ua783":"r","\u24e2":"s","\uff53":"s","\xdf":"s","\u015b":"s","\u1e65":"s","\u015d":"s","\u1e61":"s","\u0161":"s","\u1e67":"s","\u1e63":"s","\u1e69":"s","\u0219":"s","\u015f":"s","\u023f":"s","\ua7a9":"s","\ua785":"s","\u1e9b":"s","\u24e3":"t","\uff54":"t","\u1e6b":"t","\u1e97":"t","\u0165":"t","\u1e6d":"t","\u021b":"t","\u0163":"t","\u1e71":"t","\u1e6f":"t","\u0167":"t","\u01ad":"t","\u0288":"t","\u2c66":"t","\ua787":"t","\ua729":"tz","\u24e4":"u","\uff55":"u","\xf9":"u","\xfa":"u","\xfb":"u","\u0169":"u","\u1e79":"u","\u016b":"u","\u1e7b":"u","\u016d":"u","\xfc":"u","\u01dc":"u","\u01d8":"u","\u01d6":"u","\u01da":"u","\u1ee7":"u","\u016f":"u","\u0171":"u","\u01d4":"u","\u0215":"u","\u0217":"u","\u01b0":"u","\u1eeb":"u","\u1ee9":"u","\u1eef":"u","\u1eed":"u","\u1ef1":"u","\u1ee5":"u","\u1e73":"u","\u0173":"u","\u1e77":"u","\u1e75":"u","\u0289":"u","\u24e5":"v","\uff56":"v","\u1e7d":"v","\u1e7f":"v","\u028b":"v","\ua75f":"v","\u028c":"v","\ua761":"vy","\u24e6":"w","\uff57":"w","\u1e81":"w","\u1e83":"w","\u0175":"w","\u1e87":"w","\u1e85":"w","\u1e98":"w","\u1e89":"w","\u2c73":"w","\u24e7":"x","\uff58":"x","\u1e8b":"x","\u1e8d":"x","\u24e8":"y","\uff59":"y","\u1ef3":"y","\xfd":"y","\u0177":"y","\u1ef9":"y","\u0233":"y","\u1e8f":"y","\xff":"y","\u1ef7":"y","\u1e99":"y","\u1ef5":"y","\u01b4":"y","\u024f":"y","\u1eff":"y","\u24e9":"z","\uff5a":"z","\u017a":"z","\u1e91":"z","\u017c":"z","\u017e":"z","\u1e93":"z","\u1e95":"z","\u01b6":"z","\u0225":"z","\u0240":"z","\u2c6c":"z","\ua763":"z","\u0386":"\u0391","\u0388":"\u0395","\u0389":"\u0397","\u038a":"\u0399","\u03aa":"\u0399","\u038c":"\u039f","\u038e":"\u03a5","\u03ab":"\u03a5","\u038f":"\u03a9","\u03ac":"\u03b1","\u03ad":"\u03b5","\u03ae":"\u03b7","\u03af":"\u03b9","\u03ca":"\u03b9","\u0390":"\u03b9","\u03cc":"\u03bf","\u03cd":"\u03c5","\u03cb":"\u03c5","\u03b0":"\u03c5","\u03c9":"\u03c9","\u03c2":"\u03c3"};j=a(document),g=function(){var a=1;return function(){return a++}}(),d=O(Object,{bind:function(a){var b=this;return function(){a.apply(b,arguments)}},init:function(c){var d,e,f=".select2-results";this.opts=c=this.prepareOpts(c),this.id=c.id,c.element.data("select2")!==b&&null!==c.element.data("select2")&&c.element.data("select2").destroy(),this.container=this.createContainer(),this.liveRegion=a("",{role:"status","aria-live":"polite"}).addClass("select2-hidden-accessible").appendTo(document.body),this.containerId="s2id_"+(c.element.attr("id")||"autogen"+g()),this.containerEventName=this.containerId.replace(/([.])/g,"_").replace(/([;&,\-\.\+\*\~':"\!\^#$%@\[\]\(\)=>\|])/g,"\\$1"),this.container.attr("id",this.containerId),this.container.attr("title",c.element.attr("title")),this.body=a("body"),D(this.container,this.opts.element,this.opts.adaptContainerCssClass),this.container.attr("style",c.element.attr("style")),this.container.css(K(c.containerCss,this.opts.element)),this.container.addClass(K(c.containerCssClass,this.opts.element)),this.elementTabIndex=this.opts.element.attr("tabindex"),this.opts.element.data("select2",this).attr("tabindex","-1").before(this.container).on("click.select2",A),this.container.data("select2",this),this.dropdown=this.container.find(".select2-drop"),D(this.dropdown,this.opts.element,this.opts.adaptDropdownCssClass),this.dropdown.addClass(K(c.dropdownCssClass,this.opts.element)),this.dropdown.data("select2",this),this.dropdown.on("click",A),this.results=d=this.container.find(f),this.search=e=this.container.find("input.select2-input"),this.queryCount=0,this.resultsPage=0,this.context=null,this.initContainer(),this.container.on("click",A),v(this.results),this.dropdown.on("mousemove-filtered",f,this.bind(this.highlightUnderEvent)),this.dropdown.on("touchstart touchmove touchend",f,this.bind(function(a){this._touchEvent=!0,this.highlightUnderEvent(a)})),this.dropdown.on("touchmove",f,this.bind(this.touchMoved)),this.dropdown.on("touchstart touchend",f,this.bind(this.clearTouchMoved)),this.dropdown.on("click",this.bind(function(){this._touchEvent&&(this._touchEvent=!1,this.selectHighlighted())})),x(80,this.results),this.dropdown.on("scroll-debounced",f,this.bind(this.loadMoreIfNeeded)),a(this.container).on("change",".select2-input",function(a){a.stopPropagation()}),a(this.dropdown).on("change",".select2-input",function(a){a.stopPropagation()}),a.fn.mousewheel&&d.mousewheel(function(a,b,c,e){var f=d.scrollTop();e>0&&0>=f-e?(d.scrollTop(0),A(a)):0>e&&d.get(0).scrollHeight-d.scrollTop()+e<=d.height()&&(d.scrollTop(d.get(0).scrollHeight-d.height()),A(a))}),u(e),e.on("keyup-change input paste",this.bind(this.updateResults)),e.on("focus",function(){e.addClass("select2-focused")}),e.on("blur",function(){e.removeClass("select2-focused")}),this.dropdown.on("mouseup",f,this.bind(function(b){a(b.target).closest(".select2-result-selectable").length>0&&(this.highlightUnderEvent(b),this.selectHighlighted(b))})),this.dropdown.on("click mouseup mousedown touchstart touchend focusin",function(a){a.stopPropagation()}),this.nextSearchTerm=b,a.isFunction(this.opts.initSelection)&&(this.initSelection(),this.monitorSource()),null!==c.maximumInputLength&&this.search.attr("maxlength",c.maximumInputLength);var h=c.element.prop("disabled");h===b&&(h=!1),this.enable(!h);var i=c.element.prop("readonly");i===b&&(i=!1),this.readonly(i),k=k||q(),this.autofocus=c.element.prop("autofocus"),c.element.prop("autofocus",!1),this.autofocus&&this.focus(),this.search.attr("placeholder",c.searchInputPlaceholder)},destroy:function(){var a=this.opts.element,c=a.data("select2"),d=this;this.close(),a.length&&a[0].detachEvent&&a.each(function(){this.detachEvent("onpropertychange",d._sync)}),this.propertyObserver&&(this.propertyObserver.disconnect(),this.propertyObserver=null),this._sync=null,c!==b&&(c.container.remove(),c.liveRegion.remove(),c.dropdown.remove(),a.removeClass("select2-offscreen").removeData("select2").off(".select2").prop("autofocus",this.autofocus||!1),this.elementTabIndex?a.attr({tabindex:this.elementTabIndex}):a.removeAttr("tabindex"),a.show()),N.call(this,"container","liveRegion","dropdown","results","search")},optionToData:function(a){return a.is("option")?{id:a.prop("value"),text:a.text(),element:a.get(),css:a.attr("class"),disabled:a.prop("disabled"),locked:r(a.attr("locked"),"locked")||r(a.data("locked"),!0)}:a.is("optgroup")?{text:a.attr("label"),children:[],element:a.get(),css:a.attr("class")}:void 0},prepareOpts:function(c){var d,e,f,h,i=this;if(d=c.element,"select"===d.get(0).tagName.toLowerCase()&&(this.select=e=c.element),e&&a.each(["id","multiple","ajax","query","createSearchChoice","initSelection","data","tags"],function(){if(this in c)throw new Error("Option '"+this+"' is not allowed for Select2 when attached to a ","
"," ","
    ","
","
"].join(""));return b},enableInterface:function(){this.parent.enableInterface.apply(this,arguments)&&this.focusser.prop("disabled",!this.isInterfaceEnabled())},opening:function(){var c,d,e;this.opts.minimumResultsForSearch>=0&&this.showSearch(!0),this.parent.opening.apply(this,arguments),this.showSearchInput!==!1&&this.search.val(this.focusser.val()),this.opts.shouldFocusInput(this)&&(this.search.focus(),c=this.search.get(0),c.createTextRange?(d=c.createTextRange(),d.collapse(!1),d.select()):c.setSelectionRange&&(e=this.search.val().length,c.setSelectionRange(e,e))),""===this.search.val()&&this.nextSearchTerm!=b&&(this.search.val(this.nextSearchTerm),this.search.select()),this.focusser.prop("disabled",!0).val(""),this.updateResults(!0),this.opts.element.trigger(a.Event("select2-open"))},close:function(){this.opened()&&(this.parent.close.apply(this,arguments),this.focusser.prop("disabled",!1),this.opts.shouldFocusInput(this)&&this.focusser.focus())},focus:function(){this.opened()?this.close():(this.focusser.prop("disabled",!1),this.opts.shouldFocusInput(this)&&this.focusser.focus())},isFocused:function(){return this.container.hasClass("select2-container-active")},cancel:function(){this.parent.cancel.apply(this,arguments),this.focusser.prop("disabled",!1),this.opts.shouldFocusInput(this)&&this.focusser.focus()},destroy:function(){a("label[for='"+this.focusser.attr("id")+"']").attr("for",this.opts.element.attr("id")),this.parent.destroy.apply(this,arguments),N.call(this,"selection","focusser")},initContainer:function(){var b,h,d=this.container,e=this.dropdown,f=g();this.opts.minimumResultsForSearch<0?this.showSearch(!1):this.showSearch(!0),this.selection=b=d.find(".select2-choice"),this.focusser=d.find(".select2-focusser"),b.find(".select2-chosen").attr("id","select2-chosen-"+f),this.focusser.attr("aria-labelledby","select2-chosen-"+f),this.results.attr("id","select2-results-"+f),this.search.attr("aria-owns","select2-results-"+f),this.focusser.attr("id","s2id_autogen"+f),h=a("label[for='"+this.opts.element.attr("id")+"']"),this.focusser.prev().text(h.text()).attr("for",this.focusser.attr("id"));var i=this.opts.element.attr("title");this.opts.element.attr("title",i||h.text()),this.focusser.attr("tabindex",this.elementTabIndex),this.search.attr("id",this.focusser.attr("id")+"_search"),this.search.prev().text(a("label[for='"+this.focusser.attr("id")+"']").text()).attr("for",this.search.attr("id")),this.search.on("keydown",this.bind(function(a){if(this.isInterfaceEnabled()&&229!=a.keyCode){if(a.which===c.PAGE_UP||a.which===c.PAGE_DOWN)return A(a),void 0;switch(a.which){case c.UP:case c.DOWN:return this.moveHighlight(a.which===c.UP?-1:1),A(a),void 0;case c.ENTER:return this.selectHighlighted(),A(a),void 0;case c.TAB:return this.selectHighlighted({noFocus:!0}),void 0;case c.ESC:return this.cancel(a),A(a),void 0}}})),this.search.on("blur",this.bind(function(){document.activeElement===this.body.get(0)&&window.setTimeout(this.bind(function(){this.opened()&&this.search.focus()}),0)})),this.focusser.on("keydown",this.bind(function(a){if(this.isInterfaceEnabled()&&a.which!==c.TAB&&!c.isControl(a)&&!c.isFunctionKey(a)&&a.which!==c.ESC){if(this.opts.openOnEnter===!1&&a.which===c.ENTER)return A(a),void 0;if(a.which==c.DOWN||a.which==c.UP||a.which==c.ENTER&&this.opts.openOnEnter){if(a.altKey||a.ctrlKey||a.shiftKey||a.metaKey)return;return this.open(),A(a),void 0}return a.which==c.DELETE||a.which==c.BACKSPACE?(this.opts.allowClear&&this.clear(),A(a),void 0):void 0}})),u(this.focusser),this.focusser.on("keyup-change input",this.bind(function(a){if(this.opts.minimumResultsForSearch>=0){if(a.stopPropagation(),this.opened())return;this.open()}})),b.on("mousedown touchstart","abbr",this.bind(function(a){this.isInterfaceEnabled()&&(this.clear(),B(a),this.close(),this.selection.focus())})),b.on("mousedown touchstart",this.bind(function(c){n(b),this.container.hasClass("select2-container-active")||this.opts.element.trigger(a.Event("select2-focus")),this.opened()?this.close():this.isInterfaceEnabled()&&this.open(),A(c)})),e.on("mousedown touchstart",this.bind(function(){this.opts.shouldFocusInput(this)&&this.search.focus()})),b.on("focus",this.bind(function(a){A(a)})),this.focusser.on("focus",this.bind(function(){this.container.hasClass("select2-container-active")||this.opts.element.trigger(a.Event("select2-focus")),this.container.addClass("select2-container-active")})).on("blur",this.bind(function(){this.opened()||(this.container.removeClass("select2-container-active"),this.opts.element.trigger(a.Event("select2-blur")))})),this.search.on("focus",this.bind(function(){this.container.hasClass("select2-container-active")||this.opts.element.trigger(a.Event("select2-focus")),this.container.addClass("select2-container-active")})),this.initContainerWidth(),this.opts.element.addClass("select2-offscreen"),this.setPlaceholder()},clear:function(b){var c=this.selection.data("select2-data");if(c){var d=a.Event("select2-clearing");if(this.opts.element.trigger(d),d.isDefaultPrevented())return;var e=this.getPlaceholderOption();this.opts.element.val(e?e.val():""),this.selection.find(".select2-chosen").empty(),this.selection.removeData("select2-data"),this.setPlaceholder(),b!==!1&&(this.opts.element.trigger({type:"select2-removed",val:this.id(c),choice:c}),this.triggerChange({removed:c}))}},initSelection:function(){if(this.isPlaceholderOptionSelected())this.updateSelection(null),this.close(),this.setPlaceholder();else{var c=this;this.opts.initSelection.call(null,this.opts.element,function(a){a!==b&&null!==a&&(c.updateSelection(a),c.close(),c.setPlaceholder(),c.nextSearchTerm=c.opts.nextSearchTerm(a,c.search.val()))})}},isPlaceholderOptionSelected:function(){var a;return this.getPlaceholder()===b?!1:(a=this.getPlaceholderOption())!==b&&a.prop("selected")||""===this.opts.element.val()||this.opts.element.val()===b||null===this.opts.element.val()},prepareOpts:function(){var b=this.parent.prepareOpts.apply(this,arguments),c=this;return"select"===b.element.get(0).tagName.toLowerCase()?b.initSelection=function(a,b){var d=a.find("option").filter(function(){return this.selected&&!this.disabled});b(c.optionToData(d))}:"data"in b&&(b.initSelection=b.initSelection||function(c,d){var e=c.val(),f=null;b.query({matcher:function(a,c,d){var g=r(e,b.id(d));return g&&(f=d),g},callback:a.isFunction(d)?function(){d(f)}:a.noop})}),b},getPlaceholder:function(){return this.select&&this.getPlaceholderOption()===b?b:this.parent.getPlaceholder.apply(this,arguments)},setPlaceholder:function(){var a=this.getPlaceholder();if(this.isPlaceholderOptionSelected()&&a!==b){if(this.select&&this.getPlaceholderOption()===b)return;this.selection.find(".select2-chosen").html(this.opts.escapeMarkup(a)),this.selection.addClass("select2-default"),this.container.removeClass("select2-allowclear")}},postprocessResults:function(a,b,c){var d=0,e=this;if(this.findHighlightableChoices().each2(function(a,b){return r(e.id(b.data("select2-data")),e.opts.element.val())?(d=a,!1):void 0}),c!==!1&&(b===!0&&d>=0?this.highlight(d):this.highlight(0)),b===!0){var g=this.opts.minimumResultsForSearch;g>=0&&this.showSearch(L(a.results)>=g)}},showSearch:function(b){this.showSearchInput!==b&&(this.showSearchInput=b,this.dropdown.find(".select2-search").toggleClass("select2-search-hidden",!b),this.dropdown.find(".select2-search").toggleClass("select2-offscreen",!b),a(this.dropdown,this.container).toggleClass("select2-with-searchbox",b))},onSelect:function(a,b){if(this.triggerSelect(a)){var c=this.opts.element.val(),d=this.data();this.opts.element.val(this.id(a)),this.updateSelection(a),this.opts.element.trigger({type:"select2-selected",val:this.id(a),choice:a}),this.nextSearchTerm=this.opts.nextSearchTerm(a,this.search.val()),this.close(),b&&b.noFocus||!this.opts.shouldFocusInput(this)||this.focusser.focus(),r(c,this.id(a))||this.triggerChange({added:a,removed:d})}},updateSelection:function(a){var d,e,c=this.selection.find(".select2-chosen");this.selection.data("select2-data",a),c.empty(),null!==a&&(d=this.opts.formatSelection(a,c,this.opts.escapeMarkup)),d!==b&&c.append(d),e=this.opts.formatSelectionCssClass(a,c),e!==b&&c.addClass(e),this.selection.removeClass("select2-default"),this.opts.allowClear&&this.getPlaceholder()!==b&&this.container.addClass("select2-allowclear")},val:function(){var a,c=!1,d=null,e=this,f=this.data();if(0===arguments.length)return this.opts.element.val();if(a=arguments[0],arguments.length>1&&(c=arguments[1]),this.select)this.select.val(a).find("option").filter(function(){return this.selected}).each2(function(a,b){return d=e.optionToData(b),!1}),this.updateSelection(d),this.setPlaceholder(),c&&this.triggerChange({added:d,removed:f});else{if(!a&&0!==a)return this.clear(c),void 0;if(this.opts.initSelection===b)throw new Error("cannot call val() if initSelection() is not defined");this.opts.element.val(a),this.opts.initSelection(this.opts.element,function(a){e.opts.element.val(a?e.id(a):""),e.updateSelection(a),e.setPlaceholder(),c&&e.triggerChange({added:a,removed:f})})}},clearSearch:function(){this.search.val(""),this.focusser.val("")},data:function(a){var c,d=!1;return 0===arguments.length?(c=this.selection.data("select2-data"),c==b&&(c=null),c):(arguments.length>1&&(d=arguments[1]),a?(c=this.data(),this.opts.element.val(a?this.id(a):""),this.updateSelection(a),d&&this.triggerChange({added:a,removed:c})):this.clear(d),void 0)}}),f=O(d,{createContainer:function(){var b=a(document.createElement("div")).attr({"class":"select2-container select2-container-multi"}).html(["
    ","
  • "," "," ","
  • ","
","
","
    ","
","
"].join(""));return b},prepareOpts:function(){var b=this.parent.prepareOpts.apply(this,arguments),c=this;return"select"===b.element.get(0).tagName.toLowerCase()?b.initSelection=function(a,b){var d=[];a.find("option").filter(function(){return this.selected&&!this.disabled}).each2(function(a,b){d.push(c.optionToData(b))}),b(d)}:"data"in b&&(b.initSelection=b.initSelection||function(c,d){var e=s(c.val(),b.separator),f=[];b.query({matcher:function(c,d,g){var h=a.grep(e,function(a){return r(a,b.id(g))}).length;return h&&f.push(g),h},callback:a.isFunction(d)?function(){for(var a=[],c=0;c0||(this.selectChoice(null),this.clearPlaceholder(),this.container.hasClass("select2-container-active")||this.opts.element.trigger(a.Event("select2-focus")),this.open(),this.focusSearch(),b.preventDefault()))})),this.container.on("focus",b,this.bind(function(){this.isInterfaceEnabled()&&(this.container.hasClass("select2-container-active")||this.opts.element.trigger(a.Event("select2-focus")),this.container.addClass("select2-container-active"),this.dropdown.addClass("select2-drop-active"),this.clearPlaceholder())})),this.initContainerWidth(),this.opts.element.addClass("select2-offscreen"),this.clearSearch()},enableInterface:function(){this.parent.enableInterface.apply(this,arguments)&&this.search.prop("disabled",!this.isInterfaceEnabled())},initSelection:function(){if(""===this.opts.element.val()&&""===this.opts.element.text()&&(this.updateSelection([]),this.close(),this.clearSearch()),this.select||""!==this.opts.element.val()){var c=this;this.opts.initSelection.call(null,this.opts.element,function(a){a!==b&&null!==a&&(c.updateSelection(a),c.close(),c.clearSearch())})}},clearSearch:function(){var a=this.getPlaceholder(),c=this.getMaxSearchWidth();a!==b&&0===this.getVal().length&&this.search.hasClass("select2-focused")===!1?(this.search.val(a).addClass("select2-default"),this.search.width(c>0?c:this.container.css("width"))):this.search.val("").width(10)},clearPlaceholder:function(){this.search.hasClass("select2-default")&&this.search.val("").removeClass("select2-default")},opening:function(){this.clearPlaceholder(),this.resizeSearch(),this.parent.opening.apply(this,arguments),this.focusSearch(),""===this.search.val()&&this.nextSearchTerm!=b&&(this.search.val(this.nextSearchTerm),this.search.select()),this.updateResults(!0),this.opts.shouldFocusInput(this)&&this.search.focus(),this.opts.element.trigger(a.Event("select2-open"))},close:function(){this.opened()&&this.parent.close.apply(this,arguments)},focus:function(){this.close(),this.search.focus()},isFocused:function(){return this.search.hasClass("select2-focused")},updateSelection:function(b){var c=[],d=[],e=this;a(b).each(function(){p(e.id(this),c)<0&&(c.push(e.id(this)),d.push(this))}),b=d,this.selection.find(".select2-search-choice").remove(),a(b).each(function(){e.addSelectedChoice(this)}),e.postprocessResults()},tokenize:function(){var a=this.search.val();a=this.opts.tokenizer.call(this,a,this.data(),this.bind(this.onSelect),this.opts),null!=a&&a!=b&&(this.search.val(a),a.length>0&&this.open())},onSelect:function(a,c){this.triggerSelect(a)&&""!==a.text&&(this.addSelectedChoice(a),this.opts.element.trigger({type:"selected",val:this.id(a),choice:a}),this.nextSearchTerm=this.opts.nextSearchTerm(a,this.search.val()),this.clearSearch(),this.updateResults(),(this.select||!this.opts.closeOnSelect)&&this.postprocessResults(a,!1,this.opts.closeOnSelect===!0),this.opts.closeOnSelect?(this.close(),this.search.width(10)):this.countSelectableResults()>0?(this.search.width(10),this.resizeSearch(),this.getMaximumSelectionSize()>0&&this.val().length>=this.getMaximumSelectionSize()?this.updateResults(!0):this.nextSearchTerm!=b&&(this.search.val(this.nextSearchTerm),this.updateResults(),this.search.select()),this.positionDropdown()):(this.close(),this.search.width(10)),this.triggerChange({added:a}),c&&c.noFocus||this.focusSearch())},cancel:function(){this.close(),this.focusSearch()},addSelectedChoice:function(c){var j,k,d=!c.locked,e=a("
"),f=a("
  • "),g=d?e:f,h=this.id(c),i=this.getVal();j=this.opts.formatSelection(c,g.find("div"),this.opts.escapeMarkup),j!=b&&g.find("div").replaceWith("
    "+j+"
    "),k=this.opts.formatSelectionCssClass(c,g.find("div")),k!=b&&g.addClass(k),d&&g.find(".select2-search-choice-close").on("mousedown",A).on("click dblclick",this.bind(function(b){this.isInterfaceEnabled()&&(this.unselect(a(b.target)),this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus"),A(b),this.close(),this.focusSearch())})).on("focus",this.bind(function(){this.isInterfaceEnabled()&&(this.container.addClass("select2-container-active"),this.dropdown.addClass("select2-drop-active"))})),g.data("select2-data",c),g.insertBefore(this.searchContainer),i.push(h),this.setVal(i)},unselect:function(b){var d,e,c=this.getVal();if(b=b.closest(".select2-search-choice"),0===b.length)throw"Invalid argument: "+b+". Must be .select2-search-choice";if(d=b.data("select2-data")){var f=a.Event("select2-removing");if(f.val=this.id(d),f.choice=d,this.opts.element.trigger(f),f.isDefaultPrevented())return!1;for(;(e=p(this.id(d),c))>=0;)c.splice(e,1),this.setVal(c),this.select&&this.postprocessResults();return b.remove(),this.opts.element.trigger({type:"select2-removed",val:this.id(d),choice:d}),this.triggerChange({removed:d}),!0}},postprocessResults:function(a,b,c){var d=this.getVal(),e=this.results.find(".select2-result"),f=this.results.find(".select2-result-with-children"),g=this;e.each2(function(a,b){var c=g.id(b.data("select2-data"));p(c,d)>=0&&(b.addClass("select2-selected"),b.find(".select2-result-selectable").addClass("select2-selected"))}),f.each2(function(a,b){b.is(".select2-result-selectable")||0!==b.find(".select2-result-selectable:not(.select2-selected)").length||b.addClass("select2-selected")}),-1==this.highlight()&&c!==!1&&g.highlight(0),!this.opts.createSearchChoice&&!e.filter(".select2-result:not(.select2-selected)").length>0&&(!a||a&&!a.more&&0===this.results.find(".select2-no-results").length)&&J(g.opts.formatNoMatches,"formatNoMatches")&&this.results.append("
  • "+K(g.opts.formatNoMatches,g.opts.element,g.search.val())+"
  • ")},getMaxSearchWidth:function(){return this.selection.width()-t(this.search)},resizeSearch:function(){var a,b,c,d,e,f=t(this.search);a=C(this.search)+10,b=this.search.offset().left,c=this.selection.width(),d=this.selection.offset().left,e=c-(b-d)-f,a>e&&(e=c-f),40>e&&(e=c-f),0>=e&&(e=a),this.search.width(Math.floor(e))},getVal:function(){var a;return this.select?(a=this.select.val(),null===a?[]:a):(a=this.opts.element.val(),s(a,this.opts.separator))},setVal:function(b){var c;this.select?this.select.val(b):(c=[],a(b).each(function(){p(this,c)<0&&c.push(this)}),this.opts.element.val(0===c.length?"":c.join(this.opts.separator)))},buildChangeDetails:function(a,b){for(var b=b.slice(0),a=a.slice(0),c=0;c0&&c--,a.splice(d,1),d--);return{added:b,removed:a}},val:function(c,d){var e,f=this;if(0===arguments.length)return this.getVal();if(e=this.data(),e.length||(e=[]),!c&&0!==c)return this.opts.element.val(""),this.updateSelection([]),this.clearSearch(),d&&this.triggerChange({added:this.data(),removed:e}),void 0;if(this.setVal(c),this.select)this.opts.initSelection(this.select,this.bind(this.updateSelection)),d&&this.triggerChange(this.buildChangeDetails(e,this.data()));else{if(this.opts.initSelection===b)throw new Error("val() cannot be called if initSelection() is not defined");this.opts.initSelection(this.opts.element,function(b){var c=a.map(b,f.id);f.setVal(c),f.updateSelection(b),f.clearSearch(),d&&f.triggerChange(f.buildChangeDetails(e,f.data()))})}this.clearSearch()},onSortStart:function(){if(this.select)throw new Error("Sorting of elements is not supported when attached to instead.");this.search.width(0),this.searchContainer.hide()},onSortEnd:function(){var b=[],c=this;this.searchContainer.show(),this.searchContainer.appendTo(this.searchContainer.parent()),this.resizeSearch(),this.selection.find(".select2-search-choice").each(function(){b.push(c.opts.id(a(this).data("select2-data")))}),this.setVal(b),this.triggerChange()},data:function(b,c){var e,f,d=this;return 0===arguments.length?this.selection.children(".select2-search-choice").map(function(){return a(this).data("select2-data")}).get():(f=this.data(),b||(b=[]),e=a.map(b,function(a){return d.opts.id(a)}),this.setVal(e),this.updateSelection(b),this.clearSearch(),c&&this.triggerChange(this.buildChangeDetails(f,this.data())),void 0)}}),a.fn.select2=function(){var d,e,f,g,h,c=Array.prototype.slice.call(arguments,0),i=["val","destroy","opened","open","close","focus","isFocused","container","dropdown","onSortStart","onSortEnd","enable","disable","readonly","positionDropdown","data","search"],j=["opened","isFocused","container","dropdown"],k=["val","data"],l={search:"externalSearch"};return this.each(function(){if(0===c.length||"object"==typeof c[0])d=0===c.length?{}:a.extend({},c[0]),d.element=a(this),"select"===d.element.get(0).tagName.toLowerCase()?h=d.element.prop("multiple"):(h=d.multiple||!1,"tags"in d&&(d.multiple=h=!0)),e=h?new window.Select2["class"].multi:new window.Select2["class"].single,e.init(d);else{if("string"!=typeof c[0])throw"Invalid arguments to select2 plugin: "+c;if(p(c[0],i)<0)throw"Unknown method: "+c[0];if(g=b,e=a(this).data("select2"),e===b)return;if(f=c[0],"container"===f?g=e.container:"dropdown"===f?g=e.dropdown:(l[f]&&(f=l[f]),g=e[f].apply(e,c.slice(1))),p(c[0],j)>=0||p(c[0],k)>=0&&1==c.length)return!1}}),g===b?this:g},a.fn.select2.defaults={width:"copy",loadMorePadding:0,closeOnSelect:!0,openOnEnter:!0,containerCss:{},dropdownCss:{},containerCssClass:"",dropdownCssClass:"",formatResult:function(a,b,c,d){var e=[];return E(a.text,c.term,e,d),e.join("")},formatSelection:function(a,c,d){return a?d(a.text):b},sortResults:function(a){return a},formatResultCssClass:function(a){return a.css},formatSelectionCssClass:function(){return b},minimumResultsForSearch:0,minimumInputLength:0,maximumInputLength:null,maximumSelectionSize:0,id:function(a){return a==b?null:a.id},matcher:function(a,b){return o(""+b).toUpperCase().indexOf(o(""+a).toUpperCase())>=0},separator:",",tokenSeparators:[],tokenizer:M,escapeMarkup:F,blurOnChange:!1,selectOnBlur:!1,adaptContainerCssClass:function(a){return a},adaptDropdownCssClass:function(){return null},nextSearchTerm:function(){return b},searchInputPlaceholder:"",createSearchChoicePosition:"top",shouldFocusInput:function(a){var b="ontouchstart"in window||navigator.msMaxTouchPoints>0;return b?a.opts.minimumResultsForSearch<0?!1:!0:!0}},a.fn.select2.locales=[],a.fn.select2.locales.en={formatMatches:function(a){return 1===a?"One result is available, press enter to select it.":a+" results are available, use up and down arrow keys to navigate." +},formatNoMatches:function(){return"No matches found"},formatAjaxError:function(){return"Loading failed"},formatInputTooShort:function(a,b){var c=b-a.length;return"Please enter "+c+" or more character"+(1==c?"":"s")},formatInputTooLong:function(a,b){var c=a.length-b;return"Please delete "+c+" character"+(1==c?"":"s")},formatSelectionTooBig:function(a){return"You can only select "+a+" item"+(1==a?"":"s")},formatLoadMore:function(){return"Loading more results\u2026"},formatSearching:function(){return"Searching\u2026"}},a.extend(a.fn.select2.defaults,a.fn.select2.locales.en),a.fn.select2.ajaxDefaults={transport:a.ajax,params:{type:"GET",cache:!1,dataType:"json"}},window.Select2={query:{ajax:G,local:H,tags:I},util:{debounce:w,markMatch:E,escapeMarkup:F,stripDiacritics:o},"class":{"abstract":d,single:e,multi:f}}}}(jQuery); \ No newline at end of file diff --git a/frontend/client/modules/crm/res/templates/calendar-page.tpl b/frontend/client/modules/crm/res/templates/calendar-page.tpl index c11018b406..8027ea2121 100644 --- a/frontend/client/modules/crm/res/templates/calendar-page.tpl +++ b/frontend/client/modules/crm/res/templates/calendar-page.tpl @@ -1,3 +1,3 @@
    - {{{calendar}}} + {{{calendar}}}
    diff --git a/frontend/client/modules/crm/res/templates/calendar/calendar.tpl b/frontend/client/modules/crm/res/templates/calendar/calendar.tpl index 2f16796625..ea1688b950 100644 --- a/frontend/client/modules/crm/res/templates/calendar/calendar.tpl +++ b/frontend/client/modules/crm/res/templates/calendar/calendar.tpl @@ -3,24 +3,24 @@ {{#if header}} -
    -
    -
    - - -
    - -
    - -

    - -
    -
    - {{#each ../modeList}} - - {{/each}} -
    -
    +
    +
    +
    + + +
    + +
    + +

    + +
    +
    + {{#each ../modeList}} + + {{/each}} +
    +
    {{/if}} diff --git a/frontend/client/modules/crm/res/templates/calendar/modals/edit.tpl b/frontend/client/modules/crm/res/templates/calendar/modals/edit.tpl index a822642e71..d4489c79f9 100644 --- a/frontend/client/modules/crm/res/templates/calendar/modals/edit.tpl +++ b/frontend/client/modules/crm/res/templates/calendar/modals/edit.tpl @@ -1,10 +1,10 @@ {{#if isNew}}
    {{#each scopeList}} -   +   {{/each}}
    {{/if}} diff --git a/frontend/client/modules/crm/res/templates/inbound-email/fields/folder/edit.tpl b/frontend/client/modules/crm/res/templates/inbound-email/fields/folder/edit.tpl index bb60aadcb5..88c42c50c4 100644 --- a/frontend/client/modules/crm/res/templates/inbound-email/fields/folder/edit.tpl +++ b/frontend/client/modules/crm/res/templates/inbound-email/fields/folder/edit.tpl @@ -1,8 +1,8 @@
    - - + + - +
    diff --git a/frontend/client/modules/crm/res/templates/inbound-email/modals/select-folder.tpl b/frontend/client/modules/crm/res/templates/inbound-email/modals/select-folder.tpl index 5bb8d78c3f..f62dd3f962 100644 --- a/frontend/client/modules/crm/res/templates/inbound-email/modals/select-folder.tpl +++ b/frontend/client/modules/crm/res/templates/inbound-email/modals/select-folder.tpl @@ -1,11 +1,11 @@ {{#unless folders}} - {{translate 'No Data'}} + {{translate 'No Data'}} {{/unless}}
      {{#each folders}} -
    • - {{./this}} - -
    • +
    • + {{./this}} + +
    • {{/each}}
    diff --git a/frontend/client/modules/crm/res/templates/lead/convert.tpl b/frontend/client/modules/crm/res/templates/lead/convert.tpl index 4726914ad7..4ec990a7f8 100644 --- a/frontend/client/modules/crm/res/templates/lead/convert.tpl +++ b/frontend/client/modules/crm/res/templates/lead/convert.tpl @@ -1,21 +1,21 @@ {{#each scopes}}
    - -
    - {{{var this ../this}}} -
    + +
    + {{{var this ../this}}} +
    {{/each}}
    - - + +
    diff --git a/frontend/client/modules/crm/res/templates/opportunity/fields/lead-source/edit.tpl b/frontend/client/modules/crm/res/templates/opportunity/fields/lead-source/edit.tpl index 55c7536890..2c752c5ff0 100644 --- a/frontend/client/modules/crm/res/templates/opportunity/fields/lead-source/edit.tpl +++ b/frontend/client/modules/crm/res/templates/opportunity/fields/lead-source/edit.tpl @@ -1,4 +1,4 @@ diff --git a/frontend/client/modules/crm/res/templates/opportunity/fields/lead-source/search.tpl b/frontend/client/modules/crm/res/templates/opportunity/fields/lead-source/search.tpl index ee69c1780b..ead6856bab 100644 --- a/frontend/client/modules/crm/res/templates/opportunity/fields/lead-source/search.tpl +++ b/frontend/client/modules/crm/res/templates/opportunity/fields/lead-source/search.tpl @@ -1,3 +1,3 @@ diff --git a/frontend/client/modules/crm/res/templates/record/panels/activities.tpl b/frontend/client/modules/crm/res/templates/record/panels/activities.tpl index a89701461f..45a1b27cbb 100644 --- a/frontend/client/modules/crm/res/templates/record/panels/activities.tpl +++ b/frontend/client/modules/crm/res/templates/record/panels/activities.tpl @@ -1,11 +1,11 @@
    - - {{#each scopeList}} - - {{/each}} + + {{#each scopeList}} + + {{/each}}
    - {{{list}}} + {{{list}}}
    diff --git a/frontend/client/modules/crm/res/templates/record/panels/tasks.tpl b/frontend/client/modules/crm/res/templates/record/panels/tasks.tpl index 62500d9070..cbef235507 100644 --- a/frontend/client/modules/crm/res/templates/record/panels/tasks.tpl +++ b/frontend/client/modules/crm/res/templates/record/panels/tasks.tpl @@ -1,10 +1,10 @@
    - {{#each tabList}} - - {{/each}} + {{#each tabList}} + + {{/each}}
    - {{{list}}} + {{{list}}}
    diff --git a/frontend/client/modules/crm/res/templates/task/fields/date-end/detail.tpl b/frontend/client/modules/crm/res/templates/task/fields/date-end/detail.tpl index f2d80efd07..1b85e9bf34 100644 --- a/frontend/client/modules/crm/res/templates/task/fields/date-end/detail.tpl +++ b/frontend/client/modules/crm/res/templates/task/fields/date-end/detail.tpl @@ -1,7 +1,7 @@ {{#if isOverdue}} - + {{/if}} {{value}} {{#if isOverdue}} - + {{/if}} diff --git a/frontend/client/modules/crm/src/controllers/calendar.js b/frontend/client/modules/crm/src/controllers/calendar.js index 7e60cdf57b..b957728fb9 100644 --- a/frontend/client/modules/crm/src/controllers/calendar.js +++ b/frontend/client/modules/crm/src/controllers/calendar.js @@ -20,20 +20,29 @@ ************************************************************************/ Espo.define('Crm:Controllers.Calendar', 'Controller', function (Dep) { - - return Dep.extend({ - - show: function (options) { - this.index(options); - }, - - index: function (options) { - this.main('Crm:CalendarPage', { - date: options.date, - mode: options.mode, - }); - }, - }); + + return Dep.extend({ + + checkAccess: function () { + if (this.getAcl().check('Calendar')) { + return true; + } + return false; + }, + + show: function (options) { + this.index(options); + }, + + index: function (options) { + this.handleCheckAccess(); + + this.main('Crm:CalendarPage', { + date: options.date, + mode: options.mode, + }); + }, + }); }); diff --git a/frontend/client/modules/crm/src/controllers/inbound-email.js b/frontend/client/modules/crm/src/controllers/inbound-email.js index 6e9015f65a..4c3fd58849 100644 --- a/frontend/client/modules/crm/src/controllers/inbound-email.js +++ b/frontend/client/modules/crm/src/controllers/inbound-email.js @@ -20,17 +20,17 @@ ************************************************************************/ Espo.define('Crm:Controllers.InboundEmail', 'Controllers.Record', function (Dep) { - - return Dep.extend({ - - checkAccess: function () { - if (this.getUser().isAdmin()) { - return true; - } - return false; - }, - - }); + + return Dep.extend({ + + checkAccess: function () { + if (this.getUser().isAdmin()) { + return true; + } + return false; + }, + + }); }); diff --git a/frontend/client/modules/crm/src/controllers/lead.js b/frontend/client/modules/crm/src/controllers/lead.js index f40f098106..7d912ed332 100644 --- a/frontend/client/modules/crm/src/controllers/lead.js +++ b/frontend/client/modules/crm/src/controllers/lead.js @@ -20,16 +20,16 @@ ************************************************************************/ Espo.define('Crm:Controllers.Lead', 'Controllers.Record', function (Dep) { - - return Dep.extend({ - - convert: function (id) { - this.main('Crm:Lead.Convert', { - id: id - }); - }, - - }); + + return Dep.extend({ + + convert: function (id) { + this.main('Crm:Lead.Convert', { + id: id + }); + }, + + }); }); diff --git a/frontend/client/modules/crm/src/views/account/detail.js b/frontend/client/modules/crm/src/views/account/detail.js index ee858b291d..ab8fa3fc5f 100644 --- a/frontend/client/modules/crm/src/views/account/detail.js +++ b/frontend/client/modules/crm/src/views/account/detail.js @@ -21,20 +21,20 @@ Espo.define('Crm:Views.Account.Detail', 'Views.Detail', function (Dep) { - return Dep.extend({ - - relatedAttributeMap: { - 'contacts': { - 'billingAddressCity': 'addressCity', - 'billingAddressStreet': 'addressStreet', - 'billingAddressPostalCode': 'addressPostalCode', - 'billingAddressState': 'addressState', - 'billingAddressCountry': 'addressCountry', - 'id': 'accountId', - 'name': 'accountName' - }, - }, - - }); + return Dep.extend({ + + relatedAttributeMap: { + 'contacts': { + 'billingAddressCity': 'addressCity', + 'billingAddressStreet': 'addressStreet', + 'billingAddressPostalCode': 'addressPostalCode', + 'billingAddressState': 'addressState', + 'billingAddressCountry': 'addressCountry', + 'id': 'accountId', + 'name': 'accountName' + }, + }, + + }); }); diff --git a/frontend/client/modules/crm/src/views/account/fields/shipping-address.js b/frontend/client/modules/crm/src/views/account/fields/shipping-address.js index 3b890b7097..ee4d4298d2 100644 --- a/frontend/client/modules/crm/src/views/account/fields/shipping-address.js +++ b/frontend/client/modules/crm/src/views/account/fields/shipping-address.js @@ -21,32 +21,32 @@ Espo.define('Crm:Views.Account.Fields.ShippingAddress', 'Views.Fields.Address', function (Dep) { - return Dep.extend({ - - copyFrom: 'billingAddress', - - afterRender: function () { - Dep.prototype.afterRender.call(this); - - if (this.mode == 'edit') { - var label = this.translate('Copy Billing', 'labels', 'Accounts'); - $btn = $('').on('click', function () { - this.copy(this.copyFrom); - }.bind(this)); - this.$el.append($btn); - } - }, - - copy: function (fieldFrom) { - var attrList = Object.keys(this.getMetadata().get('fields.address.fields')).forEach(function (attr) { - destField = this.name + Espo.Utils.upperCaseFirst(attr); - sourceField = fieldFrom + Espo.Utils.upperCaseFirst(attr); - - this.model.set(destField, this.model.get(sourceField)); - }, this); - - }, - - }); + return Dep.extend({ + + copyFrom: 'billingAddress', + + afterRender: function () { + Dep.prototype.afterRender.call(this); + + if (this.mode == 'edit') { + var label = this.translate('Copy Billing', 'labels', 'Accounts'); + $btn = $('').on('click', function () { + this.copy(this.copyFrom); + }.bind(this)); + this.$el.append($btn); + } + }, + + copy: function (fieldFrom) { + var attrList = Object.keys(this.getMetadata().get('fields.address.fields')).forEach(function (attr) { + destField = this.name + Espo.Utils.upperCaseFirst(attr); + sourceField = fieldFrom + Espo.Utils.upperCaseFirst(attr); + + this.model.set(destField, this.model.get(sourceField)); + }, this); + + }, + + }); }); diff --git a/frontend/client/modules/crm/src/views/calendar-page.js b/frontend/client/modules/crm/src/views/calendar-page.js index 285d50fd69..a66a95e767 100644 --- a/frontend/client/modules/crm/src/views/calendar-page.js +++ b/frontend/client/modules/crm/src/views/calendar-page.js @@ -21,32 +21,32 @@ Espo.define('Crm:Views.CalendarPage', 'View', function (Dep) { - return Dep.extend({ + return Dep.extend({ - template: 'crm:calendar-page', - - el: '#main', + template: 'crm:calendar-page', + + el: '#main', - setup: function () { - this.createView('calendar', 'Crm:Calendar.Calendar', { - date: this.options.date, - mode: this.options.mode, - el: '#main > .calendar-container', - }, function (view) { - var first = true; - this.listenTo(view, 'view', function (date, mode) { - if (!first) { - this.getRouter().navigate('#Calendar/show/date=' + date + '&mode=' + mode); - } - first = false; - }.bind(this)); - }.bind(this)); - }, - - updatePageTitle: function () { - this.setPageTitle(this.translate('Calendar', 'scopeNames')); - }, - }); + setup: function () { + this.createView('calendar', 'Crm:Calendar.Calendar', { + date: this.options.date, + mode: this.options.mode, + el: '#main > .calendar-container', + }, function (view) { + var first = true; + this.listenTo(view, 'view', function (date, mode) { + if (!first) { + this.getRouter().navigate('#Calendar/show/date=' + date + '&mode=' + mode); + } + first = false; + }.bind(this)); + }.bind(this)); + }, + + updatePageTitle: function () { + this.setPageTitle(this.translate('Calendar', 'scopeNames')); + }, + }); }); diff --git a/frontend/client/modules/crm/src/views/calendar/calendar.js b/frontend/client/modules/crm/src/views/calendar/calendar.js index a65e579f3c..dfba6397b2 100644 --- a/frontend/client/modules/crm/src/views/calendar/calendar.js +++ b/frontend/client/modules/crm/src/views/calendar/calendar.js @@ -20,332 +20,332 @@ ************************************************************************/ Espo.define('Crm:Views.Calendar.Calendar', ['View', 'lib!FullCalendar'], function (Dep, FullCalendar) { - - return Dep.extend({ + + return Dep.extend({ - template: 'crm:calendar.calendar', + template: 'crm:calendar.calendar', - eventAttributes: [], + eventAttributes: [], - colors: { - 'Meeting': '#558BBD', - 'Call': '#cf605d', - 'Task': '#76BA4E', - }, + colors: { + 'Meeting': '#558BBD', + 'Call': '#cf605d', + 'Task': '#76BA4E', + }, - header: true, + header: true, - modeList: ['month', 'agendaWeek', 'agendaDay'], + modeList: ['month', 'agendaWeek', 'agendaDay'], - defaultMode: 'agendaWeek', - - slotMinutes: 30, + defaultMode: 'agendaWeek', + + slotMinutes: 30, - titleFormat: { - month: 'MMMM YYYY', - week: 'MMMM D, YYYY', - day: 'dddd, MMMM D, YYYY' - }, + titleFormat: { + month: 'MMMM YYYY', + week: 'MMMM D, YYYY', + day: 'dddd, MMMM D, YYYY' + }, - data: function () { - return { - mode: this.mode, - modeList: this.modeList, - header: this.header, - }; - }, + data: function () { + return { + mode: this.mode, + modeList: this.modeList, + header: this.header, + }; + }, - events: { - 'click button[data-action="prev"]': function () { - this.$calendar.fullCalendar('prev'); - this.updateDate(); - }, - 'click button[data-action="next"]': function () { - this.$calendar.fullCalendar('next'); - this.updateDate(); - }, - 'click button[data-action="today"]': function () { - this.$calendar.fullCalendar('today'); - this.updateDate(); - }, - 'click button[data-action="mode"]': function (e) { - var mode = $(e.currentTarget).data('mode'); - this.$el.find('button[data-action="mode"]').removeClass('active'); - this.$el.find('button[data-mode="' + mode + '"]').addClass('active'); - this.$calendar.fullCalendar('changeView', mode); - this.updateDate(); - }, - }, + events: { + 'click button[data-action="prev"]': function () { + this.$calendar.fullCalendar('prev'); + this.updateDate(); + }, + 'click button[data-action="next"]': function () { + this.$calendar.fullCalendar('next'); + this.updateDate(); + }, + 'click button[data-action="today"]': function () { + this.$calendar.fullCalendar('today'); + this.updateDate(); + }, + 'click button[data-action="mode"]': function (e) { + var mode = $(e.currentTarget).data('mode'); + this.$el.find('button[data-action="mode"]').removeClass('active'); + this.$el.find('button[data-mode="' + mode + '"]').addClass('active'); + this.$calendar.fullCalendar('changeView', mode); + this.updateDate(); + }, + }, - setup: function () { - this.date = this.options.date || null; - this.mode = this.options.mode || this.defaultMode; - this.header = ('header' in this.options) ? this.options.header : this.header; - this.slotMinutes = this.options.slotMinutes || this.slotMinutes; - }, + setup: function () { + this.date = this.options.date || null; + this.mode = this.options.mode || this.defaultMode; + this.header = ('header' in this.options) ? this.options.header : this.header; + this.slotMinutes = this.options.slotMinutes || this.slotMinutes; + }, - updateDate: function () { - if (!this.header) { - return; - } - var view = this.$calendar.fullCalendar('getView'); - var today = new Date(); - - if (view.start <= today && today < view.end) { - this.$el.find('button[data-action="today"]').addClass('active'); - } else { - this.$el.find('button[data-action="today"]').removeClass('active'); - } + updateDate: function () { + if (!this.header) { + return; + } + var view = this.$calendar.fullCalendar('getView'); + var today = new Date(); + + if (view.start <= today && today < view.end) { + this.$el.find('button[data-action="today"]').addClass('active'); + } else { + this.$el.find('button[data-action="today"]').removeClass('active'); + } - var map = { - 'agendaWeek': 'week', - 'agendaDay': 'day', - 'basicWeek': 'week', - 'basicDay': 'day', - }; + var map = { + 'agendaWeek': 'week', + 'agendaDay': 'day', + 'basicWeek': 'week', + 'basicDay': 'day', + }; - var viewName = map[view.name] || view.name - - var title; - - if (viewName == 'week') { - title = $.fullCalendar.formatRange(view.start, view.end, this.titleFormat[viewName], ' - '); - } else { - title = view.intervalStart.format(this.titleFormat[viewName]); - } - this.$el.find('.date-title h4').text(title); - }, + var viewName = map[view.name] || view.name + + var title; + + if (viewName == 'week') { + title = $.fullCalendar.formatRange(view.start, view.end, this.titleFormat[viewName], ' - '); + } else { + title = view.intervalStart.format(this.titleFormat[viewName]); + } + this.$el.find('.date-title h4').text(title); + }, - convertToFcEvent: function (o) { - var event = { - title: o.name, - scope: o.scope, - id: o.scope + '-' + o.id, - recordId: o.id, - dateStart: o.dateStart, - dateEnd: o.dateEnd, - }; - this.eventAttributes.forEach(function (attr) { - event[attr] = o[attr]; - }); - if (o.dateStart) { - event.start = this.getDateTime().toMoment(o.dateStart); - } - if (o.dateEnd) { - event.end = this.getDateTime().toMoment(o.dateEnd); - } - if (!event.start || !event.end) { - event.allDay = true; - if (event.end) { - event.start = event.end; - } - } else { - var start = new Date(event.start); - var end = new Date(event.end); - if ((start.getDate() != end.getDate()) || (end - start >= 86400000)) { - event.allDay = true; - } else { - event.allDay = false; - if (end - start < 1800000) { - var m = event.start.add('minutes', 30); - event.end = m.format(); - } - } - } + convertToFcEvent: function (o) { + var event = { + title: o.name, + scope: o.scope, + id: o.scope + '-' + o.id, + recordId: o.id, + dateStart: o.dateStart, + dateEnd: o.dateEnd, + }; + this.eventAttributes.forEach(function (attr) { + event[attr] = o[attr]; + }); + if (o.dateStart) { + event.start = this.getDateTime().toMoment(o.dateStart); + } + if (o.dateEnd) { + event.end = this.getDateTime().toMoment(o.dateEnd); + } + if (!event.start || !event.end) { + event.allDay = true; + if (event.end) { + event.start = event.end; + } + } else { + var start = new Date(event.start); + var end = new Date(event.end); + if ((start.getDate() != end.getDate()) || (end - start >= 86400000)) { + event.allDay = true; + } else { + event.allDay = false; + if (end - start < 1800000) { + var m = event.start.add('minutes', 30); + event.end = m.format(); + } + } + } - event.color = this.colors[o.scope]; - return event; - }, + event.color = this.colors[o.scope]; + return event; + }, - convertToFcEvents: function (list) { - var events = []; - list.forEach(function (o) { - event = this.convertToFcEvent(o); - events.push(event) - }.bind(this)); - return events; - }, - - convertTime: function (d) { - var format = this.getDateTime().internalDateTimeFormat; - var timeZone = this.getDateTime().timeZone; - var string = d.format(format); - - var m; - if (timeZone) { - m = moment.tz(string, format, timeZone).utc(); - } else { - m = moment.utc(string, format); - } - - return m.format(format) + ':00'; - }, + convertToFcEvents: function (list) { + var events = []; + list.forEach(function (o) { + event = this.convertToFcEvent(o); + events.push(event) + }.bind(this)); + return events; + }, + + convertTime: function (d) { + var format = this.getDateTime().internalDateTimeFormat; + var timeZone = this.getDateTime().timeZone; + var string = d.format(format); + + var m; + if (timeZone) { + m = moment.tz(string, format, timeZone).utc(); + } else { + m = moment.utc(string, format); + } + + return m.format(format) + ':00'; + }, - afterRender: function () { - var $calendar = this.$calendar = this.$el.find('div.calendar'); + afterRender: function () { + var $calendar = this.$calendar = this.$el.find('div.calendar'); - var options = { - header: false, - axisFormat: this.getDateTime().timeFormat, - timeFormat: this.getDateTime().timeFormat, - defaultView: this.mode, - weekNumbers: true, - editable: true, - aspectRatio: 1.62, - selectable: true, - selectHelper: true, - ignoreTimezone: true, - height: this.options.height || null, - firstDay: this.getPreferences().get('weekStart'), - slotEventOverlap: true, - snapDuration: 15 * 60 * 1000, - timezone: this.getDateTime().timeZone, - select: function (start, end, allDay) { - var dateStart = this.convertTime(start); - var dateEnd = this.convertTime(end); - - this.notify('Loading...'); - this.createView('quickEdit', 'Crm:Calendar.Modals.Edit', { - attributes: { - dateStart: dateStart, - dateEnd: dateEnd, - }, - }, function (view) { - view.render(); - view.notify(false); - }); - $calendar.fullCalendar('unselect'); - }.bind(this), - eventClick: function (event) { - this.notify('Loading...'); - this.createView('quickEdit', 'Crm:Calendar.Modals.Edit', { - scope: event.scope, - id: event.recordId - }, function (view) { - view.render(); - view.notify(false); - }); - }.bind(this), - viewRender: function (view, el) { - var mode = view.name; - var date = this.getDateTime().fromIso(this.$calendar.fullCalendar('getDate')); - - var m = moment(this.$calendar.fullCalendar('getDate')); - this.trigger('view', m.format('YYYY-MM-DD'), mode); - }.bind(this), - events: function (from, to, timezone, callback) { - var fromServer = this.getDateTime().fromIso(from); - var toServer = this.getDateTime().fromIso(to); - - this.fetchEvents(fromServer, toServer, callback); - }.bind(this), - eventDrop: function (event, delta, callback) { - var dateStart = this.convertTime(event.start) || null; - var dateEnd = this.convertTime(event.end) || null; - - var attributes = {}; - if (!event.dateStart && event.dateEnd) { - attributes.dateEnd = dateStart; - event.dateEnd = attributes.dateEnd; - } else { - if (event.dateStart) { - attributes.dateStart = dateStart; - event.dateStart = dateStart; - } - if (event.dateEnd) { - attributes.dateEnd = dateEnd; - event.dateEnd = dateEnd; - } - } + var options = { + header: false, + axisFormat: this.getDateTime().timeFormat, + timeFormat: this.getDateTime().timeFormat, + defaultView: this.mode, + weekNumbers: true, + editable: true, + aspectRatio: 1.62, + selectable: true, + selectHelper: true, + ignoreTimezone: true, + height: this.options.height || null, + firstDay: this.getPreferences().get('weekStart'), + slotEventOverlap: true, + snapDuration: 15 * 60 * 1000, + timezone: this.getDateTime().timeZone, + select: function (start, end, allDay) { + var dateStart = this.convertTime(start); + var dateEnd = this.convertTime(end); + + this.notify('Loading...'); + this.createView('quickEdit', 'Crm:Calendar.Modals.Edit', { + attributes: { + dateStart: dateStart, + dateEnd: dateEnd, + }, + }, function (view) { + view.render(); + view.notify(false); + }); + $calendar.fullCalendar('unselect'); + }.bind(this), + eventClick: function (event) { + this.notify('Loading...'); + this.createView('quickEdit', 'Crm:Calendar.Modals.Edit', { + scope: event.scope, + id: event.recordId + }, function (view) { + view.render(); + view.notify(false); + }); + }.bind(this), + viewRender: function (view, el) { + var mode = view.name; + var date = this.getDateTime().fromIso(this.$calendar.fullCalendar('getDate')); + + var m = moment(this.$calendar.fullCalendar('getDate')); + this.trigger('view', m.format('YYYY-MM-DD'), mode); + }.bind(this), + events: function (from, to, timezone, callback) { + var fromServer = this.getDateTime().fromIso(from); + var toServer = this.getDateTime().fromIso(to); + + this.fetchEvents(fromServer, toServer, callback); + }.bind(this), + eventDrop: function (event, delta, callback) { + var dateStart = this.convertTime(event.start) || null; + var dateEnd = this.convertTime(event.end) || null; + + var attributes = {}; + if (!event.dateStart && event.dateEnd) { + attributes.dateEnd = dateStart; + event.dateEnd = attributes.dateEnd; + } else { + if (event.dateStart) { + attributes.dateStart = dateStart; + event.dateStart = dateStart; + } + if (event.dateEnd) { + attributes.dateEnd = dateEnd; + event.dateEnd = dateEnd; + } + } - if (!(event.dateStart && event.dateEnd)) { - event.allDay = true; - } else { - var start = new Date(event.start); - var end = new Date(event.end); - if ((start.getDate() != end.getDate()) || (end - start >= 86400000)) { - event.allDay = true; - } - } + if (!(event.dateStart && event.dateEnd)) { + event.allDay = true; + } else { + var start = new Date(event.start); + var end = new Date(event.end); + if ((start.getDate() != end.getDate()) || (end - start >= 86400000)) { + event.allDay = true; + } + } - this.$calendar.fullCalendar('renderEvent', event); - - this.notify('Saving...'); - this.getModelFactory().create(event.scope, function (model) { - model.once('sync', function () { - this.notify(false); - }.bind(this)); - model.id = event.recordId; - model.save(attributes, {patch: true}); - }, this); - }.bind(this), - eventResize: function (event) { - var attributes = { - dateEnd: this.convertTime(event.end) - }; - this.notify('Saving...'); - this.getModelFactory().create(event.scope, function (model) { - model.once('sync', function () { - this.notify(false); - }.bind(this)); - model.id = event.recordId; - model.save(attributes, {patch: true}); - }.bind(this)); - }.bind(this), - allDayText: '', - firstHour: 8, - columnFormat: { - week: 'ddd DD', - day: 'ddd DD', - }, - weekNumberTitle: '', - }; + this.$calendar.fullCalendar('renderEvent', event); + + this.notify('Saving...'); + this.getModelFactory().create(event.scope, function (model) { + model.once('sync', function () { + this.notify(false); + }.bind(this)); + model.id = event.recordId; + model.save(attributes, {patch: true}); + }, this); + }.bind(this), + eventResize: function (event) { + var attributes = { + dateEnd: this.convertTime(event.end) + }; + this.notify('Saving...'); + this.getModelFactory().create(event.scope, function (model) { + model.once('sync', function () { + this.notify(false); + }.bind(this)); + model.id = event.recordId; + model.save(attributes, {patch: true}); + }.bind(this)); + }.bind(this), + allDayText: '', + firstHour: 8, + columnFormat: { + week: 'ddd DD', + day: 'ddd DD', + }, + weekNumberTitle: '', + }; - if (this.date) { - options.defaultDate = moment.utc(this.date); - } + if (this.date) { + options.defaultDate = moment.utc(this.date); + } - setTimeout(function () { - $calendar.fullCalendar(options); - this.updateDate(); - }.bind(this), 150); - }, + setTimeout(function () { + $calendar.fullCalendar(options); + this.updateDate(); + }.bind(this), 150); + }, - fetchEvents: function (from, to, callback) { - $.ajax({ - url: 'Activities?from=' + from + '&to=' + to, - success: function (data) { - var events = this.convertToFcEvents(data); - callback(events); - this.notify(false); - }.bind(this) - }); - }, + fetchEvents: function (from, to, callback) { + $.ajax({ + url: 'Activities?from=' + from + '&to=' + to, + success: function (data) { + var events = this.convertToFcEvents(data); + callback(events); + this.notify(false); + }.bind(this) + }); + }, - addModel: function (model) { - var d = model.attributes; - d.scope = model.name; - var event = this.convertToFcEvent(d); - this.$calendar.fullCalendar('renderEvent', event); - }, + addModel: function (model) { + var d = model.attributes; + d.scope = model.name; + var event = this.convertToFcEvent(d); + this.$calendar.fullCalendar('renderEvent', event); + }, - updateModel: function (model) { - var events = this.$calendar.fullCalendar('clientEvents', model.name + '-' + model.id); - events.forEach(function (event) { - var d = model.attributes; - d.scope = model.name; - var data = this.convertToFcEvent(d); - for (var key in data) { - event[key] = data[key]; - } - this.$calendar.fullCalendar('updateEvent', event); - }.bind(this)); - }, - - removeModel: function (model) { - this.$calendar.fullCalendar('removeEvents', model.name + '-' + model.id); - } + updateModel: function (model) { + var events = this.$calendar.fullCalendar('clientEvents', model.name + '-' + model.id); + events.forEach(function (event) { + var d = model.attributes; + d.scope = model.name; + var data = this.convertToFcEvent(d); + for (var key in data) { + event[key] = data[key]; + } + this.$calendar.fullCalendar('updateEvent', event); + }.bind(this)); + }, + + removeModel: function (model) { + this.$calendar.fullCalendar('removeEvents', model.name + '-' + model.id); + } - }); + }); }); diff --git a/frontend/client/modules/crm/src/views/calendar/modals/edit.js b/frontend/client/modules/crm/src/views/calendar/modals/edit.js index bda4df1e97..5109cb9a87 100644 --- a/frontend/client/modules/crm/src/views/calendar/modals/edit.js +++ b/frontend/client/modules/crm/src/views/calendar/modals/edit.js @@ -21,95 +21,142 @@ Espo.define('Crm:Views.Calendar.Modals.Edit', 'Views.Modals.Edit', function (Dep) { - return Dep.extend({ + return Dep.extend({ - template: 'crm:calendar.modals.edit', + template: 'crm:calendar.modals.edit', - scopeList: [ - 'Meeting', - 'Call', - 'Task', - ], - - data: function () { - return { - scopeList: this.scopeList, - scope: this.scope, - isNew: !(this.id) - }; - }, - - events: { - 'change .scope-switcher input[name="scope"]': function () { - this.notify('Loading...'); - var scope = $('.scope-switcher input[name="scope"]:checked').val(); - this.scope = scope; - this.getModelFactory().create(this.scope, function (model) { - model.populateDefaults(); - var attributes = this.getView('edit').fetch(); - attributes = _.extend(attributes, this.getView('edit').model.toJSON()); - model.set(attributes); - this.createEdit(model, function (view) { - view.render(); - view.notify(false); - }); - }.bind(this)); - }, - }, - - disableButtons: function () { - - }, + scopeList: [ + 'Meeting', + 'Call', + 'Task', + ], + + data: function () { + return { + scopeList: this.scopeList, + scope: this.scope, + isNew: !(this.id) + }; + }, + + events: { + 'change .scope-switcher input[name="scope"]': function () { + this.notify('Loading...'); + var scope = $('.scope-switcher input[name="scope"]:checked').val(); + this.scope = scope; + this.getModelFactory().create(this.scope, function (model) { + model.populateDefaults(); + var attributes = this.getView('edit').fetch(); + attributes = _.extend(attributes, this.getView('edit').model.toJSON()); + model.set(attributes); + this.createEdit(model, function (view) { + view.render(); + view.notify(false); + }); + this.handleAccess(model); + }.bind(this)); + }, + }, - setup: function () { - if (!this.options.id && !this.options.scope) { - this.options.scope = this.getConfig().get('calendarDefaultEntity', this.scopeList[0]); - } - Dep.prototype.setup.call(this); - - if (!this.id) { - this.header = this.translate('Create', 'labels', 'Calendar'); - } - - if (this.id) { - this.buttons.splice(1, 0, { - name: 'remove', - text: this.translate('Remove'), - style: 'danger', - onClick: function (dialog) { - var model = this.getView('edit').model; - - if (confirm(this.translate('removeRecordConfirmation', 'messages'))) { - var $buttons = dialog.$el.find('.modal-footer button'); - $buttons.addClass('disabled'); - model.destroy({ - success: function () { - this.trigger('after:destroy', model); - dialog.close(); - }.bind(this), - error: function () { - $buttons.removeClass('disabled'); - }, - }); - } - }.bind(this) - }); - } - - this.once('after:save', function (model) { - var parentView = this.getParentView(); - if (!this.id) { - parentView.addModel.call(parentView, model); - } else { - parentView.updateModel.call(parentView, model); - } - }.bind(this)); - - this.once('after:destroy', function (model) { - var parentView = this.getParentView(); - parentView.removeModel.call(parentView, model); - }.bind(this)); - }, - }); + handleAccess: function (model) { + if (!this.getAcl().checkModel(model, 'edit')) { + this.$el.find('button[data-name="save"]').addClass('hidden'); + this.$el.find('button[data-name="fullForm"]').addClass('hidden'); + } else { + this.$el.find('button[data-name="save"]').removeClass('hidden'); + this.$el.find('button[data-name="fullForm"]').removeClass('hidden'); + } + + if (!this.getAcl().checkModel(model, 'delete')) { + this.$el.find('button[data-name="remove"]').addClass('hidden'); + } else { + this.$el.find('button[data-name="remove"]').removeClass('hidden'); + } + }, + + afterRender: function () { + Dep.prototype.afterRender.call(this); + if (this.hasView('edit')) { + var model = this.getView('edit').model; + if (model) { + this.handleAccess(model); + } + } + + }, + + disableButtons: function () { + + }, + + setup: function () { + if (!this.options.id && !this.options.scope) { + var scopeList = []; + this.scopeList.forEach(function (scope) { + if (this.getAcl().check(scope, 'edit')) { + scopeList.push(scope); + } + }, this); + this.scopeList = scopeList; + + var calendarDefaultEntity = this.getConfig().get('calendarDefaultEntity'); + + if (calendarDefaultEntity && ~this.scopeList.indexOf(calendarDefaultEntity)) { + this.options.scope = calendarDefaultEntity; + } else { + this.options.scope = this.scopeList[0] || null; + } + + if (this.scopeList.length == 0) { + this.remove(); + return; + } + } + Dep.prototype.setup.call(this); + + if (!this.id) { + this.header = this.translate('Create', 'labels', 'Calendar'); + } + + if (this.id) { + this.buttons.splice(1, 0, { + name: 'remove', + text: this.translate('Remove'), + style: 'danger', + onClick: function (dialog) { + var model = this.getView('edit').model; + + if (confirm(this.translate('removeRecordConfirmation', 'messages'))) { + var $buttons = dialog.$el.find('.modal-footer button'); + $buttons.addClass('disabled'); + model.destroy({ + success: function () { + this.trigger('after:destroy', model); + dialog.close(); + }.bind(this), + error: function () { + $buttons.removeClass('disabled'); + }, + }); + } + }.bind(this) + }); + } + + this.once('after:save', function (model) { + var parentView = this.getParentView(); + if (!this.id) { + parentView.addModel.call(parentView, model); + } else { + parentView.updateModel.call(parentView, model); + } + }, this); + + this.once('after:destroy', function (model) { + var parentView = this.getParentView(); + parentView.removeModel.call(parentView, model); + }, this); + }, + }); }); diff --git a/frontend/client/modules/crm/src/views/call/detail.js b/frontend/client/modules/crm/src/views/call/detail.js index 469981cd5b..9810249da2 100644 --- a/frontend/client/modules/crm/src/views/call/detail.js +++ b/frontend/client/modules/crm/src/views/call/detail.js @@ -21,81 +21,81 @@ Espo.define('Crm:Views.Call.Detail', 'Views.Detail', function (Dep) { - return Dep.extend({ + return Dep.extend({ - setup: function () { - Dep.prototype.setup.call(this); - if (['Held', 'Not Held'].indexOf(this.model.get('status')) == -1) { - if (this.getAcl().checkModel(this.model, 'edit')) { - this.menu.buttons.push({ - 'label': 'Send Invitations', - 'action': 'sendInvitations', - icon: 'glyphicon glyphicon-send', - 'acl': 'edit', - }); - this.menu.dropdown.push({ - 'label': 'Set Held', - 'action': 'setHeld', - 'acl': 'edit' - }); - this.menu.dropdown.push({ - 'label': 'Set Not Held', - 'action': 'setNotHeld', - 'acl': 'edit' - }); - } - } - }, - - actionSendInvitations: function () { - if (confirm(this.translate('confirmation', 'messages'))) { - this.$el.find('button[data-action="sendInvitations"]').addClass('disabled'); - this.notify('Sending...'); - $.ajax({ - url: 'Meeting/action/sendInvitations', - type: 'POST', - data: JSON.stringify({ - id: this.model.id - }), - success: function () { - this.notify('Sent', 'success'); - this.$el.find('button[data-action="sendInvitations"]').removeClass('disabled'); - }.bind(this), - error: function () { - this.$el.find('button[data-action="sendInvitations"]').removeClass('disabled'); - }.bind(this), - }); - } - }, - - actionSetHeld: function () { - this.model.save({ - status: 'Held' - }, { - patch: true, - success: function () { - this.notify('Saved as Held', 'success'); - this.$el.find('button[data-action="sendInvitations"]').remove(); - this.$el.find('a[data-action="setHeld"]').remove(); - this.$el.find('a[data-action="setNotHeld"]').remove(); - }.bind(this), - }); - }, - - actionSetNotHeld: function () { - this.model.save({ - status: 'Not Held' - }, { - patch: true, - success: function () { - this.notify('Saved as Not Held', 'success'); - this.$el.find('button[data-action="sendInvitations"]').remove(); - this.$el.find('a[data-action="setHeld"]').remove(); - this.$el.find('a[data-action="setNotHeld"]').remove(); - }.bind(this), - }); - }, + setup: function () { + Dep.prototype.setup.call(this); + if (['Held', 'Not Held'].indexOf(this.model.get('status')) == -1) { + if (this.getAcl().checkModel(this.model, 'edit')) { + this.menu.buttons.push({ + 'label': 'Send Invitations', + 'action': 'sendInvitations', + icon: 'glyphicon glyphicon-send', + 'acl': 'edit', + }); + this.menu.dropdown.push({ + 'label': 'Set Held', + 'action': 'setHeld', + 'acl': 'edit' + }); + this.menu.dropdown.push({ + 'label': 'Set Not Held', + 'action': 'setNotHeld', + 'acl': 'edit' + }); + } + } + }, + + actionSendInvitations: function () { + if (confirm(this.translate('confirmation', 'messages'))) { + this.$el.find('[data-action="sendInvitations"]').addClass('disabled'); + this.notify('Sending...'); + $.ajax({ + url: 'Call/action/sendInvitations', + type: 'POST', + data: JSON.stringify({ + id: this.model.id + }), + success: function () { + this.notify('Sent', 'success'); + this.$el.find('[data-action="sendInvitations"]').removeClass('disabled'); + }.bind(this), + error: function () { + this.$el.find('[data-action="sendInvitations"]').removeClass('disabled'); + }.bind(this), + }); + } + }, + + actionSetHeld: function () { + this.model.save({ + status: 'Held' + }, { + patch: true, + success: function () { + this.notify('Saved', 'success'); + this.$el.find('[data-action="sendInvitations"]').remove(); + this.$el.find('[data-action="setHeld"]').remove(); + this.$el.find('[data-action="setNotHeld"]').remove(); + }.bind(this), + }); + }, + + actionSetNotHeld: function () { + this.model.save({ + status: 'Not Held' + }, { + patch: true, + success: function () { + this.notify('Saved', 'success'); + this.$el.find('[data-action="sendInvitations"]').remove(); + this.$el.find('[data-action="setHeld"]').remove(); + this.$el.find('[data-action="setNotHeld"]').remove(); + }.bind(this), + }); + }, - }); + }); }); diff --git a/frontend/client/modules/crm/src/views/call/list.js b/frontend/client/modules/crm/src/views/call/list.js new file mode 100644 index 0000000000..2a7ff4b1c5 --- /dev/null +++ b/frontend/client/modules/crm/src/views/call/list.js @@ -0,0 +1,72 @@ +/************************************************************************ + * 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/. + ************************************************************************/ + +Espo.define('Crm:Views.Call.List', 'Views.List', function (Dep) { + + return Dep.extend({ + + actionSetHeld: function (data) { + var id = data.id; + if (!id) { + return; + } + var model = this.collection.get(id); + if (!model) { + return; + } + + model.set('status', 'Held'); + + this.listenToOnce(model, 'sync', function () { + this.notify(false); + this.collection.fetch(); + }, this); + + this.notify('Saving...'); + model.save(); + + }, + + actionSetNotHeld: function (data) { + var id = data.id; + if (!id) { + return; + } + var model = this.collection.get(id); + if (!model) { + return; + } + + model.set('status', 'Not Held'); + + this.listenToOnce(model, 'sync', function () { + this.notify(false); + this.collection.fetch(); + }, this); + + this.notify('Saving...'); + model.save(); + + }, + + }); + +}); diff --git a/frontend/client/src/views/team/record/edit-side.js b/frontend/client/modules/crm/src/views/call/record/list.js similarity index 76% rename from frontend/client/src/views/team/record/edit-side.js rename to frontend/client/modules/crm/src/views/call/record/list.js index b2cb12dcd8..70b3a23960 100644 --- a/frontend/client/src/views/team/record/edit-side.js +++ b/frontend/client/modules/crm/src/views/call/record/list.js @@ -18,25 +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/. ************************************************************************/ + +Espo.define('Crm:Views.Call.Record.List', 'Views.Record.List', function (Dep) { - -Espo.define('Views.Team.Record.EditSide', 'Views.Record.EditSide', function (Dep) { - - return Dep.extend({ - - panels: [ - { - name: 'default', - label: false, - view: 'Record.Panels.Side', - options: { - fields: ['roles'], - mode: 'edit', - } - } - ], - - }); - + return Dep.extend({ + + rowActionsView: 'Crm:Call.Record.RowActions.Default', + + }); + }); - diff --git a/frontend/client/modules/crm/src/views/call/record/row-actions/default.js b/frontend/client/modules/crm/src/views/call/record/row-actions/default.js new file mode 100644 index 0000000000..fee53d6c0e --- /dev/null +++ b/frontend/client/modules/crm/src/views/call/record/row-actions/default.js @@ -0,0 +1,50 @@ +/************************************************************************ + * 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/. + ************************************************************************/ + +Espo.define('Crm:Views.Call.Record.RowActions.Default', 'Views.Record.RowActions.Default', function (Dep) { + + return Dep.extend({ + + getActions: function () { + var actions = Dep.prototype.getActions.call(this); + + if (this.options.acl.edit && !~['Held', 'Not Held'].indexOf(this.model.get('status'))) { + actions.push({ + action: 'setHeld', + label: 'Set Held', + data: { + id: this.model.id + } + }); + actions.push({ + action: 'setNotHeld', + label: 'Set Not Held', + data: { + id: this.model.id + } + }); + } + + return actions; + }, + }); + +}); diff --git a/frontend/client/modules/crm/src/views/case/fields/contact.js b/frontend/client/modules/crm/src/views/case/fields/contact.js new file mode 100644 index 0000000000..87e125d1ff --- /dev/null +++ b/frontend/client/modules/crm/src/views/case/fields/contact.js @@ -0,0 +1,40 @@ +/************************************************************************ + * 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/. + ************************************************************************/ + +Espo.define('Crm:Views.Case.Fields.Contact', 'Views.Fields.Link', function (Dep) { + + return Dep.extend({ + + getSelectFilters: function () { + if (this.model.get('accountId')) { + return { + 'account': { + type: 'equals', + field: 'accountId', + value: this.model.get('accountId'), + valueName: this.model.get('accountName'), + } + }; + } + }, + }); + +}); diff --git a/frontend/client/modules/crm/src/views/case/record/panels/activities.js b/frontend/client/modules/crm/src/views/case/record/panels/activities.js index 4adf5aa2f4..ea0537bb65 100644 --- a/frontend/client/modules/crm/src/views/case/record/panels/activities.js +++ b/frontend/client/modules/crm/src/views/case/record/panels/activities.js @@ -21,38 +21,38 @@ Espo.define('Crm:Views.Case.Record.Panels.Activities', 'Crm:Views.Record.Panels.Activities', function (Dep) { - return Dep.extend({ - - getComposeEmailAttributes: function (data, callback) { - data = data || {}; - var attributes = { - status: 'Draft', - name: '[#' + this.model.get('number') + '] ' + this.model.get('name') - }; - - if (this.model.get('contactId')) { - this.getModelFactory().create('Contact', function (contact) { - contact.id = this.model.get('contactId'); - - this.listenToOnce(contact, 'sync', function () { - var emailAddress = contact.get('emailAddress'); - if (emailAddress) { - attributes.to = emailAddress; - } - - callback.call(this, attributes); - }); - contact.fetch({ - error: function () { - callback.call(this, attributes); - }.bind(this) - }); - }, this); - } else { - callback.call(this, attributes); - } - }, - - }); + return Dep.extend({ + + getComposeEmailAttributes: function (data, callback) { + data = data || {}; + var attributes = { + status: 'Draft', + name: '[#' + this.model.get('number') + '] ' + this.model.get('name') + }; + + if (this.model.get('contactId')) { + this.getModelFactory().create('Contact', function (contact) { + contact.id = this.model.get('contactId'); + + this.listenToOnce(contact, 'sync', function () { + var emailAddress = contact.get('emailAddress'); + if (emailAddress) { + attributes.to = emailAddress; + } + + callback.call(this, attributes); + }); + contact.fetch({ + error: function () { + callback.call(this, attributes); + }.bind(this) + }); + }, this); + } else { + callback.call(this, attributes); + } + }, + + }); }); diff --git a/frontend/client/modules/crm/src/views/contact/detail.js b/frontend/client/modules/crm/src/views/contact/detail.js index daa66d50ee..a0ee0c9a34 100644 --- a/frontend/client/modules/crm/src/views/contact/detail.js +++ b/frontend/client/modules/crm/src/views/contact/detail.js @@ -21,48 +21,48 @@ Espo.define('Crm:Views.Contact.Detail', 'Views.Detail', function (Dep) { - return Dep.extend({ + return Dep.extend({ - relatedAttributeMap: { - 'opportunities': { - 'accountId': 'accountId', - 'accountName': 'accountName' - }, - 'cases': { - 'accountId': 'accountId', - 'accountName': 'accountName' - }, - }, - - selectRelatedFilters: { - 'cases': { - 'account': function () { - if (this.model.get('accountId')) { - return { - field: 'accountId', - type: 'equals', - value: this.model.get('accountId'), - valueName: this.model.get('accountName') - }; - } - }, - - }, - 'opportunities': { - 'account': function () { - if (this.model.get('accountId')) { - return { - field: 'accountId', - type: 'equals', - value: this.model.get('accountId'), - valueName: this.model.get('accountName') - }; - } - }, - - }, - }, - - }); + relatedAttributeMap: { + 'opportunities': { + 'accountId': 'accountId', + 'accountName': 'accountName' + }, + 'cases': { + 'accountId': 'accountId', + 'accountName': 'accountName' + }, + }, + + selectRelatedFilters: { + 'cases': { + 'account': function () { + if (this.model.get('accountId')) { + return { + field: 'accountId', + type: 'equals', + value: this.model.get('accountId'), + valueName: this.model.get('accountName') + }; + } + }, + + }, + 'opportunities': { + 'account': function () { + if (this.model.get('accountId')) { + return { + field: 'accountId', + type: 'equals', + value: this.model.get('accountId'), + valueName: this.model.get('accountName') + }; + } + }, + + }, + }, + + }); }); diff --git a/frontend/client/modules/crm/src/views/contact/fields/accounts.js b/frontend/client/modules/crm/src/views/contact/fields/accounts.js index 95e1297567..da771f5d1b 100644 --- a/frontend/client/modules/crm/src/views/contact/fields/accounts.js +++ b/frontend/client/modules/crm/src/views/contact/fields/accounts.js @@ -21,144 +21,144 @@ Espo.define('Crm:Views.Contact.Fields.Accounts', 'Views.Fields.LinkMultipleWithRole', function (Dep) { - return Dep.extend({ - - roleType: 'varchar', - - events: { - 'click [data-action="switchPrimary"]': function (e) { - $target = $(e.currentTarget); - var id = $target.data('id'); - - if (!$target.hasClass('active')) { - this.$el.find('button[data-action="switchPrimary"]').removeClass('active').children().addClass('text-muted'); - $target.addClass('active').children().removeClass('text-muted'); - this.setPrimaryId(id); - } - } - }, - - getAttributeList: function () { - var list = Dep.prototype.getAttributeList.call(this); - list.push('accountId'); - list.push('accountName'); - list.push('title'); - return list; - }, - - setup: function () { - Dep.prototype.setup.call(this); - - this.primaryIdFieldName = 'accountId'; - this.primaryNameFieldName = 'accountName'; - this.primaryRoleFieldName = 'title'; - - this.primaryId = this.model.get(this.primaryIdFieldName); - this.primaryName = this.model.get(this.primaryNameFieldName); - - this.listenTo(this.model, 'change:' + this.primaryIdFieldName, function () { - this.primaryId = this.model.get(this.primaryIdFieldName); - this.primaryName = this.model.get(this.primaryNameFieldName); - }.bind(this)); - }, - - setPrimaryId: function (id) { - this.primaryId = id; - if (id) { - this.primaryName = this.nameHash[id]; - } else { - this.primaryName = null; - } - - this.trigger('change'); - }, - - renderLinks: function () { - if (this.primaryId) { - this.addLinkHtml(this.primaryId, this.primaryName); - } - this.ids.forEach(function (id) { - if (id != this.primaryId) { - this.addLinkHtml(id, this.nameHash[id]); - } - }, this); - }, - - getValueForDisplay: function () { - if (this.mode == 'detail' || this.mode == 'list') { - var names = []; - if (this.primaryId) { - names.push(this.getDetailLinkHtml(this.primaryId, this.primaryName)); - } - this.ids.forEach(function (id) { - if (id != this.primaryId) { - names.push(this.getDetailLinkHtml(id)); - } - }, this); - return names.join(''); - } - }, - - deleteLink: function (id) { - if (id == this.primaryId) { - this.setPrimaryId(null); - } - Dep.prototype.deleteLink.call(this, id); - }, - - deleteLinkHtml: function (id) { - Dep.prototype.deleteLinkHtml.call(this, id); - this.managePrimaryButton(); - }, - - addLinkHtml: function (id, name) { - if (this.mode == 'search') { - return Dep.prototype.addLinkHtml.call(this, id, name); - } - - $el = Dep.prototype.addLinkHtml.call(this, id, name); - - var isPrimary = (id == this.primaryId); - - var iconHtml = ''; - var title = this.translate('Primary'); - - var $primary = $(''); - $primary.insertAfter($el.children().first().children().first()); - this.managePrimaryButton(); - }, - - afterRender: function () { - Dep.prototype.afterRender.call(this); - }, - - managePrimaryButton: function () { - var $primary = this.$el.find('button[data-action="switchPrimary"]'); - if ($primary.size() > 1) { - $primary.removeClass('hidden'); - } else { - $primary.addClass('hidden'); - } - - if ($primary.filter('.active').size() == 0) { - var $first = $primary.first(); - if ($first.size()) { - $first.addClass('active').children().removeClass('text-muted'); - this.setPrimaryId($first.data('id')); - } - } - }, - - fetch: function () { - var data = Dep.prototype.fetch.call(this); - - data[this.primaryIdFieldName] = this.primaryId; - data[this.primaryNameFieldName] = this.primaryName; - data[this.primaryRoleFieldName] = (this.columns[this.primaryId] || {}).role || ''; - - return data; - }, + return Dep.extend({ + + roleType: 'varchar', + + events: { + 'click [data-action="switchPrimary"]': function (e) { + $target = $(e.currentTarget); + var id = $target.data('id'); + + if (!$target.hasClass('active')) { + this.$el.find('button[data-action="switchPrimary"]').removeClass('active').children().addClass('text-muted'); + $target.addClass('active').children().removeClass('text-muted'); + this.setPrimaryId(id); + } + } + }, + + getAttributeList: function () { + var list = Dep.prototype.getAttributeList.call(this); + list.push('accountId'); + list.push('accountName'); + list.push('title'); + return list; + }, + + setup: function () { + Dep.prototype.setup.call(this); + + this.primaryIdFieldName = 'accountId'; + this.primaryNameFieldName = 'accountName'; + this.primaryRoleFieldName = 'title'; + + this.primaryId = this.model.get(this.primaryIdFieldName); + this.primaryName = this.model.get(this.primaryNameFieldName); + + this.listenTo(this.model, 'change:' + this.primaryIdFieldName, function () { + this.primaryId = this.model.get(this.primaryIdFieldName); + this.primaryName = this.model.get(this.primaryNameFieldName); + }.bind(this)); + }, + + setPrimaryId: function (id) { + this.primaryId = id; + if (id) { + this.primaryName = this.nameHash[id]; + } else { + this.primaryName = null; + } + + this.trigger('change'); + }, + + renderLinks: function () { + if (this.primaryId) { + this.addLinkHtml(this.primaryId, this.primaryName); + } + this.ids.forEach(function (id) { + if (id != this.primaryId) { + this.addLinkHtml(id, this.nameHash[id]); + } + }, this); + }, + + getValueForDisplay: function () { + if (this.mode == 'detail' || this.mode == 'list') { + var names = []; + if (this.primaryId) { + names.push(this.getDetailLinkHtml(this.primaryId, this.primaryName)); + } + this.ids.forEach(function (id) { + if (id != this.primaryId) { + names.push(this.getDetailLinkHtml(id)); + } + }, this); + return names.join(''); + } + }, + + deleteLink: function (id) { + if (id == this.primaryId) { + this.setPrimaryId(null); + } + Dep.prototype.deleteLink.call(this, id); + }, + + deleteLinkHtml: function (id) { + Dep.prototype.deleteLinkHtml.call(this, id); + this.managePrimaryButton(); + }, + + addLinkHtml: function (id, name) { + if (this.mode == 'search') { + return Dep.prototype.addLinkHtml.call(this, id, name); + } + + $el = Dep.prototype.addLinkHtml.call(this, id, name); + + var isPrimary = (id == this.primaryId); + + var iconHtml = ''; + var title = this.translate('Primary'); + + var $primary = $(''); + $primary.insertAfter($el.children().first().children().first()); + this.managePrimaryButton(); + }, + + afterRender: function () { + Dep.prototype.afterRender.call(this); + }, + + managePrimaryButton: function () { + var $primary = this.$el.find('button[data-action="switchPrimary"]'); + if ($primary.size() > 1) { + $primary.removeClass('hidden'); + } else { + $primary.addClass('hidden'); + } + + if ($primary.filter('.active').size() == 0) { + var $first = $primary.first(); + if ($first.size()) { + $first.addClass('active').children().removeClass('text-muted'); + this.setPrimaryId($first.data('id')); + } + } + }, + + fetch: function () { + var data = Dep.prototype.fetch.call(this); + + data[this.primaryIdFieldName] = this.primaryId; + data[this.primaryNameFieldName] = this.primaryName; + data[this.primaryRoleFieldName] = (this.columns[this.primaryId] || {}).role || ''; + + return data; + }, - }); + }); }); diff --git a/frontend/client/modules/crm/src/views/dashlets/abstract/chart.js b/frontend/client/modules/crm/src/views/dashlets/abstract/chart.js index 24349963aa..5f7980df49 100644 --- a/frontend/client/modules/crm/src/views/dashlets/abstract/chart.js +++ b/frontend/client/modules/crm/src/views/dashlets/abstract/chart.js @@ -21,95 +21,95 @@ Espo.define('Crm:Views.Dashlets.Abstract.Chart', ['Views.Dashlets.Abstract.Base','lib!Flotr'], function (Dep, Flotr) { - return Dep.extend({ - - _template: '
    ', - - decimalMark: '.', - - thousandSeparator: ',', - - colors: ['#6FA8D6', '#4E6CAD', '#EDC555', '#ED8F42', '#DE6666', '#7CC4A4', '#8A7CC2', '#D4729B'], - - successColor: '#5ABD37', - - init: function () { - Dep.prototype.init.call(this); - - this.flotr = Flotr; - - if (this.getPreferences().has('decimalMark')) { - this.decimalMark = this.getPreferences().get('decimalMark') - } else { - if (this.getConfig().has('decimalMark')) { - this.decimalMark = this.getConfig().get('decimalMark') - } - } - if (this.getPreferences().has('thousandSeparator')) { - this.thousandSeparator = this.getPreferences().get('thousandSeparator') - } else { - if (this.getConfig().has('thousandSeparator')) { - this.thousandSeparator = this.getConfig().get('thousandSeparator') - } - } - - this.once('after:render', function () { - $(window).on('resize.chart' + this.name, function () { - this.drow(); - }.bind(this)); - }, this); - - this.once('remove', function () { - $(window).off('resize.chart' + this.name) - }, this); - }, - - formatNumber: function (value) { - if (value !== null) { - var parts = value.toString().split("."); - parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, this.thousandSeparator); - if (parts[1] == 0) { - parts.splice(1, 1); - } - return parts.join(this.decimalMark); - } - return ''; - }, - - afterRender: function () { - this.fetch(function (data) { - this.chartData = this.prepareData(data); - - var $container = this.$container = this.$el.find('.chart-container'); - - var height = '245px'; - if (this.chartData.length > 5) { - height = '215px'; - } - $container.css('height', height); - - setTimeout(function () { - this.drow(); - }.bind(this), 1); - }); - }, - - url: function () {}, - - prepareData: function (response) { - return response; - }, - - fetch: function (callback) { - $.ajax({ - type: 'get', - url: this.url(), - success: function (response) { - callback.call(this, response); - }.bind(this) - }); - }, + return Dep.extend({ + + _template: '
    ', + + decimalMark: '.', + + thousandSeparator: ',', + + colors: ['#6FA8D6', '#4E6CAD', '#EDC555', '#ED8F42', '#DE6666', '#7CC4A4', '#8A7CC2', '#D4729B'], + + successColor: '#5ABD37', + + init: function () { + Dep.prototype.init.call(this); + + this.flotr = Flotr; + + if (this.getPreferences().has('decimalMark')) { + this.decimalMark = this.getPreferences().get('decimalMark') + } else { + if (this.getConfig().has('decimalMark')) { + this.decimalMark = this.getConfig().get('decimalMark') + } + } + if (this.getPreferences().has('thousandSeparator')) { + this.thousandSeparator = this.getPreferences().get('thousandSeparator') + } else { + if (this.getConfig().has('thousandSeparator')) { + this.thousandSeparator = this.getConfig().get('thousandSeparator') + } + } + + this.once('after:render', function () { + $(window).on('resize.chart' + this.name, function () { + this.drow(); + }.bind(this)); + }, this); + + this.once('remove', function () { + $(window).off('resize.chart' + this.name) + }, this); + }, + + formatNumber: function (value) { + if (value !== null) { + var parts = value.toString().split("."); + parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, this.thousandSeparator); + if (parts[1] == 0) { + parts.splice(1, 1); + } + return parts.join(this.decimalMark); + } + return ''; + }, + + afterRender: function () { + this.fetch(function (data) { + this.chartData = this.prepareData(data); + + var $container = this.$container = this.$el.find('.chart-container'); + + var height = '245px'; + if (this.chartData.length > 5) { + height = '215px'; + } + $container.css('height', height); + + setTimeout(function () { + this.drow(); + }.bind(this), 1); + }); + }, + + url: function () {}, + + prepareData: function (response) { + return response; + }, + + fetch: function (callback) { + $.ajax({ + type: 'get', + url: this.url(), + success: function (response) { + callback.call(this, response); + }.bind(this) + }); + }, - }); + }); }); diff --git a/frontend/client/modules/crm/src/views/dashlets/calendar.js b/frontend/client/modules/crm/src/views/dashlets/calendar.js index 8e78b5b5ee..2337dd950d 100644 --- a/frontend/client/modules/crm/src/views/dashlets/calendar.js +++ b/frontend/client/modules/crm/src/views/dashlets/calendar.js @@ -21,22 +21,22 @@ Espo.define('Crm:Views.Dashlets.Calendar', 'Views.Dashlets.Abstract.Base', function (Dep) { - return Dep.extend({ + return Dep.extend({ - name: 'Calendar', + name: 'Calendar', - _template: '
    {{{calendar}}}
    ', + _template: '
    {{{calendar}}}
    ', - setup: function () { - this.createView('calendar', 'Crm:Calendar.Calendar', { - mode: 'agendaWeek', - el: this.$el.selector + ' > .calendar-container', - header: false, - height: 296, - }); - }, + setup: function () { + this.createView('calendar', 'Crm:Calendar.Calendar', { + mode: 'agendaWeek', + el: this.$el.selector + ' > .calendar-container', + header: false, + height: 296, + }); + }, - }); + }); }); diff --git a/frontend/client/modules/crm/src/views/dashlets/calls.js b/frontend/client/modules/crm/src/views/dashlets/calls.js index 033257ac54..127eae16d9 100644 --- a/frontend/client/modules/crm/src/views/dashlets/calls.js +++ b/frontend/client/modules/crm/src/views/dashlets/calls.js @@ -21,63 +21,63 @@ Espo.define('Crm:Views.Dashlets.Calls', 'Views.Dashlets.Abstract.RecordList', function (Dep) { - return Dep.extend({ + return Dep.extend({ - name: 'Calls', + name: 'Calls', - scope: 'Call', + scope: 'Call', - defaultOptions: { - sortBy: 'createdAt', - asc: false, - displayRecords: 5, - columnLayout: [ - { - name: 'name', - link: true, - sortable: false, - width: 40, - }, - { - name: 'status', - sortable: false, - }, - { - name: 'dateStart', - sortable: false, - } - ], - expandedLayout: { - rows: [ - [ - { - name: 'name', - link: true, - } - ], - [ - { - name: 'status' - }, - { - name: 'dateStart' - } - ] - ] - }, - searchData: { - bool: { - onlyMy: true, - }, - advanced: { - status: { - type: 'notIn', - value: ['Held', 'Not Held'] - } - } - }, - }, + defaultOptions: { + sortBy: 'createdAt', + asc: false, + displayRecords: 5, + columnLayout: [ + { + name: 'name', + link: true, + sortable: false, + width: 40, + }, + { + name: 'status', + sortable: false, + }, + { + name: 'dateStart', + sortable: false, + } + ], + expandedLayout: { + rows: [ + [ + { + name: 'name', + link: true, + } + ], + [ + { + name: 'status' + }, + { + name: 'dateStart' + } + ] + ] + }, + searchData: { + bool: { + onlyMy: true, + }, + advanced: { + status: { + type: 'notIn', + value: ['Held', 'Not Held'] + } + } + }, + }, - }); + }); }); diff --git a/frontend/client/modules/crm/src/views/dashlets/cases.js b/frontend/client/modules/crm/src/views/dashlets/cases.js index 21cf241833..56b986ce9c 100644 --- a/frontend/client/modules/crm/src/views/dashlets/cases.js +++ b/frontend/client/modules/crm/src/views/dashlets/cases.js @@ -22,73 +22,56 @@ Espo.define('Crm:Views.Dashlets.Cases', 'Views.Dashlets.Abstract.RecordList', function (Dep) { - return Dep.extend({ + return Dep.extend({ - name: 'Cases', + name: 'Cases', - scope: 'Case', + scope: 'Case', - defaultOptions: { - sortBy: 'number', - asc: false, - displayRecords: 5, - columnLayout: [ - { - name: 'name', - link: true, - sortable: false, - width: 40, - }, - { - name: 'type', - }, - { - name: 'status', - }, - { - name: 'priority', - } - ], - expandedLayout: { - rows: [ - [ - { - name: 'name', - link: true, - }, - { - name: 'number', - }, - { - name: 'type', - }, - ], - [ - { - name: 'status' - }, - { - name: 'priority' - } - ] - ] - }, - searchData: { - bool: { - onlyMy: true, - open: true, - }, - advanced: { - status: { - type: 'notIn', - value: ['Duplicate', 'Rejected', 'Closed'] - }, - }, + defaultOptions: { + sortBy: 'number', + asc: false, + displayRecords: 5, + expandedLayout: { + rows: [ + [ + { + name: 'name', + link: true, + }, + { + name: 'number', + }, + { + name: 'type', + }, + ], + [ + { + name: 'status' + }, + { + name: 'priority' + } + ] + ] + }, + searchData: { + bool: { + onlyMy: true, + open: true, + }, + advanced: { + status: { + type: 'notIn', + value: ['Duplicate', 'Rejected', 'Closed'] + }, + }, - }, - }, + }, + }, - }); + }); }); diff --git a/frontend/client/modules/crm/src/views/dashlets/leads.js b/frontend/client/modules/crm/src/views/dashlets/leads.js index e6f139e680..cc2c6fd39e 100644 --- a/frontend/client/modules/crm/src/views/dashlets/leads.js +++ b/frontend/client/modules/crm/src/views/dashlets/leads.js @@ -21,67 +21,51 @@ Espo.define('Crm:Views.Dashlets.Leads', 'Views.Dashlets.Abstract.RecordList', function (Dep) { - return Dep.extend({ + return Dep.extend({ - name: 'Leads', + name: 'Leads', - scope: 'Lead', + scope: 'Lead', - defaultOptions: { - sortBy: 'createdAt', - asc: false, - displayRecords: 5, - columnLayout: [ - { - name: 'name', - link: true, - sortable: false, - width: 40, - }, - { - name: 'email', - sortable: false, - }, - { - name: 'phone', - sortable: false, - } - ], - expandedLayout: { - rows: [ - [ - { - name: 'name', - link: true, - }, - { - name: 'addressCity' - } - ], - [ - { - name: 'status' - }, - { - name: 'source' - } - ] - ] - }, - searchData: { - bool: { - onlyMy: true, - }, - advanced: { - status: { - type: 'notIn', - value: ['Converted', 'Hoax', 'Dead'] - }, - }, + defaultOptions: { + sortBy: 'createdAt', + asc: false, + displayRecords: 5, + expandedLayout: { + rows: [ + [ + { + name: 'name', + link: true, + }, + { + name: 'addressCity' + } + ], + [ + { + name: 'status' + }, + { + name: 'source' + } + ] + ] + }, + searchData: { + bool: { + onlyMy: true, + }, + advanced: { + status: { + type: 'notIn', + value: ['Converted', 'Hoax', 'Dead'] + }, + }, - }, - }, + }, + }, - }); + }); }); diff --git a/frontend/client/modules/crm/src/views/dashlets/meetings.js b/frontend/client/modules/crm/src/views/dashlets/meetings.js index 811433fe2a..9a367d6c20 100644 --- a/frontend/client/modules/crm/src/views/dashlets/meetings.js +++ b/frontend/client/modules/crm/src/views/dashlets/meetings.js @@ -21,63 +21,47 @@ Espo.define('Crm:Views.Dashlets.Meetings', 'Views.Dashlets.Abstract.RecordList', function (Dep) { - return Dep.extend({ + return Dep.extend({ - name: 'Meetings', + name: 'Meetings', - scope: 'Meeting', + scope: 'Meeting', - defaultOptions: { - sortBy: 'createdAt', - asc: false, - displayRecords: 5, - columnLayout: [ - { - name: 'name', - link: true, - sortable: false, - width: 40, - }, - { - name: 'status', - sortable: false, - }, - { - name: 'dateStart', - sortable: false, - } - ], - expandedLayout: { - rows: [ - [ - { - name: 'name', - link: true, - } - ], - [ - { - name: 'status' - }, - { - name: 'dateStart' - } - ] - ] - }, - searchData: { - bool: { - onlyMy: true, - }, - advanced: { - status: { - type: 'notIn', - value: ['Held', 'Not Held'] - } - } - }, - }, + defaultOptions: { + sortBy: 'createdAt', + asc: false, + displayRecords: 5, + expandedLayout: { + rows: [ + [ + { + name: 'name', + link: true, + } + ], + [ + { + name: 'status' + }, + { + name: 'dateStart' + } + ] + ] + }, + searchData: { + bool: { + onlyMy: true, + }, + advanced: { + status: { + type: 'notIn', + value: ['Held', 'Not Held'] + } + } + }, + }, - }); + }); }); diff --git a/frontend/client/modules/crm/src/views/dashlets/opportunities-by-lead-source.js b/frontend/client/modules/crm/src/views/dashlets/opportunities-by-lead-source.js index e8a407bb2f..25eca93ed5 100644 --- a/frontend/client/modules/crm/src/views/dashlets/opportunities-by-lead-source.js +++ b/frontend/client/modules/crm/src/views/dashlets/opportunities-by-lead-source.js @@ -21,95 +21,95 @@ Espo.define('Crm:Views.Dashlets.OpportunitiesByLeadSource', 'Crm:Views.Dashlets.Abstract.Chart', function (Dep) { - return Dep.extend({ + return Dep.extend({ - name: 'OpportunitiesByLeadSource', - - - optionsFields: _.extend(_.clone(Dep.prototype.optionsFields), { - 'dateFrom': { - type: 'date', - required: true, - }, - 'dateTo': { - type: 'date', - required: true, - } - }), - - defaultOptions: { - dateFrom: function () { - return moment().format('YYYY') + '-01-01' - }, - dateTo: function () { - return moment().format('YYYY') + '-12-31' - }, - }, - - url: function () { - return 'Opportunity/action/reportByLeadSource?dateFrom=' + this.getOption('dateFrom') + '&dateTo=' + this.getOption('dateTo'); - }, - - prepareData: function (response) { - var data = []; - for (var label in response) { - var value = response[label]; - data.push({ - label: this.getLanguage().translateOption(label, 'leadSource', 'Opportunity'), - data: [[0, value]] - }); - } - return data; - }, - - setup: function () { - this.currency = this.getConfig().get('defaultCurrency'); - this.currencySymbol = ''; - }, - - drow: function () { - var self = this; - this.flotr.draw(this.$container.get(0), this.chartData, { - colors: this.colors, - shadowSize: false, - pie: { - show: true, - explode: 4, - lineWidth: 1, - fillOpacity: 1, - sizeRatio: 0.8, - }, - grid: { - horizontalLines: false, - verticalLines: false, - outline: 's' - }, - yaxis: { - showLabels: false, - }, - xaxis: { - showLabels: false, - }, - legend: { - show: false, - }, - mouse: { - track: true, - relative: true, - trackFormatter: function (obj) { - return self.formatNumber(obj.y) + ' ' + self.currency; - }, - }, - legend: { - show: true, - noColumns: 8, - container: this.$el.find('.legend-container'), - labelBoxMargin: 0 - }, - }); - }, + name: 'OpportunitiesByLeadSource', + + + optionsFields: _.extend(_.clone(Dep.prototype.optionsFields), { + 'dateFrom': { + type: 'date', + required: true, + }, + 'dateTo': { + type: 'date', + required: true, + } + }), + + defaultOptions: { + dateFrom: function () { + return moment().format('YYYY') + '-01-01' + }, + dateTo: function () { + return moment().format('YYYY') + '-12-31' + }, + }, + + url: function () { + return 'Opportunity/action/reportByLeadSource?dateFrom=' + this.getOption('dateFrom') + '&dateTo=' + this.getOption('dateTo'); + }, + + prepareData: function (response) { + var data = []; + for (var label in response) { + var value = response[label]; + data.push({ + label: this.getLanguage().translateOption(label, 'leadSource', 'Opportunity'), + data: [[0, value]] + }); + } + return data; + }, + + setup: function () { + this.currency = this.getConfig().get('defaultCurrency'); + this.currencySymbol = ''; + }, + + drow: function () { + var self = this; + this.flotr.draw(this.$container.get(0), this.chartData, { + colors: this.colors, + shadowSize: false, + pie: { + show: true, + explode: 0, + lineWidth: 1, + fillOpacity: 1, + sizeRatio: 0.8, + }, + grid: { + horizontalLines: false, + verticalLines: false, + outline: 's' + }, + yaxis: { + showLabels: false, + }, + xaxis: { + showLabels: false, + }, + legend: { + show: false, + }, + mouse: { + track: true, + relative: true, + trackFormatter: function (obj) { + return self.formatNumber(obj.y) + ' ' + self.currency; + }, + }, + legend: { + show: true, + noColumns: 8, + container: this.$el.find('.legend-container'), + labelBoxMargin: 0 + }, + }); + }, - }); + }); }); diff --git a/frontend/client/modules/crm/src/views/dashlets/opportunities-by-stage.js b/frontend/client/modules/crm/src/views/dashlets/opportunities-by-stage.js index ce9139c119..4ba224befe 100644 --- a/frontend/client/modules/crm/src/views/dashlets/opportunities-by-stage.js +++ b/frontend/client/modules/crm/src/views/dashlets/opportunities-by-stage.js @@ -21,117 +21,117 @@ Espo.define('Crm:Views.Dashlets.OpportunitiesByStage', 'Crm:Views.Dashlets.Abstract.Chart', function (Dep) { - return Dep.extend({ + return Dep.extend({ - name: 'OpportunitiesByStage', - - optionsFields: _.extend(_.clone(Dep.prototype.optionsFields), { - 'dateFrom': { - type: 'date', - required: true, - }, - 'dateTo': { - type: 'date', - required: true, - } - }), - - defaultOptions: { - dateFrom: function () { - return moment().format('YYYY') + '-01-01' - }, - dateTo: function () { - return moment().format('YYYY') + '-12-31' - }, - }, - - url: function () { - return 'Opportunity/action/reportByStage?dateFrom=' + this.getOption('dateFrom') + '&dateTo=' + this.getOption('dateTo'); - }, - - prepareData: function (response) { - var d = []; - for (var label in response) { - var value = response[label]; - d.push({ - stage: label, - value: value - }); - } - - this.stageList = []; - - var data = []; - var i = 0; - d.forEach(function (item) { - var o = { - data: [[item.value, d.length - i]], - label: this.getLanguage().translateOption(item.stage, 'stage', 'Opportunity'), - } - if (item.stage == 'Closed Won') { - o.color = this.successColor; - } - data.push(o); - this.stageList.push(this.getLanguage().translateOption(item.stage, 'stage', 'Opportunity')); - i++; - }, this); - - return data; - }, - - setup: function () { - this.currency = this.getConfig().get('defaultCurrency'); - this.currencySymbol = ''; - }, - - drow: function () { - var self = this; - this.flotr.draw(this.$container.get(0), this.chartData, { - colors: this.colors, - shadowSize: false, - bars: { - show: true, - horizontal: true, - shadowSize: 0, - lineWidth: 1, - fillOpacity: 1, - barWidth: 0.5, - }, - grid: { - horizontalLines: false, - outline: 'sw' - }, - yaxis: { - min: 0, - showLabels: false, - }, - xaxis: { - min: 0, - tickFormatter: function (value) { - if (value != 0) { - return self.formatNumber(value) + ' ' + self.currency; - } - return ''; - }, - }, - mouse: { - track: true, - relative: true, - position: 's', - trackFormatter: function (obj) { - return self.formatNumber(obj.x) + ' ' + self.currency; - }, - }, - legend: { - show: true, - noColumns: 5, - container: this.$el.find('.legend-container'), - labelBoxMargin: 0 - }, - }); - }, + name: 'OpportunitiesByStage', + + optionsFields: _.extend(_.clone(Dep.prototype.optionsFields), { + 'dateFrom': { + type: 'date', + required: true, + }, + 'dateTo': { + type: 'date', + required: true, + } + }), + + defaultOptions: { + dateFrom: function () { + return moment().format('YYYY') + '-01-01' + }, + dateTo: function () { + return moment().format('YYYY') + '-12-31' + }, + }, + + url: function () { + return 'Opportunity/action/reportByStage?dateFrom=' + this.getOption('dateFrom') + '&dateTo=' + this.getOption('dateTo'); + }, + + prepareData: function (response) { + var d = []; + for (var label in response) { + var value = response[label]; + d.push({ + stage: label, + value: value + }); + } + + this.stageList = []; + + var data = []; + var i = 0; + d.forEach(function (item) { + var o = { + data: [[item.value, d.length - i]], + label: this.getLanguage().translateOption(item.stage, 'stage', 'Opportunity'), + } + if (item.stage == 'Closed Won') { + o.color = this.successColor; + } + data.push(o); + this.stageList.push(this.getLanguage().translateOption(item.stage, 'stage', 'Opportunity')); + i++; + }, this); + + return data; + }, + + setup: function () { + this.currency = this.getConfig().get('defaultCurrency'); + this.currencySymbol = ''; + }, + + drow: function () { + var self = this; + this.flotr.draw(this.$container.get(0), this.chartData, { + colors: this.colors, + shadowSize: false, + bars: { + show: true, + horizontal: true, + shadowSize: 0, + lineWidth: 1, + fillOpacity: 1, + barWidth: 0.5, + }, + grid: { + horizontalLines: false, + outline: 'sw' + }, + yaxis: { + min: 0, + showLabels: false, + }, + xaxis: { + min: 0, + tickFormatter: function (value) { + if (value != 0) { + return self.formatNumber(value) + ' ' + self.currency; + } + return ''; + }, + }, + mouse: { + track: true, + relative: true, + position: 's', + trackFormatter: function (obj) { + return self.formatNumber(obj.x) + ' ' + self.currency; + }, + }, + legend: { + show: true, + noColumns: 5, + container: this.$el.find('.legend-container'), + labelBoxMargin: 0 + }, + }); + }, - }); + }); }); diff --git a/frontend/client/modules/crm/src/views/dashlets/opportunities.js b/frontend/client/modules/crm/src/views/dashlets/opportunities.js index b1ff1099c4..c32c263735 100644 --- a/frontend/client/modules/crm/src/views/dashlets/opportunities.js +++ b/frontend/client/modules/crm/src/views/dashlets/opportunities.js @@ -21,62 +21,46 @@ Espo.define('Crm:Views.Dashlets.Opportunities', 'Views.Dashlets.Abstract.RecordList', function (Dep) { - return Dep.extend({ + return Dep.extend({ - name: 'Opportunities', + name: 'Opportunities', - scope: 'Opportunity', + scope: 'Opportunity', - defaultOptions: { - sortBy: 'createdAt', - asc: false, - displayRecords: 5, - columnLayout: [ - { - name: 'name', - link: true, - sortable: false, - width: 40, - }, - { - name: 'stage', - sortable: false, - }, - { - name: 'amount', - sortable: false, - } - ], - expandedLayout: { - rows: [ - [ - { - name: 'name', - link: true, - }, - { - name: 'account' - } - ], - [ - { - name: 'stage' - }, - { - name: 'amount' - } - ] - ] - }, - searchData: { - bool: { - onlyMy: true, - open: true, - } - }, - }, + defaultOptions: { + sortBy: 'createdAt', + asc: false, + displayRecords: 5, + expandedLayout: { + rows: [ + [ + { + name: 'name', + link: true, + }, + { + name: 'account' + } + ], + [ + { + name: 'stage' + }, + { + name: 'amount' + } + ] + ] + }, + searchData: { + bool: { + onlyMy: true, + open: true, + } + }, + }, - }); + }); }); diff --git a/frontend/client/modules/crm/src/views/dashlets/sales-by-month.js b/frontend/client/modules/crm/src/views/dashlets/sales-by-month.js index 97d5d5a169..369c30ff77 100644 --- a/frontend/client/modules/crm/src/views/dashlets/sales-by-month.js +++ b/frontend/client/modules/crm/src/views/dashlets/sales-by-month.js @@ -21,118 +21,118 @@ Espo.define('Crm:Views.Dashlets.SalesByMonth', 'Crm:Views.Dashlets.Abstract.Chart', function (Dep) { - return Dep.extend({ + return Dep.extend({ - name: 'SalesByMonth', - - optionsFields: _.extend(_.clone(Dep.prototype.optionsFields), { - 'dateFrom': { - type: 'date', - required: true, - }, - 'dateTo': { - type: 'date', - required: true, - } - }), - - defaultOptions: { - dateFrom: function () { - return moment().format('YYYY') + '-01-01' - }, - dateTo: function () { - return moment().format('YYYY') + '-12-31' - }, - }, - - url: function () { - return 'Opportunity/action/reportSalesByMonth?dateFrom=' + this.getOption('dateFrom') + '&dateTo=' + this.getOption('dateTo'); - }, - - prepareData: function (response) { - var months = this.months = Object.keys(response).sort(); - - var values = []; - - for (var month in response) { - values.push(response[month]); - } - - this.chartData = []; - - var mid = 0; - if (values.length) { - mid = values.reduce(function(a, b) {return a + b}) / values.length; - } - - var data = []; - - values.forEach(function (value, i) { - data.push({ - data: [[i, value]], - color: (value >= mid) ? this.successColor : this.colorBad - }); - }, this); - - return data; - }, - - setup: function () { - this.currency = this.getConfig().get('defaultCurrency'); - this.currencySymbol = ''; - - this.colorBad = this.successColor; - }, - - drow: function () { - var self = this; - this.flotr.draw(this.$container.get(0), this.chartData, { - shadowSize: false, - bars: { - show: true, - horizontal: false, - shadowSize: 0, - lineWidth: 1, - fillOpacity: 1, - barWidth: 0.5, - }, - grid: { - horizontalLines: true, - verticalLines: false, - outline: 'sw' - }, - yaxis: { - min: 0, - showLabels: true, - tickFormatter: function (value) { - if (value == 0) { - return ''; - } - return self.formatNumber(value) + ' ' + self.currency; - }, - }, - xaxis: { - min: 0, - tickFormatter: function (value) { - if (value % 1 == 0) { - var i = parseInt(value); - if (i in self.months) { - return moment(self.months[i] + '-01').format('MMM YYYY'); - } - } - return ''; - }, - }, - mouse: { - track: true, - relative: true, - trackFormatter: function (obj) { - return self.formatNumber(obj.y) + ' ' + self.currency; - }, - }, - }); - }, - }); + name: 'SalesByMonth', + + optionsFields: _.extend(_.clone(Dep.prototype.optionsFields), { + 'dateFrom': { + type: 'date', + required: true, + }, + 'dateTo': { + type: 'date', + required: true, + } + }), + + defaultOptions: { + dateFrom: function () { + return moment().format('YYYY') + '-01-01' + }, + dateTo: function () { + return moment().format('YYYY') + '-12-31' + }, + }, + + url: function () { + return 'Opportunity/action/reportSalesByMonth?dateFrom=' + this.getOption('dateFrom') + '&dateTo=' + this.getOption('dateTo'); + }, + + prepareData: function (response) { + var months = this.months = Object.keys(response).sort(); + + var values = []; + + for (var month in response) { + values.push(response[month]); + } + + this.chartData = []; + + var mid = 0; + if (values.length) { + mid = values.reduce(function(a, b) {return a + b}) / values.length; + } + + var data = []; + + values.forEach(function (value, i) { + data.push({ + data: [[i, value]], + color: (value >= mid) ? this.successColor : this.colorBad + }); + }, this); + + return data; + }, + + setup: function () { + this.currency = this.getConfig().get('defaultCurrency'); + this.currencySymbol = ''; + + this.colorBad = this.successColor; + }, + + drow: function () { + var self = this; + this.flotr.draw(this.$container.get(0), this.chartData, { + shadowSize: false, + bars: { + show: true, + horizontal: false, + shadowSize: 0, + lineWidth: 1, + fillOpacity: 1, + barWidth: 0.5, + }, + grid: { + horizontalLines: true, + verticalLines: false, + outline: 'sw' + }, + yaxis: { + min: 0, + showLabels: true, + tickFormatter: function (value) { + if (value == 0) { + return ''; + } + return self.formatNumber(value) + ' ' + self.currency; + }, + }, + xaxis: { + min: 0, + tickFormatter: function (value) { + if (value % 1 == 0) { + var i = parseInt(value); + if (i in self.months) { + return moment(self.months[i] + '-01').format('MMM YYYY'); + } + } + return ''; + }, + }, + mouse: { + track: true, + relative: true, + trackFormatter: function (obj) { + return self.formatNumber(obj.y) + ' ' + self.currency; + }, + }, + }); + }, + }); }); diff --git a/frontend/client/modules/crm/src/views/dashlets/sales-pipeline.js b/frontend/client/modules/crm/src/views/dashlets/sales-pipeline.js index f5eae726aa..6279dbf346 100644 --- a/frontend/client/modules/crm/src/views/dashlets/sales-pipeline.js +++ b/frontend/client/modules/crm/src/views/dashlets/sales-pipeline.js @@ -21,184 +21,184 @@ Espo.define('Crm:Views.Dashlets.SalesPipeline', 'Crm:Views.Dashlets.Abstract.Chart', function (Dep) { - return Dep.extend({ + return Dep.extend({ - name: 'SalesPipeline', - - optionsFields: _.extend(_.clone(Dep.prototype.optionsFields), { - 'dateFrom': { - type: 'date', - required: true, - }, - 'dateTo': { - type: 'date', - required: true, - } - }), - - defaultOptions: { - dateFrom: function () { - return moment().format('YYYY') + '-01-01' - }, - dateTo: function () { - return moment().format('YYYY') + '-12-31' - }, - }, - - url: function () { - return 'Opportunity/action/reportSalesPipeline?dateFrom=' + this.getOption('dateFrom') + '&dateTo=' + this.getOption('dateTo'); - }, - - prepareData: function (response) { - var d = []; - for (var label in response) { - var value = response[label]; - d.push({ - stage: this.getLanguage().translateOption(label, 'stage', 'Opportunity'), - value: value - }); - } - - var data = []; - for (var i = 0; i < d.length; i++) { - var item = d[i]; - var value = item.value; - var nextValue = ((i + 1) < d.length) ? d[i + 1].value : value; - data.push({ - data: [[i, value], [i + 1, nextValue]], - label: item.stage - }); - } - - this.maxY = 1000; - if (d.length) { - for (var i = 0; i < d.length; i++) { - var y = d[i].value + (d[i].value / 20); - if (y > this.maxY) { - this.maxY = y; - } - } - - } - - return data; - }, - - setup: function () { - this.currency = this.getConfig().get('defaultCurrency'); - this.currencySymbol = ''; - - var data = [ - { - value: 12000, - stage: 'Prospecting' - }, - { - value: 5050, - stage: 'Qualification' - }, - { - value: 4050, - stage: 'Needs Analysis' - }, - { - value: 3230, - stage: 'Value Proposition' - }, - { - value: 2000, - stage: 'Proposal/Price Quote' - }, - { - value: 1200.5, - stage: 'Negotiation/Review' - }, - { - value: 700, - stage: 'Closed Won' - }, - ]; - - this.chartData = []; - - for (var i = 0; i < data.length; i++) { - var item = data[i]; - var value = item.value; - var nextValue = ((i + 1) < data.length) ? data[i + 1].value : value; - var o = { - data: [[i, value], [i + 1, nextValue]], - label: item.stage - }; + name: 'SalesPipeline', + + optionsFields: _.extend(_.clone(Dep.prototype.optionsFields), { + 'dateFrom': { + type: 'date', + required: true, + }, + 'dateTo': { + type: 'date', + required: true, + } + }), + + defaultOptions: { + dateFrom: function () { + return moment().format('YYYY') + '-01-01' + }, + dateTo: function () { + return moment().format('YYYY') + '-12-31' + }, + }, + + url: function () { + return 'Opportunity/action/reportSalesPipeline?dateFrom=' + this.getOption('dateFrom') + '&dateTo=' + this.getOption('dateTo'); + }, + + prepareData: function (response) { + var d = []; + for (var label in response) { + var value = response[label]; + d.push({ + stage: this.getLanguage().translateOption(label, 'stage', 'Opportunity'), + value: value + }); + } + + var data = []; + for (var i = 0; i < d.length; i++) { + var item = d[i]; + var value = item.value; + var nextValue = ((i + 1) < d.length) ? d[i + 1].value : value; + data.push({ + data: [[i, value], [i + 1, nextValue]], + label: item.stage + }); + } + + this.maxY = 1000; + if (d.length) { + for (var i = 0; i < d.length; i++) { + var y = d[i].value + (d[i].value / 20); + if (y > this.maxY) { + this.maxY = y; + } + } + + } + + return data; + }, + + setup: function () { + this.currency = this.getConfig().get('defaultCurrency'); + this.currencySymbol = ''; + + var data = [ + { + value: 12000, + stage: 'Prospecting' + }, + { + value: 5050, + stage: 'Qualification' + }, + { + value: 4050, + stage: 'Needs Analysis' + }, + { + value: 3230, + stage: 'Value Proposition' + }, + { + value: 2000, + stage: 'Proposal/Price Quote' + }, + { + value: 1200.5, + stage: 'Negotiation/Review' + }, + { + value: 700, + stage: 'Closed Won' + }, + ]; + + this.chartData = []; + + for (var i = 0; i < data.length; i++) { + var item = data[i]; + var value = item.value; + var nextValue = ((i + 1) < data.length) ? data[i + 1].value : value; + var o = { + data: [[i, value], [i + 1, nextValue]], + label: item.stage + }; - this.chartData.push(o); - } - - this.maxY = 1000; - if (data.length) { - this.maxY = data[0].value + (data[0].value / 20); - } - }, - - drow: function () { - var self = this; - - var colors = Espo.Utils.clone(this.colors); - - this.chartData.forEach(function (item, i) { - if (i + 1 > colors.length) { - colors.push('#164'); - } - if (this.chartData.length == i + 1) { - colors[i] = this.successColor; - } - }, this); - - - this.flotr.draw(this.$container.get(0), this.chartData, { - colors: colors, - shadowSize: false, - lines: { - show: true, - fill: true, - fillOpacity: 1, - }, - points: { - show: true, - }, - grid: { - horizontalLines: false, - outline: 'sw' - }, - yaxis: { - min: 0, - max: this.maxY, - showLabels: false, - }, - xaxis: { - min: 0, - showLabels: false, - }, - mouse: { - track: true, - relative: true, - position: 'ne', - trackFormatter: function (obj) { - if (obj.x >= self.chartData.length) { - return null; - } - return self.formatNumber(obj.y) + ' ' + self.currency; - }, - }, - legend: { - show: true, - noColumns: 5, - container: this.$el.find('.legend-container'), - labelBoxMargin: 0 - }, - }); - }, + this.chartData.push(o); + } + + this.maxY = 1000; + if (data.length) { + this.maxY = data[0].value + (data[0].value / 20); + } + }, + + drow: function () { + var self = this; + + var colors = Espo.Utils.clone(this.colors); + + this.chartData.forEach(function (item, i) { + if (i + 1 > colors.length) { + colors.push('#164'); + } + if (this.chartData.length == i + 1) { + colors[i] = this.successColor; + } + }, this); + + + this.flotr.draw(this.$container.get(0), this.chartData, { + colors: colors, + shadowSize: false, + lines: { + show: true, + fill: true, + fillOpacity: 1, + }, + points: { + show: true, + }, + grid: { + horizontalLines: false, + outline: 'sw' + }, + yaxis: { + min: 0, + max: this.maxY, + showLabels: false, + }, + xaxis: { + min: 0, + showLabels: false, + }, + mouse: { + track: true, + relative: true, + position: 'ne', + trackFormatter: function (obj) { + if (obj.x >= self.chartData.length) { + return null; + } + return self.formatNumber(obj.y) + ' ' + self.currency; + }, + }, + legend: { + show: true, + noColumns: 5, + container: this.$el.find('.legend-container'), + labelBoxMargin: 0 + }, + }); + }, - }); + }); }); diff --git a/frontend/client/modules/crm/src/views/dashlets/tasks.js b/frontend/client/modules/crm/src/views/dashlets/tasks.js index abc03443af..78c72ca651 100644 --- a/frontend/client/modules/crm/src/views/dashlets/tasks.js +++ b/frontend/client/modules/crm/src/views/dashlets/tasks.js @@ -21,69 +21,49 @@ Espo.define('Crm:Views.Dashlets.Tasks', 'Views.Dashlets.Abstract.RecordList', function (Dep) { - return Dep.extend({ + return Dep.extend({ - name: 'Tasks', + name: 'Tasks', - scope: 'Task', + scope: 'Task', - defaultOptions: { - sortBy: 'createdAt', - asc: false, - displayRecords: 5, - columnLayout: [ - { - name: 'name', - link: true, - sortable: false, - width: 40, - }, - { - name: 'status', - sortable: false, - }, - { - name: 'priority', - sortable: false, - }, - { - name: 'dateEnd', - sortable: false, - } - ], - expandedLayout: { - rows: [ - [ - { - name: 'name', - link: true, - } - ], - [ - { - name: 'status' - }, - { - name: 'dateEnd' - } - ] - ] - }, - searchData: { - bool: { - onlyMy: true, - open: true, - }, - advanced: { - status: { - type: 'notIn', - value: ['Completed', 'Canceled'] - }, - }, + defaultOptions: { + sortBy: 'createdAt', + asc: false, + displayRecords: 5, + expandedLayout: { + rows: [ + [ + { + name: 'name', + link: true, + } + ], + [ + { + name: 'status' + }, + { + name: 'dateEnd' + } + ] + ] + }, + searchData: { + bool: { + onlyMy: true, + open: true, + }, + advanced: { + status: { + type: 'notIn', + value: ['Completed', 'Canceled'] + }, + }, - }, - }, + }, + }, - }); + }); }); diff --git a/frontend/client/modules/crm/src/views/document/fields/file-short.js b/frontend/client/modules/crm/src/views/document/fields/file-short.js index d497f67193..ca1a4ca925 100644 --- a/frontend/client/modules/crm/src/views/document/fields/file-short.js +++ b/frontend/client/modules/crm/src/views/document/fields/file-short.js @@ -21,22 +21,22 @@ Espo.define('Crm:Views.Document.Fields.FileShort', 'Views.Fields.File', function (Dep) { - return Dep.extend({ - - getValueForDisplay: function () { - if (this.mode == 'detail' || this.mode == 'list') { - var name = this.model.get(this.nameName); - var type = this.model.get(this.typeName) || this.defaultType; - var id = this.model.get(this.idName); - - if (!id) { - return false; - } + return Dep.extend({ + + getValueForDisplay: function () { + if (this.mode == 'detail' || this.mode == 'list') { + var name = this.model.get(this.nameName); + var type = this.model.get(this.typeName) || this.defaultType; + var id = this.model.get(this.idName); + + if (!id) { + return false; + } - return ''; - } - }, - - }); + return ''; + } + }, + + }); }); diff --git a/frontend/client/modules/crm/src/views/document/fields/name.js b/frontend/client/modules/crm/src/views/document/fields/name.js index 23a33e9a5a..edb3546e73 100644 --- a/frontend/client/modules/crm/src/views/document/fields/name.js +++ b/frontend/client/modules/crm/src/views/document/fields/name.js @@ -21,17 +21,17 @@ Espo.define('Crm:Views.Document.Fields.Name', 'Views.Fields.Varchar', function (Dep) { - return Dep.extend({ - - setup: function () { - Dep.prototype.setup.call(this); - if (this.model.isNew()) { - this.listenTo(this.model, 'change:fileName', function () { - this.model.set('name', this.model.get('fileName')); - }, this); - } - }, - - }); + return Dep.extend({ + + setup: function () { + Dep.prototype.setup.call(this); + if (this.model.isNew()) { + this.listenTo(this.model, 'change:fileName', function () { + this.model.set('name', this.model.get('fileName')); + }, this); + } + }, + + }); }); diff --git a/frontend/client/modules/crm/src/views/fields/ico.js b/frontend/client/modules/crm/src/views/fields/ico.js index a68ce9487a..faafb5fde7 100644 --- a/frontend/client/modules/crm/src/views/fields/ico.js +++ b/frontend/client/modules/crm/src/views/fields/ico.js @@ -20,27 +20,27 @@ ************************************************************************/ Espo.define('Crm:Views.Fields.Ico', 'Views.Fields.Base', function (Dep) { - return Dep.extend({ - - //detailTemplate: '', + return Dep.extend({ + + //detailTemplate: '', - setup: function () { - var tpl; - - switch (this.model.name) { - case 'Meeting': - tpl = ''; - break; - case 'Call': - tpl = ''; - break; - case 'Email': - tpl = ''; - break; - } - this._template = tpl; - }, + setup: function () { + var tpl; + + switch (this.model.name) { + case 'Meeting': + tpl = ''; + break; + case 'Call': + tpl = ''; + break; + case 'Email': + tpl = ''; + break; + } + this._template = tpl; + }, - }); + }); }); diff --git a/frontend/client/modules/crm/src/views/inbound-email/fields/folder.js b/frontend/client/modules/crm/src/views/inbound-email/fields/folder.js index 0c099930f1..8c503c7bc0 100644 --- a/frontend/client/modules/crm/src/views/inbound-email/fields/folder.js +++ b/frontend/client/modules/crm/src/views/inbound-email/fields/folder.js @@ -21,58 +21,58 @@ Espo.define('Crm:Views.InboundEmail.Fields.Folder', 'Views.Fields.Base', function (Dep) { - return Dep.extend({ - - editTemplate: 'crm:inbound-email.fields.folder.edit', - - events: { - 'click [data-action="selectFolder"]': function () { - var self = this; - - this.notify('Please wait...'); - - var data = { - host: this.model.get('host'), - port: this.model.get('port'), - ssl: this.model.get('ssl'), - username: this.model.get('username'), - }; - - if (this.model.has('password')) { - data.password = this.model.get('password'); - } else { - if (!this.model.isNew()) { - data.id = this.model.id; - } - } - - - $.ajax({ - type: 'GET', - url: 'InboundEmail/action/getFolders', - data: data, - error: function (xhr) { - Espo.Ui.error(self.translate('couldNotConnectToImap', 'messages', 'InboundEmail')); - xhr.errorIsHandled = true; - }, - }).done(function (folders) { - this.createView('modal', 'Crm:InboundEmail.Modals.SelectFolder', { - folders: folders - }, function (view) { - self.notify(false); - view.render(); - - self.listenToOnce(view, 'select', function (folder) { - view.close(); - self.addFolder(folder); - }); - }); - }.bind(this)); - } - }, - - addFolder: function (folder) { - this.$element.val(folder); - }, - }); + return Dep.extend({ + + editTemplate: 'crm:inbound-email.fields.folder.edit', + + events: { + 'click [data-action="selectFolder"]': function () { + var self = this; + + this.notify('Please wait...'); + + var data = { + host: this.model.get('host'), + port: this.model.get('port'), + ssl: this.model.get('ssl'), + username: this.model.get('username'), + }; + + if (this.model.has('password')) { + data.password = this.model.get('password'); + } else { + if (!this.model.isNew()) { + data.id = this.model.id; + } + } + + + $.ajax({ + type: 'GET', + url: 'InboundEmail/action/getFolders', + data: data, + error: function (xhr) { + Espo.Ui.error(self.translate('couldNotConnectToImap', 'messages', 'InboundEmail')); + xhr.errorIsHandled = true; + }, + }).done(function (folders) { + this.createView('modal', 'Crm:InboundEmail.Modals.SelectFolder', { + folders: folders + }, function (view) { + self.notify(false); + view.render(); + + self.listenToOnce(view, 'select', function (folder) { + view.close(); + self.addFolder(folder); + }); + }); + }.bind(this)); + } + }, + + addFolder: function (folder) { + this.$element.val(folder); + }, + }); }); diff --git a/frontend/client/modules/crm/src/views/inbound-email/fields/folders.js b/frontend/client/modules/crm/src/views/inbound-email/fields/folders.js index 8e9de5b89d..85fad8396e 100644 --- a/frontend/client/modules/crm/src/views/inbound-email/fields/folders.js +++ b/frontend/client/modules/crm/src/views/inbound-email/fields/folders.js @@ -21,20 +21,20 @@ Espo.define('Crm:Views.InboundEmail.Fields.Folders', 'Crm:Views.InboundEmail.Fields.Folder', function (Dep) { - return Dep.extend({ - - addFolder: function (folder) { - var value = this.$element.val(); - - var folders = []; - if (value != '') { - folders = value.split(','); - } - - if (!~folders.indexOf(folder)) { - folders.push(folder); - } - this.$element.val(folders.join(',')); - }, - }); + return Dep.extend({ + + addFolder: function (folder) { + var value = this.$element.val(); + + var folders = []; + if (value != '') { + folders = value.split(','); + } + + if (!~folders.indexOf(folder)) { + folders.push(folder); + } + this.$element.val(folders.join(',')); + }, + }); }); diff --git a/frontend/client/modules/crm/src/views/inbound-email/fields/target-user-position.js b/frontend/client/modules/crm/src/views/inbound-email/fields/target-user-position.js new file mode 100644 index 0000000000..3563e21611 --- /dev/null +++ b/frontend/client/modules/crm/src/views/inbound-email/fields/target-user-position.js @@ -0,0 +1,74 @@ +/************************************************************************ + * 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/. + ************************************************************************/ + +Espo.define('Crm:Views.InboundEmail.Fields.TargetUserPosition', 'Views.Fields.Enum', function (Dep) { + + return Dep.extend({ + + setup: function () { + Dep.prototype.setup.call(this); + + this.translatedOptions = { + '': '--' + this.translate('All') + '--' + }; + + this.params.options = ['']; + if (this.model.get('targetUserPosition') && this.model.get('teamId')) { + this.params.options.push(this.model.get('targetUserPosition')); + } + + this.loadRoleList(function () { + if (this.mode == 'edit') { + if (this.isRendered()) { + this.render(); + } + } + }, this); + + this.listenTo(this.model, 'change:teamId', function () { + this.loadRoleList(function () { + this.render(); + }, this); + }, this); + }, + + loadRoleList: function (callback, context) { + var teamId = this.model.get('teamId'); + if (!teamId) { + this.params.options = ['']; + } + + this.getModelFactory().create('Team', function (team) { + team.id = teamId; + + this.listenToOnce(team, 'sync', function () { + this.params.options = team.get('positionList') || []; + this.params.options.unshift(''); + callback.call(context); + }, this); + + team.fetch(); + }, this); + + }, + + }); +}); diff --git a/frontend/client/modules/crm/src/views/inbound-email/modals/select-folder.js b/frontend/client/modules/crm/src/views/inbound-email/modals/select-folder.js index 95a1c9eac7..868a42937d 100644 --- a/frontend/client/modules/crm/src/views/inbound-email/modals/select-folder.js +++ b/frontend/client/modules/crm/src/views/inbound-email/modals/select-folder.js @@ -21,39 +21,39 @@ Espo.define('Crm:Views.InboundEmail.Modals.SelectFolder', 'Views.Modal', function (Dep) { - return Dep.extend({ - - cssName: 'select-folder-modal', - - template: 'crm:inbound-email.modals.select-folder', - - data: function () { - return { - folders: this.options.folders, - }; - }, - - events: { - 'click button[data-action="select"]': function (e) { - var value = $(e.currentTarget).data('value'); - this.trigger('select', value); - }, - }, - - setup: function () { - - this.buttons = [ - { - name: 'cancel', - label: 'Cancel', - onClick: function (dialog) { - dialog.close(); - } - } - ]; + return Dep.extend({ + + cssName: 'select-folder-modal', + + template: 'crm:inbound-email.modals.select-folder', + + data: function () { + return { + folders: this.options.folders, + }; + }, + + events: { + 'click button[data-action="select"]': function (e) { + var value = $(e.currentTarget).data('value'); + this.trigger('select', value); + }, + }, + + setup: function () { + + this.buttons = [ + { + name: 'cancel', + label: 'Cancel', + onClick: function (dialog) { + dialog.close(); + } + } + ]; - }, + }, - }); + }); }); diff --git a/frontend/client/modules/crm/src/views/inbound-email/record/detail.js b/frontend/client/modules/crm/src/views/inbound-email/record/detail.js index b00392a2b3..7a44af23cc 100644 --- a/frontend/client/modules/crm/src/views/inbound-email/record/detail.js +++ b/frontend/client/modules/crm/src/views/inbound-email/record/detail.js @@ -21,49 +21,55 @@ Espo.define('Crm:Views.InboundEmail.Record.Detail', 'Views.Record.Detail', function (Dep) { - return Dep.extend({ + return Dep.extend({ - setup: function () { - Dep.prototype.setup.call(this); - this.handleDistributionField(); - }, + setup: function () { + Dep.prototype.setup.call(this); + this.handleDistributionField(); + }, - afterRender: function () { - Dep.prototype.afterRender.call(this); - this.initSslFieldListening(); - }, + afterRender: function () { + Dep.prototype.afterRender.call(this); + this.initSslFieldListening(); + }, - handleDistributionField: function () { - var handleRequirement = function (model) { - if (model.get('createCase') && ['Round-Robin', 'Least-Busy'].indexOf(model.get('caseDistribution')) != -1) { - this.getFieldView('team').setRequired(); - } else { - this.getFieldView('team').setNotRequired(); - } - }.bind(this); + handleDistributionField: function () { + var handleRequirement = function (model) { + if (model.get('createCase') && ['Round-Robin', 'Least-Busy'].indexOf(model.get('caseDistribution')) != -1) { + this.getFieldView('team').setRequired(); + } else { + this.getFieldView('team').setNotRequired(); + } + }.bind(this); - this.on('render', function () { - handleRequirement(this.model); - }, this); + this.listenTo(this.model, 'change:createCase', function (model) { + if (!model.get('createCase')) { + this.model.set('caseDistribution', 'Direct-Assignment'); + } + }, this); - this.listenTo(this.model, 'change:caseDistribution', function (model) { - handleRequirement(model); - }); - }, + this.on('render', function () { + handleRequirement(this.model); + }, this); - initSslFieldListening: function () { - var sslField = this.getFieldView('ssl'); - this.listenTo(sslField, 'change', function () { - var ssl = sslField.fetch()['ssl']; - if (ssl) { - this.model.set('port', '993'); - } else { - this.model.set('port', '143'); - } - }, this); - } + this.listenTo(this.model, 'change:caseDistribution', function (model) { + handleRequirement(model); + }); + }, - }); + initSslFieldListening: function () { + var sslField = this.getFieldView('ssl'); + this.listenTo(sslField, 'change', function () { + var ssl = sslField.fetch()['ssl']; + if (ssl) { + this.model.set('port', '993'); + } else { + this.model.set('port', '143'); + } + }, this); + } + + }); }); diff --git a/frontend/client/modules/crm/src/views/inbound-email/record/edit.js b/frontend/client/modules/crm/src/views/inbound-email/record/edit.js index 23b27925fe..b9c2710539 100644 --- a/frontend/client/modules/crm/src/views/inbound-email/record/edit.js +++ b/frontend/client/modules/crm/src/views/inbound-email/record/edit.js @@ -21,19 +21,19 @@ Espo.define('Crm:Views.InboundEmail.Record.Edit', ['Views.Record.Edit', 'Crm:Views.InboundEmail.Record.Detail'], function (Dep, Detail) { - return Dep.extend({ + return Dep.extend({ - setup: function () { - Dep.prototype.setup.call(this); - Detail.prototype.handleDistributionField.call(this); + setup: function () { + Dep.prototype.setup.call(this); + Detail.prototype.handleDistributionField.call(this); - }, + }, - afterRender: function () { - Dep.prototype.afterRender.call(this); - Detail.prototype.initSslFieldListening.call(this); - }, + afterRender: function () { + Dep.prototype.afterRender.call(this); + Detail.prototype.initSslFieldListening.call(this); + }, - }); + }); }); diff --git a/frontend/client/modules/crm/src/views/inbound-email/record/list.js b/frontend/client/modules/crm/src/views/inbound-email/record/list.js index b9f33cda87..ff0b5685bf 100644 --- a/frontend/client/modules/crm/src/views/inbound-email/record/list.js +++ b/frontend/client/modules/crm/src/views/inbound-email/record/list.js @@ -18,14 +18,14 @@ * You should have received a copy of the GNU General Public License * along with EspoCRM. If not, see http://www.gnu.org/licenses/. ************************************************************************/ - -Espo.define('Crm:Views.InboundEmail.Record.List', 'Views.Record.List', function (Dep) { + +Espo.define('Crm:Views.InboundEmail.Record.List', 'Views.Record.List', function (Dep) { - return Dep.extend({ - - allowQuickEdit: false, - - }); - + return Dep.extend({ + + allowQuickEdit: false, + + }); + }); diff --git a/frontend/client/modules/crm/src/views/lead/convert.js b/frontend/client/modules/crm/src/views/lead/convert.js index 8aa9833563..ef6c22ed0d 100644 --- a/frontend/client/modules/crm/src/views/lead/convert.js +++ b/frontend/client/modules/crm/src/views/lead/convert.js @@ -21,157 +21,157 @@ Espo.define('Crm:Views.Lead.Convert', 'View', function (Dep) { - return Dep.extend({ + return Dep.extend({ - template: 'crm:lead.convert', + template: 'crm:lead.convert', - data: function () { - return { - scopes: this.scopes, - scope: this.model.name, - }; - }, + data: function () { + return { + scopes: this.scopes, + scope: this.model.name, + }; + }, - events: { - 'change input.check-scope': function (e) { - var scope = $(e.currentTarget).data('scope'); - var $div = this.$el.find('.edit-container-' + Espo.Utils.toDom(scope)); - if (e.currentTarget.checked) { - $div.removeClass('hide'); - } else { - $div.addClass('hide'); - } - }, - 'click button[data-action="convert"]': function (e) { - this.convert(); - }, - 'click button[data-action="cancel"]': function (e) { - this.getRouter().navigate('#Lead/view/' + this.id, {trigger: true}); - }, - }, + events: { + 'change input.check-scope': function (e) { + var scope = $(e.currentTarget).data('scope'); + var $div = this.$el.find('.edit-container-' + Espo.Utils.toDom(scope)); + if (e.currentTarget.checked) { + $div.removeClass('hide'); + } else { + $div.addClass('hide'); + } + }, + 'click button[data-action="convert"]': function (e) { + this.convert(); + }, + 'click button[data-action="cancel"]': function (e) { + this.getRouter().navigate('#Lead/view/' + this.id, {trigger: true}); + }, + }, - setup: function () { - this.wait(true); - this.id = this.options.id; - - this.notify('Loading...'); + setup: function () { + this.wait(true); + this.id = this.options.id; + + this.notify('Loading...'); - this.getModelFactory().create('Lead', function (model) { - this.model = model; - model.id = this.id; + this.getModelFactory().create('Lead', function (model) { + this.model = model; + model.id = this.id; - this.listenToOnce(model, 'sync', function () { - this.build(); - }.bind(this)); - model.fetch(); - }.bind(this)); + this.listenToOnce(model, 'sync', function () { + this.build(); + }.bind(this)); + model.fetch(); + }.bind(this)); - }, + }, - build: function () { - var scopes = this.scopes = []; - for (var scope in this.model.defs.convertFields) { - if (this.getAcl().check(scope, 'edit')) { - scopes.push(scope); - } - } - var i = 0; - - var attributeList = this.getFieldManager().getEntityAttributes(this.model.name); - var ignoreAttributeList = ['createdAt', 'modifiedAt', 'modifiedById', 'modifiedByName', 'createdById', 'createdByName']; - - scopes.forEach(function (scope) { - this.getModelFactory().create(scope, function (model) { - model.populateDefaults(); - - this.getFieldManager().getEntityAttributes(model.name).forEach(function (attr) { - if (~attributeList.indexOf(attr) && !~ignoreAttributeList.indexOf(attr)) { - model.set(attr, this.model.get(attr), {silent: true}); - } - }, this); - - for (var field in this.model.defs.convertFields[scope]) { - var leadField = this.model.defs.convertFields[scope][field]; - var leadAttrs = this.getFieldManager().getAttributes(this.model.getFieldParam(leadField, 'type'), leadField); - var attrs = this.getFieldManager().getAttributes(model.getFieldParam(field, 'type'), field); + build: function () { + var scopes = this.scopes = []; + for (var scope in this.model.defs.convertFields) { + if (this.getAcl().check(scope, 'edit')) { + scopes.push(scope); + } + } + var i = 0; + + var attributeList = this.getFieldManager().getEntityAttributes(this.model.name); + var ignoreAttributeList = ['createdAt', 'modifiedAt', 'modifiedById', 'modifiedByName', 'createdById', 'createdByName']; + + scopes.forEach(function (scope) { + this.getModelFactory().create(scope, function (model) { + model.populateDefaults(); + + this.getFieldManager().getEntityAttributes(model.name).forEach(function (attr) { + if (~attributeList.indexOf(attr) && !~ignoreAttributeList.indexOf(attr)) { + model.set(attr, this.model.get(attr), {silent: true}); + } + }, this); + + for (var field in this.model.defs.convertFields[scope]) { + var leadField = this.model.defs.convertFields[scope][field]; + var leadAttrs = this.getFieldManager().getAttributes(this.model.getFieldParam(leadField, 'type'), leadField); + var attrs = this.getFieldManager().getAttributes(model.getFieldParam(field, 'type'), field); - attrs.forEach(function (attr, i) { - var leadAttr = leadAttrs[i]; - model.set(attr, this.model.get(leadAttr)); - }.bind(this)); - } + attrs.forEach(function (attr, i) { + var leadAttr = leadAttrs[i]; + model.set(attr, this.model.get(leadAttr)); + }.bind(this)); + } - this.createView(scope, 'Record.Edit', { - model: model, - el: '#main .edit-container-' + Espo.Utils.toDom(scope), - buttonsPosition: false, - layoutName: 'detailConvert', - exit: function () {}, - }, function (view) { - i++; - if (i == scopes.length) { - this.wait(false); - this.notify(false); - } - }.bind(this)); - }, this); - }, this); - }, + this.createView(scope, 'Record.Edit', { + model: model, + el: '#main .edit-container-' + Espo.Utils.toDom(scope), + buttonsPosition: false, + layoutName: 'detailConvert', + exit: function () {}, + }, function (view) { + i++; + if (i == scopes.length) { + this.wait(false); + this.notify(false); + } + }.bind(this)); + }, this); + }, this); + }, - convert: function () { - - var scopes = []; + convert: function () { + + var scopes = []; - this.scopes.forEach(function (scope) { - var el = this.$el.find('input[data-scope="' + scope + '"]').get(0); - if (el && el.checked) { - scopes.push(scope); - } - }.bind(this)); + this.scopes.forEach(function (scope) { + var el = this.$el.find('input[data-scope="' + scope + '"]').get(0); + if (el && el.checked) { + scopes.push(scope); + } + }.bind(this)); - if (scopes.length == 0) { - this.notify('Select one or more checkboxes', 'error'); - return; - } + if (scopes.length == 0) { + this.notify('Select one or more checkboxes', 'error'); + return; + } - var notValid = false; - scopes.forEach(function (scope) { - var editView = this.getView(scope); - editView.model.set(editView.fetch()); - notValid = editView.validate() || notValid; - }.bind(this)); - - var self = this; - - var data = { - id: self.model.id, - records: {} - }; - scopes.forEach(function (scope) { - data.records[scope] = self.getView(scope).model.attributes; - }); - + var notValid = false; + scopes.forEach(function (scope) { + var editView = this.getView(scope); + editView.model.set(editView.fetch()); + notValid = editView.validate() || notValid; + }.bind(this)); + + var self = this; + + var data = { + id: self.model.id, + records: {} + }; + scopes.forEach(function (scope) { + data.records[scope] = self.getView(scope).model.attributes; + }); + - if (!notValid) { - this.$el.find('[data-action="convert"]').addClass('disabled'); - this.notify('Please wait...'); - $.ajax({ - url: 'Lead/action/convert', - data: JSON.stringify(data), - type: 'POST', - success: function () { - self.getRouter().navigate('#Lead/view/' + self.model.id, {trigger: true}); - self.notify('Converted', 'success'); - }, - error: function () { - self.$el.find('[data-action="convert"]').removeClass('disabled'); - } - }); - } else { - this.notify('Not Valid', 'error'); - } - }, + if (!notValid) { + this.$el.find('[data-action="convert"]').addClass('disabled'); + this.notify('Please wait...'); + $.ajax({ + url: 'Lead/action/convert', + data: JSON.stringify(data), + type: 'POST', + success: function () { + self.getRouter().navigate('#Lead/view/' + self.model.id, {trigger: true}); + self.notify('Converted', 'success'); + }, + error: function () { + self.$el.find('[data-action="convert"]').removeClass('disabled'); + } + }); + } else { + this.notify('Not Valid', 'error'); + } + }, - }); + }); }); diff --git a/frontend/client/modules/crm/src/views/lead/detail.js b/frontend/client/modules/crm/src/views/lead/detail.js index 97697cc1cc..55c3122c74 100644 --- a/frontend/client/modules/crm/src/views/lead/detail.js +++ b/frontend/client/modules/crm/src/views/lead/detail.js @@ -21,24 +21,24 @@ Espo.define('Crm:Views.Lead.Detail', 'Views.Detail', function (Dep) { - return Dep.extend({ + return Dep.extend({ - setup: function () { - Dep.prototype.setup.call(this); - - if (['Converted', 'Dead'].indexOf(this.model.get('status')) == -1) { - this.menu.buttons.push({ - label: 'Convert', - action: 'convert', - acl: 'edit', - }); - } - }, - - actionConvert: function () { - this.getRouter().navigate(this.model.name + '/convert/' + this.model.id , {trigger: true}); - }, - }); + setup: function () { + Dep.prototype.setup.call(this); + + if (['Converted', 'Dead'].indexOf(this.model.get('status')) == -1) { + this.menu.buttons.push({ + label: 'Convert', + action: 'convert', + acl: 'edit', + }); + } + }, + + actionConvert: function () { + this.getRouter().navigate(this.model.name + '/convert/' + this.model.id , {trigger: true}); + }, + }); }); diff --git a/frontend/client/modules/crm/src/views/lead/record/detail-side.js b/frontend/client/modules/crm/src/views/lead/record/detail-side.js index cf7077a59d..efc31c6c4d 100644 --- a/frontend/client/modules/crm/src/views/lead/record/detail-side.js +++ b/frontend/client/modules/crm/src/views/lead/record/detail-side.js @@ -21,34 +21,34 @@ Espo.define('Crm:Views.Lead.Record.DetailSide', 'Views.Record.DetailSide', function (Dep) { - return Dep.extend({ + return Dep.extend({ - setup: function () { - if (this.model.get('status') == 'Converted') { - var panel = { - name: 'convertedTo', - label: 'Converted To', - view: 'Record.Panels.Side', - options: { - fields: [], - mode: 'detail', - } - }; - if (this.model.get('createdAccountId')) { - panel.options.fields.push('createdAccount'); - } - if (this.model.get('createdContactId')) { - panel.options.fields.push('createdContact'); - } - if (this.model.get('createdOpportunityId')) { - panel.options.fields.push('createdOpportunity'); - } - if (panel.options.fields.length) { - this.panels.splice(1, 0, panel); - } - } - Dep.prototype.setup.call(this); - }, - }); + setup: function () { + if (this.model.get('status') == 'Converted') { + var panel = { + name: 'convertedTo', + label: 'Converted To', + view: 'Record.Panels.Side', + options: { + fields: [], + mode: 'detail', + } + }; + if (this.model.get('createdAccountId')) { + panel.options.fields.push('createdAccount'); + } + if (this.model.get('createdContactId')) { + panel.options.fields.push('createdContact'); + } + if (this.model.get('createdOpportunityId')) { + panel.options.fields.push('createdOpportunity'); + } + if (panel.options.fields.length) { + this.panels.splice(1, 0, panel); + } + } + Dep.prototype.setup.call(this); + }, + }); }); diff --git a/frontend/client/modules/crm/src/views/lead/record/detail.js b/frontend/client/modules/crm/src/views/lead/record/detail.js index 68c9b5a198..4e146c1935 100644 --- a/frontend/client/modules/crm/src/views/lead/record/detail.js +++ b/frontend/client/modules/crm/src/views/lead/record/detail.js @@ -22,11 +22,11 @@ Espo.define('Crm:Views.Lead.Record.Detail', 'Views.Record.Detail', function (Dep) { - return Dep.extend({ - - sideView: 'Crm:Lead.Record.DetailSide', + return Dep.extend({ + + sideView: 'Crm:Lead.Record.DetailSide', - }); + }); }); diff --git a/frontend/client/modules/crm/src/views/meeting/detail.js b/frontend/client/modules/crm/src/views/meeting/detail.js index 593f2580ac..046cd545ee 100644 --- a/frontend/client/modules/crm/src/views/meeting/detail.js +++ b/frontend/client/modules/crm/src/views/meeting/detail.js @@ -21,81 +21,81 @@ Espo.define('Crm:Views.Meeting.Detail', 'Views.Detail', function (Dep) { - return Dep.extend({ + return Dep.extend({ - setup: function () { - Dep.prototype.setup.call(this); - if (['Held', 'Not Held'].indexOf(this.model.get('status')) == -1) { - if (this.getAcl().checkModel(this.model, 'edit')) { - this.menu.buttons.push({ - 'label': 'Send Invitations', - 'action': 'sendInvitations', - icon: 'glyphicon glyphicon-send', - 'acl': 'edit', - }); - this.menu.dropdown.push({ - 'label': 'Set Held', - 'action': 'setHeld', - 'acl': 'edit' - }); - this.menu.dropdown.push({ - 'label': 'Set Not Held', - 'action': 'setNotHeld', - 'acl': 'edit' - }); - } - } - }, - - actionSendInvitations: function () { - if (confirm(this.translate('confirmation', 'messages'))) { - this.$el.find('button[data-action="sendInvitations"]').addClass('disabled'); - this.notify('Sending...'); - $.ajax({ - url: 'Meeting/action/sendInvitations', - type: 'POST', - data: JSON.stringify({ - id: this.model.id - }), - success: function () { - this.notify('Sent', 'success'); - this.$el.find('button[data-action="sendInvitations"]').removeClass('disabled'); - }.bind(this), - error: function () { - this.$el.find('button[data-action="sendInvitations"]').removeClass('disabled'); - }.bind(this), - }); - } - }, - - actionSetHeld: function () { - this.model.save({ - status: 'Held' - }, { - patch: true, - success: function () { - Espo.Ui.success(this.translate('Saved as Held', 'labels', 'Meeting')); - this.$el.find('button[data-action="sendInvitations"]').remove(); - this.$el.find('a[data-action="setHeld"]').remove(); - this.$el.find('a[data-action="setNotHeld"]').remove(); - }.bind(this), - }); - }, - - actionSetNotHeld: function () { - this.model.save({ - status: 'Not Held' - }, { - patch: true, - success: function () { - Espo.Ui.success(this.translate('Saved as Not Held', 'labels', 'Meeting')); - this.$el.find('button[data-action="sendInvitations"]').remove(); - this.$el.find('a[data-action="setHeld"]').remove(); - this.$el.find('a[data-action="setNotHeld"]').remove(); - }.bind(this), - }); - }, + setup: function () { + Dep.prototype.setup.call(this); + if (['Held', 'Not Held'].indexOf(this.model.get('status')) == -1) { + if (this.getAcl().checkModel(this.model, 'edit')) { + this.menu.buttons.push({ + 'label': 'Send Invitations', + 'action': 'sendInvitations', + icon: 'glyphicon glyphicon-send', + 'acl': 'edit', + }); + this.menu.dropdown.push({ + 'label': 'Set Held', + 'action': 'setHeld', + 'acl': 'edit' + }); + this.menu.dropdown.push({ + 'label': 'Set Not Held', + 'action': 'setNotHeld', + 'acl': 'edit' + }); + } + } + }, + + actionSendInvitations: function () { + if (confirm(this.translate('confirmation', 'messages'))) { + this.$el.find('button[data-action="sendInvitations"]').addClass('disabled'); + this.notify('Sending...'); + $.ajax({ + url: 'Meeting/action/sendInvitations', + type: 'POST', + data: JSON.stringify({ + id: this.model.id + }), + success: function () { + this.notify('Sent', 'success'); + this.$el.find('[data-action="sendInvitations"]').removeClass('disabled'); + }.bind(this), + error: function () { + this.$el.find('[data-action="sendInvitations"]').removeClass('disabled'); + }.bind(this), + }); + } + }, + + actionSetHeld: function () { + this.model.save({ + status: 'Held' + }, { + patch: true, + success: function () { + Espo.Ui.success(this.translate('Saved', 'labels', 'Meeting')); + this.$el.find('[data-action="sendInvitations"]').remove(); + this.$el.find('[data-action="setHeld"]').remove(); + this.$el.find('[data-action="setNotHeld"]').remove(); + }.bind(this), + }); + }, + + actionSetNotHeld: function () { + this.model.save({ + status: 'Not Held' + }, { + patch: true, + success: function () { + Espo.Ui.success(this.translate('Saved', 'labels', 'Meeting')); + this.$el.find('[data-action="sendInvitations"]').remove(); + this.$el.find('[data-action="setHeld"]').remove(); + this.$el.find('[data-action="setNotHeld"]').remove(); + }.bind(this), + }); + }, - }); + }); }); diff --git a/frontend/client/modules/crm/src/views/meeting/fields/attendees.js b/frontend/client/modules/crm/src/views/meeting/fields/attendees.js index 54459626b1..5758840e39 100644 --- a/frontend/client/modules/crm/src/views/meeting/fields/attendees.js +++ b/frontend/client/modules/crm/src/views/meeting/fields/attendees.js @@ -21,12 +21,12 @@ Espo.define('Crm:Views.Meeting.Fields.Attendees', 'Views.Fields.LinkMultipleWithRole', function (Dep) { - return Dep.extend({ - - columnName: 'status', - - roleFieldIsForeign: false, - - }); + return Dep.extend({ + + columnName: 'status', + + roleFieldIsForeign: false, + + }); }); diff --git a/frontend/client/modules/crm/src/views/meeting/fields/contacts.js b/frontend/client/modules/crm/src/views/meeting/fields/contacts.js index 9d54715a7b..dcf4a7d409 100644 --- a/frontend/client/modules/crm/src/views/meeting/fields/contacts.js +++ b/frontend/client/modules/crm/src/views/meeting/fields/contacts.js @@ -21,20 +21,20 @@ Espo.define('Crm:Views.Meeting.Fields.Contacts', 'Crm:Views.Meeting.Fields.Attendees', function (Dep) { - return Dep.extend({ - - getSelectFilters: function () { - if (this.model.get('parentType') == 'Account' && this.model.get('parentId')) { - return { - 'account': { - type: 'equals', - field: 'accountId', - value: this.model.get('parentId'), - valueName: this.model.get('parentName'), - } - }; - } - }, - }); + return Dep.extend({ + + getSelectFilters: function () { + if (this.model.get('parentType') == 'Account' && this.model.get('parentId')) { + return { + 'account': { + type: 'equals', + field: 'accountId', + value: this.model.get('parentId'), + valueName: this.model.get('parentName'), + } + }; + } + }, + }); }); diff --git a/frontend/client/modules/crm/src/views/opportunity/detail.js b/frontend/client/modules/crm/src/views/opportunity/detail.js index dfcd196657..e498e5cc22 100644 --- a/frontend/client/modules/crm/src/views/opportunity/detail.js +++ b/frontend/client/modules/crm/src/views/opportunity/detail.js @@ -21,31 +21,31 @@ Espo.define('Crm:Views.Opportunity.Detail', 'Views.Detail', function (Dep) { - return Dep.extend({ + return Dep.extend({ - relatedAttributeMap: { - 'contacts': { - 'accountId': 'accountId', - 'accountName': 'accountName' - }, - }, - - selectRelatedFilters: { - 'contacts': { - 'account': function () { - if (this.model.get('accountId')) { - return { - field: 'accountId', - type: 'equals', - value: this.model.get('accountId'), - valueName: this.model.get('accountName') - }; - } - }, - - }, - }, - - }); + relatedAttributeMap: { + 'contacts': { + 'accountId': 'accountId', + 'accountName': 'accountName' + }, + }, + + selectRelatedFilters: { + 'contacts': { + 'account': function () { + if (this.model.get('accountId')) { + return { + field: 'accountId', + type: 'equals', + value: this.model.get('accountId'), + valueName: this.model.get('accountName') + }; + } + }, + + }, + }, + + }); }); diff --git a/frontend/client/modules/crm/src/views/opportunity/fields/contacts.js b/frontend/client/modules/crm/src/views/opportunity/fields/contacts.js index 80c7309e01..ae2874d0cf 100644 --- a/frontend/client/modules/crm/src/views/opportunity/fields/contacts.js +++ b/frontend/client/modules/crm/src/views/opportunity/fields/contacts.js @@ -21,20 +21,20 @@ Espo.define('Crm:Views.Opportunity.Fields.Contacts', 'Views.Fields.LinkMultipleWithRole', function (Dep) { - return Dep.extend({ - - getSelectFilters: function () { - if (this.model.get('accountId')) { - return { - 'account': { - type: 'equals', - field: 'accountId', - value: this.model.get('accountId'), - valueName: this.model.get('accountName'), - } - }; - } - }, - }); + return Dep.extend({ + + getSelectFilters: function () { + if (this.model.get('accountId')) { + return { + 'account': { + type: 'equals', + field: 'accountId', + value: this.model.get('accountId'), + valueName: this.model.get('accountName'), + } + }; + } + }, + }); }); diff --git a/frontend/client/modules/crm/src/views/opportunity/fields/lead-source.js b/frontend/client/modules/crm/src/views/opportunity/fields/lead-source.js index 3f7d7fcd50..5fe76254e9 100644 --- a/frontend/client/modules/crm/src/views/opportunity/fields/lead-source.js +++ b/frontend/client/modules/crm/src/views/opportunity/fields/lead-source.js @@ -21,21 +21,21 @@ Espo.define('Crm:Views.Opportunity.Fields.LeadSource', 'Views.Fields.Enum', function (Dep) { - return Dep.extend({ - - listTemplate: 'crm:opportunity.fields.lead-source.detail', + return Dep.extend({ + + listTemplate: 'crm:opportunity.fields.lead-source.detail', - detailTemplate: 'crm:opportunity.fields.lead-source.detail', + detailTemplate: 'crm:opportunity.fields.lead-source.detail', - editTemplate: 'crm:opportunity.fields.lead-source.edit', + editTemplate: 'crm:opportunity.fields.lead-source.edit', - searchTemplate: 'crm:opportunity.fields.lead-source.search', - - setup: function () { - Dep.prototype.setup.call(this); - this.params.options = this.getMetadata().get('entityDefs.Lead.fields.source.options'); - }, - - }); + searchTemplate: 'crm:opportunity.fields.lead-source.search', + + setup: function () { + Dep.prototype.setup.call(this); + this.params.options = this.getMetadata().get('entityDefs.Lead.fields.source.options'); + }, + + }); }); diff --git a/frontend/client/modules/crm/src/views/opportunity/fields/stage.js b/frontend/client/modules/crm/src/views/opportunity/fields/stage.js index 9cc509e2fb..c83615c47a 100644 --- a/frontend/client/modules/crm/src/views/opportunity/fields/stage.js +++ b/frontend/client/modules/crm/src/views/opportunity/fields/stage.js @@ -21,58 +21,48 @@ Espo.define('Crm:Views.Opportunity.Fields.Stage', 'Views.Fields.Enum', function (Dep) { - return Dep.extend({ - - listTemplate: 'fields.enum-styled.detail', - - detailTemplate: 'fields.enum-styled.detail', - - data: function () { - var style = 'default'; - var stage = this.model.get('stage'); - if (stage == 'Closed Won') { - style = 'success'; - } else if (stage == 'Closed Lost') { - style = 'danger'; - } - return _.extend({ - style: style, - }, Dep.prototype.data.call(this)); - }, + return Dep.extend({ + + listTemplate: 'fields.enum-styled.detail', + + detailTemplate: 'fields.enum-styled.detail', + + data: function () { + var style = 'default'; + var stage = this.model.get('stage'); + if (stage == 'Closed Won') { + style = 'success'; + } else if (stage == 'Closed Lost') { + style = 'danger'; + } + return _.extend({ + style: style, + }, Dep.prototype.data.call(this)); + }, - probabilityMap: { - 'Prospecting': 10, - 'Qualification': 10, - 'Needs Analysis': 20, - 'Value Proposition': 50, - 'Id. Decision Makers': 60, - 'Perception Analysis': 70, - 'Proposal/Price Quote': 75, - 'Negotiation/Review': 90, - 'Closed Won': 100, - 'Closed Lost': 0, - }, + setup: function () { + Dep.prototype.setup.call(this); + + this.probabilityMap = this.getMetadata().get('entityDefs.Opportunity.probabilityMap') || {}; + + if (this.mode != 'list') { + if (!this.model.has('probability') && this.model.has('stage')) { + this.model.set('probability', this.probabilityMap[this.model.get('stage')]); + } - setup: function () { - Dep.prototype.setup.call(this); - if (this.mode != 'list') { - if (!this.model.has('probability') && this.model.has('stage')) { - this.model.set('probability', this.probabilityMap[this.model.get('stage')]); - } + this.on('change', function () { + this.model.set('probability', this.probabilityMap[this.model.get(this.name)]); + }, this); + } + }, - this.on('change', function () { - this.model.set('probability', this.probabilityMap[this.model.get(this.name)]); - }, this); - } - }, - - fetch: function () { - var data = Dep.prototype.fetch.call(this); - if (this.probabilityChanged) { - data['probability'] = this.model.get('probability'); - } - return data; - }, - }); + fetch: function () { + var data = Dep.prototype.fetch.call(this); + if (this.probabilityChanged) { + data['probability'] = this.model.get('probability'); + } + return data; + }, + }); }); diff --git a/frontend/client/modules/crm/src/views/record/panels/activities.js b/frontend/client/modules/crm/src/views/record/panels/activities.js index dad8f10e27..a179a330c3 100644 --- a/frontend/client/modules/crm/src/views/record/panels/activities.js +++ b/frontend/client/modules/crm/src/views/record/panels/activities.js @@ -21,266 +21,272 @@ Espo.define('Crm:Views.Record.Panels.Activities', 'Views.Record.Panels.Relationship', function (Dep) { - return Dep.extend({ + return Dep.extend({ - name: 'activities', + name: 'activities', - template: 'crm:record.panels.activities', + template: 'crm:record.panels.activities', - scopeList: ['Meeting', 'Call'], + scopeList: ['Meeting', 'Call'], - sortBy: 'dateStart', + sortBy: 'dateStart', - asc: false, - - actions: [ - { - action: 'createActivity', - label: 'Schedule Meeting', - data: { - link: 'meetings', - status: 'Planned', - }, - acl: 'edit', - aclScope: 'Meeting', - }, - { - action: 'createActivity', - label: 'Schedule Call', - data: { - link: 'calls', - status: 'Planned', - }, - acl: 'edit', - aclScope: 'Call', - }, - { - action: 'composeEmail', - label: 'Compose Email', - acl: 'edit', - aclScope: 'Email', - } - ], + asc: false, + + actions: [ + { + action: 'createActivity', + label: 'Schedule Meeting', + data: { + link: 'meetings', + status: 'Planned', + }, + acl: 'edit', + aclScope: 'Meeting', + }, + { + action: 'createActivity', + label: 'Schedule Call', + data: { + link: 'calls', + status: 'Planned', + }, + acl: 'edit', + aclScope: 'Call', + }, + { + action: 'composeEmail', + label: 'Compose Email', + acl: 'edit', + aclScope: 'Email', + } + ], - listLayout: { - 'Meeting': { - rows: [ - [ - {name: 'ico', view: 'Crm:Fields.Ico'}, - { - name: 'name', - link: true, - }, - ], - [ - {name: 'assignedUser'}, - {name: 'dateStart'}, - ] - ] - }, - 'Call': { - rows: [ - [ - {name: 'ico', view: 'Crm:Fields.Ico'}, - { - name: 'name', - link: true, - }, - ], - [ - {name: 'assignedUser'}, - {name: 'dateStart'}, - ] - ] - } - }, + listLayout: { + 'Meeting': { + rows: [ + [ + {name: 'ico', view: 'Crm:Fields.Ico'}, + { + name: 'name', + link: true, + }, + ], + [ + {name: 'assignedUser'}, + {name: 'dateStart'}, + ] + ] + }, + 'Call': { + rows: [ + [ + {name: 'ico', view: 'Crm:Fields.Ico'}, + { + name: 'name', + link: true, + }, + ], + [ + {name: 'assignedUser'}, + {name: 'dateStart'}, + ] + ] + } + }, - where: { - scope: false, - }, - - events: _.extend({ - 'click button.scope-switcher': function (e) { - var $target = $(e.currentTarget); - this.$el.find('button.scope-switcher').removeClass('active'); - $target.addClass('active'); - this.where.scope = $target.data('scope') || false; - - this.listenToOnce(this.collection, 'sync', function () { - this.notify(false); - }.bind(this)); - this.notify('Loading...'); - this.collection.fetch(); - - this.currentTab = this.where.scope || 'all'; - this.getStorage().set('state', this.getStorageKey(), this.currentTab); - } - }, Dep.prototype.events), + where: { + scope: false, + }, + + events: _.extend({ + 'click button.scope-switcher': function (e) { + var $target = $(e.currentTarget); + this.$el.find('button.scope-switcher').removeClass('active'); + $target.addClass('active'); + this.where.scope = $target.data('scope') || false; + + this.listenToOnce(this.collection, 'sync', function () { + this.notify(false); + }.bind(this)); + this.notify('Loading...'); + this.collection.fetch(); + + this.currentTab = this.where.scope || 'all'; + this.getStorage().set('state', this.getStorageKey(), this.currentTab); + } + }, Dep.prototype.events), - data: function () { - return { - currentTab: this.currentTab, - scopeList: this.scopeList - }; - }, - - getStorageKey: function () { - return 'activities-' + this.model.name + '-' + this.name; - }, + data: function () { + return { + currentTab: this.currentTab, + scopeList: this.scopeList + }; + }, + + getStorageKey: function () { + return 'activities-' + this.model.name + '-' + this.name; + }, - setup: function () { - - this.currentTab = this.getStorage().get('state', this.getStorageKey()) || 'all'; - - if (this.currentTab != 'all') { - this.where = {scope: this.currentTab}; - } - - this.seeds = {}; + setup: function () { + + this.currentTab = this.getStorage().get('state', this.getStorageKey()) || 'all'; + + if (this.currentTab != 'all') { + this.where = {scope: this.currentTab}; + } + + this.seeds = {}; - this.wait(true); - var i = 0; - this.scopeList.forEach(function (scope) { - this.getModelFactory().getSeed(scope, function (seed) { - this.seeds[scope] = seed; - i++; - if (i == this.scopeList.length) { - this.wait(false); - } - }.bind(this)); - }.bind(this)); - }, + this.wait(true); + var i = 0; + this.scopeList.forEach(function (scope) { + this.getModelFactory().getSeed(scope, function (seed) { + this.seeds[scope] = seed; + i++; + if (i == this.scopeList.length) { + this.wait(false); + } + }.bind(this)); + }.bind(this)); + }, - afterRender: function () { - var url = 'Activities/' + this.model.name + '/' + this.model.id + '/' + this.name; + afterRender: function () { + var url = 'Activities/' + this.model.name + '/' + this.model.id + '/' + this.name; - this.collection = new Espo.MultiCollection(); - this.collection.seeds = this.seeds; - this.collection.url = url; - this.collection.where = this.where; - this.collection.sortBy = this.sortBy; - this.collection.asc = this.asc; - this.collection.maxSize = this.getConfig().get('recordsPerPageSmall') || 5; + this.collection = new Espo.MultiCollection(); + this.collection.seeds = this.seeds; + this.collection.url = url; + this.collection.where = this.where; + this.collection.sortBy = this.sortBy; + this.collection.asc = this.asc; + this.collection.maxSize = this.getConfig().get('recordsPerPageSmall') || 5; - this.listenToOnce(this.collection, 'sync', function () { - this.createView('list', 'Record.ListExpanded', { - el: this.$el.selector + ' > .list-container', - pagination: false, - type: 'listRelationship', - rowActionsView: 'Record.RowActions.RelationshipNoUnlink', - checkboxes: false, - collection: this.collection, - listLayout: this.listLayout, - }, function (view) { - view.render(); - }); - }.bind(this)); - this.collection.fetch(); - }, - - getCreateActivityAttributes: function (data, callback) { - data = data || {}; - - var attributes = { - status: data.status - }; - - if (this.model.name == 'Contact') { - if (this.model.get('accountId')) { - attributes.parentType = 'Account', - attributes.parentId = this.model.get('accountId'); - attributes.parentName = this.model.get('accountName'); - } - } else if (this.model.name == 'Lead') { - attributes.parentType = 'Lead', - attributes.parentId = this.model.id - attributes.parentName = this.model.get('name'); - } - if (this.model.name != 'Account' && this.model.has('contactsIds')) { - attributes.contactsIds = this.model.get('contactsIds'); - attributes.contactsNames = this.model.get('contactsNames'); - } - - callback.call(this, attributes); - }, + this.listenToOnce(this.collection, 'sync', function () { + this.createView('list', 'Record.ListExpanded', { + el: this.$el.selector + ' > .list-container', + pagination: false, + type: 'listRelationship', + rowActionsView: 'Record.RowActions.RelationshipNoUnlink', + checkboxes: false, + collection: this.collection, + listLayout: this.listLayout, + }, function (view) { + view.render(); + }); + }.bind(this)); + this.collection.fetch(); + }, + + getCreateActivityAttributes: function (data, callback) { + data = data || {}; + + var attributes = { + status: data.status + }; + + if (this.model.name == 'Contact') { + if (this.model.get('accountId')) { + attributes.parentType = 'Account', + attributes.parentId = this.model.get('accountId'); + attributes.parentName = this.model.get('accountName'); + } + } else if (this.model.name == 'Lead') { + attributes.parentType = 'Lead', + attributes.parentId = this.model.id + attributes.parentName = this.model.get('name'); + } + if (this.model.name != 'Account' && this.model.has('contactsIds')) { + attributes.contactsIds = this.model.get('contactsIds'); + attributes.contactsNames = this.model.get('contactsNames'); + } + + callback.call(this, attributes); + }, - actionCreateActivity: function (data) { - var self = this; - var link = data.link; - var scope = this.model.defs['links'][link].entity; - var foreignLink = this.model.defs['links'][link].foreign; + actionCreateActivity: function (data) { + var self = this; + var link = data.link; + var scope = this.model.defs['links'][link].entity; + var foreignLink = this.model.defs['links'][link].foreign; - this.notify('Loading...'); - - this.getCreateActivityAttributes(data, function (attributes) { - this.createView('quickCreate', 'Modals.Edit', { - scope: scope, - relate: { - model: this.model, - link: foreignLink, - }, - attributes: attributes, - }, function (view) { - view.render(); - view.notify(false); - view.once('after:save', function () { - self.collection.fetch(); - }); - }); - }); + this.notify('Loading...'); + + this.getCreateActivityAttributes(data, function (attributes) { + this.createView('quickCreate', 'Modals.Edit', { + scope: scope, + relate: { + model: this.model, + link: foreignLink, + }, + attributes: attributes, + }, function (view) { + view.render(); + view.notify(false); + view.once('after:save', function () { + self.collection.fetch(); + }); + }); + }); - }, - - getComposeEmailAttributes: function (data, callback) { - data = data || {}; - var attributes = { - status: 'Draft', - to: this.model.get('emailAddress') - }; - callback.call(this, attributes); - }, - - actionComposeEmail: function () { - var self = this; - var link = 'emails'; - var scope = 'Email'; - - var relate = null; - if ('emails' in this.model.defs['links']) { - relate = { - model: this.model, - link: this.model.defs['links']['emails'].foreign - }; - } + }, + + getComposeEmailAttributes: function (data, callback) { + data = data || {}; + var attributes = { + status: 'Draft', + to: this.model.get('emailAddress') + }; + callback.call(this, attributes); + }, + + actionComposeEmail: function () { + var self = this; + var link = 'emails'; + var scope = 'Email'; + + var relate = null; + if ('emails' in this.model.defs['links']) { + relate = { + model: this.model, + link: this.model.defs['links']['emails'].foreign + }; + } - this.notify('Loading...'); - - this.getComposeEmailAttributes(null, function (attributes) { - if (this.model.name == 'Contact') { - if (this.model.get('accountId')) { - attributes.parentType = 'Account', - attributes.parentId = this.model.get('accountId'); - attributes.parentName = this.model.get('accountName'); - } - } else if (this.model.name == 'Lead') { - attributes.parentType = 'Lead', - attributes.parentId = this.model.id - attributes.parentName = this.model.get('name'); - } + this.notify('Loading...'); + + this.getComposeEmailAttributes(null, function (attributes) { + if (this.model.name == 'Contact') { + if (this.getConfig().get('b2cMode')) { + attributes.parentType = 'Contact'; + attributes.parentName = this.model.get('name'); + attributes.parentId = this.model.id; + } else { + if (this.model.get('accountId')) { + attributes.parentType = 'Account', + attributes.parentId = this.model.get('accountId'); + attributes.parentName = this.model.get('accountName'); + } + } + } else if (this.model.name == 'Lead') { + attributes.parentType = 'Lead', + attributes.parentId = this.model.id + attributes.parentName = this.model.get('name'); + } - this.createView('quickCreate', 'Modals.ComposeEmail', { - relate: relate, - attributes: attributes - }, function (view) { - view.render(); - view.notify(false); - view.once('after:save', function () { - self.collection.fetch(); - }); - }); - }); + this.createView('quickCreate', 'Modals.ComposeEmail', { + relate: relate, + attributes: attributes + }, function (view) { + view.render(); + view.notify(false); + view.once('after:save', function () { + self.collection.fetch(); + }); + }); + }); - }, - }); + }, + }); }); diff --git a/frontend/client/modules/crm/src/views/record/panels/history.js b/frontend/client/modules/crm/src/views/record/panels/history.js index 512bf71edb..0554a0dd96 100644 --- a/frontend/client/modules/crm/src/views/record/panels/history.js +++ b/frontend/client/modules/crm/src/views/record/panels/history.js @@ -21,154 +21,154 @@ Espo.define('Crm:Views.Record.Panels.History', 'Crm:Views.Record.Panels.Activities', function (Dep) { - return Dep.extend({ - - name: 'history', + return Dep.extend({ + + name: 'history', - scopeList: ['Meeting', 'Call', 'Email'], - - sortBy: 'dateStart', - - asc: false, - - actions: [ - { - action: 'createActivity', - label: 'Log Meeting', - data: { - link: 'meetings', - status: 'Held', - }, - acl: 'edit', - aclScope: 'Meeting', - }, - { - action: 'createActivity', - label: 'Log Call', - data: { - link: 'calls', - status: 'Held', - }, - acl: 'edit', - aclScope: 'Call', - }, - { - action: 'archiveEmail', - label: 'Archive Email', - acl: 'edit', - aclScope: 'Email', - }, - ], - - listLayout: { - 'Meeting': { - rows: [ - [ - {name: 'ico', view: 'Crm:Fields.Ico'}, - { - name: 'name', - link: true, - }, - {name: 'status'}, - ], - [ - {name: 'assignedUser'}, - {name: 'dateStart'}, - ] - ] - }, - 'Call': { - rows: [ - [ - {name: 'ico', view: 'Crm:Fields.Ico'}, - { - name: 'name', - link: true, - }, - {name: 'status'}, - ], - [ - {name: 'assignedUser'}, - {name: 'dateStart'}, - ] - ] - }, - 'Email': { - rows: [ - [ - {name: 'ico', view: 'Crm:Fields.Ico'}, - { - name: 'name', - link: true, - }, - ], - [ - {name: 'assignedUser'}, - {name: 'status'}, - {name: 'dateSent'}, - ] - ] - }, - }, - - where: { - scope: false, - }, - - getArchiveEmailAttributes: function (data, callback) { - data = data || {}; - var attributes = { - dateSent: this.getDateTime().getNow(15), - status: 'Archived', - from: this.model.get('emailAddress'), - to: this.getUser().get('emailAddress') - }; - - if (this.model.name == 'Contact') { - if (this.model.get('accountId')) { - attributes.parentType = 'Account', - attributes.parentId = this.model.get('accountId'); - attributes.parentName = this.model.get('accountName'); - } - } else if (this.model.name == 'Lead') { - attributes.parentType = 'Lead', - attributes.parentId = this.model.id - attributes.parentName = this.model.get('name'); - } - callback.call(this, attributes); - }, - - actionArchiveEmail: function (data) { - var self = this; - var link = 'emails'; - var scope = 'Email'; - - var relate = null; - if ('emails' in this.model.defs['links']) { - relate = { - model: this.model, - link: this.model.defs['links']['emails'].foreign - }; - } + scopeList: ['Meeting', 'Call', 'Email'], + + sortBy: 'dateStart', + + asc: false, + + actions: [ + { + action: 'createActivity', + label: 'Log Meeting', + data: { + link: 'meetings', + status: 'Held', + }, + acl: 'edit', + aclScope: 'Meeting', + }, + { + action: 'createActivity', + label: 'Log Call', + data: { + link: 'calls', + status: 'Held', + }, + acl: 'edit', + aclScope: 'Call', + }, + { + action: 'archiveEmail', + label: 'Archive Email', + acl: 'edit', + aclScope: 'Email', + }, + ], + + listLayout: { + 'Meeting': { + rows: [ + [ + {name: 'ico', view: 'Crm:Fields.Ico'}, + { + name: 'name', + link: true, + }, + {name: 'status'}, + ], + [ + {name: 'assignedUser'}, + {name: 'dateStart'}, + ] + ] + }, + 'Call': { + rows: [ + [ + {name: 'ico', view: 'Crm:Fields.Ico'}, + { + name: 'name', + link: true, + }, + {name: 'status'}, + ], + [ + {name: 'assignedUser'}, + {name: 'dateStart'}, + ] + ] + }, + 'Email': { + rows: [ + [ + {name: 'ico', view: 'Crm:Fields.Ico'}, + { + name: 'name', + link: true, + }, + ], + [ + {name: 'assignedUser'}, + {name: 'status'}, + {name: 'dateSent'}, + ] + ] + }, + }, + + where: { + scope: false, + }, + + getArchiveEmailAttributes: function (data, callback) { + data = data || {}; + var attributes = { + dateSent: this.getDateTime().getNow(15), + status: 'Archived', + from: this.model.get('emailAddress'), + to: this.getUser().get('emailAddress') + }; + + if (this.model.name == 'Contact') { + if (this.model.get('accountId')) { + attributes.parentType = 'Account', + attributes.parentId = this.model.get('accountId'); + attributes.parentName = this.model.get('accountName'); + } + } else if (this.model.name == 'Lead') { + attributes.parentType = 'Lead', + attributes.parentId = this.model.id + attributes.parentName = this.model.get('name'); + } + callback.call(this, attributes); + }, + + actionArchiveEmail: function (data) { + var self = this; + var link = 'emails'; + var scope = 'Email'; + + var relate = null; + if ('emails' in this.model.defs['links']) { + relate = { + model: this.model, + link: this.model.defs['links']['emails'].foreign + }; + } - this.notify('Loading...'); - - this.getArchiveEmailAttributes(data, function (attributes) { - this.createView('quickCreate', 'Modals.Edit', { - scope: scope, - relate: relate, - attributes: attributes - }, function (view) { - view.render(); - view.notify(false); - view.once('after:save', function () { - self.collection.fetch(); - }); - }); - }); + this.notify('Loading...'); + + this.getArchiveEmailAttributes(data, function (attributes) { + this.createView('quickCreate', 'Modals.Edit', { + scope: scope, + relate: relate, + attributes: attributes + }, function (view) { + view.render(); + view.notify(false); + view.once('after:save', function () { + self.collection.fetch(); + }); + }); + }); - }, - }); + }, + }); }); diff --git a/frontend/client/modules/crm/src/views/record/panels/tasks.js b/frontend/client/modules/crm/src/views/record/panels/tasks.js index 7955b0772b..82a3c08a94 100644 --- a/frontend/client/modules/crm/src/views/record/panels/tasks.js +++ b/frontend/client/modules/crm/src/views/record/panels/tasks.js @@ -21,147 +21,153 @@ Espo.define('Crm:Views.Record.Panels.Tasks', 'Views.Record.Panels.Relationship', function (Dep) { - return Dep.extend({ + return Dep.extend({ - name: 'tasks', + name: 'tasks', - template: 'crm:record.panels.tasks', + template: 'crm:record.panels.tasks', - tabList: ['Active', 'Inactive'], + tabList: ['Active', 'Inactive'], - sortBy: 'createdAt', + sortBy: 'createdAt', - asc: false, - - actions: [ - { - action: 'createTask', - label: 'Create Task', - acl: 'edit', - aclScope: 'Task', - } - ], + asc: false, + + actions: [ + { + action: 'createTask', + label: 'Create Task', + acl: 'edit', + aclScope: 'Task', + } + ], - listLayout: { - rows: [ - [ - { - name: 'name', - link: true, - }, - { - name: 'isOverdue' - } - ], - [ - {name: 'assignedUser'}, - {name: 'status'}, - {name: 'dateEnd'}, - ] - ] - }, + listLayout: { + rows: [ + [ + { + name: 'name', + link: true, + }, + { + name: 'isOverdue' + } + ], + [ + {name: 'assignedUser'}, + {name: 'status'}, + {name: 'dateEnd'}, + ] + ] + }, - - events: _.extend({ - 'click button.tab-switcher': function (e) { - var $target = $(e.currentTarget); - this.$el.find('button.tab-switcher').removeClass('active'); - $target.addClass('active'); - - this.currentTab = $target.data('tab'); - - this.collection.where = this.where = [ - { - type: 'boolFilters', - value: [this.currentTab] - } - ]; - - this.listenToOnce(this.collection, 'sync', function () { - this.notify(false); - }.bind(this)); - this.notify('Loading...'); - this.collection.fetch(); - - this.getStorage().set('state', this.getStorageKey(), this.currentTab); - } - }, Dep.prototype.events), + + events: _.extend({ + 'click button.tab-switcher': function (e) { + var $target = $(e.currentTarget); + this.$el.find('button.tab-switcher').removeClass('active'); + $target.addClass('active'); + + this.currentTab = $target.data('tab'); + + this.collection.where = this.where = [ + { + type: 'boolFilters', + value: [this.currentTab] + } + ]; + + this.listenToOnce(this.collection, 'sync', function () { + this.notify(false); + }.bind(this)); + this.notify('Loading...'); + this.collection.fetch(); + + this.getStorage().set('state', this.getStorageKey(), this.currentTab); + } + }, Dep.prototype.events), - data: function () { - return { - currentTab: this.currentTab, - tabList: this.tabList - }; - }, - - getStorageKey: function () { - return 'tasks-' + this.model.name + '-' + this.name; - }, + data: function () { + return { + currentTab: this.currentTab, + tabList: this.tabList + }; + }, + + getStorageKey: function () { + return 'tasks-' + this.model.name + '-' + this.name; + }, - setup: function () { - this.currentTab = this.getStorage().get('state', this.getStorageKey()) || 'Active'; - - this.where = [ - { - type: 'boolFilters', - value: [this.currentTab] - } - ]; - }, + setup: function () { + this.currentTab = this.getStorage().get('state', this.getStorageKey()) || 'Active'; + + this.where = [ + { + type: 'boolFilters', + value: [this.currentTab] + } + ]; + }, - afterRender: function () { - var url = this.model.name + '/' + this.model.id + '/tasks'; + afterRender: function () { + var url = this.model.name + '/' + this.model.id + '/tasks'; - this.getCollectionFactory().create('Task', function (collection) { - this.collection = collection; - collection.seeds = this.seeds; - collection.url = url; - collection.where = this.where; - collection.sortBy = this.sortBy; - collection.asc = this.asc; - collection.maxSize = this.getConfig().get('recordsPerPageSmall') || 5; + if (!this.getAcl().check('Task', 'read')) { + this.$el.find('.list-container').html(this.translate('No Access')); + this.$el.find('.button-container').remove(); + return; + }; - this.listenToOnce(this.collection, 'sync', function () { - this.createView('list', 'Record.ListExpanded', { - el: this.$el.selector + ' > .list-container', - pagination: false, - type: 'listRelationship', - rowActionsView: 'Record.RowActions.RelationshipNoUnlink', - checkboxes: false, - collection: collection, - listLayout: this.listLayout, - }, function (view) { - view.render(); - }); - }.bind(this)); - this.collection.fetch(); - }, this); - }, - - actionCreateTask: function (data) { - var self = this; - var link = 'tasks'; - var scope = 'Task'; - var foreignLink = this.model.defs['links'][link].foreign; + this.getCollectionFactory().create('Task', function (collection) { + this.collection = collection; + collection.seeds = this.seeds; + collection.url = url; + collection.where = this.where; + collection.sortBy = this.sortBy; + collection.asc = this.asc; + collection.maxSize = this.getConfig().get('recordsPerPageSmall') || 5; - this.notify('Loading...'); - this.getModelFactory().create(scope, function (model) { - this.createView('quickCreate', 'Modals.Edit', { - scope: scope, - relate: { - model: this.model, - link: foreignLink, - } - }, function (view) { - view.render(); - view.notify(false); - view.once('after:save', function () { - self.collection.fetch(); - }); - }); - }.bind(this)); - }, + this.listenToOnce(this.collection, 'sync', function () { + this.createView('list', 'Record.ListExpanded', { + el: this.$el.selector + ' > .list-container', + pagination: false, + type: 'listRelationship', + rowActionsView: 'Record.RowActions.RelationshipNoUnlink', + checkboxes: false, + collection: collection, + listLayout: this.listLayout, + }, function (view) { + view.render(); + }); + }.bind(this)); + this.collection.fetch(); + }, this); + }, + + actionCreateTask: function (data) { + var self = this; + var link = 'tasks'; + var scope = 'Task'; + var foreignLink = this.model.defs['links'][link].foreign; - }); + this.notify('Loading...'); + this.getModelFactory().create(scope, function (model) { + this.createView('quickCreate', 'Modals.Edit', { + scope: scope, + relate: { + model: this.model, + link: foreignLink, + } + }, function (view) { + view.render(); + view.notify(false); + view.once('after:save', function () { + self.collection.fetch(); + }); + }); + }.bind(this)); + }, + + }); }); diff --git a/frontend/client/modules/crm/src/views/target/detail.js b/frontend/client/modules/crm/src/views/target/detail.js index 306a0eccaa..a2b5699ed1 100644 --- a/frontend/client/modules/crm/src/views/target/detail.js +++ b/frontend/client/modules/crm/src/views/target/detail.js @@ -21,26 +21,26 @@ Espo.define('Crm:Views.Target.Detail', 'Views.Detail', function (Dep) { - return Dep.extend({ + return Dep.extend({ - actionConvertToLead: function () { - var id = this.model.id; - var self = this; - - if (confirm(this.translate('confirmation', 'messages'))) { - self.notify('Please wait...'); - $.ajax({ - url: 'Target/action/convert', - data: JSON.stringify({id: id}), - type: 'POST', - success: function (data) { - self.getRouter().navigate('#Lead/view/' + data.id, {trigger: true}); - self.notify('Converted', 'success'); - } - }); - } - }, + actionConvertToLead: function () { + var id = this.model.id; + var self = this; + + if (confirm(this.translate('confirmation', 'messages'))) { + self.notify('Please wait...'); + $.ajax({ + url: 'Target/action/convert', + data: JSON.stringify({id: id}), + type: 'POST', + success: function (data) { + self.getRouter().navigate('#Lead/view/' + data.id, {trigger: true}); + self.notify('Converted', 'success'); + } + }); + } + }, - }); + }); }); diff --git a/frontend/client/modules/crm/src/views/task/detail.js b/frontend/client/modules/crm/src/views/task/detail.js new file mode 100644 index 0000000000..15f3331339 --- /dev/null +++ b/frontend/client/modules/crm/src/views/task/detail.js @@ -0,0 +1,57 @@ +/************************************************************************ + * 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/. + ************************************************************************/ + +Espo.define('Crm:Views.Task.Detail', 'Views.Detail', function (Dep) { + + return Dep.extend({ + + setup: function () { + Dep.prototype.setup.call(this); + if (!~['Completed', 'Canceled'].indexOf(this.model.get('status'))) { + if (this.getAcl().checkModel(this.model, 'edit')) { + this.menu.buttons.push({ + 'label': 'Complete', + 'action': 'setCompleted', + icon: 'glyphicon glyphicon-ok', + 'acl': 'edit', + }); + } + } + }, + + actionSetCompleted: function (data) { + var id = data.id; + + this.model.save({ + status: 'Completed' + }, { + patch: true, + success: function () { + Espo.Ui.success(this.translate('Saved')); + this.$el.find('[data-action="setCompleted"]').remove(); + }.bind(this), + }); + + }, + + }); + +}); diff --git a/frontend/client/modules/crm/src/views/task/fields/date-end.js b/frontend/client/modules/crm/src/views/task/fields/date-end.js index 5345478778..1de6f1c406 100644 --- a/frontend/client/modules/crm/src/views/task/fields/date-end.js +++ b/frontend/client/modules/crm/src/views/task/fields/date-end.js @@ -21,31 +21,31 @@ Espo.define('Crm:Views.Task.Fields.DateEnd', 'Views.Fields.Datetime', function (Dep) { - return Dep.extend({ - - detailTemplate: 'crm:task.fields.date-end.detail', - - listTemplate: 'crm:task.fields.date-end.detail', - - data: function () { - var data = Dep.prototype.data.call(this); - - if (!~['Completed', 'Canceled'].indexOf(this.model.get('status'))) { - if (this.mode == 'list' || this.mode == 'detail') { - var value = this.model.get(this.name); - if (value) { - var d = this.getDateTime().toMoment(value); - var now = moment().tz(this.getDateTime().timeZone || 'UTC'); - if (d.unix() < now.unix()) { - data.isOverdue = true; - } - } - } - } - - return data; - }, - - }); + return Dep.extend({ + + detailTemplate: 'crm:task.fields.date-end.detail', + + listTemplate: 'crm:task.fields.date-end.detail', + + data: function () { + var data = Dep.prototype.data.call(this); + + if (!~['Completed', 'Canceled'].indexOf(this.model.get('status'))) { + if (this.mode == 'list' || this.mode == 'detail') { + var value = this.model.get(this.name); + if (value) { + var d = this.getDateTime().toMoment(value); + var now = moment().tz(this.getDateTime().timeZone || 'UTC'); + if (d.unix() < now.unix()) { + data.isOverdue = true; + } + } + } + } + + return data; + }, + + }); }); diff --git a/frontend/client/modules/crm/src/views/task/fields/is-overdue.js b/frontend/client/modules/crm/src/views/task/fields/is-overdue.js index e2201418e8..da014aa8e8 100644 --- a/frontend/client/modules/crm/src/views/task/fields/is-overdue.js +++ b/frontend/client/modules/crm/src/views/task/fields/is-overdue.js @@ -20,29 +20,29 @@ ************************************************************************/ Espo.define('Crm:Views.Task.Fields.IsOverdue', 'Views.Fields.Base', function (Dep) { - - return Dep.extend({ - - readOnly: true, - - _template: '{{#if isOverdue}}{{translate "overdue"}}{{/if}}', - - data: function () { - var isOverdue = false; - if (['Completed', 'Canceled'].indexOf(this.model.get('status')) == -1) { - if (this.model.has('dateEnd')) { - isOverdue = moment.utc().unix() > moment.utc(this.model.get('dateEnd')).unix(); - } - } - return { - isOverdue: isOverdue - }; - }, - - setup: function () { - this.mode = 'detail'; - }, - - }); + + return Dep.extend({ + + readOnly: true, + + _template: '{{#if isOverdue}}{{translate "overdue"}}{{/if}}', + + data: function () { + var isOverdue = false; + if (['Completed', 'Canceled'].indexOf(this.model.get('status')) == -1) { + if (this.model.has('dateEnd')) { + isOverdue = moment.utc().unix() > moment.utc(this.model.get('dateEnd')).unix(); + } + } + return { + isOverdue: isOverdue + }; + }, + + setup: function () { + this.mode = 'detail'; + }, + + }); }); diff --git a/frontend/client/modules/crm/src/views/task/list.js b/frontend/client/modules/crm/src/views/task/list.js new file mode 100644 index 0000000000..8852420860 --- /dev/null +++ b/frontend/client/modules/crm/src/views/task/list.js @@ -0,0 +1,50 @@ +/************************************************************************ + * 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/. + ************************************************************************/ + +Espo.define('Crm:Views.Task.List', 'Views.List', function (Dep) { + + return Dep.extend({ + + actionSetCompleted: function (data) { + var id = data.id; + if (!id) { + return; + } + var model = this.collection.get(id); + if (!model) { + return; + } + + model.set('status', 'Completed'); + + this.listenToOnce(model, 'sync', function () { + this.notify(false); + this.collection.fetch(); + }, this); + + this.notify('Saving...'); + model.save(); + + }, + + }); + +}); diff --git a/frontend/client/src/views/team/record/detail-side.js b/frontend/client/modules/crm/src/views/task/record/list.js similarity index 76% rename from frontend/client/src/views/team/record/detail-side.js rename to frontend/client/modules/crm/src/views/task/record/list.js index 31d6818878..5470adf2bd 100644 --- a/frontend/client/src/views/team/record/detail-side.js +++ b/frontend/client/modules/crm/src/views/task/record/list.js @@ -18,24 +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/. ************************************************************************/ - -Espo.define('Views.Team.Record.DetailSide', 'Views.Record.DetailSide', function (Dep) { + +Espo.define('Crm:Views.Task.Record.List', 'Views.Record.List', function (Dep) { - return Dep.extend({ - - panels: [ - { - name: 'default', - label: false, - view: 'Record.Panels.Side', - options: { - fields: ['roles'], - mode: 'detail', - } - } - ], - - }); - + return Dep.extend({ + + rowActionsView: 'Crm:Task.Record.RowActions.Default', + + }); + }); - diff --git a/frontend/client/modules/crm/src/views/task/record/row-actions/default.js b/frontend/client/modules/crm/src/views/task/record/row-actions/default.js new file mode 100644 index 0000000000..95d8989c63 --- /dev/null +++ b/frontend/client/modules/crm/src/views/task/record/row-actions/default.js @@ -0,0 +1,43 @@ +/************************************************************************ + * 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/. + ************************************************************************/ + +Espo.define('Crm:Views.Task.Record.RowActions.Default', 'Views.Record.RowActions.Default', function (Dep) { + + return Dep.extend({ + + getActions: function () { + var actions = Dep.prototype.getActions.call(this); + + if (this.options.acl.edit && !~['Completed', 'Canceled'].indexOf(this.model.get('status'))) { + actions.push({ + action: 'setCompleted', + label: 'Complete', + data: { + id: this.model.id + } + }); + } + + return actions; + }, + }); + +}); diff --git a/frontend/client/res/layout-types/columns-2.tpl b/frontend/client/res/layout-types/columns-2.tpl index 3372bdd032..db2ad4433e 100644 --- a/frontend/client/res/layout-types/columns-2.tpl +++ b/frontend/client/res/layout-types/columns-2.tpl @@ -1,22 +1,22 @@ - + <% _.each(layout, function (row, rowNumber) { %> -
    - <% _.each(row, function (defs, key) { %> - <% - var tag = 'tag' in defs ? defs.tag : 'div'; - print( '<' + tag); - if ('id' in defs) { - print(' id="'+defs.id+'"'); - } - print(' class="'); - if ('class' in defs) { - print(defs.class); - }; - print('"'); - print('>'); - %> - {{{<%= defs.name %>}}} - <%= '' %> - <% }); %> -
    +
    + <% _.each(row, function (defs, key) { %> + <% + var tag = 'tag' in defs ? defs.tag : 'div'; + print( '<' + tag); + if ('id' in defs) { + print(' id="'+defs.id+'"'); + } + print(' class="'); + if ('class' in defs) { + print(defs.class); + }; + print('"'); + print('>'); + %> + {{{<%= defs.name %>}}} + <%= '' %> + <% }); %> +
    <% }); %> diff --git a/frontend/client/res/layout-types/default.tpl b/frontend/client/res/layout-types/default.tpl index 1ce0001080..707706aa35 100644 --- a/frontend/client/res/layout-types/default.tpl +++ b/frontend/client/res/layout-types/default.tpl @@ -1,15 +1,15 @@ - + <% _.each(layout, function (defs, key) { - var tag = 'tag' in defs ? defs.tag : 'div'; - print( '<' + tag); - if ('id' in defs) { - print(' id="'+defs.id+'"'); - } - if ('class' in defs) { - print(' class="'+defs.class+'"'); - } - print('>'); - %> - {{{<%= defs.name %>}}} - <%= '' %> + var tag = 'tag' in defs ? defs.tag : 'div'; + print( '<' + tag); + if ('id' in defs) { + print(' id="'+defs.id+'"'); + } + if ('class' in defs) { + print(' class="'+defs.class+'"'); + } + print('>'); + %> + {{{<%= defs.name %>}}} + <%= '' %> <% }); %> diff --git a/frontend/client/res/layout-types/list-row-expanded.tpl b/frontend/client/res/layout-types/list-row-expanded.tpl index 6a0802b5c2..1e8621c9f3 100644 --- a/frontend/client/res/layout-types/list-row-expanded.tpl +++ b/frontend/client/res/layout-types/list-row-expanded.tpl @@ -1,30 +1,30 @@ -
  • +
  • <% if (layout.right) { %>
    - {{{<%= layout.right.name %>}}} -
    + {{{<%= layout.right.name %>}}} +
  • <% } %> <% _.each(layout.rows, function (row, key) { %> -
    - <% _.each(row, function (defs, key) { %> - <% - var tag = 'tag' in defs ? defs.tag : false; - if (tag) { - print( '<' + tag); - if ('id' in defs) { - print(' id="'+defs.id+'"'); - } - if ('class' in defs) { - print(' class="'+defs.class+'"'); - }; - print('>'); - } - %>{{{<%= defs.name %>}}}<% - if (tag) { - print( ''); - } - %> - <% }); %> -
    +
    + <% _.each(row, function (defs, key) { %> + <% + var tag = 'tag' in defs ? defs.tag : false; + if (tag) { + print( '<' + tag); + if ('id' in defs) { + print(' id="'+defs.id+'"'); + } + if ('class' in defs) { + print(' class="'+defs.class+'"'); + }; + print('>'); + } + %>{{{<%= defs.name %>}}}<% + if (tag) { + print( ''); + } + %> + <% }); %> +
    <% }); %> diff --git a/frontend/client/res/layout-types/list-row.tpl b/frontend/client/res/layout-types/list-row.tpl index 3f2cb213f2..bd4dc62a2b 100644 --- a/frontend/client/res/layout-types/list-row.tpl +++ b/frontend/client/res/layout-types/list-row.tpl @@ -1,33 +1,33 @@
  • <% _.each(layout, function (defs, key) { %> - <% - var width = ''; - if (defs.options && defs.options.defs && defs.options.defs.params) { - width = defs.options.defs.params.width || ''; - } - var align = false; - if (defs.options && defs.options.defs && defs.options.defs.params) { - align = defs.options.defs.params.align || false; - } - %> - + <% + var width = ''; + if (defs.options && defs.options.defs && defs.options.defs.params) { + width = defs.options.defs.params.width || ''; + } + var align = false; + if (defs.options && defs.options.defs && defs.options.defs.params) { + align = defs.options.defs.params.align || false; + } + %> + <% }); %> diff --git a/frontend/client/res/layout-types/record.tpl b/frontend/client/res/layout-types/record.tpl index 13155a4b27..ef7611c056 100644 --- a/frontend/client/res/layout-types/record.tpl +++ b/frontend/client/res/layout-types/record.tpl @@ -1,41 +1,41 @@ <% _.each(layout, function (panel, columnNumber) { %> -
    > - {{#if "<%= panel.label %>"}} -

    <%= "{{translate \"" + panel.label + "\" scope=\""+model.name+"\"}}" %>

    - {{/if}} -
    - <% _.each(panel.rows, function (row, rowNumber) { %> -
    - <% _.each(row, function (cell, cellNumber) { %> - <% if (cell != false) { %> -
    - -
    - <% - if ('customCode' in cell) { - print (cell.customCode); - } else { - print ("{{{"+cell.name+"}}}"); - } - %> -
    -
    - <% } else { %> -
    - <% } %> - <% }); %> -
    - <% }); %> -
    -
    +
    > + {{#if "<%= panel.label %>"}} +

    <%= "{{translate \"" + panel.label + "\" scope=\""+model.name+"\"}}" %>

    + {{/if}} +
    + <% _.each(panel.rows, function (row, rowNumber) { %> +
    + <% _.each(row, function (cell, cellNumber) { %> + <% if (cell != false) { %> +
    + +
    + <% + if ('customCode' in cell) { + print (cell.customCode); + } else { + print ("{{{"+cell.name+"}}}"); + } + %> +
    +
    + <% } else { %> +
    + <% } %> + <% }); %> +
    + <% }); %> +
    +
    <% }); %> diff --git a/frontend/client/res/templates/about.tpl b/frontend/client/res/templates/about.tpl index ae6b472003..05d8a48386 100644 --- a/frontend/client/res/templates/about.tpl +++ b/frontend/client/res/templates/about.tpl @@ -1,27 +1,27 @@
    -
    -

    - Version {{version}} -

    -

    - Copyright © 2014 EspoCRM: 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. -

    -
    +
    +

    + Version {{version}} +

    +

    + Copyright © 2014 EspoCRM: 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. +

    +
    diff --git a/frontend/client/res/templates/admin/extensions/done.tpl b/frontend/client/res/templates/admin/extensions/done.tpl index 5bebd05fc6..21465c8413 100644 --- a/frontend/client/res/templates/admin/extensions/done.tpl +++ b/frontend/client/res/templates/admin/extensions/done.tpl @@ -1,5 +1,5 @@

    - {{{text}}} + {{{text}}}

    diff --git a/frontend/client/res/templates/admin/extensions/index.tpl b/frontend/client/res/templates/admin/extensions/index.tpl index fd3f20f1e0..4e9cdc3549 100644 --- a/frontend/client/res/templates/admin/extensions/index.tpl +++ b/frontend/client/res/templates/admin/extensions/index.tpl @@ -1,18 +1,18 @@
    -
    -

    {{translate 'selectExtensionPackage' category='messages' scope='Admin'}}

    -
    -
    -
    - -
    -
    -
    - -
    -
    +
    +

    {{translate 'selectExtensionPackage' category='messages' scope='Admin'}}

    +
    +
    +
    + +
    +
    +
    + +
    +
    diff --git a/frontend/client/res/templates/admin/extensions/ready.tpl b/frontend/client/res/templates/admin/extensions/ready.tpl index 030262da6d..76d39c0cab 100644 --- a/frontend/client/res/templates/admin/extensions/ready.tpl +++ b/frontend/client/res/templates/admin/extensions/ready.tpl @@ -1,5 +1,5 @@

    - {{{text}}} + {{{text}}}

    diff --git a/frontend/client/res/templates/admin/field-manager/edit.tpl b/frontend/client/res/templates/admin/field-manager/edit.tpl index 79bcc6d09d..35a3bcac5b 100644 --- a/frontend/client/res/templates/admin/field-manager/edit.tpl +++ b/frontend/client/res/templates/admin/field-manager/edit.tpl @@ -1,30 +1,30 @@
    - - + +
    -
    -
    - -
    {{translate type scope='Admin' category='fieldTypes'}}
    -
    -
    - -
    {{{name}}}
    -
    -
    - -
    {{{label}}}
    -
    - - {{#each params}} - {{#unless hidden}} -
    - -
    {{{var ../name ../../this}}}
    -
    - {{/unless}} - {{/each}} -
    +
    +
    + +
    {{translate type scope='Admin' category='fieldTypes'}}
    +
    +
    + +
    {{{name}}}
    +
    +
    + +
    {{{label}}}
    +
    + + {{#each params}} + {{#unless hidden}} +
    + +
    {{{var ../name ../../this}}}
    +
    + {{/unless}} + {{/each}} +
    diff --git a/frontend/client/res/templates/admin/field-manager/index.tpl b/frontend/client/res/templates/admin/field-manager/index.tpl index 148d99f717..0b315febaa 100644 --- a/frontend/client/res/templates/admin/field-manager/index.tpl +++ b/frontend/client/res/templates/admin/field-manager/index.tpl @@ -1,20 +1,20 @@
    -
    - -
    +
    + +
    -
    -

    -
    - {{{content}}} -
    -
    +
    +

    +
    + {{{content}}} +
    +
    diff --git a/frontend/client/res/templates/admin/field-manager/list.tpl b/frontend/client/res/templates/admin/field-manager/list.tpl index 52945494c3..fa5e810f81 100644 --- a/frontend/client/res/templates/admin/field-manager/list.tpl +++ b/frontend/client/res/templates/admin/field-manager/list.tpl @@ -1,29 +1,29 @@
    -
    - - -
    +
    + + +
    > - <% - var tag = 'tag' in defs ? defs.tag : false; - if (tag) { - print( '<' + tag); - if ('id' in defs) { - print(' id="'+defs.id+'"'); - } - if ('class' in defs) { - print(' class="'+defs.class+'"'); - }; - print('>'); - } - %>{{{<%= defs.name %>}}}<% - if (tag) { - print( ''); - } - %> - > + <% + var tag = 'tag' in defs ? defs.tag : false; + if (tag) { + print( '<' + tag); + if ('id' in defs) { + print(' id="'+defs.id+'"'); + } + if ('class' in defs) { + print(' class="'+defs.class+'"'); + }; + print('>'); + } + %>{{{<%= defs.name %>}}}<% + if (tag) { + print( ''); + } + %> +
    - - - - {{#each fieldDefsArray}} - - - - - - - {{/each}} - + + + + {{#each fieldDefsArray}} + + + + + + + {{/each}} +
    {{translate 'Name'}} - {{translate 'Label'}} - {{translate 'Type'}} - -
    {{name}}{{translate name scope=../scope category='fields'}}{{translate type category='fieldTypes' scope='Admin'}}{{#if isCustom}}remove{{/if}}
    {{translate 'Name'}} + {{translate 'Label'}} + {{translate 'Type'}} + +
    {{name}}{{translate name scope=../scope category='fields'}}{{translate type category='fieldTypes' scope='Admin'}}{{#if isCustom}}remove{{/if}}
    diff --git a/frontend/client/res/templates/admin/index.tpl b/frontend/client/res/templates/admin/index.tpl index 879d6bd370..1c4e92ab96 100644 --- a/frontend/client/res/templates/admin/index.tpl +++ b/frontend/client/res/templates/admin/index.tpl @@ -3,14 +3,14 @@ {{#each links}}

    {{translate label scope='Admin'}}

    - {{#each items}} - - - - - {{/each}} + {{#each items}} + + + + + {{/each}}
    - {{translate label scope='Admin' category='labels'}} - {{translate description scope='Admin' category='descriptions'}}
    + {{translate label scope='Admin' category='labels'}} + {{translate description scope='Admin' category='descriptions'}}
    {{/each}} diff --git a/frontend/client/res/templates/admin/integrations/edit.tpl b/frontend/client/res/templates/admin/integrations/edit.tpl index 74c17e7faa..97a3497f13 100644 --- a/frontend/client/res/templates/admin/integrations/edit.tpl +++ b/frontend/client/res/templates/admin/integrations/edit.tpl @@ -1,26 +1,26 @@
    - - + +
    -
    -
    - -
    {{{enabled}}}
    -
    - {{#each dataFieldList}} -
    - -
    {{{var this ../this}}}
    -
    - {{/each}} -
    -
    - {{#if helpText}} -
    - {{{../helpText}}} -
    - {{/if}} -
    +
    +
    + +
    {{{enabled}}}
    +
    + {{#each dataFieldList}} +
    + +
    {{{var this ../this}}}
    +
    + {{/each}} +
    +
    + {{#if helpText}} +
    + {{{../helpText}}} +
    + {{/if}} +
    diff --git a/frontend/client/res/templates/admin/integrations/index.tpl b/frontend/client/res/templates/admin/integrations/index.tpl index 4de3328d50..96d71c1eb1 100644 --- a/frontend/client/res/templates/admin/integrations/index.tpl +++ b/frontend/client/res/templates/admin/integrations/index.tpl @@ -1,20 +1,20 @@
    -
    -
      - {{#each integrationList}} -
    • {{./this}}
    • - {{/each}} -
    -
    +
    +
      + {{#each integrationList}} +
    • {{./this}}
    • + {{/each}} +
    +
    -
    -

    -
    - {{{content}}} -
    -
    +
    +

    +
    + {{{content}}} +
    +
    diff --git a/frontend/client/res/templates/admin/integrations/oauth2.tpl b/frontend/client/res/templates/admin/integrations/oauth2.tpl index f661420a58..90b510bb5e 100644 --- a/frontend/client/res/templates/admin/integrations/oauth2.tpl +++ b/frontend/client/res/templates/admin/integrations/oauth2.tpl @@ -1,32 +1,32 @@
    - - + +
    -
    -
    - -
    {{{enabled}}}
    -
    - {{#each dataFieldList}} -
    - -
    {{{var this ../this}}}
    -
    - {{/each}} -
    - -
    - -
    -
    -
    -
    - {{#if helpText}} -
    - {{{../helpText}}} -
    - {{/if}} -
    +
    +
    + +
    {{{enabled}}}
    +
    + {{#each dataFieldList}} +
    + +
    {{{var this ../this}}}
    +
    + {{/each}} +
    + +
    + +
    +
    +
    +
    + {{#if helpText}} +
    + {{{../helpText}}} +
    + {{/if}} +
    diff --git a/frontend/client/res/templates/admin/layouts/grid.tpl b/frontend/client/res/templates/admin/layouts/grid.tpl index c2a9c7829c..c3e4990f33 100644 --- a/frontend/client/res/templates/admin/layouts/grid.tpl +++ b/frontend/client/res/templates/admin/layouts/grid.tpl @@ -1,214 +1,220 @@
    {{#each buttons}} - {{button name label=label scope='Admin' style=style}} + {{button name label=label scope='Admin' style=style}} {{/each}}
    - -
    -
    -
    {{translate 'Available Fields' scope='Admin'}}
    -
      - {{#each disabledFields}} -
    • {{translate this scope=../scope category='fields'}} -   -
    • - {{/each}} -
    -
    -
    + +
    +
    +
    {{translate 'Available Fields' scope='Admin'}}
    +
      + {{#each disabledFields}} +
    • {{translate this scope=../scope category='fields'}} +   +
    • + {{/each}} +
    +
    +
    diff --git a/frontend/client/res/templates/admin/layouts/index.tpl b/frontend/client/res/templates/admin/layouts/index.tpl index 18d51f3367..4771a0725d 100644 --- a/frontend/client/res/templates/admin/layouts/index.tpl +++ b/frontend/client/res/templates/admin/layouts/index.tpl @@ -1,35 +1,35 @@
    -
    -
    - {{#each scopeList}} -
    - -
    -
    -
      - {{#each ../typeList}} -
    • - -
    • - {{/each}} -
    -
    -
    -
    - {{/each}} -
    -
    +
    +
    + {{#each layoutScopeDataList}} +
    + +
    +
    +
      + {{#each typeList}} +
    • + +
    • + {{/each}} +
    +
    +
    +
    + {{/each}} +
    +
    -
    -

    -
    - {{{content}}} -
    -
    +
    +

    +
    + {{{content}}} +
    +
    diff --git a/frontend/client/res/templates/admin/layouts/rows.tpl b/frontend/client/res/templates/admin/layouts/rows.tpl index cf49e8daf0..141ea30a7b 100644 --- a/frontend/client/res/templates/admin/layouts/rows.tpl +++ b/frontend/client/res/templates/admin/layouts/rows.tpl @@ -1,121 +1,121 @@
    {{#each buttons}} - {{button name label=label scope='Admin' style=style}} + {{button name label=label scope='Admin' style=style}} {{/each}}
    -
    -
    -
    {{translate 'Enabled' scope='Admin'}}
    -
      - {{#each layout}} -
    • -
      - -
      - {{#if ../editable}} -
      - {{/if}} -
    • - {{/each}} -
    -
    -
    -
    -
    -
    {{translate 'Disabled' scope='Admin'}}
    -
      - {{#each disabledFields}} -
    • -
      - -
      - {{#if ../editable}} -
      - {{/if}} -
    • - {{/each}} -
    -
    -
    +
    +
    +
    {{translate 'Enabled' scope='Admin'}}
    +
      + {{#each layout}} +
    • +
      + +
      + {{#if ../editable}} +
      + {{/if}} +
    • + {{/each}} +
    +
    +
    +
    +
    +
    {{translate 'Disabled' scope='Admin'}}
    +
      + {{#each disabledFields}} +
    • +
      + +
      + {{#if ../editable}} +
      + {{/if}} +
    • + {{/each}} +
    +
    +
    diff --git a/frontend/client/res/templates/admin/upgrade/index.tpl b/frontend/client/res/templates/admin/upgrade/index.tpl index 1792c4ecb5..e1650ad9dc 100644 --- a/frontend/client/res/templates/admin/upgrade/index.tpl +++ b/frontend/client/res/templates/admin/upgrade/index.tpl @@ -1,30 +1,30 @@
    -
    -

    - {{backupsMsg}} -

    -
    +
    +

    + {{backupsMsg}} +

    +
    -
    -

    {{translate 'selectUpgradePackage' scope='Admin' category="messages"}}

    -
    -
    - -

    - {{{translate 'downloadUpgradePackage' scope='Admin' category="messages"}}} -

    -
    - -
    -
    -
    - -
    -
    +
    +

    {{translate 'selectUpgradePackage' scope='Admin' category="messages"}}

    +
    +
    + +

    + {{{translate 'downloadUpgradePackage' scope='Admin' category="messages"}}} +

    +
    + +
    +
    +
    + +
    +
    diff --git a/frontend/client/res/templates/dashboard.tpl b/frontend/client/res/templates/dashboard.tpl index b499dc887c..68c6fbde2a 100644 --- a/frontend/client/res/templates/dashboard.tpl +++ b/frontend/client/res/templates/dashboard.tpl @@ -1,11 +1,11 @@
    {{{dashlets}}}
    diff --git a/frontend/client/res/templates/dashlet.tpl b/frontend/client/res/templates/dashlet.tpl index 7c9f1e42e9..8ada50de8d 100644 --- a/frontend/client/res/templates/dashlet.tpl +++ b/frontend/client/res/templates/dashlet.tpl @@ -1,14 +1,14 @@ diff --git a/frontend/client/res/templates/dashlets/options/base.tpl b/frontend/client/res/templates/dashlets/options/base.tpl index 50ee81b290..b13282d25f 100644 --- a/frontend/client/res/templates/dashlets/options/base.tpl +++ b/frontend/client/res/templates/dashlets/options/base.tpl @@ -1,3 +1,3 @@
    -
    {{{record}}}
    +
    {{{record}}}
    diff --git a/frontend/client/res/templates/dashlets/options/record-list.tpl b/frontend/client/res/templates/dashlets/options/record-list.tpl index b9e3c96612..450258838b 100644 --- a/frontend/client/res/templates/dashlets/options/record-list.tpl +++ b/frontend/client/res/templates/dashlets/options/record-list.tpl @@ -1,17 +1,17 @@
    -
    -
    - - -
    -
    - - -
    -
    +
    +
    + + +
    +
    + + +
    +
    diff --git a/frontend/client/res/templates/email-account/fields/folder/edit.tpl b/frontend/client/res/templates/email-account/fields/folder/edit.tpl index bb60aadcb5..88c42c50c4 100644 --- a/frontend/client/res/templates/email-account/fields/folder/edit.tpl +++ b/frontend/client/res/templates/email-account/fields/folder/edit.tpl @@ -1,8 +1,8 @@
    - - + + - +
    diff --git a/frontend/client/res/templates/email-account/modals/select-folder.tpl b/frontend/client/res/templates/email-account/modals/select-folder.tpl index 5bb8d78c3f..f62dd3f962 100644 --- a/frontend/client/res/templates/email-account/modals/select-folder.tpl +++ b/frontend/client/res/templates/email-account/modals/select-folder.tpl @@ -1,11 +1,11 @@ {{#unless folders}} - {{translate 'No Data'}} + {{translate 'No Data'}} {{/unless}}
      {{#each folders}} -
    • - {{./this}} - -
    • +
    • + {{./this}} + +
    • {{/each}}
    diff --git a/frontend/client/res/templates/email-template/fields/insert-field/edit.tpl b/frontend/client/res/templates/email-template/fields/insert-field/edit.tpl index 8483fd0262..32afb27381 100644 --- a/frontend/client/res/templates/email-template/fields/insert-field/edit.tpl +++ b/frontend/client/res/templates/email-template/fields/insert-field/edit.tpl @@ -1,11 +1,11 @@
    -
    - -
    -
    - -
    -
    - -
    +
    + +
    +
    + +
    +
    + +
    diff --git a/frontend/client/res/templates/email/fields/compose-from-address/edit.tpl b/frontend/client/res/templates/email/fields/compose-from-address/edit.tpl index 441aa1c98e..a33b219137 100644 --- a/frontend/client/res/templates/email/fields/compose-from-address/edit.tpl +++ b/frontend/client/res/templates/email/fields/compose-from-address/edit.tpl @@ -1,5 +1,9 @@ - + {{#each list}} +