Currency rates as entities (#3543)
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* 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 Acl from 'acl';
|
||||
|
||||
export default class extends Acl {
|
||||
|
||||
checkScope(data, action, precise, entityAccessData) {
|
||||
if (action === 'create' || action === 'delete') {
|
||||
action = 'edit';
|
||||
}
|
||||
|
||||
return super.checkScope(data, action, precise, entityAccessData);
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,7 @@ import SettingsEditView from 'views/settings/edit';
|
||||
import AdminIndexView from 'views/admin/index';
|
||||
import {inject} from 'di';
|
||||
import Language from 'language';
|
||||
import EditView from 'views/edit';
|
||||
|
||||
class AdminController extends Controller {
|
||||
|
||||
@@ -51,7 +52,7 @@ class AdminController extends Controller {
|
||||
}
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
actionPage(options) {
|
||||
async actionPage(options) {
|
||||
const page = options.page;
|
||||
|
||||
if (options.options) {
|
||||
@@ -81,7 +82,7 @@ class AdminController extends Controller {
|
||||
throw new Espo.Exceptions.NotFound();
|
||||
}
|
||||
|
||||
if (defs.view) {
|
||||
if (defs.view && !defs.recordView) {
|
||||
this.main(defs.view, options);
|
||||
|
||||
return;
|
||||
@@ -93,23 +94,32 @@ class AdminController extends Controller {
|
||||
|
||||
const model = this.getSettingsModel();
|
||||
|
||||
model.fetch().then(() => {
|
||||
model.id = '1';
|
||||
await model.fetch();
|
||||
|
||||
const editView = new SettingsEditView({
|
||||
model: model,
|
||||
headerTemplate: 'admin/settings/headers/page',
|
||||
recordView: defs.recordView,
|
||||
page: page,
|
||||
label: defs.label,
|
||||
optionsToPass: [
|
||||
'page',
|
||||
'label',
|
||||
],
|
||||
});
|
||||
model.id = '1';
|
||||
|
||||
this.main(editView);
|
||||
const view = defs.view ?? 'views/settings/edit';
|
||||
|
||||
const ViewClass = await Espo.loader.requirePromise(view);
|
||||
|
||||
if (!EditView.isPrototypeOf(ViewClass)) {
|
||||
throw new Error("View should inherit views/edit.");
|
||||
}
|
||||
|
||||
const editView = new ViewClass({
|
||||
model: model,
|
||||
headerTemplate: 'admin/settings/headers/page',
|
||||
recordView: defs.recordView,
|
||||
page: page,
|
||||
label: defs.label,
|
||||
optionsToPass: [
|
||||
'page',
|
||||
'label',
|
||||
],
|
||||
});
|
||||
|
||||
this.main(editView);
|
||||
|
||||
}
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* 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 DefaultsPreparator from 'handlers/model/defaults-preparator';
|
||||
import {inject} from 'di';
|
||||
import Settings from 'models/settings';
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
export default class extends DefaultsPreparator {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Settings}
|
||||
*/
|
||||
@inject(Settings)
|
||||
config
|
||||
|
||||
async prepare(model) {
|
||||
return {
|
||||
baseCode: this.config.get('baseCurrency'),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
export default class CurrencyRecordRecordDetailHandler {
|
||||
|
||||
/**
|
||||
* @param {import('views/record/detail').default} view
|
||||
*/
|
||||
constructor(view) {
|
||||
this.view = view;
|
||||
}
|
||||
|
||||
process() {
|
||||
const model = this.view.model;
|
||||
|
||||
this.view.listenTo(model, 'after:relate:rates after:unrelate:rates after:related-change:rates', () => {
|
||||
model.fetch();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* 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 EditView from 'views/edit';
|
||||
|
||||
export default class CurrencyMainView extends EditView {
|
||||
|
||||
scope = 'Settings'
|
||||
|
||||
getHeader() {
|
||||
return this.buildHeaderHtml([
|
||||
(() => {
|
||||
const a = document.createElement('a');
|
||||
a.href = '#Admin';
|
||||
a.text = this.translate('Administration');
|
||||
|
||||
return a;
|
||||
})(),
|
||||
(() => {
|
||||
return this.options.label;
|
||||
})(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,7 @@
|
||||
************************************************************************/
|
||||
|
||||
import SettingsEditRecordView from 'views/settings/record/edit';
|
||||
import EditView from 'views/edit';
|
||||
|
||||
export default class extends SettingsEditRecordView {
|
||||
|
||||
@@ -65,6 +66,22 @@ export default class extends SettingsEditRecordView {
|
||||
});
|
||||
|
||||
this.controlCurrencyRatesVisibility();
|
||||
|
||||
this.whenReady().then(() => {
|
||||
const view = /** @type {EditView} view */
|
||||
this.getParentView();
|
||||
|
||||
if (!view instanceof EditView) {
|
||||
return;
|
||||
}
|
||||
|
||||
view.addMenuItem('buttons', {
|
||||
name: 'currencyRecords',
|
||||
link: '#CurrencyRecord',
|
||||
labelTranslation: 'Settings.labels.Currency Rates',
|
||||
iconClass: 'fas fa-euro-sign',
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
controlCurrencyRatesVisibility() {
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* 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 DecimalFieldView from 'views/fields/decimal';
|
||||
|
||||
export default class CurrencyRecordRateRateFieldView extends DecimalFieldView {
|
||||
|
||||
// language=Handlebars
|
||||
listTemplateContent = `
|
||||
{{#if isNotEmpty~}}
|
||||
<span class="text-soft">{{targetCode}} = </span>
|
||||
<span class="numeric-text">{{value}}</span>
|
||||
<span class="text-soft">{{baseCode}}</span>
|
||||
{{~/if~}}
|
||||
`
|
||||
|
||||
// language=Handlebars
|
||||
detailTemplateContent = `
|
||||
{{~#if isNotEmpty~}}
|
||||
<span class="text-soft">{{targetCode}} = </span>
|
||||
<span class="numeric-text">{{value}}</span>
|
||||
<span class="text-soft">{{baseCode}}</span>
|
||||
{{~else~}}
|
||||
{{~#if valueIsSet~}}
|
||||
<span class="none-value">{{translate 'None'}}</span>
|
||||
{{~else~}}<span class="loading-value"></span>
|
||||
{{~/if}}
|
||||
{{~/if~}}
|
||||
`
|
||||
|
||||
// language=Handlebars
|
||||
editTemplateContent = `
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon radius-left" style="width: 24%">1 {{targetCode}} = </span>
|
||||
<span class="input-group-item">
|
||||
<input
|
||||
type="text"
|
||||
class="main-element form-control numeric-text"
|
||||
data-name="{{name}}"
|
||||
value="{{value}}"
|
||||
autocomplete="espo-{{name}}"
|
||||
pattern="[\\-]?[0-9]*"
|
||||
style="text-align: end;"
|
||||
>
|
||||
</span>
|
||||
<span class="input-group-addon radius-right" style="width: 21%">{{baseCode}}</span>
|
||||
</div>
|
||||
`
|
||||
|
||||
getAttributeList() {
|
||||
return [
|
||||
...super.getAttributeList(),
|
||||
'baseCode',
|
||||
'recordName',
|
||||
];
|
||||
}
|
||||
|
||||
data() {
|
||||
let baseCode = this.model.attributes.baseCode;
|
||||
let targetCode = this.model.attributes.recordName;
|
||||
|
||||
if (this.model.entityType === 'CurrencyRecord') {
|
||||
baseCode = this.getConfig().get('baseCurrency');
|
||||
targetCode = this.model.attributes.code;
|
||||
}
|
||||
|
||||
return {
|
||||
...super.data(),
|
||||
baseCode,
|
||||
targetCode,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* 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 RelationshipPanelView from 'views/record/panels/relationship';
|
||||
|
||||
export default class RatesPanelView extends RelationshipPanelView {
|
||||
|
||||
setup() {
|
||||
if (this.model.attributes.code === this.getConfig().get('baseCurrency')) {
|
||||
this.defs.createDisabled = true;
|
||||
}
|
||||
|
||||
super.setup();
|
||||
}
|
||||
}
|
||||
@@ -28,23 +28,33 @@
|
||||
|
||||
import BaseFieldView from 'views/fields/base';
|
||||
|
||||
/**
|
||||
* Not used.
|
||||
* @todo Remove.
|
||||
*/
|
||||
export default class extends BaseFieldView {
|
||||
|
||||
editTemplate = 'settings/fields/currency-rates/edit'
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string}
|
||||
*/
|
||||
baseCode
|
||||
|
||||
data() {
|
||||
const baseCurrency = this.model.get('baseCurrency');
|
||||
const baseCode = this.baseCode;
|
||||
const currencyRates = this.model.get('currencyRates') || {};
|
||||
|
||||
const rateValues = {};
|
||||
|
||||
(this.model.get('currencyList') || []).forEach(currency => {
|
||||
if (currency !== baseCurrency) {
|
||||
if (currency !== baseCode) {
|
||||
rateValues[currency] = currencyRates[currency];
|
||||
|
||||
if (!rateValues[currency]) {
|
||||
if (currencyRates[baseCurrency]) {
|
||||
rateValues[currency] = Math.round(1 / currencyRates[baseCurrency] * 1000) / 1000;
|
||||
if (currencyRates[baseCode]) {
|
||||
rateValues[currency] = Math.round(1 / currencyRates[baseCode] * 1000) / 1000;
|
||||
}
|
||||
|
||||
if (!rateValues[currency]) {
|
||||
@@ -56,36 +66,23 @@ export default class extends BaseFieldView {
|
||||
|
||||
return {
|
||||
rateValues: rateValues,
|
||||
baseCurrency: baseCurrency,
|
||||
baseCurrency: baseCode,
|
||||
};
|
||||
}
|
||||
|
||||
fetch() {
|
||||
const data = {};
|
||||
const currencyRates = {};
|
||||
setup() {
|
||||
const sync = () => {
|
||||
this.baseCode = this.model.get('baseCurrency');
|
||||
};
|
||||
|
||||
const baseCurrency = this.model.get('baseCurrency');
|
||||
sync();
|
||||
|
||||
const currencyList = this.model.get('currencyList') || [];
|
||||
|
||||
currencyList.forEach(currency => {
|
||||
if (currency !== baseCurrency) {
|
||||
const value = this.$el.find(`input[data-currency="${currency}"]`).val() || '1';
|
||||
|
||||
currencyRates[currency] = parseFloat(value);
|
||||
}
|
||||
this.listenTo(this.model, 'sync', () => {
|
||||
sync();
|
||||
});
|
||||
}
|
||||
|
||||
delete currencyRates[baseCurrency];
|
||||
|
||||
for (const c in currencyRates) {
|
||||
if (!~currencyList.indexOf(c)) {
|
||||
delete currencyRates[c];
|
||||
}
|
||||
}
|
||||
|
||||
data[this.name] = currencyRates;
|
||||
|
||||
return data;
|
||||
fetch() {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user