mirror of
https://github.com/espocrm/espocrm.git
synced 2026-06-28 06:56:05 +00:00
import 1
This commit is contained in:
@@ -18,50 +18,67 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use Espo\Core\Utils as Utils;
|
||||
use \Espo\Core\Exceptions\Error;
|
||||
use \Espo\Core\Exceptions\Forbidden;
|
||||
use \Espo\Core\Exceptions\BadRequest;
|
||||
|
||||
class Import extends \Espo\Core\Controllers\Record
|
||||
{
|
||||
protected function checkControllerAccess()
|
||||
{
|
||||
if (!$this->getUser()->isAdmin()) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
}
|
||||
|
||||
public function actionPatch($params, $data)
|
||||
{
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
public function actionUpdate($params, $data)
|
||||
{
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
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');
|
||||
$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'],
|
||||
@@ -74,13 +91,13 @@ class Import extends \Espo\Core\Controllers\Base
|
||||
'defaultValues' => $data['defaultValues'],
|
||||
'action' => $data['action'],
|
||||
);
|
||||
|
||||
|
||||
$attachmentId = $data['attachmentId'];
|
||||
|
||||
|
||||
if (!$this->getAcl()->check($data['entityType'], 'edit')) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
|
||||
return $this->getService('Import')->import($data['entityType'], $data['fields'], $attachmentId, $importParams);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* 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/.
|
||||
************************************************************************/
|
||||
|
||||
return array(
|
||||
|
||||
'ImportEntity' => 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'
|
||||
),
|
||||
'importId' => array(
|
||||
'type' => 'varchar',
|
||||
'len' => '24',
|
||||
'index' => true
|
||||
),
|
||||
'isImported' => array(
|
||||
'type' => 'bool'
|
||||
),
|
||||
'isUpdated' => array(
|
||||
'type' => 'bool'
|
||||
),
|
||||
'isDuplicate' => array(
|
||||
'type' => 'bool'
|
||||
),
|
||||
),
|
||||
"indexes" => array(
|
||||
"entityImport" => array(
|
||||
"columns" => ["importId", "entityType"]
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
);
|
||||
|
||||
28
application/Espo/Entities/Import.php
Normal file
28
application/Espo/Entities/Import.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* 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/.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Entities;
|
||||
|
||||
class Import extends \Espo\Core\ORM\Entity
|
||||
{
|
||||
|
||||
}
|
||||
@@ -12,7 +12,8 @@
|
||||
"ExternalAccount": "External Account",
|
||||
"Extension": "Extension",
|
||||
"Dashboard": "Dashboard",
|
||||
"Stream": "Stream"
|
||||
"Stream": "Stream",
|
||||
"Import": "Import"
|
||||
},
|
||||
"scopeNamesPlural": {
|
||||
"Email": "Emails",
|
||||
@@ -27,7 +28,8 @@
|
||||
"ExternalAccount": "External Accounts",
|
||||
"Extension": "Extensions",
|
||||
"Dashboard": "Dashboard",
|
||||
"Stream": "Stream"
|
||||
"Stream": "Stream",
|
||||
"Import": "Import Results"
|
||||
},
|
||||
"labels": {
|
||||
"Misc": "Misc",
|
||||
|
||||
11
application/Espo/Resources/metadata/clientDefs/Import.json
Normal file
11
application/Espo/Resources/metadata/clientDefs/Import.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"controller": "Controllers.Import",
|
||||
"recordViews": {
|
||||
"list":"Import.Record.List",
|
||||
"detail": "Import.Record.Detail"
|
||||
},
|
||||
"views": {
|
||||
"list": "Import.List"
|
||||
},
|
||||
"disableSearchPanel": true
|
||||
}
|
||||
26
application/Espo/Resources/metadata/entityDefs/Import.json
Normal file
26
application/Espo/Resources/metadata/entityDefs/Import.json
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"fields": {
|
||||
"entityType": {
|
||||
"type": "varchar",
|
||||
"required": true
|
||||
},
|
||||
"createdAt": {
|
||||
"type": "datetime",
|
||||
"readOnly": true
|
||||
},
|
||||
"createdBy": {
|
||||
"type": "link",
|
||||
"readOnly": true
|
||||
}
|
||||
},
|
||||
"links": {
|
||||
"createdBy": {
|
||||
"type": "belongsTo",
|
||||
"entity": "User"
|
||||
}
|
||||
},
|
||||
"collection": {
|
||||
"sortBy": "createdAt",
|
||||
"asc": false
|
||||
}
|
||||
}
|
||||
7
application/Espo/Resources/metadata/scopes/Import.json
Normal file
7
application/Espo/Resources/metadata/scopes/Import.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"entity": true,
|
||||
"layouts": false,
|
||||
"tab": false,
|
||||
"acl": false,
|
||||
"customizable": false
|
||||
}
|
||||
@@ -28,18 +28,14 @@ use \Espo\Core\Exceptions\Error;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class Import extends \Espo\Core\Services\Base
|
||||
class Import extends \Espo\Services\Record
|
||||
{
|
||||
protected $dependencies = array(
|
||||
'entityManager',
|
||||
'user',
|
||||
'metadata',
|
||||
'acl',
|
||||
'selectManagerFactory',
|
||||
'config',
|
||||
'serviceFactory',
|
||||
'fileManager',
|
||||
);
|
||||
protected function init()
|
||||
{
|
||||
$this->dependencies[] = 'serviceFactory';
|
||||
$this->dependencies[] = 'fileManager';
|
||||
$this->dependencies[] = 'selectManagerFactory';
|
||||
}
|
||||
|
||||
protected $dateFormatsMap = array(
|
||||
'YYYY-MM-DD' => 'Y-m-d',
|
||||
@@ -60,6 +56,8 @@ class Import extends \Espo\Core\Services\Base
|
||||
'hh:mmA' => 'h:iA',
|
||||
);
|
||||
|
||||
protected $services = array();
|
||||
|
||||
protected function getSelectManagerFactory()
|
||||
{
|
||||
return $this->injections['selectManagerFactory'];
|
||||
@@ -85,7 +83,6 @@ class Import extends \Espo\Core\Services\Base
|
||||
return $this->injections['serviceFactory'];
|
||||
}
|
||||
|
||||
|
||||
protected function readCsvString(&$string, $CSV_SEPARATOR = ';', $CSV_ENCLOSURE = '"', $CSV_LINEBREAK = "\n")
|
||||
{
|
||||
$o = array();
|
||||
@@ -174,12 +171,20 @@ class Import extends \Espo\Core\Services\Base
|
||||
}
|
||||
|
||||
$contents = $this->getFileManager()->getContents('data/upload/' . $attachmentId);
|
||||
|
||||
if (empty($contents)) {
|
||||
throw new Error('Import error');
|
||||
}
|
||||
|
||||
$result = array(
|
||||
$import = $this->getEntityManager()->getEntity('Import');
|
||||
$import->set(array(
|
||||
'enityType' => $scope
|
||||
));
|
||||
$this->getEntityManager()->saveEntity($import);
|
||||
|
||||
$pdo = $this->getEntityManager()->getPDO();
|
||||
|
||||
|
||||
$result = array(
|
||||
'importedIds' => array(),
|
||||
'updatedIds' => array(),
|
||||
'duplicateIds' => array(),
|
||||
@@ -194,22 +199,36 @@ class Import extends \Espo\Core\Services\Base
|
||||
continue;
|
||||
}
|
||||
$r = $this->importRow($scope, $fields, $arr, $params);
|
||||
if (!empty($r['imported'])) {
|
||||
if (!empty($r['isImported'])) {
|
||||
$result['importedIds'][] = $r['id'];
|
||||
}
|
||||
if (!empty($r['updated'])) {
|
||||
if (!empty($r['isUpdated'])) {
|
||||
$result['updatedIds'][] = $r['id'];
|
||||
}
|
||||
if (!empty($r['duplicate'])) {
|
||||
if (!empty($r['isDuplicate'])) {
|
||||
$result['duplicateIds'][] = $r['id'];
|
||||
}
|
||||
$sql = "
|
||||
INSERT INTO import_entity (entity_type, entity_id, import_id, is_imported, is_updated, is_duplicate)
|
||||
(: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']),
|
||||
));
|
||||
|
||||
}
|
||||
return array(
|
||||
'id' => $import->id,
|
||||
'countCreated' => count($result['importedIds']),
|
||||
'countUpdated' => count($result['updatedIds']),
|
||||
'importedIds' => $result['importedIds'],
|
||||
'duplicateIds' => $result['duplicateIds'],
|
||||
//'importedIds' => $result['importedIds'],
|
||||
//'duplicateIds' => $result['duplicateIds'],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -229,6 +248,7 @@ class Import extends \Espo\Core\Services\Base
|
||||
}
|
||||
}
|
||||
|
||||
$recordService = $this->getRecordService($scope);
|
||||
|
||||
$entity = $this->getEntityManager()->getEntity($scope, $id);
|
||||
|
||||
@@ -260,7 +280,6 @@ class Import extends \Espo\Core\Services\Base
|
||||
$firstName = '';
|
||||
$lastName = $value;
|
||||
switch ($params['personNameFormat']) {
|
||||
|
||||
case 'f l':
|
||||
$pos = strpos($value, ' ');
|
||||
if ($pos) {
|
||||
@@ -298,8 +317,6 @@ class Import extends \Espo\Core\Services\Base
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
foreach ($fields as $i => $field) {
|
||||
if (array_key_exists($field, $fieldsDefs) && $fieldsDefs[$field]['type'] == Entity::FOREIGN) {
|
||||
if ($entity->has($field)) {
|
||||
@@ -314,7 +331,6 @@ class Import extends \Espo\Core\Services\Base
|
||||
$entity->set($relation . 'Id', $found->id);
|
||||
} else {
|
||||
if (!in_array($scope, 'User', 'Team')) {
|
||||
|
||||
// TODO create related record with name $name and relate
|
||||
}
|
||||
}
|
||||
@@ -330,15 +346,21 @@ class Import extends \Espo\Core\Services\Base
|
||||
$a = $entity->toArray();
|
||||
|
||||
try {
|
||||
$isDuplicate = $recordService->checkEntityForDuplicate($entity);
|
||||
if ($this->getEntityManager()->saveEntity($entity)) {
|
||||
$result['id'] = $entity->id;
|
||||
if (empty($id)) {
|
||||
$result['imported'] = true;
|
||||
$result['isImported'] = true;
|
||||
if ($isDuplicate) {
|
||||
$result['isDuplicate'] = true;
|
||||
}
|
||||
} else {
|
||||
$result['updated'] = true;
|
||||
$result['isUpdated'] = true;
|
||||
}
|
||||
}
|
||||
} catch (\Exception $e) {}
|
||||
} catch (\Exception $e) {
|
||||
$GLOBALS['log']->error('Import: [' . $e->getCode() . '] ' .$e->getMessage());
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
@@ -401,9 +423,16 @@ class Import extends \Espo\Core\Services\Base
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
protected function getRecordService($scope)
|
||||
{
|
||||
if (empty($this->services[$scope])) {
|
||||
$this->services[$scope] = $this->getServiceFactory()->create($scope);
|
||||
}
|
||||
return $this->services[$scope];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
<div class="page-header"><h3>{{translate 'Import'}}</h3></div>
|
||||
<div class="page-header">
|
||||
<div class="row">
|
||||
<div class="col-lg-7 col-sm-7">
|
||||
<h3>{{translate 'Import' category='scopeNames'}}</h3>
|
||||
</div>
|
||||
<div class="col-lg-5 col-sm-5">
|
||||
<div class="header-buttons btn-group pull-right">
|
||||
<a href="#Import/list" class="btn btn-default">{{translate 'Import' category='scopeNamesPlural'}}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="import-container">
|
||||
{{{step}}}
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -17,22 +17,24 @@
|
||||
*
|
||||
* 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('Controllers.Import', 'Controller', function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
************************************************************************/
|
||||
Espo.define('Controllers.Import', 'Controllers.Record', function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
defaultAction: 'index',
|
||||
|
||||
checkAccess: function () {
|
||||
if (this.getUser().isAdmin()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
index: function () {
|
||||
this.main('Import.Index', null);
|
||||
},
|
||||
|
||||
|
||||
index: function () {
|
||||
this.main('Import.Index', null);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
@@ -17,27 +17,27 @@
|
||||
*
|
||||
* 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.Index', 'View', function (Dep) {
|
||||
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
|
||||
template: 'import.index',
|
||||
|
||||
|
||||
data: function () {
|
||||
return {
|
||||
|
||||
|
||||
};
|
||||
},
|
||||
|
||||
|
||||
formData: null,
|
||||
|
||||
|
||||
fileContents: null,
|
||||
|
||||
|
||||
setup: function () {
|
||||
this.entityType = this.options.entityType || false;
|
||||
},
|
||||
|
||||
},
|
||||
|
||||
changeStep: function (num, result) {
|
||||
this.createView('step', 'Import.Step' + num.toString(), {
|
||||
el: this.options.el + ' > .import-container',
|
||||
@@ -48,14 +48,14 @@ Espo.define('Views.Import.Index', 'View', function (Dep) {
|
||||
view.render();
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
afterRender: function () {
|
||||
this.changeStep(1);
|
||||
},
|
||||
|
||||
|
||||
updatePageTitle: function () {
|
||||
this.setPageTitle(this.getLanguage().translate('Import'));
|
||||
},
|
||||
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
57
frontend/client/src/views/import/list.js
Normal file
57
frontend/client/src/views/import/list.js
Normal file
@@ -0,0 +1,57 @@
|
||||
/************************************************************************
|
||||
* 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.List', 'Views.List', function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
createButton: false,
|
||||
|
||||
setup: function () {
|
||||
Dep.prototype.setup.call(this);
|
||||
|
||||
this.menu.buttons.unshift({
|
||||
label: this.translate('Import', 'scopeNames'),
|
||||
link: '#Import',
|
||||
style: 'danger',
|
||||
acl: 'edit'
|
||||
});
|
||||
},
|
||||
|
||||
actionCreateEmailAccount: function () {
|
||||
if (this.options.userId) {
|
||||
this.getRouter().dispatch('EmailAccount', 'create', {
|
||||
attributes: {
|
||||
assignedUserId: this.options.userId,
|
||||
assignedUserName: this.options.userId
|
||||
}
|
||||
});
|
||||
this.getRouter().navigate('#EmailAccount/create', {trigger: false});
|
||||
} else {
|
||||
this.getRouter().navigate('#EmailAccount/create', {trigger: true});
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
31
frontend/client/src/views/import/record/detail.js
Normal file
31
frontend/client/src/views/import/record/detail.js
Normal file
@@ -0,0 +1,31 @@
|
||||
/************************************************************************
|
||||
* 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.Detail', 'Views.Record.Detail', function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
readOnly: true
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
36
frontend/client/src/views/import/record/list.js
Normal file
36
frontend/client/src/views/import/record/list.js
Normal file
@@ -0,0 +1,36 @@
|
||||
/************************************************************************
|
||||
* 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.List', 'Views.Record.List', function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
allowQuickEdit: false,
|
||||
|
||||
checkAllResultDisabled: true,
|
||||
|
||||
massActionList: ['remove'],
|
||||
|
||||
rowActionsView: 'Record.RowActions.RemoveOnly'
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
@@ -17,13 +17,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.Import.Step1', 'View', function (Dep) {
|
||||
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
|
||||
template: 'import.step-1',
|
||||
|
||||
|
||||
events: {
|
||||
'change #import-file': function (e) {
|
||||
var $file = $(e.currentTarget);
|
||||
@@ -32,25 +32,25 @@ Espo.define('Views.Import.Step1', 'View', function (Dep) {
|
||||
this.loadFile(files[0]);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
'change #import-field-delimiter': function (e) {
|
||||
this.formData.fieldDelimiter = e.currentTarget.value;
|
||||
this.preview();
|
||||
},
|
||||
|
||||
|
||||
'change #import-text-qualifier': function (e) {
|
||||
this.formData.textQualifier = e.currentTarget.value;
|
||||
this.preview();
|
||||
},
|
||||
|
||||
|
||||
'click button[data-action="next"]': function () {
|
||||
this.next();
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
getEntityList: function () {
|
||||
var list = [];
|
||||
var scopes = this.getMetadata().get('scopes');
|
||||
var scopes = this.getMetadata().get('scopes');
|
||||
for (var scopeName in scopes) {
|
||||
if (scopes[scopeName].importable) {
|
||||
list.push(scopeName);
|
||||
@@ -61,15 +61,15 @@ Espo.define('Views.Import.Step1', 'View', function (Dep) {
|
||||
}.bind(this));
|
||||
return list;
|
||||
},
|
||||
|
||||
|
||||
data: function () {
|
||||
return {
|
||||
entityList: this.getEntityList(),
|
||||
currencyList: this.getConfig().get('currencyList'),
|
||||
};
|
||||
},
|
||||
|
||||
setup: function () {
|
||||
|
||||
setup: function () {
|
||||
this.formData = this.options.formData || {
|
||||
entityType: this.options.entityType || false,
|
||||
headerRow: true,
|
||||
@@ -79,9 +79,9 @@ Espo.define('Views.Import.Step1', 'View', function (Dep) {
|
||||
timeFormat: 'HH:mm',
|
||||
decimalMark: '.',
|
||||
personNameFormat: 'f l',
|
||||
};
|
||||
};
|
||||
},
|
||||
|
||||
|
||||
afterRender: function () {
|
||||
this.setupFormData();
|
||||
if (this.getParentView() && this.getParentView().fileContents) {
|
||||
@@ -89,7 +89,7 @@ Espo.define('Views.Import.Step1', 'View', function (Dep) {
|
||||
this.preview();
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
next: function () {
|
||||
this.formData.headerRow = $('#import-header-row').get(0).checked;
|
||||
this.formData.entityType = $('#import-entity-type').val();
|
||||
@@ -101,69 +101,69 @@ Espo.define('Views.Import.Step1', 'View', function (Dep) {
|
||||
this.formData.decimalMark = $('#import-decimal-mark').val();
|
||||
this.formData.currency = $('#import-currency').val();
|
||||
this.formData.personNameFormat = $('#import-person-name-format').val();
|
||||
|
||||
|
||||
this.getParentView().formData = this.formData;
|
||||
this.getParentView().changeStep(2);
|
||||
},
|
||||
|
||||
setupFormData: function () {
|
||||
|
||||
setupFormData: function () {
|
||||
$('#import-header-row').get(0).checked = this.formData.headerRow || false;
|
||||
|
||||
|
||||
if (this.formData.entityType) {
|
||||
$('#import-entity-type').val(this.formData.entityType);
|
||||
}
|
||||
if (this.formData.action) {
|
||||
$('#import-action').val(this.formData.action);
|
||||
}
|
||||
|
||||
|
||||
$('#import-field-delimiter').val(this.formData.fieldDelimiter);
|
||||
$('#import-text-qualifier').val(this.formData.textQualifier);
|
||||
$('#import-date-format').val(this.formData.dateFormat);
|
||||
$('#import-time-format').val(this.formData.timeFormat);
|
||||
$('#import-decimal-mark').val(this.formData.decimalMark);
|
||||
$('#import-person-name-format').val(this.formData.personNameFormat);
|
||||
|
||||
|
||||
if (this.formData.currency) {
|
||||
$('#import-currency').val(this.formData.currency);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
loadFile: function (file) {
|
||||
var blob = file.slice(0, 1024 * 16);
|
||||
|
||||
var readerPreview = new FileReader();
|
||||
|
||||
var readerPreview = new FileReader();
|
||||
readerPreview.onloadend = function (e) {
|
||||
if (e.target.readyState == FileReader.DONE) {
|
||||
this.formData.previewString = e.target.result;
|
||||
this.preview();
|
||||
}
|
||||
}.bind(this);
|
||||
}
|
||||
}.bind(this);
|
||||
readerPreview.readAsText(blob);
|
||||
|
||||
var reader = new FileReader();
|
||||
|
||||
var reader = new FileReader();
|
||||
reader.onloadend = function (e) {
|
||||
if (e.target.readyState == FileReader.DONE) {
|
||||
this.getParentView().fileContents = e.target.result;
|
||||
this.setFileIsLoaded();
|
||||
}
|
||||
}.bind(this);
|
||||
reader.readAsText(file);
|
||||
}
|
||||
}.bind(this);
|
||||
reader.readAsText(file);
|
||||
},
|
||||
|
||||
|
||||
setFileIsLoaded: function () {
|
||||
this.$el.find('button[data-action="next"]').removeClass('hidden');
|
||||
},
|
||||
|
||||
preview: function () {
|
||||
|
||||
preview: function () {
|
||||
if (!this.formData.previewString) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
var arr = this.csvToArray(this.formData.previewString, this.formData.fieldDelimiter, this.formData.textQualifier);
|
||||
|
||||
|
||||
this.formData.previewArray = arr;
|
||||
|
||||
|
||||
var $table = $('<table>').addClass('table').addClass('table-bordered');
|
||||
|
||||
|
||||
arr.forEach(function (row, i) {
|
||||
if (i >= 3) {
|
||||
return;
|
||||
@@ -173,15 +173,15 @@ Espo.define('Views.Import.Step1', 'View', function (Dep) {
|
||||
$cell = $('<td>').html(value);
|
||||
$row.append($cell);
|
||||
});
|
||||
|
||||
|
||||
$table.append($row);
|
||||
});
|
||||
|
||||
|
||||
var $container = $('#import-preview');
|
||||
$container.empty().append($table);
|
||||
},
|
||||
|
||||
csvToArray: function (strData, strDelimiter, strQualifier) {
|
||||
|
||||
csvToArray: function (strData, strDelimiter, strQualifier) {
|
||||
strDelimiter = (strDelimiter || ',');
|
||||
strQualifier = (strQualifier || '\"');
|
||||
|
||||
@@ -226,6 +226,6 @@ Espo.define('Views.Import.Step1', 'View', function (Dep) {
|
||||
|
||||
return arrData;
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
@@ -17,14 +17,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('Views.Import.Step2', 'View', function (Dep) {
|
||||
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
|
||||
template: 'import.step-2',
|
||||
|
||||
events: {
|
||||
|
||||
events: {
|
||||
'click button[data-action="back"]': function () {
|
||||
this.back();
|
||||
},
|
||||
@@ -36,36 +36,36 @@ Espo.define('Views.Import.Step2', 'View', function (Dep) {
|
||||
$(e.currentTarget).parent().addClass('hidden');
|
||||
this.addField(field);
|
||||
},
|
||||
|
||||
|
||||
'click a[data-action="removeField"]': function (e) {
|
||||
var field = $(e.currentTarget).data('name');
|
||||
|
||||
this.$el.find('a[data-action="addField"]').parent().removeClass('hidden');
|
||||
|
||||
var index = this.additionalFields.indexOf(field);
|
||||
this.$el.find('a[data-action="addField"]').parent().removeClass('hidden');
|
||||
|
||||
var index = this.additionalFields.indexOf(field);
|
||||
if (~index) {
|
||||
this.additionalFields.splice(index, 1);
|
||||
}
|
||||
this.$el.find('.field-' + field).parent().remove();
|
||||
},
|
||||
},
|
||||
|
||||
},
|
||||
|
||||
data: function () {
|
||||
return {
|
||||
scope: this.scope,
|
||||
fieldList: this.getFieldList(),
|
||||
};
|
||||
},
|
||||
|
||||
setup: function () {
|
||||
|
||||
setup: function () {
|
||||
this.formData = this.options.formData;
|
||||
|
||||
|
||||
this.scope = this.formData.entityType;
|
||||
|
||||
|
||||
var mapping = [];
|
||||
|
||||
|
||||
this.additionalFields = [];
|
||||
|
||||
|
||||
if (this.formData.previewArray) {
|
||||
var index = 0;
|
||||
if (this.formData.headerRow) {
|
||||
@@ -81,23 +81,23 @@ Espo.define('Views.Import.Step2', 'View', function (Dep) {
|
||||
}
|
||||
mapping.push(d);
|
||||
}, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
this.wait(true);
|
||||
this.getModelFactory().create(this.scope, function (model) {
|
||||
this.model = model;
|
||||
this.wait(false);
|
||||
this.wait(false);
|
||||
}, this);
|
||||
|
||||
this.mapping = mapping;
|
||||
|
||||
this.mapping = mapping;
|
||||
},
|
||||
|
||||
|
||||
afterRender: function () {
|
||||
$container = $('#mapping-container');
|
||||
|
||||
|
||||
$table = $('<table>').addClass('table').addClass('table-bordered');
|
||||
|
||||
|
||||
$row = $('<tr>');
|
||||
if (this.formData.headerRow) {
|
||||
$cell = $('<th>').html(this.translate('Header Row Value', 'labels', 'Import'));
|
||||
@@ -108,7 +108,7 @@ Espo.define('Views.Import.Step2', 'View', function (Dep) {
|
||||
$cell = $('<th>').html(this.translate('First Row Value', 'labels', 'Import'));
|
||||
$row.append($cell);
|
||||
$table.append($row);
|
||||
|
||||
|
||||
this.mapping.forEach(function (d, i) {
|
||||
$row = $('<tr>');
|
||||
if (this.formData.headerRow) {
|
||||
@@ -117,59 +117,59 @@ Espo.define('Views.Import.Step2', 'View', function (Dep) {
|
||||
}
|
||||
$select = this.getFieldDropdown(i, d.name);
|
||||
$cell = $('<td>').append($select);
|
||||
$row.append($cell);
|
||||
|
||||
$row.append($cell);
|
||||
|
||||
$cell = $('<td>').html(d.value);
|
||||
$row.append($cell);
|
||||
|
||||
|
||||
$table.append($row);
|
||||
}, this);
|
||||
|
||||
|
||||
$container.empty();
|
||||
$container.append($table);
|
||||
|
||||
},
|
||||
|
||||
|
||||
getFieldList: function () {
|
||||
var defs = this.getMetadata().get('entityDefs.' + this.scope + '.fields');
|
||||
|
||||
|
||||
var fieldList = [];
|
||||
for (var field in defs) {
|
||||
fieldList.push(field);
|
||||
}
|
||||
|
||||
return fieldList;
|
||||
|
||||
return fieldList;
|
||||
},
|
||||
|
||||
|
||||
getFieldDropdown: function (num, name) {
|
||||
name = name || false;
|
||||
|
||||
|
||||
var fields = this.getMetadata().get('entityDefs.' + this.scope + '.fields');
|
||||
|
||||
|
||||
var fieldList = [];
|
||||
fieldList.push('id');
|
||||
|
||||
|
||||
for (var field in fields) {
|
||||
var d = fields[field];
|
||||
|
||||
|
||||
if (['modifiedBy', 'createdBy', 'modifiedAt', 'createdAt'].indexOf(field) !== -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (d.type == 'link') {
|
||||
fieldList.push(field + 'Name');
|
||||
fieldList.push(field + 'Id');
|
||||
}
|
||||
|
||||
|
||||
if (['linkMultiple', 'foreign'].indexOf(d.type) !== -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (d.type == 'personName') {
|
||||
fieldList.push(field);
|
||||
}
|
||||
|
||||
var type = d.type;
|
||||
|
||||
var type = d.type;
|
||||
var actualFields = this.getFieldManager().getActualAttributes(type, field);
|
||||
actualFields.forEach(function (f) {
|
||||
if (fieldList.indexOf(f) === -1) {
|
||||
@@ -177,14 +177,14 @@ Espo.define('Views.Import.Step2', 'View', function (Dep) {
|
||||
}
|
||||
}, this);
|
||||
}
|
||||
|
||||
|
||||
$select = $('<select>').addClass('form-control').attr('id', 'column-' + num.toString());
|
||||
$option = $('<option>').val('').html('-' + this.translate('Skip', 'labels', 'Import') + '-');
|
||||
|
||||
|
||||
$select.append($option);
|
||||
fieldList.forEach(function (field) {
|
||||
$option = $('<option>').val(field).html(this.translate(field, 'fields', this.formData.entityType));
|
||||
|
||||
|
||||
if (name) {
|
||||
if (field == name) {
|
||||
$option.prop('selected', true);
|
||||
@@ -196,18 +196,18 @@ Espo.define('Views.Import.Step2', 'View', function (Dep) {
|
||||
}
|
||||
$select.append($option);
|
||||
}, this);
|
||||
|
||||
|
||||
return $select;
|
||||
},
|
||||
|
||||
|
||||
addField: function (name) {
|
||||
$(this.containerSelector + ' button[data-name="update"]').removeClass('disabled');
|
||||
|
||||
this.notify('Loading...');
|
||||
var label = this.translate(name, 'fields', this.scope);
|
||||
|
||||
|
||||
var removeLink = '<a href="javascript:" class="pull-right" data-action="removeField" data-name="'+name+'"><span class="glyphicon glyphicon-remove"></span></a>';
|
||||
|
||||
|
||||
var html = '<div class="cell form-group col-sm-3">'+removeLink+'<label class="control-label">' + label + '</label><div class="field field-'+name+'" /></div>';
|
||||
$('#default-values-container').append(html);
|
||||
|
||||
@@ -225,19 +225,19 @@ Espo.define('Views.Import.Step2', 'View', function (Dep) {
|
||||
view.notify(false);
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
|
||||
disableButtons: function () {
|
||||
this.$el.find('button[data-action="next"]').addClass('disabled');
|
||||
this.$el.find('button[data-action="back"]').addClass('disabled');
|
||||
},
|
||||
|
||||
|
||||
enableButtons: function () {
|
||||
this.$el.find('button[data-action="next"]').removeClass('disabled');
|
||||
this.$el.find('button[data-action="back"]').removeClass('disabled');
|
||||
},
|
||||
|
||||
|
||||
fetch: function () {
|
||||
|
||||
|
||||
var attributes = {};
|
||||
this.additionalFields.forEach(function (field) {
|
||||
var view = this.getView(field);
|
||||
@@ -245,45 +245,44 @@ Espo.define('Views.Import.Step2', 'View', function (Dep) {
|
||||
}, this);
|
||||
|
||||
this.model.set(attributes);
|
||||
|
||||
|
||||
var notValid = false;
|
||||
this.additionalFields.forEach(function (field) {
|
||||
var view = this.getView(field);
|
||||
notValid = view.validate() || notValid;
|
||||
}, this);
|
||||
|
||||
|
||||
if (!notValid) {
|
||||
this.formData.defaultValues = attributes;
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
back: function () {
|
||||
this.getParentView().changeStep(1);
|
||||
},
|
||||
|
||||
|
||||
next: function () {
|
||||
|
||||
back: function () {
|
||||
this.getParentView().changeStep(1);
|
||||
},
|
||||
|
||||
|
||||
next: function () {
|
||||
if (!this.fetch()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var fields = [];
|
||||
|
||||
|
||||
this.mapping.forEach(function (d, i) {
|
||||
fields.push($('#column-' + i).val());
|
||||
}, this);
|
||||
|
||||
|
||||
|
||||
|
||||
this.formData.fields = fields;
|
||||
|
||||
|
||||
|
||||
this.getParentView().formData = this.formData;
|
||||
|
||||
|
||||
this.disableButtons();
|
||||
|
||||
|
||||
this.notify('File uploading...');
|
||||
|
||||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: 'Import/action/uploadFile',
|
||||
@@ -291,20 +290,20 @@ Espo.define('Views.Import.Step2', 'View', function (Dep) {
|
||||
data: this.getParentView().fileContents,
|
||||
timeout: 0,
|
||||
success: function (data) {
|
||||
if (data.attachmentId) {
|
||||
if (data.attachmentId) {
|
||||
this.runImport(data.attachmentId);
|
||||
} else {
|
||||
this.notify('Bad response', 'error');
|
||||
}
|
||||
}.bind(this)
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
runImport: function (attachmentId) {
|
||||
this.formData.attachmentId = attachmentId;
|
||||
|
||||
|
||||
this.notify('Import running...');
|
||||
|
||||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: 'Import',
|
||||
@@ -317,8 +316,8 @@ Espo.define('Views.Import.Step2', 'View', function (Dep) {
|
||||
error: function () {
|
||||
this.enableButtons();
|
||||
}.bind(this),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
53
frontend/client/src/views/record/row-actions/remove-only.js
Normal file
53
frontend/client/src/views/record/row-actions/remove-only.js
Normal file
@@ -0,0 +1,53 @@
|
||||
/************************************************************************
|
||||
* 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.Record.RowActions.RemoveOnly', 'View', function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
template: 'record.row-actions.default',
|
||||
|
||||
getActions: function () {
|
||||
if (this.options.acl.remove) {
|
||||
return [
|
||||
{
|
||||
action: 'quickRemove',
|
||||
label: 'Remove',
|
||||
data: {
|
||||
id: this.model.id
|
||||
}
|
||||
}
|
||||
];
|
||||
}
|
||||
},
|
||||
|
||||
data: function () {
|
||||
return {
|
||||
acl: this.options.acl,
|
||||
actions: this.getActions(),
|
||||
scope: this.model.name
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user