diff --git a/application/Espo/Controllers/Import.php b/application/Espo/Controllers/Import.php index 2bdee9852a..46f2b3e89c 100644 --- a/application/Espo/Controllers/Import.php +++ b/application/Espo/Controllers/Import.php @@ -46,6 +46,21 @@ class Import extends \Espo\Core\Controllers\Record throw new BadRequest(); } + public function actionMassUpdate($params, $data, $request) + { + throw new BadRequest(); + } + + public function actionCreateLink($params, $data) + { + throw new BadRequest(); + } + + public function actionRemoveLink($params, $data) + { + throw new BadRequest(); + } + protected function getFileManager() { return $this->getContainer()->get('fileManager'); @@ -63,6 +78,7 @@ class Import extends \Espo\Core\Controllers\Record $attachment = $this->getEntityManager()->getEntity('Attachment'); $attachment->set('type', 'text/csv'); $attachment->set('role', 'Import File'); + $attachment->set('name', 'import-batch-file.csv'); $this->getEntityManager()->saveEntity($attachment); $this->getFileManager()->putContents('data/upload/' . $attachment->id, $contents); diff --git a/application/Espo/Repositories/Import.php b/application/Espo/Repositories/Import.php new file mode 100644 index 0000000000..504ad0663f --- /dev/null +++ b/application/Espo/Repositories/Import.php @@ -0,0 +1,99 @@ +get('entityType'); + + + + $selectParams['customJoin'] .= $this->getRelatedJoin($entity, $link); + + return $this->getEntityManager()->getRepository($entityType)->find($selectParams); + } + + protected function getRelatedJoin(Entity $entity, $link) + { + $entityType = $entity->get('entityType'); + $pdo = $this->getEntityManager()->getPDO(); + $table = $this->getEntityManager()->getQuery()->toDb($entityType); + + $part = "0"; + switch ($link) { + case 'imported': + $part = "import_entity.is_imported = 1"; + break; + case 'duplicates': + $part = "import_entity.is_duplicate = 1"; + break; + case 'updates': + $part = "import_entity.is_updated = 1"; + break; + } + + + $sql = " + JOIN import_entity ON + import_entity.import_id = " . $pdo->quote($entity->id) . " AND + import_entity.entity_type = " . $pdo->quote($entity->get('entityType')) . " AND + import_entity.entity_id = " . $table . ".id AND + ".$part." + "; + + return $sql; + } + + public function countRelated(Entity $entity, $link, $selectParams) + { + $entityType = $entity->get('entityType'); + + + $selectParams['customJoin'] .= $this->getRelatedJoin($entity, $link); + + return $this->getEntityManager()->getRepository($entityType)->count($selectParams); + } + + protected function afterRemove(Entity $entity) + { + if ($entity->get('fileId')) { + $attachment = $this->getEntityManager()->getEntity('Attachment', $entity->get('fileId')); + if ($attachment) { + $this->getEntityManager()->removeEntity($attachment); + } + } + $sql = "DELETE FROM import_entity WHERE import_id = :importId"; + $sth = $pdo->prepare($sql); + $sth->bindValue(':importId', $entity->id); + $sth->execute(); + + parent::afterRemove($entity); + + } + +} + diff --git a/application/Espo/Resources/i18n/en_US/Import.json b/application/Espo/Resources/i18n/en_US/Import.json index 4044d43f75..79d3a20ac5 100644 --- a/application/Espo/Resources/i18n/en_US/Import.json +++ b/application/Espo/Resources/i18n/en_US/Import.json @@ -18,9 +18,7 @@ }, "fields": { "file": "File", - "entityType": "Entity Type" - }, - "links": { + "entityType": "Entity Type", "imported": "Imported Records", "duplicates": "Duplicate Records", "updated": "Updated Records" diff --git a/application/Espo/Resources/metadata/clientDefs/Import.json b/application/Espo/Resources/metadata/clientDefs/Import.json index e99a4287be..67386e0b9c 100644 --- a/application/Espo/Resources/metadata/clientDefs/Import.json +++ b/application/Espo/Resources/metadata/clientDefs/Import.json @@ -5,7 +5,27 @@ "detail": "Import.Record.Detail" }, "views": { - "list": "Import.List" + "list": "Import.List", + "detail": "Import.Detail" + }, + "bottomPanels": { + "detail": [ + { + "name": "imported", + "label": "Imported", + "view": "Import.Record.Panels.Imported" + }, + { + "name": "duplicates", + "label": "Duplicates", + "view": "Import.Record.Panels.Duplicates" + }, + { + "name": "updated", + "label": "Updated", + "view": "Import.Record.Panels.Updated" + } + ] }, "disableSearchPanel": true } diff --git a/application/Espo/Services/Import.php b/application/Espo/Services/Import.php index cc1394cf5f..3e5609292f 100644 --- a/application/Espo/Services/Import.php +++ b/application/Espo/Services/Import.php @@ -83,6 +83,42 @@ class Import extends \Espo\Services\Record return $this->injections['serviceFactory']; } + public function findLinkedEntities($id, $link, $params) + { + $entity = $this->getRepository()->get($id); + $foreignEntityName = $entity->get('entityType'); + + 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) { + $recordService->loadAdditionalFieldsForList($e); + $recordService->prepareEntityForOutput($e); + } + + $total = $this->getRepository()->countRelated($entity, $link, $selectParams); + + return array( + 'total' => $total, + 'collection' => $collection + ); + } + protected function readCsvString(&$string, $CSV_SEPARATOR = ';', $CSV_ENCLOSURE = '"', $CSV_LINEBREAK = "\n") { $o = array(); @@ -177,7 +213,8 @@ class Import extends \Espo\Services\Record $import = $this->getEntityManager()->getEntity('Import'); $import->set(array( - 'enityType' => $scope + 'entityType' => $scope, + 'fileId' => $attachmentId )); $this->getEntityManager()->saveEntity($import); @@ -209,18 +246,20 @@ class Import extends \Espo\Services\Record $result['duplicateIds'][] = $r['id']; } $sql = " - INSERT INTO import_entity (entity_type, entity_id, import_id, is_imported, is_updated, is_duplicate) + INSERT INTO import_entity + (entity_type, entity_id, import_id, is_imported, is_updated, is_duplicate) + VALUES (:entityType, :entityId, :importId, :isImported, :isUpdated, :isDuplicate) "; $sth = $pdo->prepare($sql); - $sth->execute(array( - ':entityType' => $scope, - ':entityId' => $r['id'], - ':importId' => $import->id, - ':isImported' => !empty($r['isImported']), - ':isUpdated' => !empty($r['isUpdated']), - ':isDuplicate' => !empty($r['isDuplicate']), - )); + $sth->bindValue(':entityType', $scope); + $sth->bindValue(':entityId', $r['id']); + $sth->bindValue(':importId', $import->id); + $sth->bindValue(':isImported', !empty($r['isImported']), \PDO::PARAM_BOOL); + $sth->bindValue(':isUpdated', !empty($r['isUpdated']), \PDO::PARAM_BOOL); + $sth->bindValue(':isDuplicate', !empty($r['isDuplicate']), \PDO::PARAM_BOOL); + + $sth->execute(); } return array( diff --git a/frontend/client/src/views/import/detail.js b/frontend/client/src/views/import/detail.js new file mode 100644 index 0000000000..7d80093552 --- /dev/null +++ b/frontend/client/src/views/import/detail.js @@ -0,0 +1,37 @@ +/************************************************************************ + * This file is part of EspoCRM. + * + * EspoCRM - Open Source CRM application. + * Copyright (C) 2014-2015 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('Views.Import.Detail', 'Views.Detail', function (Dep) { + + return Dep.extend({ + + getHeader: function () { + var name = Handlebars.Utils.escapeExpression(this.model.get('createdAt')); + + return this.buildHeaderHtml([ + '' + this.getLanguage().translate(this.model.name, 'scopeNamesPlural') + '', + name + ]); + }, + + }); +}); + diff --git a/frontend/client/src/views/import/record/panels/duplicates.js b/frontend/client/src/views/import/record/panels/duplicates.js new file mode 100644 index 0000000000..4e9976fd12 --- /dev/null +++ b/frontend/client/src/views/import/record/panels/duplicates.js @@ -0,0 +1,30 @@ +/************************************************************************ + * This file is part of EspoCRM. + * + * EspoCRM - Open Source CRM application. + * Copyright (C) 2014-2015 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('Views.Import.Record.Panels.Duplicates', 'Views.Import.Record.Panels.Imported', function (Dep) { + + return Dep.extend({ + + link: 'duplicates', + + }); +}); + diff --git a/frontend/client/src/views/import/record/panels/imported.js b/frontend/client/src/views/import/record/panels/imported.js new file mode 100644 index 0000000000..5d4c6bc199 --- /dev/null +++ b/frontend/client/src/views/import/record/panels/imported.js @@ -0,0 +1,39 @@ +/************************************************************************ + * This file is part of EspoCRM. + * + * EspoCRM - Open Source CRM application. + * Copyright (C) 2014-2015 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('Views.Import.Record.Panels.Imported', 'Views.Record.Panels.Relationship', function (Dep) { + + return Dep.extend({ + + link: 'imported', + + readOlny: true, + + rowActionsView: 'Record.RowActions.RelationshipNoUnlink', + + setup: function () { + this.scope = this.model.get('entityType'); + Dep.prototype.setup.call(this); + } + + }); +}); + diff --git a/frontend/client/src/views/import/record/panels/updated.js b/frontend/client/src/views/import/record/panels/updated.js new file mode 100644 index 0000000000..d3601bbb89 --- /dev/null +++ b/frontend/client/src/views/import/record/panels/updated.js @@ -0,0 +1,30 @@ +/************************************************************************ + * This file is part of EspoCRM. + * + * EspoCRM - Open Source CRM application. + * Copyright (C) 2014-2015 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('Views.Import.Record.Panels.Updated', 'Views.Import.Record.Panels.Imported', function (Dep) { + + return Dep.extend({ + + link: 'updated', + + }); +}); + diff --git a/frontend/client/src/views/import/step2.js b/frontend/client/src/views/import/step2.js index 99d0593562..628e15ba6e 100644 --- a/frontend/client/src/views/import/step2.js +++ b/frontend/client/src/views/import/step2.js @@ -308,9 +308,15 @@ Espo.define('Views.Import.Step2', 'View', function (Dep) { type: 'POST', url: 'Import', data: JSON.stringify(this.formData), - timeout: 150000, + timeout: 0, success: function (result) { - this.getParentView().changeStep(3, result); + var id = result.id; + if (id) { + this.getRouter().navigate('#Import/view/' + id, {trigger: true}); + } else { + this.notify('Error', 'error'); + this.enableButtons(); + } this.notify(false); }.bind(this), error: function () { diff --git a/frontend/client/src/views/record/panels/relationship.js b/frontend/client/src/views/record/panels/relationship.js index afcb16e0d5..7d4a85c776 100644 --- a/frontend/client/src/views/record/panels/relationship.js +++ b/frontend/client/src/views/record/panels/relationship.js @@ -27,17 +27,24 @@ Espo.define('Views.Record.Panels.Relationship', ['Views.Record.Panels.Bottom', ' rowActionsView: 'Record.RowActions.Relationship', + url: null, + + scope: null, + + readOlny: false, + setup: function () { this.link = this.panelName; - if (!(this.link in this.model.defs.links)) { + if (!this.scope && !(this.link in this.model.defs.links)) { throw new Error('Link \'' + this.link + '\' is not defined in model \'' + this.model.name + '\''); } - this.scope = this.model.defs.links[this.link].entity; + this.scope = this.scope || this.model.defs.links[this.link].entity; this.title = this.translate(this.link, 'links', this.model.name); - var url = this.model.name + '/' + this.model.id + '/' + this.link; - if (!this.defs.readOnly) { + var url = this.url || this.model.name + '/' + this.model.id + '/' + this.link; + + if (!this.readOlny && !this.defs.readOnly) { if (!('create' in this.defs)) { this.defs.create = true; } @@ -96,9 +103,11 @@ Espo.define('Views.Record.Panels.Relationship', ['Views.Record.Panels.Bottom', ' } this.collection = collection; + var viewName = this.defs.recordListView || this.getMetadata().get('clientDefs.' + this.scope + '.recordViews.list') || 'Record.List'; + this.once('after:render', function () { collection.once('sync', function () { - this.createView('list', 'Record.List', { + this.createView('list', viewName, { collection: collection, type: type, listLayout: listLayout,