address country list

This commit is contained in:
Yuri Kuznetsov
2024-05-15 14:12:29 +03:00
parent 547b77423a
commit a1d5174372
28 changed files with 2100 additions and 5 deletions

View File

@@ -0,0 +1,48 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM Open Source CRM application.
* Copyright (C) 2014-2024 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Classes\AppParams;
use Espo\Core\Utils\Address\CountryDataProvider;
use Espo\Tools\App\AppParam;
class AddressCountryData implements AppParam
{
public function __construct(
private CountryDataProvider $provider
) {}
/**
* @return array{list: string[], preferredList: string[]}
*/
public function get(): array
{
return $this->provider->get();
}
}

View File

@@ -0,0 +1,56 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM Open Source CRM application.
* Copyright (C) 2014-2024 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Classes\FieldSanitizers;
use Espo\Core\FieldSanitize\Sanitizer;
use Espo\Core\FieldSanitize\Sanitizer\Data;
/**
* @noinspection PhpUnused
*/
class StringUpperCase implements Sanitizer
{
public function sanitize(Data $data, string $field): void
{
if (!$data->has($field)) {
return;
}
$value = $data->get($field);
if (!is_string($value)) {
return;
}
$value = mb_strtoupper($value);
$data->set($field, $value);
}
}

View File

@@ -0,0 +1,45 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM Open Source CRM application.
* Copyright (C) 2014-2024 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Classes\Select\AddressCountry;
use Espo\Core\Select\Order\Item;
use Espo\Core\Select\Order\Orderer;
use Espo\ORM\Query\Part\Order;
use Espo\ORM\Query\SelectBuilder;
class PreferredNameOrderer implements Orderer
{
public function apply(SelectBuilder $queryBuilder, Item $item): void
{
$queryBuilder
->order('isPreferred', $item->getOrder() === Order::ASC ? Order::DESC : Order::ASC)
->order('name', $item->getOrder());
}
}

View File

@@ -0,0 +1,50 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM Open Source CRM application.
* Copyright (C) 2014-2024 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Controllers;
use Espo\Core\Controllers\RecordBase;
use Espo\Tools\Address\CountryDefaultsPopulator;
class AddressCountry extends RecordBase
{
protected function checkAccess(): bool
{
return $this->user->isAdmin();
}
public function postActionPopulateDefaults(): bool
{
$populate = $this->injectableFactory->create(CountryDefaultsPopulator::class);
$populate->populate();
return true;
}
}

View File

@@ -0,0 +1,117 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM Open Source CRM application.
* Copyright (C) 2014-2024 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Core\Utils\Address;
use Espo\Core\Utils\Config;
use Espo\Core\Utils\DataCache;
use Espo\Entities\AddressCountry;
use Espo\ORM\EntityManager;
use Espo\ORM\Query\Part\Order;
class CountryDataProvider
{
/** @var ?array{list: string[], preferredList: string[]} */
private ?array $data = null;
private bool $useCache;
private const CACHE_KEY = 'addressCountryData';
private const LIMIT = 500;
public function __construct(
private DataCache $dataCache,
private Config $config,
private EntityManager $entityManager
) {
$this->useCache = (bool) $this->config->get('useCache');
}
/**
* @return array{list: string[], preferredList: string[]}
*/
public function get(): array
{
if ($this->data === null) {
$this->data = $this->load();
}
return $this->data;
}
/**
* @return array{list: string[], preferredList: string[]}
*/
private function load(): array
{
if ($this->useCache && $this->dataCache->has(self::CACHE_KEY)) {
$list = $this->dataCache->get(self::CACHE_KEY);
if (
is_array($list) ||
is_array($list['list'] ?? null) ||
is_array($list['preferredList'] ?? null)
) {
/** @var array{list: string[], preferredList: string[]} */
return $list;
}
}
$list = [];
$preferredList = [];
/** @var iterable<AddressCountry> $collection */
$collection = $this->entityManager
->getRDBRepositoryByClass(AddressCountry::class)
->sth()
->select(['name', 'isPreferred'])
->order('name', Order::ASC)
->limit(0, self::LIMIT)
->find();
foreach ($collection as $entity) {
$list[] = $entity->getName();
if ($entity->isPreferred()) {
$preferredList[] = $entity->getName();
}
}
if ($this->useCache) {
$this->dataCache->store(self::CACHE_KEY, [
'list' => $list,
'preferredList' => $preferredList,
]);
}
return [
'list' => $list,
'preferredList' => $preferredList,
];
}
}

View File

@@ -0,0 +1,52 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM Open Source CRM application.
* Copyright (C) 2014-2024 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Entities;
use Espo\Core\ORM\Entity;
class AddressCountry extends Entity
{
public const ENTITY_TYPE = 'AddressCountry';
public function getName(): string
{
return $this->get('name');
}
public function getCode(): string
{
return $this->get('code');
}
public function isPreferred(): bool
{
return (bool) $this->get('isPreferred');
}
}

View File

@@ -0,0 +1,61 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM Open Source CRM application.
* Copyright (C) 2014-2024 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Hooks\AddressCountry;
use Espo\Core\Hook\Hook\AfterRemove;
use Espo\Core\Hook\Hook\AfterSave;
use Espo\Core\Utils\DataCache;
use Espo\Entities\AddressCountry;
use Espo\ORM\Entity;
use Espo\ORM\Repository\Option\RemoveOptions;
use Espo\ORM\Repository\Option\SaveOptions;
/**
* @implements AfterRemove<AddressCountry>
* @implements AfterSave<AddressCountry>
*/
class ClearCache implements AfterRemove, AfterSave
{
private const CACHE_KEY = 'addressCountryData';
public function __construct(
private DataCache $dataCache,
) {}
public function afterSave(Entity $entity, SaveOptions $options): void
{
$this->dataCache->clear(self::CACHE_KEY);
}
public function afterRemove(Entity $entity, RemoveOptions $options): void
{
$this->dataCache->clear(self::CACHE_KEY);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,20 @@
{
"labels": {
"Create AddressCountry": "Create Address Country",
"Populate": "Populate"
},
"fields": {
"code": "Code",
"isPreferred": "Is Preferred"
},
"tooltips": {
"code": "ISO 3166-1 alpha-2 code.",
"isPreferred": "Preferred counties appear first in the picklist."
},
"messages": {
"confirmPopulateDefaults": "All existing countries will be deleted, the default country list will be created. It won't be possible to revert the operation.\n\nAre you sure?"
},
"strings": {
"populateDefaults": "Populate with default country list"
}
}

View File

@@ -80,6 +80,7 @@
"Working Time Calendars": "Working Time Calendars",
"Group Email Folders": "Group Email Folders",
"Authentication Providers": "Authentication Providers",
"Address Countries": "Address Countries",
"Success": "Success",
"Fail": "Fail",
"Configuration Instructions": "Configuration Instructions",
@@ -309,7 +310,8 @@
"jobsSettings": "Job processing settings. Jobs execute tasks in the background.",
"sms": "SMS settings.",
"pdfTemplates": "Templates for printing to PDF.",
"formulaSandbox": "Write and test formula scripts."
"formulaSandbox": "Write and test formula scripts.",
"addressCountries": "Countries available for address fields."
},
"keywords": {
"settings": "system",

View File

@@ -62,7 +62,8 @@
"WorkingTimeCalendar": "Working Time Calendar",
"WorkingTimeRange": "Working Time Exception",
"AuthenticationProvider": "Authentication Provider",
"GlobalStream": "Global Stream"
"GlobalStream": "Global Stream",
"AddressCountry": "Address Country"
},
"scopeNamesPlural": {
"Note": "Notes",
@@ -115,7 +116,8 @@
"WorkingTimeCalendar": "Working Time Calendars",
"WorkingTimeRange": "Working Time Exceptions",
"AuthenticationProvider": "Authentication Providers",
"GlobalStream": "Global Stream"
"GlobalStream": "Global Stream",
"AddressCountry": "Address Countries"
},
"labels": {
"Previous Page": "Previous Page",

View File

@@ -0,0 +1,14 @@
[
{
"rows": [
[
{"name": "name"},
{"name": "code"}
],
[
{"name": "isPreferred"},
false
]
]
}
]

View File

@@ -0,0 +1,14 @@
[
{
"rows": [
[
{"name": "name"},
{"name": "code"}
],
[
{"name": "isPreferred"},
false
]
]
}
]

View File

@@ -0,0 +1,4 @@
[
"code",
"isPreferred"
]

View File

@@ -0,0 +1,5 @@
[
{"name": "name", "link": true},
{"name": "code", "width": 20},
{"name": "isPreferred", "width": 15}
]

View File

@@ -0,0 +1,3 @@
[
"isPreferred"
]

View File

@@ -290,6 +290,12 @@
"iconClass": "fas fa-share-alt icon-rotate-90",
"description": "webhooks"
},
{
"url": "#Admin/addressCountries",
"label": "Address Countries",
"iconClass": "far fa-flag",
"description": "addressCountries"
},
{
"url": "#Admin/authenticationProviders",
"label": "Authentication Providers",

View File

@@ -4,5 +4,8 @@
},
"extensions": {
"className": "Espo\\Classes\\AppParams\\Extensions"
},
"addressCountryData": {
"className": "Espo\\Classes\\AppParams\\AddressCountryData"
}
}

View File

@@ -0,0 +1,17 @@
{
"controller": "controllers/record",
"duplicateDisabled": true,
"mergeDisabled": true,
"menu": {
"list": {
"dropdown": [
{
"name": "populateDefaults",
"labelTranslation": "AddressCountry.strings.populateDefaults",
"handler": "handlers/admin/address-country/populate-defaults",
"actionFunction": "populate"
}
]
}
}
}

View File

@@ -0,0 +1,293 @@
{
"fields": {
"name": {
"type": "varchar",
"required": true,
"maxLength": 100
},
"code": {
"type": "varchar",
"required": true,
"maxLength": 2,
"tooltip": true,
"pattern": "[A-Z]{2}",
"sanitizerClassNameList": [
"Espo\\Classes\\FieldSanitizers\\StringUpperCase"
],
"options": [
"AF",
"AX",
"AL",
"DZ",
"AS",
"AD",
"AO",
"AI",
"AQ",
"AG",
"AR",
"AM",
"AW",
"AU",
"AT",
"AZ",
"BS",
"BH",
"BD",
"BB",
"BY",
"BE",
"BZ",
"BJ",
"BM",
"BT",
"BO",
"BA",
"BW",
"BV",
"BR",
"IO",
"BN",
"BG",
"BF",
"BI",
"KH",
"CM",
"CA",
"CV",
"KY",
"CF",
"TD",
"CL",
"CN",
"CX",
"CC",
"CO",
"KM",
"CG",
"CD",
"CK",
"CR",
"CI",
"HR",
"CU",
"CY",
"CZ",
"DK",
"DJ",
"DM",
"DO",
"EC",
"EG",
"SV",
"GQ",
"ER",
"EE",
"ET",
"FK",
"FO",
"FJ",
"FI",
"FR",
"GF",
"PF",
"TF",
"GA",
"GM",
"GE",
"DE",
"GH",
"GI",
"GR",
"GL",
"GD",
"GP",
"GU",
"GT",
"GG",
"GN",
"GW",
"GY",
"HT",
"HM",
"VA",
"HN",
"HK",
"HU",
"IS",
"IN",
"ID",
"IR",
"IQ",
"IE",
"IM",
"IL",
"IT",
"JM",
"JP",
"JE",
"JO",
"KZ",
"KE",
"KI",
"KR",
"KW",
"KG",
"LA",
"LV",
"LB",
"LS",
"LR",
"LY",
"LI",
"LT",
"LU",
"MO",
"MK",
"MG",
"MW",
"MY",
"MV",
"ML",
"MT",
"MH",
"MQ",
"MR",
"MU",
"YT",
"MX",
"FM",
"MD",
"MC",
"MN",
"ME",
"MS",
"MA",
"MZ",
"MM",
"NA",
"NR",
"NP",
"NL",
"AN",
"NC",
"NZ",
"NI",
"NE",
"NG",
"NU",
"NF",
"MP",
"NO",
"OM",
"PK",
"PW",
"PS",
"PA",
"PG",
"PY",
"PE",
"PH",
"PN",
"PL",
"PT",
"PR",
"QA",
"RE",
"RO",
"RU",
"RW",
"BL",
"SH",
"KN",
"LC",
"MF",
"PM",
"VC",
"WS",
"SM",
"ST",
"SA",
"SN",
"RS",
"SC",
"SL",
"SG",
"SK",
"SI",
"SB",
"SO",
"ZA",
"GS",
"ES",
"LK",
"SD",
"SR",
"SJ",
"SZ",
"SE",
"CH",
"SY",
"TW",
"TJ",
"TZ",
"TH",
"TL",
"TG",
"TK",
"TO",
"TT",
"TN",
"TR",
"TM",
"TC",
"TV",
"UG",
"UA",
"AE",
"GB",
"US",
"UM",
"UY",
"UZ",
"VU",
"VE",
"VN",
"VG",
"VI",
"WF",
"EH",
"YE",
"ZM",
"ZW"
]
},
"isPreferred": {
"type": "bool",
"tooltip": true
},
"preferredName": {
"type": "base",
"notStorable": true,
"utility": true
}
},
"links": {},
"collection": {
"orderBy": "preferredName",
"order": "asc",
"textFilterFields": [
"name",
"code"
]
},
"indexes": {
"name": {
"unique": true,
"columns": [
"name"
]
}
},
"noDeletedAttribute": true
}

View File

@@ -0,0 +1,11 @@
{
"duplicateWhereBuilderClassName": "Espo\\Classes\\DuplicateWhereBuilders\\General",
"massActions": {
"delete": {
"allowed": true
},
"update": {
"allowed": true
}
}
}

View File

@@ -0,0 +1,9 @@
{
"entity": true,
"importable": true,
"exportFormatList": ["csv"],
"duplicateCheckFieldList": [
"name",
"code"
]
}

View File

@@ -0,0 +1,5 @@
{
"ordererClassNameMap": {
"preferredName": "Espo\\Classes\\Select\\AddressCountry\\PreferredNameOrderer"
}
}

View File

@@ -0,0 +1,105 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM Open Source CRM application.
* Copyright (C) 2014-2024 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Tools\Address;
use Espo\Core\Utils\DataCache;
use Espo\Core\Utils\File\Manager;
use Espo\Core\Utils\Id\RecordIdGenerator;
use Espo\Core\Utils\Json;
use Espo\Entities\AddressCountry;
use Espo\ORM\EntityManager;
use Espo\ORM\Query\DeleteBuilder;
use RuntimeException;
class CountryDefaultsPopulator
{
private string $file = 'application/Espo/Resources/data/locale/en_US/countryList.json';
private const CACHE_KEY = 'addressCountryData';
public function __construct(
private Manager $fileManager,
private EntityManager $entityManager,
private DataCache $dataCache,
private RecordIdGenerator $recordIdGenerator
) {}
public function populate(): void
{
if (!$this->fileManager->exists($this->file)) {
throw new RuntimeException("No file '$this->file'.");
}
$contents = $this->fileManager->getContents($this->file);
$dataList = Json::decode($contents, true);
if (!is_array($dataList)) {
throw new RuntimeException("Bad data.");
}
$collection = $this->entityManager->getCollectionFactory()->create(AddressCountry::ENTITY_TYPE);
foreach ($dataList as $data) {
if (!is_array($data)) {
throw new RuntimeException("Bad data.");
}
$name = $data['name'] ?? null;
$code = $data['code'] ?? null;
$isPreferred = $data['isPreferred'] ?? false;
if (!is_string($name) || !is_string($code)) {
throw new RuntimeException("Bad data.");
}
$entity = $this->entityManager->getNewEntity(AddressCountry::ENTITY_TYPE);
$entity->setMultiple([
'id' => $this->recordIdGenerator->generate(),
'name' => $name,
'code' => $code,
'isPreferred' => $isPreferred,
]);
$collection->append($entity);
}
$this->entityManager->getQueryExecutor()->execute(
DeleteBuilder::create()
->from(AddressCountry::ENTITY_TYPE)
->build()
);
$this->entityManager->getMapper()->massInsert($collection);
$this->dataCache->clear(self::CACHE_KEY);
}
}

View File

@@ -219,6 +219,11 @@ class AdminController extends Controller {
this.getRouter().dispatch('AuthenticationProvider', 'list', {fromAdmin: true});
}
// noinspection JSUnusedGlobalSymbols
actionAddressCountries() {
this.getRouter().dispatch('AddressCountry', 'list', {fromAdmin: true});
}
// noinspection JSUnusedGlobalSymbols
actionEmailAddresses() {
this.getRouter().dispatch('EmailAddress', 'list', {fromAdmin: true});

View File

@@ -0,0 +1,48 @@
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM Open Source CRM application.
* Copyright (C) 2014-2024 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
import ActionHandler from 'action-handler';
class PopulateDefaultsHandler extends ActionHandler {
async populate() {
const confirmMessage = this.view.translate('confirmPopulateDefaults', 'messages', 'AddressCountry');
await this.view.confirm(confirmMessage);
Espo.Ui.notify(' ... ');
await Espo.Ajax.postRequest('AddressCountry/action/populateDefaults');
await this.view.collection.fetch();
Espo.Ui.success(this.view.translate('Done'));
}
}
// noinspection JSUnusedGlobalSymbols
export default PopulateDefaultsHandler;

View File

@@ -31,12 +31,57 @@ import VarcharFieldView from 'views/fields/varchar';
class AddressCountryFieldView extends VarcharFieldView {
setupOptions() {
let countryList = this.getConfig().get('addressCountryList') || [];
const countryList = this.getCountryList();
if (countryList.length) {
this.params.options = Espo.Utils.clone(countryList);
}
}
/**
* @private
* @return {string[]}
*/
getCountryList() {
const list = (this.getHelper().getAppParam('addressCountryData') || {}).list || [];
if (list.length) {
return list;
}
return this.getConfig().get('addressCountryList') || [];
}
getAutocompleteLookupFunction() {
// noinspection JSUnresolvedReference
const list = (this.getHelper().getAppParam('addressCountryData') || {}).preferredList || [];
if (!list.length) {
return undefined;
}
const fullList = (this.params.options || []);
return query => {
if (query.length === 0) {
const result = list.map(item => ({value: item}));
return Promise.resolve(result);
}
const queryLowerCase = query.toLowerCase();
const result = fullList
.filter(item => {
if (item.toLowerCase().indexOf(queryLowerCase) === 0) {
return item.length !== queryLowerCase.length;
}
})
.map(item => ({value: item}));
return Promise.resolve(result);
};
}
}
export default AddressCountryFieldView;

View File

@@ -386,7 +386,7 @@ class AddressFieldView extends BaseFieldView {
this.$city.on('change', () => this.trigger('change'));
this.$country.on('change', () => this.trigger('change'));
const countryList = this.getConfig().get('addressCountryList') || [];
const countryList = this.getCountryList();
const cityList = this.getConfig().get('addressCityList') || [];
const stateList = this.getConfig().get('addressStateList') || [];
@@ -398,6 +398,7 @@ class AddressFieldView extends BaseFieldView {
handleFocusMode: 1,
focusOnSelect: true,
lookup: countryList,
lookupFunction: this.getCountryAutocompleteLookupFunction(countryList),
onSelect: () => this.trigger('change'),
});
@@ -610,6 +611,54 @@ class AddressFieldView extends BaseFieldView {
field: this.name,
}, view => view.render());
}
/**
* @private
* @return {string[]}
*/
getCountryList() {
const list = (this.getHelper().getAppParam('addressCountryData') || {}).list || [];
if (list.length) {
return list;
}
return this.getConfig().get('addressCountryList') || [];
}
/**
* @private
* @param {string[]} fullList
* @return {function(string): Promise|undefined}
*/
getCountryAutocompleteLookupFunction(fullList) {
// noinspection JSUnresolvedReference
const list = (this.getHelper().getAppParam('addressCountryData') || {}).preferredList || [];
if (!list.length) {
return undefined;
}
return query => {
if (query.length === 0) {
const result = list.map(item => ({value: item}));
return Promise.resolve(result);
}
const queryLowerCase = query.toLowerCase();
const result = fullList
.filter(item => {
if (item.toLowerCase().indexOf(queryLowerCase) === 0) {
return item.length !== queryLowerCase.length;
}
})
.map(item => ({value: item}));
return Promise.resolve(result);
};
}
}
export default AddressFieldView;