First commit waiting for Budget Alert
This commit is contained in:
34
modules/axelor-open-suite/axelor-studio/README.md
Normal file
34
modules/axelor-open-suite/axelor-studio/README.md
Normal file
@ -0,0 +1,34 @@
|
||||
Overview
|
||||
------
|
||||
|
||||
This module adds tools that helps to create or edit a axelor module directly from the Axelor Open Platform web interface.
|
||||
|
||||
The module components like domain, view, report,..etc could be easily created by using those tools.
|
||||
|
||||
It also provides a support to create and apply the workflow.
|
||||
|
||||
It generate a module code and store it in to the specified source directory.
|
||||
|
||||
All changes could be applied to the working instance with just one button click.
|
||||
|
||||
Dependencies
|
||||
------
|
||||
|
||||
* axelor-tool
|
||||
* axelor-exception
|
||||
* axelor-message
|
||||
|
||||
Install
|
||||
------
|
||||
|
||||
* Put the axelor-studio with its dependencies in to the app module's module path.
|
||||
* Set the following properties in the app module.
|
||||
- `studio.source.dir:` A path to the app module's source directory.
|
||||
- `studio.adk.dir:` A path to the axelor-open-platform that is required to build a module.
|
||||
- `studio.restart.log:` A path to any text file. It will store the log of the backend script that restart the server.
|
||||
- `studio.doc.dir:`A path to directory containing screenshots of the form views. It will be used to generate a doc from the excel sheet.
|
||||
- `context.action = com.axelor.studio.utils.ActionHelper`. Put this as it is in the properties file.
|
||||
* Environment variables to set.
|
||||
- `JAVA_HOME:` A path to JDK used by the running app instance. It must be a JDK path and not the JRE path.
|
||||
- `CATALINA_HOME:` It is a well known tomcat environment variable. A path to the tomcat server directory used by the current running instance.
|
||||
- `PGDATA:` A path to the postgreql installation directory. For linux(ubuntu) its mostly a /usr/lib/postgresql/{postgres version}.
|
||||
55
modules/axelor-open-suite/axelor-studio/build.gradle
Normal file
55
modules/axelor-open-suite/axelor-studio/build.gradle
Normal file
@ -0,0 +1,55 @@
|
||||
apply plugin: "com.axelor.app-module"
|
||||
|
||||
apply from: "../version.gradle"
|
||||
|
||||
apply {
|
||||
version = openSuiteVersion
|
||||
}
|
||||
|
||||
axelor {
|
||||
title "Axelor Studio"
|
||||
description "Axelor Studio Module"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile project(":modules:axelor-admin")
|
||||
compile project(":modules:axelor-message")
|
||||
compile 'commons-lang:commons-lang:2.3'
|
||||
// compile 'org.xhtmlrenderer:flying-saucer-pdf:9.1.4'
|
||||
compile 'org.eclipse.birt.runtime.3_7_1:Tidy:1'
|
||||
compile 'org.apache.commons:commons-exec:1.2'
|
||||
// compile "org.bouncycastle:bcprov-jdk15on:1.62"
|
||||
}
|
||||
|
||||
def updateJsp(jspFile, check, lines) {
|
||||
def jsp = file("${rootProject.buildDir}/webapp/${jspFile}")
|
||||
def text = lines.join("\n");
|
||||
if (jsp.exists()) {
|
||||
def jspText = jsp.getText('UTF-8')
|
||||
if (jspText.indexOf(check) == -1) {
|
||||
text = jspText + text
|
||||
}
|
||||
}
|
||||
file(jsp).write(text, 'UTF-8')
|
||||
}
|
||||
|
||||
//XXX: this task should be removed when we introduce per module webapp support in Axelor Open Platform
|
||||
task copyWebapp(type: Copy) {
|
||||
destinationDir = file(rootProject.buildDir)
|
||||
into("webapp/studio") {
|
||||
from "src/main/webapp"
|
||||
}
|
||||
doLast {
|
||||
// update index-head.jsp
|
||||
updateJsp("index-head.jsp", "diagram-js.css", [
|
||||
'<link href="studio/lib/bpmn-js/assets/bpmn-font/css/bpmn-embedded.css" rel="stylesheet">',
|
||||
'<link href="studio/lib/bpmn-js/assets/diagram-js.css" rel="stylesheet">',
|
||||
'<link href="studio/css/bpmn.css" rel="stylesheet">'])
|
||||
// update index-foot.jsp
|
||||
updateJsp("index-foot.jsp", "bpmn-modeler.js", [
|
||||
'<script src="studio/lib/bpmn-js/bpmn-modeler.js"></script>',
|
||||
'<script src="studio/js/form/form.bpmn.js"></script>'])
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.tasks.war.dependsOn copyWebapp
|
||||
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.studio.db.repo;
|
||||
|
||||
import com.axelor.meta.MetaStore;
|
||||
import com.axelor.studio.db.ActionBuilder;
|
||||
import com.axelor.studio.service.StudioMetaService;
|
||||
import com.axelor.studio.service.builder.ActionBuilderService;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
public class ActionBuilderRepo extends ActionBuilderRepository {
|
||||
|
||||
@Inject private StudioMetaService metaService;
|
||||
|
||||
@Inject private ActionBuilderService builderService;
|
||||
|
||||
@Override
|
||||
public ActionBuilder save(ActionBuilder builder) {
|
||||
|
||||
builder = super.save(builder);
|
||||
|
||||
builderService.build(builder);
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(ActionBuilder actionBuilder) {
|
||||
|
||||
metaService.removeMetaActions(actionBuilder.getName());
|
||||
|
||||
MetaStore.clear();
|
||||
|
||||
super.remove(actionBuilder);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.studio.db.repo;
|
||||
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.studio.db.AppBuilder;
|
||||
import com.axelor.studio.service.builder.AppBuilderService;
|
||||
import com.google.inject.Inject;
|
||||
import javax.validation.ValidationException;
|
||||
|
||||
public class AppBuilderRepo extends AppBuilderRepository {
|
||||
|
||||
@Inject private AppBuilderService appBuilderService;
|
||||
|
||||
@Override
|
||||
public AppBuilder save(AppBuilder appBuilder) {
|
||||
|
||||
try {
|
||||
appBuilderService.build(appBuilder);
|
||||
} catch (AxelorException e) {
|
||||
throw new ValidationException(e.getMessage());
|
||||
}
|
||||
|
||||
return super.save(appBuilder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(AppBuilder appBuilder) {
|
||||
|
||||
appBuilderService.clean(appBuilder);
|
||||
|
||||
super.remove(appBuilder);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.studio.db.repo;
|
||||
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.meta.db.MetaView;
|
||||
import com.axelor.meta.db.repo.MetaViewRepository;
|
||||
import com.axelor.studio.db.ChartBuilder;
|
||||
import com.axelor.studio.service.builder.ChartBuilderService;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.util.List;
|
||||
import javax.validation.ValidationException;
|
||||
import javax.xml.bind.JAXBException;
|
||||
|
||||
public class ChartBuilderRepo extends ChartBuilderRepository {
|
||||
|
||||
@Inject private MetaViewRepository metaViewRepo;
|
||||
|
||||
@Inject private ChartBuilderService chartBuilderService;
|
||||
|
||||
@Override
|
||||
public ChartBuilder save(ChartBuilder chartBuilder) throws ValidationException {
|
||||
|
||||
try {
|
||||
chartBuilderService.build(chartBuilder);
|
||||
} catch (AxelorException | JAXBException e) {
|
||||
refresh(chartBuilder);
|
||||
throw new ValidationException(e.getMessage());
|
||||
}
|
||||
|
||||
return super.save(chartBuilder);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void remove(ChartBuilder chartBuilder) {
|
||||
|
||||
MetaView metaView = chartBuilder.getMetaViewGenerated();
|
||||
List<ChartBuilder> chartBuilders =
|
||||
all()
|
||||
.filter("self.metaViewGenerated = ?1 and self.id != ?2", metaView, chartBuilder.getId())
|
||||
.fetch();
|
||||
for (ChartBuilder builder : chartBuilders) {
|
||||
builder.setMetaViewGenerated(null);
|
||||
}
|
||||
|
||||
if (metaView != null) {
|
||||
metaViewRepo.remove(metaView);
|
||||
}
|
||||
|
||||
super.remove(chartBuilder);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.studio.db.repo;
|
||||
|
||||
import com.axelor.meta.db.MetaView;
|
||||
import com.axelor.meta.db.repo.MetaViewRepository;
|
||||
import com.axelor.studio.db.DashboardBuilder;
|
||||
import com.axelor.studio.service.builder.DashboardBuilderService;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
public class DashboardBuilderRepo extends DashboardBuilderRepository {
|
||||
|
||||
@Inject private DashboardBuilderService dashboardBuilderService;
|
||||
|
||||
@Inject private MetaViewRepository metaViewRepo;
|
||||
|
||||
@Override
|
||||
public DashboardBuilder save(DashboardBuilder dashboardBuilder) {
|
||||
|
||||
dashboardBuilder = super.save(dashboardBuilder);
|
||||
|
||||
MetaView metaView = dashboardBuilderService.build(dashboardBuilder);
|
||||
if (metaView != null) {
|
||||
dashboardBuilder.setMetaViewGenerated(metaView);
|
||||
} else {
|
||||
metaView = dashboardBuilder.getMetaViewGenerated();
|
||||
if (metaView != null) {
|
||||
metaViewRepo.remove(metaView);
|
||||
}
|
||||
}
|
||||
return dashboardBuilder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(DashboardBuilder dashboardBuilder) {
|
||||
|
||||
MetaView metaView = dashboardBuilder.getMetaViewGenerated();
|
||||
if (metaView != null) {
|
||||
metaViewRepo.remove(metaView);
|
||||
}
|
||||
|
||||
super.remove(dashboardBuilder);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.studio.db.repo;
|
||||
|
||||
import com.axelor.exception.service.TraceBackService;
|
||||
import com.axelor.meta.MetaStore;
|
||||
import com.axelor.meta.db.MetaMenu;
|
||||
import com.axelor.studio.db.ActionBuilder;
|
||||
import com.axelor.studio.db.MenuBuilder;
|
||||
import com.axelor.studio.service.StudioMetaService;
|
||||
import com.axelor.studio.service.builder.MenuBuilderService;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
public class MenuBuilderRepo extends MenuBuilderRepository {
|
||||
|
||||
@Inject private MenuBuilderService menuBuilderService;
|
||||
|
||||
@Inject private ActionBuilderRepo actionBuilderRepo;
|
||||
|
||||
@Inject private StudioMetaService metaService;
|
||||
|
||||
@Override
|
||||
public MenuBuilder save(MenuBuilder menuBuilder) {
|
||||
if (menuBuilder.getName() == null) {
|
||||
menuBuilder.setName("studio-menu-" + menuBuilder.getId());
|
||||
}
|
||||
if (menuBuilder.getActionBuilder() != null) {
|
||||
menuBuilder.getActionBuilder().setMenuAction(true);
|
||||
}
|
||||
menuBuilder = super.save(menuBuilder);
|
||||
menuBuilder.setMetaMenu(menuBuilderService.build(menuBuilder));
|
||||
return menuBuilder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuBuilder copy(MenuBuilder menuBuilder, boolean deep) {
|
||||
|
||||
ActionBuilder actionBuilder = menuBuilder.getActionBuilder();
|
||||
menuBuilder.setActionBuilder(null);
|
||||
|
||||
menuBuilder = super.copy(menuBuilder, deep);
|
||||
|
||||
if (actionBuilder != null) {
|
||||
menuBuilder.setActionBuilder(actionBuilderRepo.copy(actionBuilder, deep));
|
||||
}
|
||||
|
||||
return menuBuilder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(MenuBuilder menuBuilder) {
|
||||
MetaMenu metaMenu = menuBuilder.getMetaMenu();
|
||||
menuBuilder.setMetaMenu(null);
|
||||
metaService.removeMetaMenu(metaMenu);
|
||||
|
||||
ActionBuilder actionBuilder = menuBuilder.getActionBuilder();
|
||||
|
||||
menuBuilder.setActionBuilder(null);
|
||||
if (actionBuilder != null) {
|
||||
try {
|
||||
actionBuilderRepo.remove(actionBuilder);
|
||||
} catch (RuntimeException e) {
|
||||
TraceBackService.trace(e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
MetaStore.clear();
|
||||
|
||||
super.remove(menuBuilder);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.studio.db.repo;
|
||||
|
||||
import com.axelor.meta.db.MetaJsonField;
|
||||
import com.axelor.meta.db.repo.MetaJsonFieldRepository;
|
||||
import com.axelor.studio.db.AppBuilder;
|
||||
|
||||
public class MetaJsonFieldRepo extends MetaJsonFieldRepository {
|
||||
|
||||
@Override
|
||||
public MetaJsonField save(MetaJsonField metajsonField) {
|
||||
|
||||
AppBuilder appBuilder = metajsonField.getAppBuilder();
|
||||
if (appBuilder != null) {
|
||||
metajsonField.setIncludeIf("__config__.app.isApp('" + appBuilder.getCode() + "')");
|
||||
}
|
||||
|
||||
return super.save(metajsonField);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.studio.db.repo;
|
||||
|
||||
import com.axelor.meta.db.MetaJsonModel;
|
||||
import com.axelor.meta.db.repo.MetaJsonModelRepository;
|
||||
import com.axelor.studio.db.AppBuilder;
|
||||
|
||||
public class MetaJsonModelRepo extends MetaJsonModelRepository {
|
||||
|
||||
@Override
|
||||
public MetaJsonModel save(MetaJsonModel jsonModel) {
|
||||
jsonModel = super.save(jsonModel);
|
||||
|
||||
if (jsonModel.getMenu() != null) {
|
||||
AppBuilder appBuilder = jsonModel.getAppBuilder();
|
||||
if (appBuilder != null) {
|
||||
jsonModel
|
||||
.getMenu()
|
||||
.setConditionToCheck("__config__.app.isApp('" + appBuilder.getCode() + "')");
|
||||
} else {
|
||||
jsonModel.getMenu().setConditionToCheck(null);
|
||||
}
|
||||
}
|
||||
return jsonModel;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.studio.db.repo;
|
||||
|
||||
import com.axelor.studio.db.Wkf;
|
||||
import com.axelor.studio.service.wkf.WkfService;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
public class StudioWkfRepository extends WkfRepository {
|
||||
|
||||
@Inject private WkfService wkfService;
|
||||
|
||||
/**
|
||||
* Overridden to remove changes related with workflow. Like to remove buttons and status field
|
||||
* from view and model.
|
||||
*/
|
||||
@Override
|
||||
public void remove(Wkf wkf) {
|
||||
|
||||
wkfService.clearWkf(wkf);
|
||||
|
||||
super.remove(wkf);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.studio.exception;
|
||||
|
||||
public interface IExceptionMessage {
|
||||
|
||||
/** Check if app builder code is not conflicting with existing app. */
|
||||
static final String APP_BUILDER_1 = /*$$(*/
|
||||
"Please provide unique code. The code '%s' is already used" /*)*/;
|
||||
|
||||
/** Check if chart name doesn't contains any space. */
|
||||
static final String CHART_BUILDER_1 = /*$$(*/ "Name must not contains space" /*)*/;
|
||||
|
||||
/** Message to display on click of edit icon of node or transition if workflow is not saved. */
|
||||
static final String WKF_1 = /*$$(*/ "Workflow is not saved" /*)*/;
|
||||
}
|
||||
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.studio.module;
|
||||
|
||||
import com.axelor.app.AxelorModule;
|
||||
import com.axelor.meta.db.repo.MetaJsonFieldRepository;
|
||||
import com.axelor.meta.db.repo.MetaJsonModelRepository;
|
||||
import com.axelor.studio.db.repo.ActionBuilderRepo;
|
||||
import com.axelor.studio.db.repo.ActionBuilderRepository;
|
||||
import com.axelor.studio.db.repo.AppBuilderRepo;
|
||||
import com.axelor.studio.db.repo.AppBuilderRepository;
|
||||
import com.axelor.studio.db.repo.ChartBuilderRepo;
|
||||
import com.axelor.studio.db.repo.ChartBuilderRepository;
|
||||
import com.axelor.studio.db.repo.DashboardBuilderRepo;
|
||||
import com.axelor.studio.db.repo.DashboardBuilderRepository;
|
||||
import com.axelor.studio.db.repo.MenuBuilderRepo;
|
||||
import com.axelor.studio.db.repo.MenuBuilderRepository;
|
||||
import com.axelor.studio.db.repo.MetaJsonFieldRepo;
|
||||
import com.axelor.studio.db.repo.MetaJsonModelRepo;
|
||||
import com.axelor.studio.db.repo.StudioWkfRepository;
|
||||
import com.axelor.studio.db.repo.WkfRepository;
|
||||
|
||||
public class StudioModule extends AxelorModule {
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
bind(WkfRepository.class).to(StudioWkfRepository.class);
|
||||
bind(ChartBuilderRepository.class).to(ChartBuilderRepo.class);
|
||||
bind(ActionBuilderRepository.class).to(ActionBuilderRepo.class);
|
||||
bind(MenuBuilderRepository.class).to(MenuBuilderRepo.class);
|
||||
bind(DashboardBuilderRepository.class).to(DashboardBuilderRepo.class);
|
||||
bind(AppBuilderRepository.class).to(AppBuilderRepo.class);
|
||||
bind(MetaJsonFieldRepository.class).to(MetaJsonFieldRepo.class);
|
||||
bind(MetaJsonModelRepository.class).to(MetaJsonModelRepo.class);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.studio.service;
|
||||
|
||||
import com.axelor.exception.service.TraceBackService;
|
||||
import com.axelor.meta.MetaFiles;
|
||||
import com.axelor.meta.db.MetaFile;
|
||||
import com.axelor.studio.db.ActionBuilder;
|
||||
import com.axelor.studio.db.ActionBuilderLine;
|
||||
import com.axelor.studio.db.repo.ActionBuilderRepository;
|
||||
import com.google.common.base.Strings;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang.StringEscapeUtils;
|
||||
|
||||
public class ExportService {
|
||||
|
||||
private ExportService() {
|
||||
throw new IllegalStateException("Should not be instantiated.");
|
||||
}
|
||||
|
||||
public static String getImage(MetaFile metaFile) {
|
||||
|
||||
if (metaFile != null) {
|
||||
File file = MetaFiles.getPath(metaFile).toFile();
|
||||
if (file != null) {
|
||||
try {
|
||||
byte[] img = IOUtils.toByteArray(new FileInputStream(file));
|
||||
return Base64.getEncoder().encodeToString(img);
|
||||
} catch (IOException e) {
|
||||
TraceBackService.trace(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
public static String exportActionBuilderLines(List<ActionBuilderLine> lines, int count) {
|
||||
|
||||
String xml = "";
|
||||
|
||||
String indent = "\n" + Strings.repeat("\t", count);
|
||||
for (ActionBuilderLine line : lines) {
|
||||
|
||||
String source = "";
|
||||
String target = "";
|
||||
|
||||
if (line.getParent() == null) {
|
||||
ActionBuilder builder = line.getActionBuilder();
|
||||
if (builder != null) {
|
||||
target = builder.getTargetModel();
|
||||
source = builder.getModel();
|
||||
if (builder.getTypeSelect() == ActionBuilderRepository.TYPE_SELECT_UPDATE) {
|
||||
target = builder.getModel();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ActionBuilderLine parent = line.getParent();
|
||||
if (parent.getMetaField() != null) target = parent.getMetaField().getTypeName();
|
||||
if (parent.getMetaJsonField() != null && parent.getMetaJsonField().getTargetModel() != null)
|
||||
target = parent.getMetaJsonField().getTargetModel();
|
||||
if (parent.getMetaJsonField() != null
|
||||
&& parent.getMetaJsonField().getTargetJsonModel() != null)
|
||||
target = parent.getMetaJsonField().getTargetJsonModel().getName();
|
||||
if (parent.getValueField() != null)
|
||||
source = parent.getValueField().getMetaModel().getFullName();
|
||||
if (parent.getValueJson() != null && parent.getValueJson().getTargetModel() != null)
|
||||
source = parent.getValueJson().getTargetModel();
|
||||
if (parent.getValueJson() != null && parent.getValueJson().getTargetJsonModel() != null)
|
||||
source = parent.getValueJson().getTargetJsonModel().getName();
|
||||
}
|
||||
|
||||
xml +=
|
||||
indent
|
||||
+ "<line>"
|
||||
+ indent
|
||||
+ "<target>"
|
||||
+ target
|
||||
+ "</target>"
|
||||
+ indent
|
||||
+ "<source>"
|
||||
+ source
|
||||
+ "</source>"
|
||||
+ indent
|
||||
+ "<metaJsonField>"
|
||||
+ (line.getMetaJsonField() != null ? line.getMetaJsonField().getName() : "")
|
||||
+ "</metaJsonField>"
|
||||
+ indent
|
||||
+ "<metaField>"
|
||||
+ (line.getMetaField() != null ? line.getMetaField().getName() : "")
|
||||
+ "</metaField>"
|
||||
+ indent
|
||||
+ "<valueJson>"
|
||||
+ (line.getValueJson() != null ? line.getValueJson().getName() : "")
|
||||
+ "</valueJson>"
|
||||
+ indent
|
||||
+ "<valueField>"
|
||||
+ (line.getValueField() != null ? line.getValueField().getName() : "")
|
||||
+ "</valueField>"
|
||||
+ indent
|
||||
+ "<value>"
|
||||
+ (line.getValue() != null ? line.getValue() : "")
|
||||
+ "</value>"
|
||||
+ indent
|
||||
+ "<conditionText>"
|
||||
+ (line.getConditionText() != null ? line.getConditionText() : "")
|
||||
+ "</conditionText>"
|
||||
+ indent
|
||||
+ "<filter>"
|
||||
+ (line.getFilter() != null ? line.getFilter() : "")
|
||||
+ "</filter>"
|
||||
+ indent
|
||||
+ "<validationTypeSelect>"
|
||||
+ (line.getValidationTypeSelect() != null ? line.getValidationTypeSelect() : "")
|
||||
+ "</validationTypeSelect>"
|
||||
+ indent
|
||||
+ "<validationMsg>"
|
||||
+ (line.getValidationMsg() != null ? line.getValidationMsg() : "")
|
||||
+ "</validationMsg>"
|
||||
+ indent
|
||||
+ "<name>"
|
||||
+ (line.getName() != null ? line.getName() : "")
|
||||
+ "</name>"
|
||||
+ indent
|
||||
+ "<dummy>"
|
||||
+ (line.getDummy() != null ? line.getDummy() : "")
|
||||
+ "</dummy>"
|
||||
+ indent
|
||||
+ "<subLines>"
|
||||
+ exportActionBuilderLines(line.getSubLines(), count + 1)
|
||||
+ "</subLines>"
|
||||
+ "</line>";
|
||||
}
|
||||
|
||||
return StringEscapeUtils.unescapeXml(xml);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,242 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.studio.service;
|
||||
|
||||
import com.axelor.db.JPA;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.meta.MetaFiles;
|
||||
import com.axelor.meta.db.MetaFile;
|
||||
import com.axelor.meta.db.MetaJsonField;
|
||||
import com.axelor.meta.db.MetaJsonModel;
|
||||
import com.axelor.meta.db.repo.MetaFileRepository;
|
||||
import com.axelor.meta.db.repo.MetaJsonFieldRepository;
|
||||
import com.axelor.meta.db.repo.MetaJsonModelRepository;
|
||||
import com.axelor.studio.db.ActionBuilder;
|
||||
import com.axelor.studio.db.AppBuilder;
|
||||
import com.axelor.studio.db.ChartBuilder;
|
||||
import com.axelor.studio.db.DashboardBuilder;
|
||||
import com.axelor.studio.db.MenuBuilder;
|
||||
import com.axelor.studio.db.Wkf;
|
||||
import com.axelor.studio.db.repo.ActionBuilderRepository;
|
||||
import com.axelor.studio.db.repo.AppBuilderRepository;
|
||||
import com.axelor.studio.db.repo.ChartBuilderRepository;
|
||||
import com.axelor.studio.db.repo.DashboardBuilderRepository;
|
||||
import com.axelor.studio.db.repo.MenuBuilderRepository;
|
||||
import com.axelor.studio.service.wkf.WkfService;
|
||||
import com.google.inject.Inject;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Base64;
|
||||
import java.util.Map;
|
||||
import javax.xml.bind.JAXBException;
|
||||
|
||||
public class ImportService {
|
||||
|
||||
@Inject private ChartBuilderRepository chartBuilderRepo;
|
||||
|
||||
@Inject private MetaJsonModelRepository metaJsonModelRepo;
|
||||
|
||||
@Inject private MetaJsonFieldRepository metaJsonFieldRepo;
|
||||
|
||||
@Inject private DashboardBuilderRepository dashboardBuilderRepo;
|
||||
|
||||
@Inject private MenuBuilderRepository menuBuilderRepo;
|
||||
|
||||
@Inject private ActionBuilderRepository actionBuilderRepo;
|
||||
|
||||
@Inject private AppBuilderRepository appBuilderRepo;
|
||||
|
||||
@Inject private WkfService wkfService;
|
||||
|
||||
@Inject private MetaFiles metaFiles;
|
||||
|
||||
@Inject private MetaFileRepository metaFileRepo;
|
||||
|
||||
public Object importMetaJsonModel(Object bean, Map<String, Object> values) {
|
||||
|
||||
assert bean instanceof MetaJsonModel;
|
||||
|
||||
return metaJsonModelRepo.save((MetaJsonModel) bean);
|
||||
}
|
||||
|
||||
public Object importMetaJsonField(Object bean, Map<String, Object> values) {
|
||||
|
||||
assert bean instanceof MetaJsonField;
|
||||
|
||||
return metaJsonFieldRepo.save((MetaJsonField) bean);
|
||||
}
|
||||
|
||||
public Object importChartBuilder(Object bean, Map<String, Object> values)
|
||||
throws JAXBException, AxelorException {
|
||||
|
||||
assert bean instanceof ChartBuilder;
|
||||
|
||||
return chartBuilderRepo.save((ChartBuilder) bean);
|
||||
}
|
||||
|
||||
public Object importDashboardBuilder(Object bean, Map<String, Object> values) {
|
||||
|
||||
assert bean instanceof DashboardBuilder;
|
||||
|
||||
return dashboardBuilderRepo.save((DashboardBuilder) bean);
|
||||
}
|
||||
|
||||
public Object importMenuBuilder(Object bean, Map<String, Object> values) {
|
||||
|
||||
assert bean instanceof MenuBuilder;
|
||||
|
||||
return menuBuilderRepo.save((MenuBuilder) bean);
|
||||
}
|
||||
|
||||
public Object importActionBuilder(Object bean, Map<String, Object> values) {
|
||||
|
||||
assert bean instanceof ActionBuilder;
|
||||
|
||||
return actionBuilderRepo.save((ActionBuilder) bean);
|
||||
}
|
||||
|
||||
public Object importWkf(Object bean, Map<String, Object> values) {
|
||||
|
||||
assert bean instanceof Wkf;
|
||||
|
||||
Wkf wkf = (Wkf) bean;
|
||||
|
||||
wkfService.process(wkf);
|
||||
|
||||
return wkf;
|
||||
}
|
||||
|
||||
public Object importAppBuilderImg(Object bean, Map<String, Object> values) {
|
||||
|
||||
assert bean instanceof AppBuilder;
|
||||
|
||||
AppBuilder appBuilder = (AppBuilder) bean;
|
||||
String fileName = (String) values.get("fileName");
|
||||
String imageData = (String) values.get("imageData");
|
||||
|
||||
if (fileName != null && imageData != null) {
|
||||
appBuilder.setImage(importImg(fileName, imageData));
|
||||
}
|
||||
|
||||
appBuilder = appBuilderRepo.save(appBuilder);
|
||||
|
||||
return appBuilder;
|
||||
}
|
||||
|
||||
public Object importAppBuilder(Object bean, Map<String, Object> values) {
|
||||
|
||||
assert bean instanceof AppBuilder;
|
||||
|
||||
AppBuilder appBuilder = (AppBuilder) bean;
|
||||
|
||||
return appBuilderRepo.save(appBuilder);
|
||||
}
|
||||
|
||||
// Import methods specific for import from AppBuilder
|
||||
private MetaFile importImg(String name, String data) {
|
||||
|
||||
if (data == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
byte[] img = Base64.getDecoder().decode(data);
|
||||
|
||||
ByteArrayInputStream inImg = new ByteArrayInputStream(img);
|
||||
|
||||
MetaFile metaFile = metaFileRepo.all().filter("self.fileName = ?1", name).fetchOne();
|
||||
|
||||
try {
|
||||
if (metaFile != null) {
|
||||
return metaFiles.upload(inImg, metaFile);
|
||||
} else {
|
||||
return metaFiles.upload(inImg, name);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public MetaJsonField importJsonModelField(Object bean, Map<String, Object> values) {
|
||||
|
||||
assert bean instanceof MetaJsonField;
|
||||
|
||||
MetaJsonField field = (MetaJsonField) bean;
|
||||
|
||||
if (field.getJsonModel() == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return field;
|
||||
}
|
||||
|
||||
public MetaJsonField importJsonField(Object bean, Map<String, Object> values) {
|
||||
|
||||
assert bean instanceof MetaJsonField;
|
||||
|
||||
MetaJsonField field = (MetaJsonField) bean;
|
||||
|
||||
if (field.getJsonModel() != null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return field;
|
||||
}
|
||||
|
||||
public Object importAppMetaJsonModel(Object bean, Map<String, Object> values) {
|
||||
|
||||
assert bean instanceof MetaJsonModel;
|
||||
|
||||
MetaJsonModel model = (MetaJsonModel) bean;
|
||||
|
||||
JPA.flush();
|
||||
|
||||
JPA.refresh(model);
|
||||
|
||||
return metaJsonModelRepo.save(model);
|
||||
}
|
||||
|
||||
public Object importAppDashboardBuilder(Object bean, Map<String, Object> values) {
|
||||
|
||||
assert bean instanceof DashboardBuilder;
|
||||
|
||||
DashboardBuilder dashboard = (DashboardBuilder) bean;
|
||||
|
||||
JPA.flush();
|
||||
|
||||
JPA.refresh(dashboard);
|
||||
|
||||
return dashboardBuilderRepo.save(dashboard);
|
||||
}
|
||||
|
||||
public Object importAppWkf(Object bean, Map<String, Object> values) {
|
||||
|
||||
assert bean instanceof Wkf;
|
||||
|
||||
Wkf wkf = (Wkf) bean;
|
||||
|
||||
JPA.flush();
|
||||
|
||||
JPA.refresh(wkf);
|
||||
|
||||
wkfService.process(wkf);
|
||||
|
||||
return wkf;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,290 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.studio.service;
|
||||
|
||||
import com.axelor.auth.db.Group;
|
||||
import com.axelor.auth.db.Role;
|
||||
import com.axelor.db.JPA;
|
||||
import com.axelor.meta.db.MetaAction;
|
||||
import com.axelor.meta.db.MetaMenu;
|
||||
import com.axelor.meta.db.MetaView;
|
||||
import com.axelor.meta.db.repo.MetaActionRepository;
|
||||
import com.axelor.meta.db.repo.MetaMenuRepository;
|
||||
import com.axelor.meta.db.repo.MetaViewRepository;
|
||||
import com.axelor.meta.loader.XMLViews;
|
||||
import com.axelor.meta.schema.views.AbstractView;
|
||||
import com.axelor.studio.db.MenuBuilder;
|
||||
import com.axelor.studio.db.repo.MenuBuilderRepository;
|
||||
import com.axelor.studio.service.wkf.WkfTrackingService;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import javax.persistence.NoResultException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class StudioMetaService {
|
||||
|
||||
public static final String XML_ID_PREFIX = "studio-build-";
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(StudioMetaService.class);
|
||||
|
||||
@Inject private MetaActionRepository metaActionRepo;
|
||||
|
||||
@Inject private MetaViewRepository metaViewRepo;
|
||||
|
||||
@Inject private MetaMenuRepository metaMenuRepo;
|
||||
|
||||
@Inject private MenuBuilderRepository menuBuilderRepo;
|
||||
|
||||
/**
|
||||
* Removes MetaActions from comma separated names in string.
|
||||
*
|
||||
* @param actionNames Comma separated string of action names.
|
||||
*/
|
||||
@Transactional
|
||||
public void removeMetaActions(String actionNames) {
|
||||
|
||||
log.debug("Removing actions: {}", actionNames);
|
||||
if (actionNames == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
actionNames = actionNames.replaceAll(WkfTrackingService.ACTION_OPEN_TRACK, "");
|
||||
// .replaceAll(WkfTrackingService.ACTION_TRACK, "");
|
||||
List<MetaAction> metaActions =
|
||||
metaActionRepo
|
||||
.all()
|
||||
.filter("self.name in ?1", Arrays.asList(actionNames.split(",")))
|
||||
.fetch();
|
||||
|
||||
for (MetaAction action : metaActions) {
|
||||
if (action.getXmlId() == null
|
||||
|| !action.getXmlId().contentEquals(XML_ID_PREFIX + action.getName())) {
|
||||
continue;
|
||||
}
|
||||
List<MetaMenu> menus = metaMenuRepo.all().filter("self.action = ?1", action).fetch();
|
||||
for (MetaMenu metaMenu : menus) {
|
||||
metaMenu.setAction(null);
|
||||
metaMenuRepo.save(metaMenu);
|
||||
}
|
||||
metaActionRepo.remove(action);
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public MetaAction updateMetaAction(String name, String actionType, String xml, String model) {
|
||||
|
||||
String xmlId = XML_ID_PREFIX + name;
|
||||
MetaAction action = metaActionRepo.findByID(xmlId);
|
||||
|
||||
if (action == null) {
|
||||
action = new MetaAction(name);
|
||||
action.setXmlId(xmlId);
|
||||
Integer priority = getPriority(MetaAction.class.getSimpleName(), name);
|
||||
action.setPriority(priority);
|
||||
}
|
||||
action.setType(actionType);
|
||||
action.setModel(model);
|
||||
action.setXml(xml);
|
||||
|
||||
return metaActionRepo.save(action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates or Updates metaView from AbstractView.
|
||||
*
|
||||
* @param viewIterator ViewBuilder iterator
|
||||
*/
|
||||
@Transactional
|
||||
public MetaView generateMetaView(AbstractView view) {
|
||||
|
||||
String name = view.getName();
|
||||
String xmlId = view.getXmlId();
|
||||
String model = view.getModel();
|
||||
String viewType = view.getType();
|
||||
|
||||
log.debug("Search view name: {}, xmlId: {}", name, xmlId);
|
||||
|
||||
MetaView metaView;
|
||||
if (xmlId != null) {
|
||||
metaView =
|
||||
metaViewRepo
|
||||
.all()
|
||||
.filter(
|
||||
"self.name = ?1 and self.xmlId = ?2 and self.type = ?3", name, xmlId, viewType)
|
||||
.fetchOne();
|
||||
} else {
|
||||
metaView =
|
||||
metaViewRepo.all().filter("self.name = ?1 and self.type = ?2", name, viewType).fetchOne();
|
||||
}
|
||||
|
||||
log.debug("Meta view found: {}", metaView);
|
||||
|
||||
if (metaView == null) {
|
||||
metaView =
|
||||
metaViewRepo
|
||||
.all()
|
||||
.filter("self.name = ?1 and self.type = ?2", name, viewType)
|
||||
.order("-priority")
|
||||
.fetchOne();
|
||||
Integer priority = 20;
|
||||
if (metaView != null) {
|
||||
priority = metaView.getPriority() + 1;
|
||||
}
|
||||
metaView = new MetaView();
|
||||
metaView.setName(name);
|
||||
metaView.setXmlId(xmlId);
|
||||
metaView.setModel(model);
|
||||
metaView.setPriority(priority);
|
||||
metaView.setType(viewType);
|
||||
metaView.setTitle(view.getTitle());
|
||||
}
|
||||
|
||||
String viewXml = XMLViews.toXml(view, true);
|
||||
metaView.setXml(viewXml);
|
||||
return metaViewRepo.save(metaView);
|
||||
}
|
||||
|
||||
public String updateAction(String oldAction, String newAction, boolean remove) {
|
||||
|
||||
if (oldAction == null) {
|
||||
return newAction;
|
||||
}
|
||||
if (newAction == null) {
|
||||
return oldAction;
|
||||
}
|
||||
|
||||
if (remove) {
|
||||
oldAction = oldAction.replace(newAction, "");
|
||||
} else if (!oldAction.contains(newAction)) {
|
||||
oldAction = oldAction + "," + newAction;
|
||||
}
|
||||
|
||||
oldAction = oldAction.replace(",,", ",");
|
||||
if (oldAction.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return oldAction;
|
||||
}
|
||||
|
||||
public MetaMenu createMenu(MenuBuilder builder) {
|
||||
String xmlId = XML_ID_PREFIX + builder.getName();
|
||||
MetaMenu menu = metaMenuRepo.findByID(xmlId);
|
||||
|
||||
if (menu == null) {
|
||||
menu = new MetaMenu(builder.getName());
|
||||
menu.setXmlId(xmlId);
|
||||
Integer priority = getPriority(MetaMenu.class.getSimpleName(), menu.getName());
|
||||
menu.setPriority(priority);
|
||||
menu.setTitle(builder.getTitle());
|
||||
menu = metaMenuRepo.save(menu);
|
||||
}
|
||||
|
||||
menu.setTitle(builder.getTitle());
|
||||
menu.setIcon(builder.getIcon());
|
||||
menu.setIconBackground(builder.getIconBackground());
|
||||
menu.setOrder(builder.getOrder());
|
||||
menu.setParent(builder.getParentMenu());
|
||||
|
||||
if (builder.getGroups() != null) {
|
||||
Set<Group> groups = new HashSet<>();
|
||||
groups.addAll(builder.getGroups());
|
||||
menu.setGroups(groups);
|
||||
}
|
||||
|
||||
if (builder.getRoles() != null) {
|
||||
Set<Role> roles = new HashSet<>();
|
||||
roles.addAll(builder.getRoles());
|
||||
menu.setRoles(roles);
|
||||
}
|
||||
|
||||
String condition = builder.getConditionToCheck();
|
||||
if (builder.getAppBuilder() != null) {
|
||||
if (condition != null) {
|
||||
condition =
|
||||
"__config__.app.isApp('"
|
||||
+ builder.getAppBuilder().getCode()
|
||||
+ "') && ("
|
||||
+ condition
|
||||
+ ")";
|
||||
} else {
|
||||
condition = "__config__.app.isApp('" + builder.getAppBuilder().getCode() + "')";
|
||||
}
|
||||
}
|
||||
menu.setConditionToCheck(condition);
|
||||
menu.setModuleToCheck(builder.getModuleToCheck());
|
||||
menu.setLeft(builder.getLeft());
|
||||
menu.setTop(builder.getTop());
|
||||
menu.setHidden(builder.getHidden());
|
||||
menu.setMobile(builder.getMobile());
|
||||
|
||||
menu.setTag(builder.getTag());
|
||||
menu.setTagCount(builder.getTagCount());
|
||||
menu.setTagGet(builder.getTagGet());
|
||||
menu.setTagStyle(builder.getTagStyle());
|
||||
|
||||
menu.setLink(builder.getLink());
|
||||
if (builder.getMetaModule() != null) {
|
||||
menu.setModule(builder.getMetaModule().getName());
|
||||
}
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void removeMetaMenu(MetaMenu metaMenu) {
|
||||
Preconditions.checkNotNull(metaMenu, "metaMenu cannot be null.");
|
||||
|
||||
List<MetaMenu> subMenus = metaMenuRepo.all().filter("self.parent = ?1", metaMenu).fetch();
|
||||
for (MetaMenu subMenu : subMenus) {
|
||||
subMenu.setParent(null);
|
||||
}
|
||||
List<MenuBuilder> subBuilders =
|
||||
menuBuilderRepo.all().filter("self.parentMenu = ?1", metaMenu).fetch();
|
||||
for (MenuBuilder subBuilder : subBuilders) {
|
||||
subBuilder.setParentMenu(null);
|
||||
menuBuilderRepo.save(subBuilder);
|
||||
}
|
||||
|
||||
metaMenuRepo.remove(metaMenu);
|
||||
}
|
||||
|
||||
private Integer getPriority(String object, String name) {
|
||||
String query =
|
||||
String.format("SELECT MAX(obj.priority) FROM %s obj WHERE obj.name = :name", object);
|
||||
|
||||
try {
|
||||
Optional<Integer> priorityOpt =
|
||||
Optional.ofNullable(
|
||||
JPA.em()
|
||||
.createQuery(query, Integer.class)
|
||||
.setParameter("name", name)
|
||||
.getSingleResult());
|
||||
return priorityOpt.orElse(0) + 1;
|
||||
} catch (NoResultException e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.studio.service.builder;
|
||||
|
||||
import com.axelor.meta.MetaStore;
|
||||
import com.axelor.meta.db.MetaAction;
|
||||
import com.axelor.studio.db.ActionBuilder;
|
||||
import com.axelor.studio.db.ActionBuilderView;
|
||||
import com.axelor.studio.db.repo.ActionBuilderRepository;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class ActionBuilderService {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||
|
||||
@Inject private ActionViewBuilderService actionViewBuilderService;
|
||||
|
||||
@Inject private ActionScriptBuilderService actionScriptBuilderService;
|
||||
|
||||
@Inject private ActionEmailBuilderService actionEmailBuilderService;
|
||||
|
||||
@Transactional
|
||||
public MetaAction build(ActionBuilder builder) {
|
||||
|
||||
if (builder == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
log.debug("Processing action: {}, type: {}", builder.getName(), builder.getTypeSelect());
|
||||
|
||||
if (Arrays.asList(
|
||||
ActionBuilderRepository.TYPE_SELECT_CREATE,
|
||||
ActionBuilderRepository.TYPE_SELECT_UPDATE)
|
||||
.contains(builder.getTypeSelect())
|
||||
&& (builder.getLines() == null || builder.getLines().isEmpty())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
MetaAction metaAction = null;
|
||||
switch (builder.getTypeSelect()) {
|
||||
case ActionBuilderRepository.TYPE_SELECT_CREATE:
|
||||
metaAction = actionScriptBuilderService.build(builder);
|
||||
break;
|
||||
case ActionBuilderRepository.TYPE_SELECT_UPDATE:
|
||||
metaAction = actionScriptBuilderService.build(builder);
|
||||
break;
|
||||
case ActionBuilderRepository.TYPE_SELECT_SCRIPT:
|
||||
metaAction = actionScriptBuilderService.build(builder);
|
||||
break;
|
||||
case ActionBuilderRepository.TYPE_SELECT_VIEW:
|
||||
metaAction = actionViewBuilderService.build(builder);
|
||||
break;
|
||||
case ActionBuilderRepository.TYPE_SELECT_EMAIL:
|
||||
metaAction = actionEmailBuilderService.build(builder);
|
||||
}
|
||||
|
||||
if (builder.getMetaModule() != null) {
|
||||
metaAction.setModule(builder.getMetaModule().getName());
|
||||
}
|
||||
|
||||
MetaStore.clear();
|
||||
|
||||
return metaAction;
|
||||
}
|
||||
|
||||
public ActionBuilder setActionBuilderViews(
|
||||
ActionBuilder actionBuilder, String modelName, String formViewName, String gridViewName) {
|
||||
if (actionBuilder.getActionBuilderViews() == null) {
|
||||
actionBuilder.setActionBuilderViews(new ArrayList<>());
|
||||
}
|
||||
List<ActionBuilderView> actionBuilderViews = actionBuilder.getActionBuilderViews();
|
||||
if (formViewName != null) {
|
||||
setActionBuilderView("form", formViewName, actionBuilderViews);
|
||||
}
|
||||
if (gridViewName != null) {
|
||||
setActionBuilderView("grid", gridViewName, actionBuilderViews);
|
||||
}
|
||||
|
||||
actionBuilder.setModel(modelName);
|
||||
return actionBuilder;
|
||||
}
|
||||
|
||||
private void setActionBuilderView(
|
||||
String viewType, String viewName, List<ActionBuilderView> actionBuilderViews) {
|
||||
ActionBuilderView actionBuilderView = new ActionBuilderView();
|
||||
actionBuilderView.setViewType(viewType);
|
||||
actionBuilderView.setViewName(viewName);
|
||||
actionBuilderViews.add(actionBuilderView);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.studio.service.builder;
|
||||
|
||||
import com.axelor.apps.message.db.Message;
|
||||
import com.axelor.apps.message.db.Template;
|
||||
import com.axelor.apps.message.db.repo.TemplateRepository;
|
||||
import com.axelor.apps.message.exception.IExceptionMessage;
|
||||
import com.axelor.apps.message.service.MessageService;
|
||||
import com.axelor.apps.message.service.TemplateMessageService;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.i18n.I18n;
|
||||
import com.axelor.meta.CallMethod;
|
||||
import com.axelor.meta.db.MetaAction;
|
||||
import com.axelor.meta.db.MetaJsonModel;
|
||||
import com.axelor.meta.db.MetaModel;
|
||||
import com.axelor.meta.db.repo.MetaJsonModelRepository;
|
||||
import com.axelor.meta.db.repo.MetaModelRepository;
|
||||
import com.axelor.meta.schema.actions.ActionView;
|
||||
import com.axelor.rpc.ActionResponse;
|
||||
import com.axelor.studio.db.ActionBuilder;
|
||||
import com.axelor.studio.service.StudioMetaService;
|
||||
import com.google.inject.Inject;
|
||||
import java.io.IOException;
|
||||
import javax.mail.MessagingException;
|
||||
|
||||
public class ActionEmailBuilderService {
|
||||
|
||||
@Inject private MetaModelRepository metaModelRepo;
|
||||
|
||||
@Inject private MetaJsonModelRepository metaJsonModelRepo;
|
||||
|
||||
@Inject private StudioMetaService studioMetaService;
|
||||
|
||||
@Inject private TemplateRepository templateRepo;
|
||||
|
||||
@Inject private TemplateMessageService templateMessageService;
|
||||
|
||||
@Inject private MessageService messageService;
|
||||
|
||||
public MetaAction build(ActionBuilder builder) {
|
||||
String name = builder.getName();
|
||||
Object model =
|
||||
builder.getIsJson()
|
||||
? metaJsonModelRepo.all().filter("self.name = ?", builder.getModel()).fetchOne()
|
||||
: metaModelRepo.all().filter("self.fullName = ?", builder.getModel()).fetchOne();
|
||||
|
||||
int sendOption = builder.getEmailSendOptionSelect();
|
||||
Template template = builder.getEmailTemplate();
|
||||
|
||||
String xml =
|
||||
"<action-method name=\""
|
||||
+ name
|
||||
+ "\" id=\"studio-"
|
||||
+ name
|
||||
+ "\">\n\t"
|
||||
+ "<call class=\"com.axelor.studio.service.builder.ActionEmailBuilderService\" method=\"sendEmail(id, '"
|
||||
+ (builder.getIsJson()
|
||||
? ((MetaJsonModel) model).getName()
|
||||
: ((MetaModel) model).getFullName())
|
||||
+ "', '"
|
||||
+ (builder.getIsJson()
|
||||
? ((MetaJsonModel) model).getName()
|
||||
: ((MetaModel) model).getName())
|
||||
+ "', '"
|
||||
+ template.getId()
|
||||
+ "', '"
|
||||
+ sendOption
|
||||
+ "')\" "
|
||||
+ "if=\"id != null\"/>\n"
|
||||
+ "</action-method>";
|
||||
|
||||
return studioMetaService.updateMetaAction(name, "action-method", xml, null);
|
||||
}
|
||||
|
||||
@CallMethod
|
||||
public ActionResponse sendEmail(
|
||||
Long objectId, String model, String tag, Long templateId, int sendOption)
|
||||
throws ClassNotFoundException, InstantiationException, IllegalAccessException,
|
||||
AxelorException, IOException, MessagingException {
|
||||
|
||||
Template template = templateRepo.find(templateId);
|
||||
Message message = templateMessageService.generateMessage(objectId, model, tag, template);
|
||||
ActionResponse response = new ActionResponse();
|
||||
|
||||
if (sendOption == 0) {
|
||||
messageService.sendByEmail(message);
|
||||
} else {
|
||||
response.setView(
|
||||
ActionView.define(I18n.get(IExceptionMessage.MESSAGE_3))
|
||||
.model(Message.class.getName())
|
||||
.add("form", "message-form")
|
||||
.param("forceEdit", "true")
|
||||
.context("_showRecord", message.getId().toString())
|
||||
.map());
|
||||
}
|
||||
return response;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,644 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.studio.service.builder;
|
||||
|
||||
import com.axelor.common.Inflector;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.service.TraceBackService;
|
||||
import com.axelor.meta.db.MetaAction;
|
||||
import com.axelor.meta.db.MetaField;
|
||||
import com.axelor.meta.db.MetaJsonField;
|
||||
import com.axelor.meta.db.MetaJsonRecord;
|
||||
import com.axelor.studio.db.ActionBuilder;
|
||||
import com.axelor.studio.db.ActionBuilderLine;
|
||||
import com.axelor.studio.db.repo.ActionBuilderLineRepository;
|
||||
import com.axelor.studio.db.repo.ActionBuilderRepository;
|
||||
import com.axelor.studio.service.StudioMetaService;
|
||||
import com.axelor.studio.service.filter.FilterSqlService;
|
||||
import com.axelor.studio.service.wkf.WkfTrackingService;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.inject.Inject;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class ActionScriptBuilderService {
|
||||
|
||||
private static final String INDENT = "\t";
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||
|
||||
private final Inflector inflector = Inflector.getInstance();
|
||||
|
||||
private List<StringBuilder> fbuilder = null;
|
||||
|
||||
private int varCount = 0;
|
||||
|
||||
private boolean isCreate = false;
|
||||
|
||||
@Inject private ActionBuilderLineRepository builderLineRepo;
|
||||
|
||||
@Inject private StudioMetaService metaService;
|
||||
|
||||
@Inject private FilterSqlService filterSqlService;
|
||||
|
||||
public MetaAction build(ActionBuilder builder) {
|
||||
|
||||
String name = builder.getName();
|
||||
String code = null;
|
||||
String lang = "js";
|
||||
String transactional = "true";
|
||||
|
||||
if (builder.getTypeSelect() == ActionBuilderRepository.TYPE_SELECT_SCRIPT) {
|
||||
code = "\n" + builder.getScriptText();
|
||||
if (builder.getScriptType() == 1) {
|
||||
lang = "groovy";
|
||||
}
|
||||
if (builder.getTransactional()) {
|
||||
transactional = "false";
|
||||
}
|
||||
} else {
|
||||
code = generateScriptCode(builder);
|
||||
}
|
||||
|
||||
String xml =
|
||||
"<action-script name=\""
|
||||
+ name
|
||||
+ "\" "
|
||||
+ "id=\"studio-"
|
||||
+ name
|
||||
+ "\" model=\""
|
||||
+ MetaJsonRecord.class.getName()
|
||||
+ "\">\n\t"
|
||||
+ "<script language=\""
|
||||
+ lang
|
||||
+ "\" transactional=\""
|
||||
+ transactional
|
||||
+ "\">\n\t<![CDATA["
|
||||
+ code
|
||||
+ "\n\t]]>\n\t</script>\n</action-script>";
|
||||
|
||||
return metaService.updateMetaAction(builder.getName(), "action-script", xml, null);
|
||||
}
|
||||
|
||||
private String generateScriptCode(ActionBuilder builder) {
|
||||
|
||||
StringBuilder stb = new StringBuilder();
|
||||
fbuilder = new ArrayList<>();
|
||||
varCount = 1;
|
||||
int level = 1;
|
||||
|
||||
stb.append(format("var ctx = $request.context;", level));
|
||||
String targetModel;
|
||||
if (builder.getTypeSelect() == ActionBuilderRepository.TYPE_SELECT_CREATE) {
|
||||
targetModel = builder.getTargetModel();
|
||||
isCreate = true;
|
||||
addCreateCode(builder.getIsJson(), stb, level, targetModel);
|
||||
if (builder.getOpenRecord()) {
|
||||
addOpenRecord(builder.getIsJson(), stb, level, targetModel);
|
||||
}
|
||||
if (!Strings.isNullOrEmpty(builder.getDisplayMsg())) {
|
||||
stb.append("\n");
|
||||
stb.append(format("$response.setFlash('" + builder.getDisplayMsg() + "')", level));
|
||||
}
|
||||
} else {
|
||||
targetModel = builder.getModel();
|
||||
isCreate = false;
|
||||
addUpdateCode(builder.getIsJson(), stb, level, targetModel);
|
||||
}
|
||||
|
||||
stb.append("\n");
|
||||
|
||||
addRootFunction(builder, stb, level);
|
||||
|
||||
stb.append(Joiner.on("").join(fbuilder));
|
||||
|
||||
return stb.toString();
|
||||
}
|
||||
|
||||
private void addCreateCode(boolean isJson, StringBuilder stb, int level, String targetModel) {
|
||||
|
||||
if (isJson) {
|
||||
stb.append(format("var target = $json.create('" + targetModel + "');", level));
|
||||
stb.append(format("target = setVar0(null, ctx, {});", level));
|
||||
stb.append(format("target = $json.save(target);", level));
|
||||
stb.append(
|
||||
format(
|
||||
"Beans.get(" + WkfTrackingService.class.getName() + ".class).track(target);", level));
|
||||
} else {
|
||||
stb.append(format("var target = new " + targetModel + "();", level));
|
||||
stb.append(format("target = setVar0(null, ctx, {});", level));
|
||||
stb.append(format("$em.persist(target);", level));
|
||||
}
|
||||
}
|
||||
|
||||
private void addOpenRecord(boolean isJson, StringBuilder stb, int level, String targetModel) {
|
||||
|
||||
stb.append("\n");
|
||||
|
||||
if (isJson) {
|
||||
String title = inflector.humanize(targetModel);
|
||||
stb.append(
|
||||
format(
|
||||
"$response.setView(com.axelor.meta.schema.actions.ActionView.define('" + title + "')",
|
||||
level));
|
||||
stb.append(format(".model('com.axelor.meta.db.MetaJsonRecord')", level + 1));
|
||||
stb.append(format(".add('grid','custom-model-" + targetModel + "-grid')", level + 1));
|
||||
stb.append(format(".add('form','custom-model-" + targetModel + "-form')", level + 1));
|
||||
stb.append(format(".domain('self.jsonModel = :jsonModel')", level + 1));
|
||||
stb.append(format(".context('jsonModel', '" + targetModel + "')", level + 1));
|
||||
stb.append(format(".context('_showRecord', target.id)", level + 1));
|
||||
stb.append(format(".map())", level + 1));
|
||||
} else {
|
||||
String title = inflector.humanize(targetModel.substring(targetModel.lastIndexOf('.') + 1));
|
||||
stb.append(
|
||||
format(
|
||||
"$response.setView(com.axelor.meta.schema.actions.ActionView.define('" + title + "')",
|
||||
level));
|
||||
stb.append(format(".model('" + targetModel + "')", level + 1));
|
||||
stb.append(format(".add('grid')", level + 1));
|
||||
stb.append(format(".add('form')", level + 1));
|
||||
stb.append(format(".context('_showRecord', target.id)", level + 1));
|
||||
stb.append(format(".map())", level + 1));
|
||||
}
|
||||
}
|
||||
|
||||
private void addUpdateCode(boolean isJson, StringBuilder stb, int level, String targetModel) {
|
||||
|
||||
if (isJson) {
|
||||
stb.append(format("var target = {};", level));
|
||||
} else {
|
||||
stb.append(format("var target = ctx.asType(" + targetModel + ".class)", level));
|
||||
}
|
||||
|
||||
stb.append(format("target = setVar0(null, ctx, {});", level));
|
||||
stb.append(format("$response.setValues(target);", level));
|
||||
}
|
||||
|
||||
private void addRootFunction(ActionBuilder builder, StringBuilder stb, int level) {
|
||||
|
||||
stb.append(format("function setVar0($$, $, _$){", level));
|
||||
String bindings = addFieldsBinding("target", builder.getLines(), level + 1);
|
||||
stb.append(bindings);
|
||||
stb.append(format("return target;", level + 1));
|
||||
stb.append(format("}", level));
|
||||
}
|
||||
|
||||
private String format(String line, int level) {
|
||||
|
||||
return "\n" + Strings.repeat(INDENT, level) + line;
|
||||
}
|
||||
|
||||
private String addFieldsBinding(String target, List<ActionBuilderLine> lines, int level) {
|
||||
|
||||
StringBuilder stb = new StringBuilder();
|
||||
|
||||
lines.sort(
|
||||
(l1, l2) -> {
|
||||
if (l1.getDummy() && !l2.getDummy()) {
|
||||
return -1;
|
||||
}
|
||||
if (!l1.getDummy() && l2.getDummy()) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
for (ActionBuilderLine line : lines) {
|
||||
|
||||
String name = line.getName();
|
||||
String value = line.getValue();
|
||||
if (value != null && value.contains(".sum(")) {
|
||||
value = getSum(value, line.getFilter());
|
||||
}
|
||||
if (line.getDummy()) {
|
||||
stb.append(format("_$." + name + " = " + value + ";", level));
|
||||
continue;
|
||||
}
|
||||
|
||||
MetaJsonField jsonField = line.getMetaJsonField();
|
||||
MetaField metaField = line.getMetaField();
|
||||
|
||||
if (jsonField != null
|
||||
&& (jsonField.getTargetJsonModel() != null || jsonField.getTargetModel() != null)) {
|
||||
value = addRelationalBinding(line, target, true);
|
||||
} else if (metaField != null && metaField.getRelationship() != null) {
|
||||
value = addRelationalBinding(line, target, false);
|
||||
}
|
||||
// else {
|
||||
// MetaJsonField valueJson = line.getValueJson();
|
||||
// if (valueJson != null && valueJson.getType().contentEquals("many-to-one")) {
|
||||
// value = value.replace("$." + valueJson.getName(),"$json.create($json.find($."
|
||||
// +
|
||||
// valueJson.getName() + ".id))");
|
||||
// }
|
||||
// }
|
||||
|
||||
if (value != null
|
||||
&& metaField != null
|
||||
&& metaField.getTypeName().equals(BigDecimal.class.getSimpleName())) {
|
||||
value = "new BigDecimal(" + value + ")";
|
||||
}
|
||||
|
||||
String condition = line.getConditionText();
|
||||
if (condition != null) {
|
||||
stb.append(
|
||||
format("if(" + condition + "){" + target + "." + name + " = " + value + ";}", level));
|
||||
} else {
|
||||
stb.append(format(target + "." + name + " = " + value + ";", level));
|
||||
}
|
||||
}
|
||||
|
||||
return stb.toString();
|
||||
}
|
||||
|
||||
private String addRelationalBinding(ActionBuilderLine line, String target, boolean json) {
|
||||
|
||||
line = builderLineRepo.find(line.getId());
|
||||
String subCode = null;
|
||||
|
||||
String type =
|
||||
json
|
||||
? line.getMetaJsonField().getType()
|
||||
: inflector.dasherize(line.getMetaField().getRelationship());
|
||||
|
||||
switch (type) {
|
||||
case "many-to-one":
|
||||
subCode = addM2OBinding(line, true, true);
|
||||
break;
|
||||
case "many-to-many":
|
||||
subCode = addM2MBinding(line);
|
||||
break;
|
||||
case "one-to-many":
|
||||
subCode = addO2MBinding(line, target);
|
||||
break;
|
||||
case "one-to-one":
|
||||
subCode = addM2OBinding(line, true, true);
|
||||
break;
|
||||
case "json-many-to-one":
|
||||
subCode = addJsonM2OBinding(line, true, true);
|
||||
break;
|
||||
case "json-many-to-many":
|
||||
subCode = addJsonM2MBinding(line);
|
||||
break;
|
||||
case "json-one-to-many":
|
||||
subCode = addJsonO2MBinding(line);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown type");
|
||||
}
|
||||
|
||||
return subCode + "($," + line.getValue() + ", _$)";
|
||||
}
|
||||
|
||||
private String getTargetModel(ActionBuilderLine line) {
|
||||
|
||||
MetaJsonField jsonField = line.getMetaJsonField();
|
||||
|
||||
String targetModel = "";
|
||||
if (jsonField != null && jsonField.getTargetModel() != null) {
|
||||
targetModel = jsonField.getTargetModel();
|
||||
}
|
||||
|
||||
MetaField field = line.getMetaField();
|
||||
if (field != null && field.getTypeName() != null) {
|
||||
targetModel = field.getTypeName();
|
||||
}
|
||||
|
||||
return targetModel;
|
||||
}
|
||||
|
||||
private String getTargetJsonModel(ActionBuilderLine line) {
|
||||
|
||||
MetaJsonField jsonField = line.getMetaJsonField();
|
||||
|
||||
if (jsonField != null) {
|
||||
return jsonField.getTargetJsonModel().getName();
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
private String getRootSourceModel(ActionBuilderLine line) {
|
||||
|
||||
if (line.getActionBuilder() != null) {
|
||||
return line.getActionBuilder().getModel();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private String getSourceModel(ActionBuilderLine line) {
|
||||
|
||||
MetaJsonField jsonField = line.getValueJson();
|
||||
|
||||
String sourceModel = null;
|
||||
Object targetObject = null;
|
||||
|
||||
try {
|
||||
if (jsonField != null && jsonField.getTargetModel() != null) {
|
||||
if (line.getValue() != null && !line.getValue().contentEquals("$." + jsonField.getName())) {
|
||||
targetObject =
|
||||
filterSqlService.parseJsonField(
|
||||
jsonField, line.getValue().replace("$.", ""), null, null);
|
||||
} else {
|
||||
sourceModel = jsonField.getTargetModel();
|
||||
}
|
||||
}
|
||||
|
||||
MetaField field = line.getValueField();
|
||||
if (field != null && field.getTypeName() != null) {
|
||||
if (line.getValue() != null && !line.getValue().contentEquals("$." + field.getName())) {
|
||||
targetObject =
|
||||
filterSqlService.parseMetaField(
|
||||
field, line.getValue().replace("$.", ""), null, null, false);
|
||||
} else {
|
||||
sourceModel = field.getTypeName();
|
||||
}
|
||||
}
|
||||
} catch (AxelorException e) {
|
||||
TraceBackService.trace(e);
|
||||
}
|
||||
|
||||
if (sourceModel == null && line.getValue() != null && line.getValue().equals("$")) {
|
||||
sourceModel = getRootSourceModel(line);
|
||||
}
|
||||
|
||||
if (sourceModel == null && line.getValue() != null && line.getValue().equals("$$")) {
|
||||
sourceModel = getRootSourceModel(line);
|
||||
}
|
||||
|
||||
if (targetObject != null) {
|
||||
if (targetObject instanceof MetaJsonField) {
|
||||
sourceModel = ((MetaJsonField) targetObject).getTargetModel();
|
||||
} else if (targetObject instanceof MetaField) {
|
||||
sourceModel = ((MetaField) targetObject).getTypeName();
|
||||
}
|
||||
}
|
||||
|
||||
return sourceModel;
|
||||
}
|
||||
|
||||
private String addM2OBinding(ActionBuilderLine line, boolean search, boolean filter) {
|
||||
|
||||
String fname = "setVar" + varCount;
|
||||
varCount += 1;
|
||||
|
||||
String tModel = getTargetModel(line);
|
||||
String srcModel = getSourceModel(line);
|
||||
|
||||
StringBuilder stb = new StringBuilder();
|
||||
fbuilder.add(stb);
|
||||
if (tModel.contains(".")) {
|
||||
tModel = tModel.substring(tModel.lastIndexOf('.') + 1);
|
||||
}
|
||||
stb.append(format("", 1));
|
||||
stb.append(format("function " + fname + "($$, $, _$){", 1));
|
||||
stb.append(format("var val = null;", 2));
|
||||
if (srcModel != null) {
|
||||
stb.append(format("if ($ != null && $.id != null){", 2));
|
||||
srcModel = srcModel.substring(srcModel.lastIndexOf('.') + 1);
|
||||
stb.append(format("$ = $em.find(" + srcModel + ".class, $.id);", 3));
|
||||
log.debug("src model: {}, Target model: {}", srcModel, tModel);
|
||||
if (srcModel.contentEquals(tModel)) {
|
||||
stb.append(format("val = $", 3));
|
||||
}
|
||||
stb.append(format("}", 2));
|
||||
}
|
||||
|
||||
if (filter && line.getFilter() != null) {
|
||||
if (line.getValue() != null) {
|
||||
stb.append(format("var map = com.axelor.db.mapper.Mapper.toMap($);", 2));
|
||||
} else {
|
||||
stb.append(format("var map = com.axelor.db.mapper.Mapper.toMap($$);", 2));
|
||||
}
|
||||
stb.append(format("val = " + getQuery(tModel, line.getFilter(), false, false), 2));
|
||||
}
|
||||
|
||||
List<ActionBuilderLine> lines = line.getSubLines();
|
||||
if (lines != null && !lines.isEmpty()) {
|
||||
stb.append(format("if (!val) {", 2));
|
||||
stb.append(format("val = new " + tModel + "();", 3));
|
||||
stb.append(format("}", 2));
|
||||
stb.append(addFieldsBinding("val", lines, 2));
|
||||
// stb.append(format("$em.persist(val);", 2));
|
||||
}
|
||||
stb.append(format("return val;", 2));
|
||||
stb.append(format("}", 1));
|
||||
|
||||
return fname;
|
||||
}
|
||||
|
||||
private String addM2MBinding(ActionBuilderLine line) {
|
||||
|
||||
String fname = "setVar" + varCount;
|
||||
varCount += 1;
|
||||
StringBuilder stb = new StringBuilder();
|
||||
fbuilder.add(stb);
|
||||
stb.append(format("", 1));
|
||||
stb.append(format("function " + fname + "($$, $, _$){", 1));
|
||||
stb.append(format("var val = new HashSet();", 2));
|
||||
if (line.getFilter() != null) {
|
||||
String model = getTargetModel(line);
|
||||
stb.append(format("var map = com.axelor.db.mapper.Mapper.toMap($$);", 2));
|
||||
stb.append(format("val.addAll(" + getQuery(model, line.getFilter(), false, true) + ");", 2));
|
||||
stb.append(format("if(!val.empty){return val;}", 2));
|
||||
}
|
||||
|
||||
stb.append(format("if(!$){return val;}", 2));
|
||||
stb.append(format("$.forEach(function(v){", 2));
|
||||
stb.append(format("v = " + addM2OBinding(line, true, false) + "($$, v, _$);", 3));
|
||||
stb.append(format("val.add(v);", 3));
|
||||
stb.append(format("})", 2));
|
||||
stb.append(format("return val;", 2));
|
||||
stb.append(format("}", 1));
|
||||
|
||||
return fname;
|
||||
}
|
||||
|
||||
private String addO2MBinding(ActionBuilderLine line, String target) {
|
||||
|
||||
String fname = "setVar" + varCount;
|
||||
varCount += 1;
|
||||
StringBuilder stb = new StringBuilder();
|
||||
fbuilder.add(stb);
|
||||
stb.append(format("", 1));
|
||||
stb.append(format("function " + fname + "($$, $, _$){", 1));
|
||||
stb.append(format("var val = new ArrayList();", 2));
|
||||
stb.append(format("if(!$){return val;}", 2));
|
||||
stb.append(format("$.forEach(function(v){", 2));
|
||||
stb.append(format("var item = " + addM2OBinding(line, false, false) + "($$, v, _$);", 3));
|
||||
if (isCreate && line.getMetaField() != null && line.getMetaField().getMappedBy() != null) {
|
||||
stb.append(format("item." + line.getMetaField().getMappedBy() + " = " + target, 3));
|
||||
}
|
||||
stb.append(format("val.add(item);", 3));
|
||||
stb.append(format("})", 2));
|
||||
stb.append(format("return val;", 2));
|
||||
stb.append(format("}", 1));
|
||||
|
||||
return fname;
|
||||
}
|
||||
|
||||
private String addJsonM2OBinding(ActionBuilderLine line, boolean search, boolean filter) {
|
||||
|
||||
String fname = "setVar" + varCount;
|
||||
varCount += 1;
|
||||
|
||||
StringBuilder stb = new StringBuilder();
|
||||
fbuilder.add(stb);
|
||||
String model = getTargetJsonModel(line);
|
||||
stb.append(format("", 1));
|
||||
stb.append(format("function " + fname + "($$, $, _$){", 1));
|
||||
stb.append(format("var val = null;", 2));
|
||||
// stb.append(format("if ($ != null && $.id != null){", 2));
|
||||
// stb.append(format("$ = $json.find($.id);", 3));
|
||||
if (search) {
|
||||
stb.append(format("if ($ != null && $.id != null) {", 2));
|
||||
stb.append(format("val = $json.find($.id);", 3));
|
||||
stb.append(format("if (val.jsonModel != '" + model + "'){val = null;} ", 3));
|
||||
stb.append(format("}", 2));
|
||||
}
|
||||
// stb.append(format("}",2));
|
||||
if (filter && line.getFilter() != null) {
|
||||
String query = getQuery(model, line.getFilter(), true, false);
|
||||
stb.append(format("val = " + query, 2));
|
||||
}
|
||||
List<ActionBuilderLine> lines = line.getSubLines();
|
||||
if (lines != null && !lines.isEmpty()) {
|
||||
stb.append(format("if (!val) {", 2));
|
||||
stb.append(format("val = $json.create('" + model + "');", 3));
|
||||
stb.append(format("}", 2));
|
||||
// stb.append(format("if($ instanceof MetaJsonRecord){$ =
|
||||
// $json.create($json.find($.id))};",
|
||||
// 2));
|
||||
stb.append(addFieldsBinding("val", lines, 2));
|
||||
stb.append(format("val = $json.save(val);", 2));
|
||||
}
|
||||
stb.append(format("return val;", 2));
|
||||
stb.append(format("}", 1));
|
||||
|
||||
return fname;
|
||||
}
|
||||
|
||||
private String addJsonM2MBinding(ActionBuilderLine line) {
|
||||
|
||||
String fname = "setVar" + varCount;
|
||||
varCount += 1;
|
||||
StringBuilder stb = new StringBuilder();
|
||||
fbuilder.add(stb);
|
||||
stb.append(format("", 1));
|
||||
stb.append(format("function " + fname + "($$, $, _$){", 1));
|
||||
stb.append(format("var val = new HashSet();", 2));
|
||||
if (line.getFilter() != null) {
|
||||
String model = getTargetJsonModel(line);
|
||||
stb.append(format("val.addAll(" + getQuery(model, line.getFilter(), true, true) + ");", 2));
|
||||
stb.append(format("if(!val.empty){return val;}", 2));
|
||||
}
|
||||
stb.append(format("if(!$){return val;}", 2));
|
||||
stb.append(format("$.forEach(function(v){", 2));
|
||||
stb.append(format("v = " + addJsonM2OBinding(line, true, false) + "($$, v, _$);", 3));
|
||||
stb.append(format("val.add(v);", 3));
|
||||
stb.append(format("})", 2));
|
||||
stb.append(format("return val;", 2));
|
||||
stb.append(format("}", 1));
|
||||
|
||||
return fname;
|
||||
}
|
||||
|
||||
private String addJsonO2MBinding(ActionBuilderLine line) {
|
||||
|
||||
String fname = "setVar" + varCount;
|
||||
varCount += 1;
|
||||
StringBuilder stb = new StringBuilder();
|
||||
fbuilder.add(stb);
|
||||
stb.append(format("", 1));
|
||||
stb.append(format("function " + fname + "($$, $, _$){", 1));
|
||||
stb.append(format("var val = new ArrayList();", 2));
|
||||
stb.append(format("if(!$){return val;}", 2));
|
||||
stb.append(format("$.forEach(function(v){", 2));
|
||||
stb.append(format("v = " + addJsonM2OBinding(line, false, false) + "($$, v, _$);", 3));
|
||||
stb.append(format("val.add(v);", 3));
|
||||
stb.append(format("})", 2));
|
||||
stb.append(format("return val;", 2));
|
||||
stb.append(format("}", 1));
|
||||
|
||||
return fname;
|
||||
}
|
||||
|
||||
private String getQuery(String model, String filter, boolean json, boolean all) {
|
||||
|
||||
if (model.contains(".")) {
|
||||
model = model.substring(model.lastIndexOf('.') + 1);
|
||||
}
|
||||
|
||||
String nRecords = "fetchOne()";
|
||||
if (all) {
|
||||
nRecords = "fetch()";
|
||||
}
|
||||
|
||||
String query = null;
|
||||
|
||||
if (json) {
|
||||
query = "$json.all('" + model + "').by(" + filter + ")." + nRecords;
|
||||
} else {
|
||||
query =
|
||||
"__repo__("
|
||||
+ model
|
||||
+ ".class).all().filter(\""
|
||||
+ filter
|
||||
+ "\").bind(map).bind(_$)."
|
||||
+ nRecords;
|
||||
}
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
private String getSum(String value, String filter) {
|
||||
|
||||
value = value.substring(0, value.length() - 1);
|
||||
String[] expr = value.split("\\.sum\\(");
|
||||
|
||||
String fname = "setVar" + varCount;
|
||||
varCount += 1;
|
||||
|
||||
StringBuilder stb = new StringBuilder();
|
||||
stb.append(format("", 1));
|
||||
stb.append(format("function " + fname + "(sumOf$, $$, filter){", 1));
|
||||
stb.append(format("var val = 0", 2));
|
||||
stb.append(format("if (sumOf$ == null){ return val;}", 2));
|
||||
stb.append(format("sumOf$.forEach(function($){", 2));
|
||||
// stb.append(format("if ($ instanceof MetaJsonRecord){ $ =
|
||||
// $json.create($json.find($.id)); }",
|
||||
// 3));
|
||||
String val = "val += " + expr[1] + ";";
|
||||
if (filter != null) {
|
||||
val = "if(filter){" + val + "}";
|
||||
}
|
||||
stb.append(format(val, 3));
|
||||
stb.append(format("})", 2));
|
||||
stb.append(format("return new BigDecimal(val);", 2));
|
||||
stb.append(format("}", 1));
|
||||
|
||||
fbuilder.add(stb);
|
||||
return fname + "(" + expr[0] + ",$," + filter + ")";
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.studio.service.builder;
|
||||
|
||||
import com.axelor.common.StringUtils;
|
||||
import com.axelor.meta.db.MetaAction;
|
||||
import com.axelor.meta.db.MetaJsonRecord;
|
||||
import com.axelor.studio.db.ActionBuilder;
|
||||
import com.axelor.studio.db.ActionBuilderLine;
|
||||
import com.axelor.studio.db.ActionBuilderView;
|
||||
import com.axelor.studio.service.StudioMetaService;
|
||||
import com.google.inject.Inject;
|
||||
import java.util.List;
|
||||
import org.apache.commons.lang.StringEscapeUtils;
|
||||
|
||||
public class ActionViewBuilderService {
|
||||
|
||||
private static final String INDENT = "\t";
|
||||
|
||||
@Inject private StudioMetaService metaService;
|
||||
|
||||
public MetaAction build(ActionBuilder builder) {
|
||||
|
||||
if (builder == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<ActionBuilderView> views = builder.getActionBuilderViews();
|
||||
if (views == null || views.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
StringBuilder xml = new StringBuilder();
|
||||
|
||||
String model = appendBasic(builder, xml);
|
||||
|
||||
appendViews(views, xml);
|
||||
|
||||
appendParams(builder.getViewParams(), xml);
|
||||
|
||||
appendDomain(builder.getDomainCondition(), builder.getIsJson(), xml);
|
||||
|
||||
appendContext(builder, xml);
|
||||
|
||||
xml.append("\n" + "</action-view>");
|
||||
|
||||
return metaService.updateMetaAction(builder.getName(), "action-view", xml.toString(), model);
|
||||
}
|
||||
|
||||
private void appendParams(List<ActionBuilderLine> params, StringBuilder xml) {
|
||||
|
||||
if (params == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (ActionBuilderLine param : params) {
|
||||
xml.append("\n" + INDENT + "<view-param name=\"" + param.getName() + "\" ");
|
||||
xml.append("value=\"" + StringEscapeUtils.escapeXml(param.getValue()) + "\" />");
|
||||
}
|
||||
}
|
||||
|
||||
private void appendContext(ActionBuilder builder, StringBuilder xml) {
|
||||
boolean addJsonCtx = true;
|
||||
if (builder.getLines() != null) {
|
||||
for (ActionBuilderLine context : builder.getLines()) {
|
||||
if (context.getName().contentEquals("jsonModel")) {
|
||||
addJsonCtx = false;
|
||||
}
|
||||
xml.append("\n" + INDENT + "<context name=\"" + context.getName() + "\" ");
|
||||
xml.append("expr=\"eval:" + StringEscapeUtils.escapeXml(context.getValue()) + "\" />");
|
||||
}
|
||||
}
|
||||
|
||||
if (addJsonCtx && builder.getIsJson() && builder.getModel() != null) {
|
||||
xml.append("\n" + INDENT + "<context name=\"jsonModel\" ");
|
||||
xml.append("expr=\"" + builder.getModel() + "\" />");
|
||||
}
|
||||
}
|
||||
|
||||
private void appendDomain(String domain, Boolean isJson, StringBuilder xml) {
|
||||
|
||||
if (isJson) {
|
||||
String jsonDomain = "self.jsonModel = :jsonModel";
|
||||
if (domain == null) {
|
||||
domain = jsonDomain;
|
||||
} else if (!domain.contains(jsonDomain)) {
|
||||
domain = jsonDomain + " AND (" + domain + ")";
|
||||
}
|
||||
}
|
||||
|
||||
if (domain != null) {
|
||||
xml.append("\n" + INDENT + "<domain>" + StringEscapeUtils.escapeXml(domain) + "</domain>");
|
||||
}
|
||||
}
|
||||
|
||||
private void appendViews(List<ActionBuilderView> views, StringBuilder xml) {
|
||||
|
||||
views.sort((action1, action2) -> action1.getSequence().compareTo(action2.getSequence()));
|
||||
for (ActionBuilderView view : views) {
|
||||
xml.append("\n" + INDENT + "<view type=\"" + view.getViewType() + "\" ");
|
||||
xml.append("name=\"" + view.getViewName() + "\" ");
|
||||
if (StringUtils.notEmpty(view.getViewConditionToCheck())) {
|
||||
xml.append("if=\"" + view.getViewConditionToCheck() + "\" />");
|
||||
} else {
|
||||
xml.append("/>");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String appendBasic(ActionBuilder builder, StringBuilder xml) {
|
||||
|
||||
xml.append("<action-view name=\"" + builder.getName() + "\" ");
|
||||
xml.append("title=\"" + builder.getTitle() + "\" ");
|
||||
xml.append("id=\"studio-" + builder.getName() + "\" ");
|
||||
|
||||
String model = MetaJsonRecord.class.getName();
|
||||
if (!builder.getIsJson()) {
|
||||
model = builder.getModel();
|
||||
}
|
||||
xml.append("model=\"" + model + "\">");
|
||||
|
||||
return model;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.studio.service.builder;
|
||||
|
||||
import com.axelor.apps.base.db.App;
|
||||
import com.axelor.apps.base.db.repo.AppRepository;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||
import com.axelor.i18n.I18n;
|
||||
import com.axelor.studio.db.AppBuilder;
|
||||
import com.axelor.studio.exception.IExceptionMessage;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class AppBuilderService {
|
||||
|
||||
@Inject private AppRepository appRepo;
|
||||
|
||||
public AppBuilder build(AppBuilder appBuilder) throws AxelorException {
|
||||
|
||||
checkCode(appBuilder);
|
||||
|
||||
App app = appBuilder.getGeneratedApp();
|
||||
|
||||
if (app == null) {
|
||||
app = new App(appBuilder.getName(), appBuilder.getCode());
|
||||
} else {
|
||||
app.setCode(appBuilder.getCode());
|
||||
app.setName(appBuilder.getName());
|
||||
}
|
||||
|
||||
app.setImage(appBuilder.getImage());
|
||||
app.setDescription(appBuilder.getDescription());
|
||||
Set<App> depends = new HashSet<App>();
|
||||
if (appBuilder.getDependsOnSet() != null) {
|
||||
depends.addAll(appBuilder.getDependsOnSet());
|
||||
app.setDependsOnSet(depends);
|
||||
}
|
||||
app.setSequence(appBuilder.getSequence());
|
||||
app.setInitDataLoaded(true);
|
||||
app.setDemoDataLoaded(true);
|
||||
|
||||
appBuilder.setGeneratedApp(appRepo.save(app));
|
||||
|
||||
return appBuilder;
|
||||
}
|
||||
|
||||
private void checkCode(AppBuilder appBuilder) throws AxelorException {
|
||||
|
||||
App app = appRepo.findByCode(appBuilder.getCode());
|
||||
|
||||
if (app != null && app != appBuilder.getGeneratedApp()) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_INCONSISTENCY,
|
||||
I18n.get(IExceptionMessage.APP_BUILDER_1),
|
||||
appBuilder.getCode());
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void clean(AppBuilder appBuilder) {
|
||||
|
||||
if (appBuilder.getGeneratedApp() != null) {
|
||||
appRepo.remove(appBuilder.getGeneratedApp());
|
||||
appBuilder.setGeneratedApp(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,553 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.studio.service.builder;
|
||||
|
||||
import com.axelor.common.Inflector;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||
import com.axelor.i18n.I18n;
|
||||
import com.axelor.meta.CallMethod;
|
||||
import com.axelor.meta.db.MetaField;
|
||||
import com.axelor.meta.db.MetaJsonField;
|
||||
import com.axelor.meta.db.MetaJsonRecord;
|
||||
import com.axelor.meta.db.MetaModel;
|
||||
import com.axelor.meta.db.MetaView;
|
||||
import com.axelor.meta.db.repo.MetaModelRepository;
|
||||
import com.axelor.meta.loader.XMLViews;
|
||||
import com.axelor.meta.schema.ObjectViews;
|
||||
import com.axelor.studio.db.ChartBuilder;
|
||||
import com.axelor.studio.db.Filter;
|
||||
import com.axelor.studio.exception.IExceptionMessage;
|
||||
import com.axelor.studio.service.StudioMetaService;
|
||||
import com.axelor.studio.service.filter.FilterCommonService;
|
||||
import com.axelor.studio.service.filter.FilterSqlService;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.inject.Inject;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import javax.xml.bind.JAXBException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* This class generate charts using ViewBuilder and chart related fields. Chart xml generated by
|
||||
* adding query, search fields , onInit actions..etc. All filters with parameter checked will be
|
||||
* used as search fields. Tags also there to use context variable in filter value, like $User for
|
||||
* current user (__user__).
|
||||
*/
|
||||
public class ChartBuilderService {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||
|
||||
private static final String Tab1 = "\n \t";
|
||||
private static final String Tab2 = "\n \t\t";
|
||||
private static final String Tab3 = "\n \t\t\t";
|
||||
private static final List<String> dateTypes =
|
||||
Arrays.asList(
|
||||
new String[] {"DATE", "DATETIME", "LOCALDATE", "LOCALDATETIME", "ZONNEDDATETIME"});
|
||||
|
||||
private List<String> searchFields;
|
||||
|
||||
// private List<RecordField> onNewFields;
|
||||
|
||||
private List<String> joins;
|
||||
|
||||
private String categType;
|
||||
|
||||
@Inject private MetaModelRepository metaModelRepo;
|
||||
|
||||
@Inject private FilterSqlService filterSqlService;
|
||||
|
||||
@Inject private FilterCommonService filterCommonService;
|
||||
|
||||
@Inject private StudioMetaService metaService;
|
||||
|
||||
/**
|
||||
* Root Method to access the service it generate AbstractView from ViewBuilder.
|
||||
*
|
||||
* @param viewBuilder ViewBuilder object of type chart.
|
||||
* @return AbstractView from meta schema.
|
||||
* @throws JAXBException
|
||||
* @throws AxelorException
|
||||
*/
|
||||
public void build(ChartBuilder chartBuilder) throws JAXBException, AxelorException {
|
||||
|
||||
if (chartBuilder.getName().contains(" ")) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_MISSING_FIELD, I18n.get(IExceptionMessage.CHART_BUILDER_1));
|
||||
}
|
||||
|
||||
searchFields = new ArrayList<String>();
|
||||
// onNewFields = new ArrayList<RecordField>();
|
||||
joins = new ArrayList<String>();
|
||||
categType = "text";
|
||||
|
||||
String[] queryString = prepareQuery(chartBuilder);
|
||||
// setOnNewAction(chartBuilder);
|
||||
|
||||
String xml = createXml(chartBuilder, queryString);
|
||||
|
||||
log.debug("Chart xml: {}", xml);
|
||||
|
||||
ObjectViews chartView = XMLViews.fromXML(xml);
|
||||
|
||||
MetaView metaView = metaService.generateMetaView(chartView.getViews().get(0));
|
||||
|
||||
if (metaView != null) {
|
||||
chartBuilder.setMetaViewGenerated(metaView);
|
||||
}
|
||||
}
|
||||
|
||||
private String createXml(ChartBuilder chartBuilder, String[] queryString) {
|
||||
|
||||
String xml =
|
||||
"<chart name=\"" + chartBuilder.getName() + "\" title=\"" + chartBuilder.getTitle() + "\" ";
|
||||
|
||||
// if (onNewAction != null) {
|
||||
// xml += " onInit=\"" + onNewAction.getName() + "\" ";
|
||||
// }
|
||||
|
||||
xml += ">\n";
|
||||
|
||||
if (!searchFields.isEmpty()) {
|
||||
xml += "\t" + getSearchFields() + "\n";
|
||||
}
|
||||
|
||||
String groupLabel =
|
||||
chartBuilder.getIsJsonGroupOn()
|
||||
? chartBuilder.getGroupOnJson().getTitle()
|
||||
: chartBuilder.getGroupOn().getLabel();
|
||||
|
||||
String displayLabel =
|
||||
chartBuilder.getIsJsonDisplayField()
|
||||
? chartBuilder.getDisplayFieldJson().getTitle()
|
||||
: chartBuilder.getDisplayField().getLabel();
|
||||
|
||||
xml += "\t<dataset type=\"sql\"><![CDATA[";
|
||||
xml += Tab2 + queryString[0];
|
||||
xml += Tab2 + " ]]></dataset>";
|
||||
xml +=
|
||||
Tab1
|
||||
+ "<category key=\"group_field\" type=\""
|
||||
+ categType
|
||||
+ "\" title=\""
|
||||
+ groupLabel
|
||||
+ "\" />";
|
||||
xml +=
|
||||
Tab1
|
||||
+ "<series key=\"sum_field\" type=\""
|
||||
+ chartBuilder.getChartType()
|
||||
+ "\" title=\""
|
||||
+ displayLabel
|
||||
+ "\" ";
|
||||
if (queryString[1] != null) {
|
||||
xml += "groupBy=\"agg_field\" ";
|
||||
}
|
||||
xml += "/>\n";
|
||||
xml += "</chart>";
|
||||
|
||||
return xml;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method create query from chart filters added in chart builder.
|
||||
*
|
||||
* @param viewBuilder ViewBuilder of type chart
|
||||
* @return StringArray with first element as query string and second as aggregate field name.
|
||||
* @throws AxelorException
|
||||
*/
|
||||
private String[] prepareQuery(ChartBuilder chartBuilder) throws AxelorException {
|
||||
|
||||
String query =
|
||||
createSumQuery(
|
||||
chartBuilder.getIsJsonDisplayField(),
|
||||
chartBuilder.getDisplayField(),
|
||||
chartBuilder.getDisplayFieldJson());
|
||||
|
||||
String groupField =
|
||||
getGroup(
|
||||
chartBuilder.getIsJsonGroupOn(),
|
||||
chartBuilder.getGroupOn(),
|
||||
chartBuilder.getGroupOnJson(),
|
||||
chartBuilder.getGroupDateType(),
|
||||
chartBuilder.getGroupOnTarget());
|
||||
|
||||
String aggField =
|
||||
getGroup(
|
||||
chartBuilder.getIsJsonAggregateOn(),
|
||||
chartBuilder.getAggregateOn(),
|
||||
chartBuilder.getAggregateOnJson(),
|
||||
chartBuilder.getAggregateDateType(),
|
||||
chartBuilder.getAggregateOnTarget());
|
||||
|
||||
query += groupField + " AS group_field";
|
||||
|
||||
if (aggField != null) {
|
||||
query += "," + Tab3 + aggField + " AS agg_field";
|
||||
}
|
||||
|
||||
String filters = filterSqlService.getSqlFilters(chartBuilder.getFilterList(), joins, true);
|
||||
addSearchField(chartBuilder.getFilterList());
|
||||
String model = chartBuilder.getModel();
|
||||
|
||||
if (chartBuilder.getIsJson()) {
|
||||
if (filters != null) {
|
||||
filters = "self.json_model = '" + model + "' AND (" + filters + ")";
|
||||
} else {
|
||||
filters = "self.json_model = '" + model + "'";
|
||||
}
|
||||
model = MetaJsonRecord.class.getName();
|
||||
}
|
||||
|
||||
query += Tab2 + "FROM " + Tab3 + getTable(model) + " self";
|
||||
|
||||
if (!joins.isEmpty()) {
|
||||
query += Tab3 + Joiner.on(Tab3).join(joins);
|
||||
}
|
||||
|
||||
if (filters != null) {
|
||||
query += Tab2 + "WHERE " + Tab3 + filters;
|
||||
}
|
||||
|
||||
query += Tab2 + "group by " + Tab3 + "group_field";
|
||||
|
||||
if (aggField != null && aggField != null) {
|
||||
query += ",agg_field";
|
||||
return new String[] {query, aggField};
|
||||
}
|
||||
|
||||
return new String[] {query, null};
|
||||
}
|
||||
|
||||
private String createSumQuery(boolean isJson, MetaField metaField, MetaJsonField jsonField) {
|
||||
|
||||
String sumField = null;
|
||||
if (isJson) {
|
||||
String sqlType = filterSqlService.getSqlType(jsonField.getType());
|
||||
sumField =
|
||||
"cast(self."
|
||||
+ filterSqlService.getColumn(jsonField.getModel(), jsonField.getModelField())
|
||||
+ "->>'"
|
||||
+ jsonField.getName()
|
||||
+ "' as "
|
||||
+ sqlType
|
||||
+ ")";
|
||||
} else {
|
||||
sumField = "self." + filterSqlService.getColumn(metaField);
|
||||
}
|
||||
|
||||
return "SELECT" + Tab3 + "SUM(" + sumField + ") AS sum_field," + Tab3;
|
||||
}
|
||||
|
||||
private String getGroup(
|
||||
boolean isJson, MetaField metaField, MetaJsonField jsonField, String dateType, String target)
|
||||
throws AxelorException {
|
||||
|
||||
if (!isJson && metaField == null || isJson && jsonField == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String typeName = null;
|
||||
String group = null;
|
||||
Object object = null;
|
||||
StringBuilder parent = new StringBuilder("self");
|
||||
if (isJson) {
|
||||
group = jsonField.getName();
|
||||
typeName = filterSqlService.getSqlType(jsonField.getType());
|
||||
if (target != null) {
|
||||
object = filterSqlService.parseJsonField(jsonField, target, joins, parent);
|
||||
}
|
||||
} else {
|
||||
group = filterSqlService.getColumn(metaField);
|
||||
typeName = filterSqlService.getSqlType(metaField.getTypeName());
|
||||
if (target != null) {
|
||||
object = filterSqlService.parseMetaField(metaField, target, joins, parent, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (object != null) {
|
||||
String[] sqlField = filterSqlService.getSqlField(object, parent.toString(), joins);
|
||||
typeName = sqlField[1];
|
||||
group = sqlField[0];
|
||||
}
|
||||
|
||||
log.debug("Group field type: {}, group: {}, dateType: {}", typeName, group, dateType);
|
||||
|
||||
if (dateType != null && typeName != null && dateTypes.contains(typeName.toUpperCase())) {
|
||||
group = getDateTypeGroup(dateType, typeName, group);
|
||||
}
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
private String getDateTypeGroup(String dateType, String typeName, String group) {
|
||||
|
||||
switch (dateType) {
|
||||
case "year":
|
||||
group = "to_char(cast(" + group + " as date), 'yyyy')";
|
||||
break;
|
||||
case "month":
|
||||
group = "to_char(cast(" + group + " as date), 'yyyy-mm')";
|
||||
break;
|
||||
default:
|
||||
categType = "date";
|
||||
}
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method generate xml for search-fields.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private String getSearchFields() {
|
||||
|
||||
String search = "<search-fields>";
|
||||
|
||||
for (String searchField : searchFields) {
|
||||
search += Tab2 + searchField;
|
||||
}
|
||||
search += Tab1 + "</search-fields>";
|
||||
|
||||
return search;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method set default value for search-fields(parameters). It will add field and expression in
|
||||
* onNew for chart.
|
||||
*
|
||||
* @param fieldName Name of field of search-field.
|
||||
* @param typeName Type of field.
|
||||
* @param defaultValue Default value input in chart filter.
|
||||
* @param modelField It is for relational field. String array with first element as Model name and
|
||||
* second as its field.
|
||||
*/
|
||||
// private void setDefaultValue(String fieldName, String typeName,
|
||||
// String defaultValue, String[] modelField) {
|
||||
//
|
||||
// if (defaultValue == null) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// RecordField field = new RecordField();
|
||||
// field.setName(fieldName);
|
||||
//
|
||||
// defaultValue = filterCommonService.getTagValue(defaultValue, false);
|
||||
//
|
||||
// if (modelField != null) {
|
||||
// if (typeName.equals("STRING")) {
|
||||
// defaultValue = "__repo__(" + modelField[0]
|
||||
// + ").all().filter(\"LOWER(" + modelField[1] + ") LIKE "
|
||||
// + defaultValue + "\").fetchOne()";
|
||||
// } else {
|
||||
// defaultValue = "__repo__(" + modelField[0]
|
||||
// + ").all().filter(\"" + modelField[1] + " = "
|
||||
// + defaultValue + "\").fetchOne()";
|
||||
// }
|
||||
//
|
||||
// }
|
||||
//
|
||||
// log.debug("Default value: {}", defaultValue);
|
||||
//
|
||||
// field.setExpression("eval:" + defaultValue);
|
||||
//
|
||||
// onNewFields.add(field);
|
||||
// }
|
||||
|
||||
/**
|
||||
* It will create onNew action from onNew fields.
|
||||
*
|
||||
* @param viewBuilder ViewBuilder use to get model name also used in onNew action name creation.
|
||||
*/
|
||||
// private void setOnNewAction(ChartBuilder chartBuilder) {
|
||||
//
|
||||
// if (!onNewFields.isEmpty()) {
|
||||
// onNewAction = new ActionRecord();
|
||||
// onNewAction.setName("action-" + chartBuilder.getName() + "-default");
|
||||
// onNewAction.setModel(chartBuilder.getModel());
|
||||
// onNewAction.setFields(onNewFields);
|
||||
// }
|
||||
//
|
||||
// }
|
||||
|
||||
private void addSearchField(List<Filter> filters) throws AxelorException {
|
||||
|
||||
if (filters == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (Filter filter : filters) {
|
||||
if (!filter.getIsParameter()) {
|
||||
continue;
|
||||
}
|
||||
String fieldStr = "param" + filter.getId();
|
||||
|
||||
Object object = null;
|
||||
StringBuilder parent = new StringBuilder("self");
|
||||
if (filter.getIsJson()) {
|
||||
object =
|
||||
filterSqlService.parseJsonField(
|
||||
filter.getMetaJsonField(), filter.getTargetField(), null, parent);
|
||||
} else {
|
||||
object =
|
||||
filterSqlService.parseMetaField(
|
||||
filter.getMetaField(), filter.getTargetField(), null, parent, true);
|
||||
}
|
||||
|
||||
if (object instanceof MetaField) {
|
||||
fieldStr = getMetaSearchField(fieldStr, (MetaField) object);
|
||||
} else {
|
||||
fieldStr = getJsonSearchField(fieldStr, (MetaJsonField) object);
|
||||
}
|
||||
|
||||
searchFields.add(fieldStr + "\" x-required=\"true\" />");
|
||||
}
|
||||
}
|
||||
|
||||
private String getMetaSearchField(String fieldStr, MetaField field) {
|
||||
|
||||
fieldStr = "<field name=\"" + fieldStr + "\" title=\"" + field.getLabel();
|
||||
|
||||
if (field.getRelationship() == null) {
|
||||
String fieldType = filterCommonService.getFieldType(field);
|
||||
fieldStr += "\" type=\"" + fieldType;
|
||||
} else {
|
||||
String[] targetRef = filterSqlService.getDefaultTarget(field.getName(), field.getTypeName());
|
||||
String[] nameField = targetRef[0].split("\\.");
|
||||
fieldStr +=
|
||||
"\" widget=\"ref-text\" type=\""
|
||||
+ filterCommonService.getFieldType(targetRef[1])
|
||||
+ "\" x-target-name=\""
|
||||
+ nameField[1]
|
||||
+ "\" x-target=\""
|
||||
+ metaModelRepo.findByName(field.getTypeName()).getFullName();
|
||||
}
|
||||
|
||||
return fieldStr;
|
||||
}
|
||||
|
||||
private String getJsonSearchField(String fieldStr, MetaJsonField field) {
|
||||
|
||||
fieldStr = "<field name=\"" + fieldStr + "\" title=\"" + field.getTitle();
|
||||
|
||||
if (field.getTargetJsonModel() != null) {
|
||||
String[] targetRef =
|
||||
filterSqlService.getDefaultTargetJson(field.getName(), field.getTargetJsonModel());
|
||||
String[] nameField = targetRef[0].split("\\.");
|
||||
fieldStr +=
|
||||
"\" widget=\"ref-text\" type=\""
|
||||
+ filterCommonService.getFieldType(targetRef[1])
|
||||
+ "\" x-target-name=\""
|
||||
+ nameField[1]
|
||||
+ "\" x-target=\""
|
||||
+ MetaJsonRecord.class.getName()
|
||||
+ "\" x-domain=\"self.jsonModel = '"
|
||||
+ field.getTargetJsonModel().getName()
|
||||
+ "'";
|
||||
} else if (field.getTargetModel() != null) {
|
||||
String[] targetRef =
|
||||
filterSqlService.getDefaultTarget(field.getName(), field.getTargetModel());
|
||||
String[] nameField = targetRef[0].split("\\.");
|
||||
fieldStr +=
|
||||
"\" widget=\"ref-text\" type=\""
|
||||
+ filterCommonService.getFieldType(targetRef[1])
|
||||
+ "\" x-target-name=\""
|
||||
+ nameField[1]
|
||||
+ "\" x-target=\""
|
||||
+ field.getTargetModel();
|
||||
} else {
|
||||
String fieldType = Inflector.getInstance().camelize(field.getType(), true);
|
||||
fieldStr += "\" type=\"" + fieldType;
|
||||
}
|
||||
|
||||
return fieldStr;
|
||||
}
|
||||
|
||||
private String getTable(String model) {
|
||||
|
||||
String[] models = model.split("\\.");
|
||||
MetaModel metaModel = metaModelRepo.findByName(models[models.length - 1]);
|
||||
|
||||
if (metaModel != null) {
|
||||
return metaModel.getTableName();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@CallMethod
|
||||
public String getDefaultTarget(MetaField metaField) {
|
||||
|
||||
if (metaField.getRelationship() == null) {
|
||||
return metaField.getName();
|
||||
}
|
||||
|
||||
return filterSqlService.getDefaultTarget(metaField.getName(), metaField.getTypeName())[0];
|
||||
}
|
||||
|
||||
@CallMethod
|
||||
public String getDefaultTarget(MetaJsonField metaJsonField) {
|
||||
|
||||
if (!"many-to-one,one-to-one,json-many-to-one".contains(metaJsonField.getType())) {
|
||||
return metaJsonField.getName();
|
||||
}
|
||||
|
||||
if (metaJsonField.getTargetJsonModel() != null) {
|
||||
return filterSqlService
|
||||
.getDefaultTargetJson(metaJsonField.getName(), metaJsonField.getTargetJsonModel())[0];
|
||||
}
|
||||
|
||||
if (metaJsonField.getTargetModel() == null) {
|
||||
return metaJsonField.getName();
|
||||
}
|
||||
|
||||
return filterSqlService
|
||||
.getDefaultTarget(metaJsonField.getName(), metaJsonField.getTargetModel())[0];
|
||||
}
|
||||
|
||||
@CallMethod
|
||||
public String getTargetType(Object object, String target) {
|
||||
|
||||
if (target == null) {
|
||||
log.debug("No target provided for target type");
|
||||
return null;
|
||||
}
|
||||
|
||||
Object targetField = null;
|
||||
try {
|
||||
if (object instanceof MetaJsonField) {
|
||||
targetField = filterSqlService.parseJsonField((MetaJsonField) object, target, null, null);
|
||||
} else if (object instanceof MetaField) {
|
||||
targetField = filterSqlService.parseMetaField((MetaField) object, target, null, null, true);
|
||||
}
|
||||
} catch (AxelorException e) {
|
||||
}
|
||||
|
||||
if (targetField == null) {
|
||||
log.debug("Target field not found");
|
||||
return null;
|
||||
}
|
||||
|
||||
log.debug("Target field found: {}", targetField);
|
||||
|
||||
return filterSqlService.getTargetType(targetField);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.studio.service.builder;
|
||||
|
||||
import com.axelor.meta.MetaStore;
|
||||
import com.axelor.meta.db.MetaAction;
|
||||
import com.axelor.meta.db.MetaJsonRecord;
|
||||
import com.axelor.meta.db.MetaView;
|
||||
import com.axelor.meta.schema.views.AbstractWidget;
|
||||
import com.axelor.meta.schema.views.Dashboard;
|
||||
import com.axelor.meta.schema.views.Dashlet;
|
||||
import com.axelor.studio.db.DashboardBuilder;
|
||||
import com.axelor.studio.db.DashletBuilder;
|
||||
import com.axelor.studio.service.StudioMetaService;
|
||||
import com.google.inject.Inject;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* This service class used to generate dashboard from ViewBuilder of type Dashboard. It will take
|
||||
* all selected charts and generate xml from it.
|
||||
*
|
||||
* @author axelor
|
||||
*/
|
||||
public class DashboardBuilderService {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||
|
||||
@Inject private StudioMetaService metaService;
|
||||
|
||||
/**
|
||||
* Method to generate Dashboard (meta schema) from View Builder.
|
||||
*
|
||||
* @param viewBuilder ViewBuilder of type dashboard.
|
||||
* @return Dashboard.
|
||||
*/
|
||||
public MetaView build(DashboardBuilder dashboardBuilder) {
|
||||
|
||||
log.debug("Processing dashboard: {}", dashboardBuilder.getName());
|
||||
|
||||
log.debug("Dashlet list: {}", dashboardBuilder.getDashletBuilderList());
|
||||
|
||||
if (dashboardBuilder.getDashletBuilderList() == null
|
||||
|| dashboardBuilder.getDashletBuilderList().isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Dashboard dashboard = new Dashboard();
|
||||
String boardName = dashboardBuilder.getName();
|
||||
dashboard.setTitle(dashboardBuilder.getTitle());
|
||||
dashboard.setName(dashboardBuilder.getName());
|
||||
List<AbstractWidget> dashlets = new ArrayList<AbstractWidget>();
|
||||
|
||||
dashboardBuilder.clearGeneratedActions();
|
||||
for (DashletBuilder dashletBuilder : dashboardBuilder.getDashletBuilderList()) {
|
||||
|
||||
Dashlet dashlet = new Dashlet();
|
||||
String name = null;
|
||||
String model = null;
|
||||
MetaView metaView = dashletBuilder.getMetaView();
|
||||
MetaAction action = dashletBuilder.getAction();
|
||||
|
||||
String actionName = null;
|
||||
if (metaView != null) {
|
||||
name = metaView.getName();
|
||||
model = metaView.getModel();
|
||||
MetaAction metaAction = getAction(boardName, name, model, dashletBuilder);
|
||||
actionName = metaAction.getName();
|
||||
dashboardBuilder.addGeneratedAction(metaAction);
|
||||
} else if (action != null) {
|
||||
model = action.getModel();
|
||||
actionName = action.getName();
|
||||
}
|
||||
|
||||
dashlet.setAction(actionName);
|
||||
dashlet.setHeight("350");
|
||||
|
||||
Integer colSpan = dashletBuilder.getColspan();
|
||||
if (colSpan > 12) {
|
||||
colSpan = 12;
|
||||
} else if (colSpan <= 0) {
|
||||
colSpan = 6;
|
||||
}
|
||||
|
||||
dashlet.setColSpan(colSpan);
|
||||
dashlets.add(dashlet);
|
||||
}
|
||||
|
||||
if (dashlets.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
dashboard.setItems(dashlets);
|
||||
|
||||
MetaStore.clear();
|
||||
|
||||
return metaService.generateMetaView(dashboard);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to generate action-view for a chart
|
||||
*
|
||||
* @param dashboard Dashboard in which chart to be used.
|
||||
* @param actions
|
||||
* @param chart Chart to open from action-view.
|
||||
* @return Name of action-view.
|
||||
*/
|
||||
private MetaAction getAction(
|
||||
String dashboard, String name, String model, DashletBuilder dashletBuilder) {
|
||||
|
||||
String actionName = "action-" + (dashboard + "-" + name).replace(".", "-");
|
||||
|
||||
boolean isJson = model != null && model.contentEquals(MetaJsonRecord.class.getName());
|
||||
|
||||
String otherView = "form";
|
||||
String view = dashletBuilder.getViewType();
|
||||
if (view.equals("form")) {
|
||||
otherView = "grid";
|
||||
}
|
||||
|
||||
String xmlId = StudioMetaService.XML_ID_PREFIX + actionName;
|
||||
StringBuilder xml = new StringBuilder();
|
||||
xml.append("<action-view name=\"" + actionName + "\" ");
|
||||
xml.append("id=\"" + xmlId + "\" ");
|
||||
xml.append("title=\"" + dashletBuilder.getName() + "\" ");
|
||||
if (model != null) {
|
||||
xml.append("model=\"" + model + "\"");
|
||||
}
|
||||
xml.append(">");
|
||||
xml.append("\n\t<view type=\"" + view + "\" ");
|
||||
xml.append("name=\"" + name + "\" />");
|
||||
if (isJson) {
|
||||
xml.append("\n\t<view type=\"" + otherView + "\" ");
|
||||
xml.append("name=\"" + name.replace("-" + view, "-" + otherView) + "\" />");
|
||||
} else {
|
||||
xml.append("\n\t<view type=\"" + otherView + "\" />");
|
||||
}
|
||||
if (dashletBuilder.getPaginationLimit() > 0) {
|
||||
xml.append(
|
||||
"\n\t<view-param name=\"limit\" value=\""
|
||||
+ dashletBuilder.getPaginationLimit().toString()
|
||||
+ "\"/>");
|
||||
}
|
||||
|
||||
if (isJson) {
|
||||
String[] models = name.split("-");
|
||||
xml.append("\n\t<domain>self.jsonModel = '" + models[models.length - 2] + "'</domain>");
|
||||
}
|
||||
xml.append("\n</action-view>");
|
||||
|
||||
return metaService.updateMetaAction(actionName, "action-view", xml.toString(), model);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.studio.service.builder;
|
||||
|
||||
import com.axelor.exception.service.TraceBackService;
|
||||
import com.axelor.meta.MetaStore;
|
||||
import com.axelor.meta.db.MetaAction;
|
||||
import com.axelor.meta.db.MetaJsonRecord;
|
||||
import com.axelor.meta.db.MetaMenu;
|
||||
import com.axelor.meta.loader.XMLViews;
|
||||
import com.axelor.meta.schema.ObjectViews;
|
||||
import com.axelor.meta.schema.actions.Action;
|
||||
import com.axelor.meta.schema.actions.ActionView;
|
||||
import com.axelor.studio.db.ActionBuilder;
|
||||
import com.axelor.studio.db.ActionBuilderLine;
|
||||
import com.axelor.studio.db.ActionBuilderView;
|
||||
import com.axelor.studio.db.MenuBuilder;
|
||||
import com.axelor.studio.db.repo.ActionBuilderRepository;
|
||||
import com.axelor.studio.service.StudioMetaService;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import javax.xml.bind.JAXBException;
|
||||
|
||||
public class MenuBuilderService {
|
||||
|
||||
@Inject private ActionBuilderService actionBuilderService;
|
||||
|
||||
@Inject private StudioMetaService metaService;
|
||||
|
||||
@Transactional
|
||||
public MetaMenu build(MenuBuilder builder) {
|
||||
|
||||
MetaMenu menu = metaService.createMenu(builder);
|
||||
ActionBuilder actionBuilder = builder.getActionBuilder();
|
||||
if (actionBuilder != null) {
|
||||
if (actionBuilder.getName() == null) {
|
||||
actionBuilder.setName(menu.getName().replace("-", "."));
|
||||
}
|
||||
actionBuilder.setTitle(menu.getTitle());
|
||||
actionBuilder.setAppBuilder(builder.getAppBuilder());
|
||||
menu.setAction(actionBuilderService.build(actionBuilder));
|
||||
}
|
||||
|
||||
MetaStore.clear();
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Optional<ActionBuilder> createActionBuilder(MetaAction metaAction) {
|
||||
|
||||
try {
|
||||
ObjectViews objectViews = XMLViews.fromXML(metaAction.getXml());
|
||||
List<Action> actions = objectViews.getActions();
|
||||
if (actions != null && !actions.isEmpty()) {
|
||||
ActionView action = (ActionView) actions.get(0);
|
||||
if (action.getModel() != null
|
||||
&& action.getModel().contentEquals(MetaJsonRecord.class.getName())) {
|
||||
return Optional.empty();
|
||||
}
|
||||
ActionBuilder actionBuilder = new ActionBuilder(action.getName());
|
||||
actionBuilder.setTitle(action.getTitle());
|
||||
actionBuilder.setModel(action.getModel());
|
||||
actionBuilder.setTypeSelect(ActionBuilderRepository.TYPE_SELECT_VIEW);
|
||||
String domain = action.getDomain();
|
||||
actionBuilder.setDomainCondition(domain);
|
||||
for (ActionView.View view : action.getViews()) {
|
||||
ActionBuilderView builderView = new ActionBuilderView();
|
||||
builderView.setViewType(view.getType());
|
||||
builderView.setViewName(view.getName());
|
||||
actionBuilder.addActionBuilderView(builderView);
|
||||
}
|
||||
if (action.getParams() != null) {
|
||||
for (ActionView.Param param : action.getParams()) {
|
||||
ActionBuilderLine paramLine = new ActionBuilderLine();
|
||||
paramLine.setName(param.getName());
|
||||
paramLine.setValue(param.getValue());
|
||||
actionBuilder.addViewParam(paramLine);
|
||||
}
|
||||
}
|
||||
if (action.getContext() != null) {
|
||||
for (ActionView.Context ctx : (List<ActionView.Context>) action.getContext()) {
|
||||
ActionBuilderLine ctxLine = new ActionBuilderLine();
|
||||
ctxLine.setName(ctx.getName());
|
||||
if (ctx.getName().contentEquals("jsonModel")
|
||||
&& domain != null
|
||||
&& domain.contains("self.jsonModel = :jsonModel")) {
|
||||
actionBuilder.setIsJson(true);
|
||||
actionBuilder.setModel(ctx.getExpression());
|
||||
}
|
||||
ctxLine.setValue(ctx.getExpression());
|
||||
actionBuilder.addLine(ctxLine);
|
||||
}
|
||||
}
|
||||
|
||||
return Optional.of(actionBuilder);
|
||||
}
|
||||
} catch (JAXBException e) {
|
||||
TraceBackService.trace(e);
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,516 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.studio.service.builder;
|
||||
|
||||
import com.axelor.common.Inflector;
|
||||
import com.axelor.db.mapper.Mapper;
|
||||
import com.axelor.db.mapper.Property;
|
||||
import com.axelor.meta.db.MetaField;
|
||||
import com.axelor.meta.db.MetaModel;
|
||||
import com.axelor.meta.db.MetaView;
|
||||
import com.axelor.meta.db.repo.MetaFieldRepository;
|
||||
import com.axelor.meta.db.repo.MetaModelRepository;
|
||||
import com.axelor.meta.db.repo.MetaViewRepository;
|
||||
import com.axelor.meta.loader.XMLViews;
|
||||
import com.axelor.meta.schema.ObjectViews;
|
||||
import com.axelor.meta.schema.views.AbstractView;
|
||||
import com.axelor.meta.schema.views.AbstractWidget;
|
||||
import com.axelor.meta.schema.views.Field;
|
||||
import com.axelor.meta.schema.views.FormView;
|
||||
import com.axelor.meta.schema.views.GridView;
|
||||
import com.axelor.meta.schema.views.Panel;
|
||||
import com.axelor.meta.schema.views.PanelField;
|
||||
import com.axelor.meta.schema.views.PanelRelated;
|
||||
import com.axelor.meta.schema.views.PanelTabs;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.inject.Inject;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import javax.xml.bind.JAXBException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Service class generate html template from selected metaView for ReportBuilder. It also add button
|
||||
* into MetaView selected as buttonView in ReportBuilder.
|
||||
*
|
||||
* @author axelor
|
||||
*/
|
||||
public class ReportBuilderService {
|
||||
|
||||
private Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||
|
||||
private List<String[]> panels;
|
||||
|
||||
private List<String[]> sidePanels;
|
||||
|
||||
private String model;
|
||||
|
||||
private String template;
|
||||
|
||||
private Inflector inflector;
|
||||
|
||||
@Inject private MetaFieldRepository metaFieldRepo;
|
||||
|
||||
@Inject private MetaViewRepository metaViewRepo;
|
||||
|
||||
@Inject private MetaModelRepository metaModelRepo;
|
||||
|
||||
/**
|
||||
* Method create html template from MetaView. This is root method to create template. Html
|
||||
* contains table with two columns. If field is o2m/m2m it will take full row span.
|
||||
*
|
||||
* @param metaView MetaView to process
|
||||
* @return Html template generated.
|
||||
*/
|
||||
public String generateTemplate(MetaView metaView) {
|
||||
|
||||
panels = new ArrayList<String[]>();
|
||||
sidePanels = new ArrayList<String[]>();
|
||||
model = metaView.getModel();
|
||||
template = "";
|
||||
inflector = Inflector.getInstance();
|
||||
|
||||
try {
|
||||
processView(metaView.getXml());
|
||||
generateHtml(false);
|
||||
generateHtml(true);
|
||||
template = "<table class=\"table no-border\"><tr>" + template + "</tr></table>";
|
||||
log.debug("Template generated: {}", template);
|
||||
return template;
|
||||
} catch (JAXBException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method parse given xml to create html.
|
||||
*
|
||||
* @param xml View xml passed.
|
||||
* @throws JAXBException Xml parsing exception.
|
||||
*/
|
||||
private void processView(String xml) throws JAXBException {
|
||||
|
||||
ObjectViews objectViews = XMLViews.fromXML(xml);
|
||||
AbstractView view = objectViews.getViews().get(0);
|
||||
|
||||
FormView formView = (FormView) view;
|
||||
|
||||
for (AbstractWidget widget : formView.getItems()) {
|
||||
if (widget instanceof PanelTabs) {
|
||||
PanelTabs panelTabs = (PanelTabs) widget;
|
||||
AbstractWidget tabItem = panelTabs.getItems().get(0);
|
||||
processAbstractWidget(tabItem, false);
|
||||
continue;
|
||||
}
|
||||
processAbstractWidget(widget, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check given AbstractWidget and process it according to its type.
|
||||
*
|
||||
* @param widget AbstractWidget to process
|
||||
* @param sidePanel Boolean to check if widget is sidePanel.
|
||||
*/
|
||||
private void processAbstractWidget(AbstractWidget widget, Boolean sidePanel) {
|
||||
|
||||
if (widget instanceof Panel) {
|
||||
processPanel((Panel) widget, sidePanel);
|
||||
} else if (widget instanceof PanelRelated) {
|
||||
PanelRelated panelRelated = (PanelRelated) widget;
|
||||
sidePanel = sidePanel != null && sidePanel ? sidePanel : panelRelated.getSidebar();
|
||||
processPanelRelated(panelRelated, sidePanel, "12");
|
||||
} else if (widget instanceof PanelField) {
|
||||
processField((PanelField) widget, sidePanel);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process panel to create html from it and to process items of panels. It add panel title in full
|
||||
* row span of html table.
|
||||
*
|
||||
* @param panel Panels to process.
|
||||
* @param sidePanel Boolean to check if panel is sidePanel.
|
||||
*/
|
||||
private void processPanel(Panel panel, Boolean sidePanel) {
|
||||
|
||||
sidePanel = sidePanel != null && sidePanel ? sidePanel : panel.getSidebar();
|
||||
|
||||
String title = panel.getTitle();
|
||||
|
||||
if (title != null) {
|
||||
title = "<td><h4><u>" + title + "</u></h4></td>";
|
||||
if (sidePanel != null && sidePanel) {
|
||||
sidePanels.add(new String[] {"12", title});
|
||||
} else {
|
||||
panels.add(new String[] {"12", title});
|
||||
}
|
||||
}
|
||||
for (AbstractWidget widget : panel.getItems()) {
|
||||
processAbstractWidget(widget, sidePanel);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process PanelField and extend html table of html template.
|
||||
*
|
||||
* @param field PanelField to process.
|
||||
* @param sidePanel Boolean to check if field is in sidePanel.
|
||||
* @param colSpan Colspan of field.
|
||||
*/
|
||||
private void processField(PanelField field, Boolean sidePanel) {
|
||||
|
||||
String title = field.getTitle();
|
||||
String name = field.getName();
|
||||
|
||||
MetaField metaField = getMetaField(name, model);
|
||||
|
||||
if (Strings.isNullOrEmpty(title)) {
|
||||
title = getFieldTitle(name, metaField);
|
||||
}
|
||||
|
||||
name = processRelational(name, metaField);
|
||||
|
||||
String value = "<td><b>" + title + "</b> : $" + name + "$</td>";
|
||||
String colSpan = "6";
|
||||
|
||||
if (field.getColSpan() != null && field.getColSpan() == 12) {
|
||||
colSpan = "12";
|
||||
value = "<td colSpan=\"2\"><b>" + title + "</b> : $" + name + "$</td>";
|
||||
} else {
|
||||
value = "<td><b>" + title + "</b> : $" + name + "$</td>";
|
||||
}
|
||||
|
||||
if (sidePanel != null && sidePanel) {
|
||||
sidePanels.add(new String[] {"12", value});
|
||||
} else {
|
||||
panels.add(new String[] {colSpan, value});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check given metaField and process relational field to create proper string template friendly
|
||||
* string.
|
||||
*
|
||||
* @param name Name of field.
|
||||
* @param metaField MetaField to process.
|
||||
* @return Template friendly string created for relational field.
|
||||
*/
|
||||
private String processRelational(String name, MetaField metaField) {
|
||||
|
||||
if (metaField == null) {
|
||||
return name;
|
||||
}
|
||||
|
||||
String relationship = metaField.getRelationship();
|
||||
if (relationship == null) {
|
||||
return name;
|
||||
}
|
||||
|
||||
String nameColumn = getNameColumn(name, metaField);
|
||||
if (!relationship.equals("ManyToOne")) {
|
||||
String[] names = nameColumn.split("\\.");
|
||||
nameColumn = name + " : {item | $item." + names[1] + "$ }";
|
||||
}
|
||||
|
||||
return nameColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get nameColumn for given relational metaField.
|
||||
*
|
||||
* @param name Field name
|
||||
* @param metaField MetaField to check.
|
||||
* @return Name column of field.
|
||||
*/
|
||||
private String getNameColumn(String name, MetaField metaField) {
|
||||
|
||||
String refModel = getRefModel(metaField.getTypeName());
|
||||
try {
|
||||
Mapper mapper = Mapper.of(Class.forName(refModel));
|
||||
boolean nameField = false;
|
||||
boolean codeField = false;
|
||||
for (Property property : Arrays.asList(mapper.getProperties())) {
|
||||
if (property.isNameColumn()) {
|
||||
return name + "." + property.getName();
|
||||
} else if (property.getName().equals("name")) {
|
||||
nameField = true;
|
||||
} else if (property.getName().equals("code")) {
|
||||
codeField = true;
|
||||
}
|
||||
}
|
||||
if (nameField) {
|
||||
return name + ".name";
|
||||
}
|
||||
if (codeField) {
|
||||
return name + ".code";
|
||||
}
|
||||
return name + "." + "id";
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method generate main html table of html template, from 'panels' and 'sidePanels' list created
|
||||
* during view xml processing.
|
||||
*
|
||||
* @param sidePanel Boolean to check which panel list to process.
|
||||
*/
|
||||
private void generateHtml(boolean sidePanel) {
|
||||
|
||||
List<String[]> panelList = sidePanel ? sidePanels : panels;
|
||||
|
||||
if (panelList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
template += "<td><table>";
|
||||
int totalSpan = 0;
|
||||
for (String[] field : panelList) {
|
||||
|
||||
int colSpan = Integer.parseInt(field[0]);
|
||||
|
||||
if (colSpan == 12) {
|
||||
if (totalSpan > 0) {
|
||||
totalSpan = 0;
|
||||
template += "</tr>";
|
||||
}
|
||||
|
||||
template += "<tr>" + field[1] + "</tr>";
|
||||
} else {
|
||||
if (totalSpan == 0) {
|
||||
template += "<tr>";
|
||||
}
|
||||
template += field[1];
|
||||
totalSpan += colSpan;
|
||||
|
||||
if (totalSpan == 12) {
|
||||
totalSpan = 0;
|
||||
template += "</tr>";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (totalSpan > 0) {
|
||||
template += "</tr>";
|
||||
}
|
||||
|
||||
template += "</table></td>";
|
||||
}
|
||||
|
||||
/**
|
||||
* It returns title of MetaField and if title is empty it create human readable title from field
|
||||
* name.
|
||||
*
|
||||
* @param name Name of field.
|
||||
* @param metaField MetaField to process.
|
||||
* @return Title of field.
|
||||
*/
|
||||
private String getFieldTitle(String name, MetaField metaField) {
|
||||
|
||||
log.debug("Meta field for name : {}, metaField: {}", name, metaField);
|
||||
|
||||
if (metaField != null) {
|
||||
String title = metaField.getLabel();
|
||||
if (!Strings.isNullOrEmpty(title)) {
|
||||
return metaField.getLabel();
|
||||
}
|
||||
}
|
||||
|
||||
return inflector.humanize(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get MetaField record from field name and model.
|
||||
*
|
||||
* @param name Field name to search.
|
||||
* @param modelName Model of field.
|
||||
* @return Return MetaField found.
|
||||
*/
|
||||
private MetaField getMetaField(String name, String modelName) {
|
||||
|
||||
MetaField metaField =
|
||||
metaFieldRepo
|
||||
.all()
|
||||
.filter("self.name = ? AND self.metaModel.fullName = ?", name, modelName)
|
||||
.fetchOne();
|
||||
|
||||
return metaField;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process panelRelated and update 'panels' or 'sidePanels' list with new table created for
|
||||
* panelRelated.
|
||||
*
|
||||
* @param panelRelated PanelRelated to process.
|
||||
* @param sidePanel Boolean to check if panelRelated is sidePanel.
|
||||
* @param colSpan Colspan to add in panel lists.
|
||||
*/
|
||||
public void processPanelRelated(PanelRelated panelRelated, Boolean sidePanel, String colSpan) {
|
||||
|
||||
String title = panelRelated.getTitle();
|
||||
String name = panelRelated.getName();
|
||||
MetaField metaField = getMetaField(name, model);
|
||||
|
||||
if (Strings.isNullOrEmpty(title) && metaField != null) {
|
||||
title = metaField.getLabel();
|
||||
}
|
||||
|
||||
if (Strings.isNullOrEmpty(title)) {
|
||||
title = inflector.humanize(name);
|
||||
}
|
||||
|
||||
String field = "<td colSpan=\"2\"><h4>" + title + "</h4></td>";
|
||||
|
||||
String refModel = getRefModel(metaField.getTypeName());
|
||||
|
||||
String itemTable = createTable(panelRelated, refModel);
|
||||
|
||||
if (sidePanel != null && sidePanel) {
|
||||
sidePanels.add(new String[] {"12", field});
|
||||
sidePanels.add(new String[] {"12", itemTable});
|
||||
} else {
|
||||
panels.add(new String[] {colSpan, field});
|
||||
panels.add(new String[] {colSpan, itemTable});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process panelRelated to find right grid view of reference model. Grid view used to create html
|
||||
* table.
|
||||
*
|
||||
* @param panelRelated PanelRelated to use.
|
||||
* @param refModel Name of model refer by panelRelated.
|
||||
* @return Html table string created.
|
||||
*/
|
||||
private String createTable(PanelRelated panelRelated, String refModel) {
|
||||
|
||||
List<AbstractWidget> items = panelRelated.getItems();
|
||||
if (items != null && !items.isEmpty()) {
|
||||
return getHtmlTable(panelRelated.getName(), items, refModel);
|
||||
}
|
||||
|
||||
MetaView gridView = findGridView(panelRelated.getGridView(), refModel);
|
||||
|
||||
if (gridView != null) {
|
||||
try {
|
||||
ObjectViews views = XMLViews.fromXML(gridView.getXml());
|
||||
|
||||
GridView grid = (GridView) views.getViews().get(0);
|
||||
|
||||
return getHtmlTable(panelRelated.getName(), grid.getItems(), refModel);
|
||||
|
||||
} catch (JAXBException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Create html table string from list of widgets(Items of grd view).
|
||||
*
|
||||
* @param fieldName Name of relational field.
|
||||
* @param widgets List of widgets in reference model's grid view.
|
||||
* @param refModel Name of reference model.
|
||||
* @return Html table created.
|
||||
*/
|
||||
private String getHtmlTable(String fieldName, List<AbstractWidget> widgets, String refModel) {
|
||||
|
||||
String header = "";
|
||||
String row = "";
|
||||
|
||||
for (AbstractWidget widget : widgets) {
|
||||
|
||||
if (widget instanceof Field) {
|
||||
|
||||
Field field = (Field) widget;
|
||||
String name = field.getName();
|
||||
String title = field.getTitle();
|
||||
MetaField metaField = getMetaField(name, refModel);
|
||||
if (Strings.isNullOrEmpty(title)) {
|
||||
title = getFieldTitle(name, metaField);
|
||||
}
|
||||
name = processRelational(name, metaField);
|
||||
|
||||
header += "<th>" + title + "</th>";
|
||||
row += "<td>$" + fieldName + "." + name + "$</td>";
|
||||
}
|
||||
}
|
||||
|
||||
String table =
|
||||
"<td colSpan=\"2\"><table class=\"table table-bordered table-header\">"
|
||||
+ "<tr>"
|
||||
+ header
|
||||
+ "</tr>"
|
||||
+ "<tr>"
|
||||
+ row
|
||||
+ "</tr>"
|
||||
+ "</table></td>";
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find MetaView record from given gridName and reference model.
|
||||
*
|
||||
* @param gridName Name of grid view.
|
||||
* @param refModel Model of grid view.
|
||||
* @return MetaView record searched.
|
||||
*/
|
||||
private MetaView findGridView(String gridName, String refModel) {
|
||||
|
||||
MetaView gridView = null;
|
||||
|
||||
if (gridName != null) {
|
||||
gridView = metaViewRepo.findByName(gridName);
|
||||
}
|
||||
|
||||
if (gridView == null) {
|
||||
gridView =
|
||||
metaViewRepo.all().filter("self.type = 'grid' and self.model = ?", refModel).fetchOne();
|
||||
}
|
||||
|
||||
return gridView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get fullName of reference model.
|
||||
*
|
||||
* @param refModel Name of reference model.
|
||||
* @return FullName of Model
|
||||
*/
|
||||
private String getRefModel(String refModel) {
|
||||
|
||||
MetaModel metaModel = metaModelRepo.findByName(refModel);
|
||||
if (metaModel != null) {
|
||||
refModel = metaModel.getFullName();
|
||||
}
|
||||
|
||||
return refModel;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,170 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.studio.service.filter;
|
||||
|
||||
import com.axelor.meta.db.MetaField;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class FilterCommonService {
|
||||
|
||||
/**
|
||||
* It will return value of tag used by filter 'value'.
|
||||
*
|
||||
* @param value Value of chart filter.
|
||||
* @return Context variable to use instead of tag.
|
||||
*/
|
||||
public String getTagValue(String value, boolean addColon) {
|
||||
|
||||
if (value != null) {
|
||||
if (addColon) {
|
||||
value = value.replace("$user", ":__user__");
|
||||
value = value.replace("$date", ":__date__");
|
||||
value = value.replace("$time", ":__datetime__");
|
||||
} else {
|
||||
value = value.replace("$user", "__user__");
|
||||
value = value.replace("$date", "__date__");
|
||||
value = value.replace("$time", "__datetime__");
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method create like condition for filter with string field.
|
||||
*
|
||||
* @param conditionField Chart filter field name
|
||||
* @param value Value of input in chart filter.
|
||||
* @param isLike boolean to check if condition is like or notLike
|
||||
* @return String condition.
|
||||
*/
|
||||
public String getLikeCondition(String conditionField, String value, boolean isLike) {
|
||||
|
||||
String likeCondition = null;
|
||||
|
||||
String likeOpr = "LIKE";
|
||||
if (!isLike) {
|
||||
likeOpr = "NOT LIKE";
|
||||
}
|
||||
|
||||
if (value.contains(",")) {
|
||||
for (String val : Arrays.asList(value.split(","))) {
|
||||
if (likeCondition == null) {
|
||||
likeCondition = conditionField + " " + likeOpr + " " + val;
|
||||
} else {
|
||||
likeCondition += " OR " + conditionField + " " + likeOpr + " " + val;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
likeCondition = conditionField + " " + likeOpr + " " + value;
|
||||
}
|
||||
|
||||
return likeCondition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get simple field type from typeName of MetaField
|
||||
*
|
||||
* @param metaField MetaField to check for typeName.
|
||||
* @return Simple field type.
|
||||
*/
|
||||
public String getFieldType(MetaField metaField) {
|
||||
|
||||
String relationship = metaField.getRelationship();
|
||||
|
||||
if (relationship != null) {
|
||||
switch (relationship) {
|
||||
case "OneToMany":
|
||||
return "one-to-many";
|
||||
case "ManyToMany":
|
||||
return "many-to-many";
|
||||
case "ManyToOne":
|
||||
return "many-to-one";
|
||||
}
|
||||
}
|
||||
|
||||
return getFieldType(metaField.getTypeName());
|
||||
}
|
||||
|
||||
public String getFieldType(String type) {
|
||||
|
||||
switch (type) {
|
||||
case "String":
|
||||
return "string";
|
||||
case "Integer":
|
||||
return "integer";
|
||||
case "Boolean":
|
||||
return "boolean";
|
||||
case "BigDecimal":
|
||||
return "decimal";
|
||||
case "Long":
|
||||
return "long";
|
||||
case "byte[]":
|
||||
return "binary";
|
||||
case "LocalDate":
|
||||
return "date";
|
||||
case "ZonedDateTime":
|
||||
return "datetime";
|
||||
case "LocalDateTime":
|
||||
return "datetime";
|
||||
default:
|
||||
return "string";
|
||||
}
|
||||
}
|
||||
|
||||
public String getCondition(String conditionField, String operator, String value) {
|
||||
|
||||
value = getTagValue(value, true);
|
||||
|
||||
String[] values = new String[] {""};
|
||||
if (value != null) {
|
||||
values = value.split(",");
|
||||
}
|
||||
|
||||
switch (operator) {
|
||||
case "like":
|
||||
return getLikeCondition(conditionField, value, true);
|
||||
case "notLike":
|
||||
return getLikeCondition(conditionField, value, false);
|
||||
case "in":
|
||||
return conditionField + " IN" + " (" + value + ") ";
|
||||
case "notIn":
|
||||
return conditionField + " NOT IN" + " (" + value + ") ";
|
||||
case "isNull":
|
||||
return conditionField + " IS NULL ";
|
||||
case "notNull":
|
||||
return conditionField + " IS NOT NULL ";
|
||||
case "between":
|
||||
if (values.length > 1) {
|
||||
return conditionField + " BETWEEN " + values[0] + " AND " + values[1];
|
||||
}
|
||||
return conditionField + " BETWEEN " + values[0] + " AND " + values[0];
|
||||
case "notBetween":
|
||||
if (values.length > 1) {
|
||||
return conditionField + " NOT BETWEEN " + values[0] + " AND " + values[1];
|
||||
}
|
||||
return conditionField + " NOT BETWEEN " + values[0] + " AND " + values[0];
|
||||
case "isTrue":
|
||||
return conditionField + " IS TRUE ";
|
||||
case "isFalse":
|
||||
return conditionField + " IS FALSE ";
|
||||
default:
|
||||
return conditionField + " " + operator + " " + value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.studio.service.filter;
|
||||
|
||||
import com.axelor.meta.db.MetaJsonField;
|
||||
import com.axelor.studio.db.Filter;
|
||||
import com.google.inject.Inject;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.List;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class FilterGroovyService {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||
|
||||
@Inject private FilterCommonService filterCommonService;
|
||||
|
||||
/**
|
||||
* Method to convert chart filter list to groovy expression string. Each filter of list will be
|
||||
* joined by logical operator(logicalOp) selected.
|
||||
*
|
||||
* @param conditions List for chart filters.
|
||||
* @param parentField Field that represent parent.
|
||||
* @return Groovy expression string.
|
||||
*/
|
||||
public String getGroovyFilters(List<Filter> conditions, String parentField) {
|
||||
|
||||
String condition = null;
|
||||
|
||||
if (conditions == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (Filter filter : conditions) {
|
||||
String activeFilter = createGroovyFilter(filter, parentField);
|
||||
log.debug("Active filter: {}", filter);
|
||||
|
||||
if (condition == null) {
|
||||
condition = "(" + activeFilter;
|
||||
} else if (filter.getLogicOp() > 0) {
|
||||
condition += ") || (" + activeFilter;
|
||||
} else {
|
||||
condition += " && " + activeFilter;
|
||||
}
|
||||
}
|
||||
|
||||
if (condition == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return condition + ")";
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to generate groovy expression for a single chart filter.
|
||||
*
|
||||
* @param chartFilter Chart filter to use .
|
||||
* @param parentField Parent field.
|
||||
* @return Groovy expression string.
|
||||
*/
|
||||
private String createGroovyFilter(Filter filter, String parentField) {
|
||||
|
||||
MetaJsonField metaJsonField = filter.getMetaJsonField();
|
||||
String field =
|
||||
parentField != null ? parentField + "." + metaJsonField.getName() : metaJsonField.getName();
|
||||
String targetField =
|
||||
parentField != null ? parentField + "." + filter.getTargetField() : filter.getTargetField();
|
||||
String value = processValue(filter);
|
||||
String operator = filter.getOperator();
|
||||
|
||||
if (targetField != null) {
|
||||
targetField = targetField.replace(".", "?.");
|
||||
if (metaJsonField.getType().equals("many-to-one")
|
||||
|| metaJsonField.getType().equals("json-many-to-one")) {
|
||||
field = targetField;
|
||||
} else if (metaJsonField.getType().equals("many-to-many") && !operator.contains("empty")) {
|
||||
targetField = targetField.replace(field + "?.", "it?.");
|
||||
String condition = getConditionExpr(operator, targetField, value);
|
||||
return field + ".findAll{it->" + condition + "}.size() > 0";
|
||||
}
|
||||
}
|
||||
|
||||
return getConditionExpr(operator, field, value);
|
||||
}
|
||||
|
||||
private String processValue(Filter filter) {
|
||||
|
||||
String value = filter.getValue();
|
||||
if (value == null) {
|
||||
return value;
|
||||
}
|
||||
|
||||
value = value.replace("$$", "_parent.");
|
||||
|
||||
return filterCommonService.getTagValue(value, false);
|
||||
}
|
||||
|
||||
private String getConditionExpr(String operator, String field, String value) {
|
||||
|
||||
switch (operator) {
|
||||
case "=":
|
||||
return field + " == " + value;
|
||||
case "isNull":
|
||||
return field + " == null";
|
||||
case "notNull":
|
||||
return field + " != null";
|
||||
case "empty":
|
||||
return field + ".empty";
|
||||
case "notEmpty":
|
||||
return "!" + field + ".empty";
|
||||
case "isTrue":
|
||||
return field;
|
||||
case "isFalse":
|
||||
return "!" + field;
|
||||
default:
|
||||
return field + " " + operator + " " + value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.studio.service.filter;
|
||||
|
||||
import com.axelor.meta.db.MetaField;
|
||||
import com.axelor.meta.db.MetaJsonField;
|
||||
import com.axelor.studio.db.Filter;
|
||||
import com.google.inject.Inject;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.List;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* This service class use to generate groovy expression from chart filters.
|
||||
*
|
||||
* @author axelor
|
||||
*/
|
||||
public class FilterJpqlService {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||
|
||||
@Inject private FilterCommonService filterCommonService;
|
||||
|
||||
public String getJpqlFilters(List<Filter> filterList) {
|
||||
|
||||
String filters = null;
|
||||
|
||||
if (filterList == null) {
|
||||
return filters;
|
||||
}
|
||||
|
||||
for (Filter filter : filterList) {
|
||||
|
||||
MetaField field = filter.getMetaField();
|
||||
|
||||
if (filter.getValue() != null) {
|
||||
String value = filter.getValue();
|
||||
value = value.replaceAll("\"", "");
|
||||
value = value.replaceAll("'", "");
|
||||
|
||||
if (filter.getOperator().contains("like") && !value.contains("%")) {
|
||||
value = "%" + value + "%";
|
||||
}
|
||||
filter.setValue("'" + value + "'");
|
||||
}
|
||||
String relationship = field.getRelationship();
|
||||
String fieldName =
|
||||
relationship != null ? filter.getTargetField() : filter.getMetaField().getName();
|
||||
fieldName = "self." + fieldName;
|
||||
if (filter.getTargetType().equals("String")) {
|
||||
fieldName = "LOWER(" + fieldName + ")";
|
||||
filter.setValue("LOWER(" + filter.getValue() + ")");
|
||||
}
|
||||
String condition =
|
||||
filterCommonService.getCondition(fieldName, filter.getOperator(), filter.getValue());
|
||||
|
||||
if (filters == null) {
|
||||
filters = condition;
|
||||
} else {
|
||||
String opt = filter.getLogicOp() != null && filter.getLogicOp() == 0 ? " AND " : " OR ";
|
||||
filters = filters + opt + condition;
|
||||
}
|
||||
}
|
||||
|
||||
log.debug("JPQL filter: {}", filters);
|
||||
return filters;
|
||||
}
|
||||
|
||||
public String getJsonJpql(MetaJsonField jsonField) {
|
||||
|
||||
switch (jsonField.getType()) {
|
||||
case "integer":
|
||||
return "json_extract_integer";
|
||||
case "decimal":
|
||||
return "json_extract_decimal";
|
||||
case "boolean":
|
||||
return "json_extract_boolean";
|
||||
default:
|
||||
return "json_extract";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,485 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.studio.service.filter;
|
||||
|
||||
import com.axelor.common.Inflector;
|
||||
import com.axelor.db.JPA;
|
||||
import com.axelor.db.mapper.Mapper;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||
import com.axelor.meta.db.MetaField;
|
||||
import com.axelor.meta.db.MetaJsonField;
|
||||
import com.axelor.meta.db.MetaJsonModel;
|
||||
import com.axelor.meta.db.MetaJsonRecord;
|
||||
import com.axelor.meta.db.MetaModel;
|
||||
import com.axelor.meta.db.repo.MetaFieldRepository;
|
||||
import com.axelor.meta.db.repo.MetaJsonFieldRepository;
|
||||
import com.axelor.meta.db.repo.MetaModelRepository;
|
||||
import com.axelor.studio.db.Filter;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.inject.Inject;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.List;
|
||||
import org.hibernate.internal.SessionImpl;
|
||||
import org.hibernate.persister.entity.AbstractEntityPersister;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class FilterSqlService {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||
|
||||
@Inject private FilterCommonService filterCommonService;
|
||||
|
||||
@Inject private MetaFieldRepository metaFieldRepo;
|
||||
|
||||
@Inject private MetaModelRepository metaModelRepo;
|
||||
|
||||
@Inject private MetaJsonFieldRepository metaJsonFieldRepo;
|
||||
|
||||
public String getColumn(String model, String field) {
|
||||
|
||||
SessionImpl sessionImpl = (SessionImpl) JPA.em().getDelegate();
|
||||
@SuppressWarnings("deprecation")
|
||||
AbstractEntityPersister aep =
|
||||
((AbstractEntityPersister)
|
||||
sessionImpl.getSession().getSessionFactory().getClassMetadata(model));
|
||||
String[] columns = aep.getPropertyColumnNames(field);
|
||||
if (columns != null && columns.length > 0) {
|
||||
return columns[0];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getColumn(MetaField metaField) {
|
||||
|
||||
return getColumn(metaField.getMetaModel().getFullName(), metaField.getName());
|
||||
}
|
||||
|
||||
public String getSqlType(String type) {
|
||||
|
||||
switch (type) {
|
||||
case "string":
|
||||
return "varchar";
|
||||
case "String":
|
||||
return "varchar";
|
||||
case "LocalDate":
|
||||
return "date";
|
||||
case "LocalDateTime":
|
||||
return "timestamp";
|
||||
case "datetime":
|
||||
return "timestamp";
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getSqlFilters(List<Filter> filterList, List<String> joins, boolean checkJson)
|
||||
throws AxelorException {
|
||||
|
||||
String filters = null;
|
||||
|
||||
if (filterList == null) {
|
||||
return filters;
|
||||
}
|
||||
|
||||
for (Filter filter : filterList) {
|
||||
|
||||
StringBuilder parent = new StringBuilder("self");
|
||||
Object target = getTargetField(parent, filter, joins, checkJson);
|
||||
if (target == null) {
|
||||
continue;
|
||||
}
|
||||
String[] fields = getSqlField(target, parent.toString(), null);
|
||||
String field = checkDateTime(fields);
|
||||
String value =
|
||||
getParam(filter.getIsParameter(), filter.getValue(), filter.getId(), fields[1]);
|
||||
String condition = filterCommonService.getCondition(field, filter.getOperator(), value);
|
||||
|
||||
if (filters == null) {
|
||||
filters = condition;
|
||||
} else {
|
||||
String opt = filter.getLogicOp() == 0 ? " AND " : " OR ";
|
||||
filters = filters + opt + condition;
|
||||
}
|
||||
}
|
||||
|
||||
return filters;
|
||||
}
|
||||
|
||||
private String checkDateTime(String[] fields) {
|
||||
switch (fields[1]) {
|
||||
case "LocalDateTime":
|
||||
return "(cast(to_char("
|
||||
+ fields[0]
|
||||
+ ",'yyyy-MM-dd hh24:mi') as timestamp with time zone)) at time zone 'utc'";
|
||||
}
|
||||
|
||||
return fields[0];
|
||||
}
|
||||
|
||||
public String[] getSqlField(Object target, String source, List<String> joins) {
|
||||
|
||||
String field = null;
|
||||
String type = null;
|
||||
String selection = null;
|
||||
|
||||
if (target instanceof MetaField) {
|
||||
MetaField metaField = (MetaField) target;
|
||||
field = source + "." + getColumn(metaField);
|
||||
type = metaField.getTypeName();
|
||||
try {
|
||||
selection =
|
||||
Mapper.of(Class.forName(metaField.getMetaModel().getFullName()))
|
||||
.getProperty(metaField.getName())
|
||||
.getSelection();
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
MetaJsonField metaJsonField = (MetaJsonField) target;
|
||||
selection = metaJsonField.getSelection();
|
||||
String jsonColumn = getColumn(metaJsonField.getModel(), metaJsonField.getModelField());
|
||||
field =
|
||||
"cast("
|
||||
+ source
|
||||
+ "."
|
||||
+ jsonColumn
|
||||
+ "->>'"
|
||||
+ metaJsonField.getName()
|
||||
+ "' as "
|
||||
+ getSqlType(metaJsonField.getType())
|
||||
+ ")";
|
||||
type = metaJsonField.getType();
|
||||
}
|
||||
|
||||
log.debug("Selection for field :{} : {}", field, selection);
|
||||
if (joins != null && !Strings.isNullOrEmpty(selection)) {
|
||||
int join = joins.size();
|
||||
joins.add(
|
||||
"left join meta_select obj" + join + " on (obj" + join + ".name = '" + selection + "')");
|
||||
join = joins.size();
|
||||
joins.add(
|
||||
"left join meta_select_item obj"
|
||||
+ join
|
||||
+ " on (obj"
|
||||
+ join
|
||||
+ ".select_id = obj"
|
||||
+ (join - 1)
|
||||
+ ".id and obj"
|
||||
+ join
|
||||
+ ".value = cast("
|
||||
+ field
|
||||
+ " as varchar))");
|
||||
join = joins.size();
|
||||
joins.add(
|
||||
"left join meta_translation obj"
|
||||
+ join
|
||||
+ " on (obj"
|
||||
+ join
|
||||
+ ".message_key = obj"
|
||||
+ (join - 1)
|
||||
+ ".title and obj"
|
||||
+ join
|
||||
+ ".language = (select language from auth_user where id = :__user__))");
|
||||
field = "COALESCE(nullif(obj" + join + ".message_value,''), obj" + (join - 1) + ".title)";
|
||||
}
|
||||
|
||||
return new String[] {field, type};
|
||||
}
|
||||
|
||||
private String getParam(boolean isParam, String value, Long filterId, String type) {
|
||||
|
||||
if (isParam) {
|
||||
String sqlType = getSqlType(type);
|
||||
if (!sqlType.equals(type) || sqlType.equals("date")) {
|
||||
value = "cast(:param" + filterId + " as " + getSqlType(type) + ")";
|
||||
} else {
|
||||
value = ":param" + filterId;
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public String[] getDefaultTarget(String fieldName, String modelName) {
|
||||
|
||||
MetaModel targetModel = null;
|
||||
if (modelName.contains(".")) {
|
||||
targetModel = metaModelRepo.all().filter("self.fullName = ?1", modelName).fetchOne();
|
||||
} else {
|
||||
targetModel = metaModelRepo.findByName(modelName);
|
||||
}
|
||||
|
||||
if (targetModel == null) {
|
||||
return new String[] {fieldName, null};
|
||||
}
|
||||
|
||||
try {
|
||||
Mapper mapper = Mapper.of(Class.forName(targetModel.getFullName()));
|
||||
if (mapper.getNameField() != null) {
|
||||
return new String[] {
|
||||
fieldName + "." + mapper.getNameField().getName(),
|
||||
mapper.getNameField().getJavaType().getSimpleName()
|
||||
};
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
for (MetaField field : targetModel.getMetaFields()) {
|
||||
if (field.getName().equals("name")) {
|
||||
return new String[] {fieldName + ".name", field.getTypeName()};
|
||||
}
|
||||
if (field.getName().equals("code")) {
|
||||
return new String[] {fieldName + ".code", field.getTypeName()};
|
||||
}
|
||||
}
|
||||
|
||||
return new String[] {fieldName, null};
|
||||
}
|
||||
|
||||
public String[] getDefaultTargetJson(String fieldName, MetaJsonModel targetModel) {
|
||||
|
||||
String name = targetModel.getNameField();
|
||||
if (name == null) {
|
||||
MetaJsonField nameField =
|
||||
metaJsonFieldRepo
|
||||
.all()
|
||||
.filter("self.name = 'name' and self.jsonModel = ?1", targetModel)
|
||||
.fetchOne();
|
||||
if (nameField == null) {
|
||||
nameField =
|
||||
metaJsonFieldRepo
|
||||
.all()
|
||||
.filter("self.name = 'code' and self.jsonModel = ?1", targetModel)
|
||||
.fetchOne();
|
||||
}
|
||||
if (nameField != null) {
|
||||
name = nameField.getName();
|
||||
}
|
||||
}
|
||||
return new String[] {fieldName + "." + name, "string"};
|
||||
}
|
||||
|
||||
public Object getTargetField(
|
||||
StringBuilder parent, Filter filter, List<String> joins, boolean checkJson)
|
||||
throws AxelorException {
|
||||
|
||||
Object target = null;
|
||||
|
||||
if (!filter.getIsJson() && filter.getMetaField() != null) {
|
||||
target =
|
||||
parseMetaField(filter.getMetaField(), filter.getTargetField(), joins, parent, checkJson);
|
||||
} else if (checkJson && filter.getMetaJsonField() != null) {
|
||||
target = parseJsonField(filter.getMetaJsonField(), filter.getTargetField(), joins, parent);
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
public String getTargetType(Object target) {
|
||||
|
||||
String targetType = null;
|
||||
if (target instanceof MetaField) {
|
||||
MetaField metaField = (MetaField) target;
|
||||
String relationship = metaField.getRelationship();
|
||||
if (relationship != null) {
|
||||
targetType = relationship;
|
||||
} else {
|
||||
targetType = metaField.getTypeName();
|
||||
}
|
||||
} else if (target instanceof MetaJsonField) {
|
||||
targetType = ((MetaJsonField) target).getType();
|
||||
log.debug("Target json type:", targetType);
|
||||
targetType = Inflector.getInstance().camelize(targetType);
|
||||
}
|
||||
|
||||
log.debug("Target type: {}, field: {}", targetType, target);
|
||||
|
||||
return targetType;
|
||||
}
|
||||
|
||||
public Object parseMetaField(
|
||||
MetaField field, String target, List<String> joins, StringBuilder parent, boolean checkJson)
|
||||
throws AxelorException {
|
||||
|
||||
if (target == null || !target.contains(".")) {
|
||||
if (field.getRelationship() != null && joins != null) {
|
||||
target = getDefaultTarget(field.getName(), field.getTypeName())[0];
|
||||
} else {
|
||||
return field;
|
||||
}
|
||||
}
|
||||
|
||||
target = target.substring(target.indexOf(".") + 1);
|
||||
String targetName = target.contains(".") ? target.substring(0, target.indexOf(".")) : target;
|
||||
if (field.getRelationship() == null) {
|
||||
return field;
|
||||
}
|
||||
|
||||
MetaModel model = metaModelRepo.findByName(field.getTypeName());
|
||||
MetaField subMeta = findMetaField(targetName, model.getFullName());
|
||||
if (subMeta != null) {
|
||||
if (joins != null) {
|
||||
addJoin(field, joins, parent);
|
||||
}
|
||||
return parseMetaField(subMeta, target, joins, parent, checkJson);
|
||||
} else if (checkJson) {
|
||||
MetaJsonField subJson = findJsonField(targetName, model.getName());
|
||||
if (subJson != null) {
|
||||
if (joins != null) {
|
||||
addJoin(field, joins, parent);
|
||||
}
|
||||
return parseJsonField(subJson, target, joins, parent);
|
||||
}
|
||||
}
|
||||
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_MISSING_FIELD,
|
||||
"No sub field found field: %s model: %s ",
|
||||
targetName,
|
||||
model.getFullName());
|
||||
}
|
||||
|
||||
public Object parseJsonField(
|
||||
MetaJsonField field, String target, List<String> joins, StringBuilder parent)
|
||||
throws AxelorException {
|
||||
|
||||
log.debug("Parse json target: {}", target);
|
||||
|
||||
if (target == null || !target.contains(".")) {
|
||||
if (field.getTargetJsonModel() != null && joins != null) {
|
||||
target = getDefaultTargetJson(field.getName(), field.getTargetJsonModel())[0];
|
||||
} else if (field.getTargetModel() != null && joins != null) {
|
||||
target = getDefaultTarget(field.getName(), field.getTargetModel())[0];
|
||||
} else {
|
||||
return field;
|
||||
}
|
||||
}
|
||||
|
||||
target = target.substring(target.indexOf(".") + 1);
|
||||
|
||||
String targetName = target.contains(".") ? target.substring(0, target.indexOf(".")) : target;
|
||||
if (field.getTargetJsonModel() == null && field.getTargetModel() == null) {
|
||||
return field;
|
||||
}
|
||||
|
||||
if (field.getTargetJsonModel() != null) {
|
||||
MetaJsonField subJson =
|
||||
metaJsonFieldRepo
|
||||
.all()
|
||||
.filter(
|
||||
"self.name = ?1 and self.jsonModel = ?2", targetName, field.getTargetJsonModel())
|
||||
.fetchOne();
|
||||
if (subJson != null) {
|
||||
if (joins != null) {
|
||||
addJoin(field, joins, parent);
|
||||
}
|
||||
return parseJsonField(subJson, target, joins, parent);
|
||||
}
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_MISSING_FIELD,
|
||||
"No sub field found model: %s field %s ",
|
||||
field.getTargetJsonModel().getName(),
|
||||
targetName);
|
||||
} else {
|
||||
MetaField subMeta = findMetaField(targetName, field.getTargetModel());
|
||||
if (subMeta != null) {
|
||||
if (joins != null) {
|
||||
addJoin(field, joins, parent);
|
||||
}
|
||||
return parseMetaField(subMeta, target, joins, parent, true);
|
||||
}
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_MISSING_FIELD,
|
||||
"No sub field found model: %s field %s ",
|
||||
field.getTargetModel(),
|
||||
targetName);
|
||||
}
|
||||
}
|
||||
|
||||
private MetaField findMetaField(String name, String model) {
|
||||
|
||||
return metaFieldRepo
|
||||
.all()
|
||||
.filter("self.name = ?1 and self.metaModel.fullName = ?2", name, model)
|
||||
.fetchOne();
|
||||
}
|
||||
|
||||
private MetaJsonField findJsonField(String name, String model) {
|
||||
|
||||
return metaJsonFieldRepo
|
||||
.all()
|
||||
.filter("self.name = ?1 and self.model = ?2", name, model)
|
||||
.fetchOne();
|
||||
}
|
||||
|
||||
private void addJoin(MetaField field, List<String> joins, StringBuilder parent) {
|
||||
|
||||
MetaModel metaModel = metaModelRepo.findByName(field.getTypeName());
|
||||
String parentField = getColumn(field);
|
||||
joins.add(
|
||||
"left join "
|
||||
+ metaModel.getTableName()
|
||||
+ " "
|
||||
+ "obj"
|
||||
+ joins.size()
|
||||
+ " on ("
|
||||
+ "obj"
|
||||
+ joins.size()
|
||||
+ ".id = "
|
||||
+ parent.toString()
|
||||
+ "."
|
||||
+ parentField
|
||||
+ ")");
|
||||
parent.replace(0, parent.length(), "obj" + (joins.size() - 1));
|
||||
}
|
||||
|
||||
private void addJoin(MetaJsonField field, List<String> joins, StringBuilder parent) {
|
||||
|
||||
String targetModel = null;
|
||||
if (field.getTargetModel() != null) {
|
||||
targetModel = field.getTargetModel();
|
||||
} else if (field.getTargetJsonModel() != null) {
|
||||
targetModel = MetaJsonRecord.class.getName();
|
||||
}
|
||||
|
||||
MetaModel metaModel = metaModelRepo.all().filter("self.fullName = ?1", targetModel).fetchOne();
|
||||
|
||||
joins.add(
|
||||
"left join "
|
||||
+ metaModel.getTableName()
|
||||
+ " "
|
||||
+ "obj"
|
||||
+ joins.size()
|
||||
+ " on (obj"
|
||||
+ joins.size()
|
||||
+ ".id = "
|
||||
+ "cast("
|
||||
+ parent
|
||||
+ "."
|
||||
+ getColumn(field.getModel(), field.getModelField())
|
||||
+ "->'"
|
||||
+ field.getName()
|
||||
+ "'->>'id' as integer))");
|
||||
|
||||
parent.replace(0, parent.length(), "obj" + (joins.size() - 1));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,289 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.studio.service.wkf;
|
||||
|
||||
import com.axelor.apps.tool.xml.XPathParse;
|
||||
import com.axelor.auth.db.repo.RoleRepository;
|
||||
import com.axelor.common.Inflector;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.axelor.meta.db.MetaField;
|
||||
import com.axelor.studio.db.Wkf;
|
||||
import com.axelor.studio.db.WkfNode;
|
||||
import com.axelor.studio.db.WkfTransition;
|
||||
import com.axelor.studio.db.repo.WkfNodeRepository;
|
||||
import com.axelor.studio.db.repo.WkfRepository;
|
||||
import com.axelor.studio.db.repo.WkfTransitionRepository;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
/**
|
||||
* Handles bpmn xml processing of work-flow. Creates/removes work-flow nodes and transitions using
|
||||
* bpmn xml.
|
||||
*
|
||||
* @author axelor
|
||||
*/
|
||||
public class WkfDesignerService {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||
|
||||
protected static final String WKF_STATUS = "wkfStatus";
|
||||
|
||||
protected MetaField statusField = null;
|
||||
|
||||
protected String dasherizeModel = null;
|
||||
|
||||
protected String modelName = null;
|
||||
|
||||
protected Inflector inflector;
|
||||
|
||||
protected String defaultStatus = null;
|
||||
|
||||
private Set<WkfNode> nodes = new LinkedHashSet<>();
|
||||
|
||||
private Set<WkfTransition> transitions = new LinkedHashSet<>();
|
||||
|
||||
private Wkf instance;
|
||||
|
||||
private List<Integer> nodeSequences;
|
||||
|
||||
@Inject protected RoleRepository roleRepo;
|
||||
|
||||
@Inject private WkfRepository wkfRepo;
|
||||
|
||||
@Inject private WkfService wkfService;
|
||||
|
||||
/**
|
||||
* Parses xml doc to create workflow nodes from it. Sets incoming and outgoing transitions of
|
||||
* node.
|
||||
*
|
||||
* @param doc
|
||||
*/
|
||||
public void traverseXMLElement(Document doc) {
|
||||
|
||||
nodeSequences = new ArrayList<>();
|
||||
|
||||
NodeList list = doc.getElementsByTagName("*");
|
||||
|
||||
int nodeCount = 1;
|
||||
|
||||
Map<String, WkfNode> nodeMap = getNodeMap();
|
||||
|
||||
for (int i = 0; i < list.getLength(); i++) {
|
||||
|
||||
Element element = (Element) list.item(i);
|
||||
|
||||
if ((!element.getParentNode().getNodeName().equals("process"))
|
||||
|| element.getNodeName().equals("sequenceFlow")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String elementName = element.getTagName();
|
||||
|
||||
WkfNode node = nodeMap.get(element.getAttribute("id"));
|
||||
|
||||
if (node == null) {
|
||||
node = new WkfNode();
|
||||
node.setXmlId(element.getAttribute("id"));
|
||||
node.setName(element.getAttribute("name"));
|
||||
node.setTitle(node.getName());
|
||||
node.setWkf(instance);
|
||||
while (nodeSequences.contains(nodeCount)) {
|
||||
nodeCount += 10;
|
||||
}
|
||||
node.setSequence(nodeCount);
|
||||
nodeCount += 10;
|
||||
if (elementName.equals("startEvent")) node.setNodeType(WkfNodeRepository.START_NODE);
|
||||
else if (elementName.equals("endEvent")) node.setNodeType(WkfNodeRepository.END_NODE);
|
||||
} else {
|
||||
node.setName(element.getAttribute("name"));
|
||||
nodeMap.remove(node.getXmlId());
|
||||
}
|
||||
|
||||
wkfService.clearNodes(nodeMap.values());
|
||||
NodeList incomings = element.getElementsByTagName("incoming");
|
||||
|
||||
for (int j = 0; j < incomings.getLength(); j++) {
|
||||
Element incElement = (Element) incomings.item(j);
|
||||
String innerText = incElement.getTextContent();
|
||||
|
||||
for (WkfTransition trn : transitions) {
|
||||
if (trn.getXmlId().equals(innerText)) {
|
||||
Set<WkfTransition> existIncomings = node.getIncoming();
|
||||
|
||||
if (existIncomings == null) existIncomings = new HashSet<>();
|
||||
|
||||
existIncomings.add(trn);
|
||||
node.setIncoming(existIncomings);
|
||||
trn.setTarget(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NodeList outgoings = element.getElementsByTagName("outgoing");
|
||||
|
||||
for (int j = 0; j < outgoings.getLength(); j++) {
|
||||
Element outElement = (Element) outgoings.item(j);
|
||||
String innerText = outElement.getTextContent();
|
||||
|
||||
for (WkfTransition trn : transitions) {
|
||||
if (trn.getXmlId().equals(innerText)) {
|
||||
Set<WkfTransition> existOutgoings = node.getOutgoing();
|
||||
|
||||
if (existOutgoings == null) existOutgoings = new HashSet<>();
|
||||
|
||||
existOutgoings.add(trn);
|
||||
node.setOutgoing(existOutgoings);
|
||||
trn.setSource(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
nodes.add(node);
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, WkfNode> getNodeMap() {
|
||||
|
||||
WkfNodeRepository wkfNodeRepository = Beans.get(WkfNodeRepository.class);
|
||||
|
||||
Map<String, WkfNode> nodeMap = new HashMap<>();
|
||||
if (instance != null) {
|
||||
List<WkfNode> wkfNodes =
|
||||
wkfNodeRepository.all().filter("self.wkf.id = ?1", instance.getId()).fetch();
|
||||
for (WkfNode node : wkfNodes) {
|
||||
nodeMap.put(node.getXmlId(), node);
|
||||
nodeSequences.add(node.getSequence());
|
||||
}
|
||||
}
|
||||
|
||||
return nodeMap;
|
||||
}
|
||||
|
||||
private Map<String, WkfTransition> getTransitionMap() {
|
||||
|
||||
WkfTransitionRepository wkfTransitionRepo = Beans.get(WkfTransitionRepository.class);
|
||||
|
||||
Map<String, WkfTransition> transitionMap = new HashMap<>();
|
||||
if (instance != null) {
|
||||
List<WkfTransition> wkfTransitions =
|
||||
wkfTransitionRepo.all().filter("self.wkf.id = ?1", instance.getId()).fetch();
|
||||
for (WkfTransition transition : wkfTransitions) {
|
||||
transitionMap.put(transition.getXmlId(), transition);
|
||||
}
|
||||
}
|
||||
|
||||
return transitionMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches bpmn xml from workflow. Generates document from xml using dom parser. Generates
|
||||
* transitions from dom document and calls method to create nodes.
|
||||
*
|
||||
* @param instance Workflow instance
|
||||
* @throws ParserConfigurationException
|
||||
* @throws IOException
|
||||
* @throws SAXException
|
||||
* @throws Exception
|
||||
*/
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public Wkf processXml(Wkf instance)
|
||||
throws ParserConfigurationException, SAXException, IOException {
|
||||
|
||||
this.instance = instance;
|
||||
String bpmnXml = instance.getBpmnXml();
|
||||
if (bpmnXml != null) {
|
||||
DocumentBuilder db =
|
||||
Beans.get(XPathParse.class).getDocumentBuilderFactory().newDocumentBuilder();
|
||||
InputSource is = new InputSource();
|
||||
is.setCharacterStream(new StringReader(bpmnXml));
|
||||
|
||||
Document doc = db.parse(is);
|
||||
|
||||
NodeList list;
|
||||
|
||||
Map<String, WkfTransition> transitionMap = getTransitionMap();
|
||||
list = doc.getElementsByTagName("sequenceFlow");
|
||||
for (int i = 0; i < list.getLength(); i++) {
|
||||
Element element = (Element) list.item(i);
|
||||
|
||||
WkfTransition transition = transitionMap.get(element.getAttribute("id"));
|
||||
|
||||
if (transition == null) {
|
||||
transition = new WkfTransition();
|
||||
transition.setXmlId(element.getAttribute("id"));
|
||||
transition.setName(element.getAttribute("name"));
|
||||
transition.setWkf(instance);
|
||||
log.debug(
|
||||
"New transition : {}, Version: {}", transition.getName(), transition.getVersion());
|
||||
} else {
|
||||
transition.setName(element.getAttribute("name"));
|
||||
}
|
||||
|
||||
transitions.add(transition);
|
||||
}
|
||||
|
||||
List<WkfNode> allRemoveNodes = instance.getNodes();
|
||||
|
||||
if (!allRemoveNodes.isEmpty()) {
|
||||
for (WkfNode tempNode : allRemoveNodes) {
|
||||
tempNode.getIncoming().clear();
|
||||
tempNode.getOutgoing().clear();
|
||||
}
|
||||
}
|
||||
|
||||
instance.getTransitions().clear();
|
||||
|
||||
for (WkfTransition transition : transitions) {
|
||||
if (transition.getVersion() == null) {
|
||||
transition.setIsButton(true);
|
||||
transition.setButtonTitle(transition.getName());
|
||||
transition.setColSpan(transition.getColSpan());
|
||||
}
|
||||
instance.addTransition(transition);
|
||||
}
|
||||
|
||||
traverseXMLElement(doc);
|
||||
|
||||
instance.getNodes().clear();
|
||||
|
||||
for (WkfNode node : nodes) {
|
||||
instance.addNode(node);
|
||||
}
|
||||
}
|
||||
|
||||
return wkfRepo.save(instance);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,267 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.studio.service.wkf;
|
||||
|
||||
import com.axelor.auth.db.Permission;
|
||||
import com.axelor.auth.db.Role;
|
||||
import com.axelor.auth.db.repo.PermissionRepository;
|
||||
import com.axelor.meta.db.MetaAction;
|
||||
import com.axelor.meta.db.MetaJsonField;
|
||||
import com.axelor.meta.db.MetaModel;
|
||||
import com.axelor.meta.db.MetaSelect;
|
||||
import com.axelor.meta.db.MetaSelectItem;
|
||||
import com.axelor.meta.db.repo.MetaModelRepository;
|
||||
import com.axelor.meta.db.repo.MetaSelectRepository;
|
||||
import com.axelor.studio.db.WkfNode;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Service handle processing of WkfNode. From wkfNode it generates status field for related model.
|
||||
* It will generate field's selection according to nodes and add field in related ViewBuilder.
|
||||
* Creates permissions for status related with node and assign to roles selected in node. Add status
|
||||
* menus(MenuBuilder) according to menu details in WkfNode.
|
||||
*
|
||||
* @author axelor
|
||||
*/
|
||||
class WkfNodeService {
|
||||
|
||||
private WkfService wkfService;
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||
|
||||
private List<String[]> nodeActions;
|
||||
|
||||
@Inject private MetaModelRepository metaModelRepo;
|
||||
|
||||
@Inject private PermissionRepository permissionRepo;
|
||||
|
||||
@Inject private MetaSelectRepository metaSelectRepo;
|
||||
|
||||
@Inject
|
||||
protected WkfNodeService(WkfService wkfService) {
|
||||
this.wkfService = wkfService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Root method to access the service. It start processing of WkfNode and call different methods
|
||||
* for that.
|
||||
*/
|
||||
protected List<String[]> process() {
|
||||
|
||||
MetaJsonField statusField = wkfService.workflow.getStatusField();
|
||||
MetaSelect metaSelect = addMetaSelect(statusField);
|
||||
|
||||
nodeActions = new ArrayList<String[]>();
|
||||
String defaultValue = processNodes(metaSelect, statusField);
|
||||
statusField.setDefaultValue(defaultValue);
|
||||
|
||||
return nodeActions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add MetaSelect in statusField, if MetaSelect of field is null.
|
||||
*
|
||||
* @param statusField MetaField to update with MetaSelect.
|
||||
* @return MetaSelect of statusField.
|
||||
*/
|
||||
@Transactional
|
||||
public MetaSelect addMetaSelect(MetaJsonField statusField) {
|
||||
|
||||
String selectName = wkfService.getSelectName();
|
||||
|
||||
MetaSelect metaSelect = metaSelectRepo.findByName(selectName);
|
||||
if (metaSelect == null) {
|
||||
metaSelect = new MetaSelect(selectName);
|
||||
metaSelect.setIsCustom(true);
|
||||
metaSelect.setAppBuilder(wkfService.workflow.getAppBuilder());
|
||||
metaSelect = metaSelectRepo.save(metaSelect);
|
||||
}
|
||||
|
||||
if (metaSelect.getItems() == null) {
|
||||
metaSelect.setItems(new ArrayList<MetaSelectItem>());
|
||||
}
|
||||
|
||||
metaSelect.clearItems();
|
||||
|
||||
return metaSelect;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method remove old options from metaSelect options if not found in nodeList.
|
||||
*
|
||||
* @param metaSelect MetaSelect to process.
|
||||
* @param nodeList WkfNode list to compare.
|
||||
* @return Updated MetaSelect.
|
||||
*/
|
||||
private MetaSelect removeOldOptions(MetaSelect metaSelect, List<WkfNode> nodeList) {
|
||||
|
||||
log.debug("Cleaning meta select: {}", metaSelect.getName());
|
||||
|
||||
List<MetaSelectItem> itemsToRemove = new ArrayList<MetaSelectItem>();
|
||||
|
||||
Iterator<MetaSelectItem> itemIter = metaSelect.getItems().iterator();
|
||||
|
||||
while (itemIter.hasNext()) {
|
||||
MetaSelectItem item = itemIter.next();
|
||||
boolean found = false;
|
||||
for (WkfNode node : nodeList) {
|
||||
if (item.getValue().equals(node.getSequence().toString())) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
itemsToRemove.add(item);
|
||||
itemIter.remove();
|
||||
}
|
||||
}
|
||||
|
||||
return metaSelect;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add or update items in MetaSelect according to WkfNodes.
|
||||
*
|
||||
* @param metaSelect MetaSelect to update.
|
||||
* @return Return first item as default value for wkfStatus field.
|
||||
*/
|
||||
private String processNodes(MetaSelect metaSelect, MetaJsonField statusField) {
|
||||
|
||||
List<WkfNode> nodeList = wkfService.workflow.getNodes();
|
||||
|
||||
String defaultValue = null;
|
||||
removeOldOptions(metaSelect, nodeList);
|
||||
|
||||
Collections.sort(
|
||||
nodeList,
|
||||
(WkfNode node1, WkfNode node2) -> node1.getSequence().compareTo(node2.getSequence()));
|
||||
|
||||
for (WkfNode node : nodeList) {
|
||||
|
||||
log.debug("Procesing node: {}", node.getName());
|
||||
String option = node.getSequence().toString();
|
||||
MetaSelectItem metaSelectItem = getMetaSelectItem(metaSelect, option);
|
||||
if (metaSelectItem == null) {
|
||||
metaSelectItem = new MetaSelectItem();
|
||||
metaSelectItem.setValue(option);
|
||||
metaSelect.addItem(metaSelectItem);
|
||||
}
|
||||
|
||||
metaSelectItem.setTitle(node.getTitle());
|
||||
metaSelectItem.setOrder(node.getSequence());
|
||||
|
||||
if (defaultValue == null) {
|
||||
defaultValue = metaSelectItem.getValue();
|
||||
log.debug("Default value set: {}", defaultValue);
|
||||
}
|
||||
|
||||
List<String[]> actions = new ArrayList<String[]>();
|
||||
|
||||
if (node.getMetaActionSet() != null) {
|
||||
Stream<MetaAction> actionStream =
|
||||
node.getMetaActionSet().stream().sorted(Comparator.comparing(MetaAction::getSequence));
|
||||
actionStream.forEach(metaAction -> actions.add(new String[] {metaAction.getName()}));
|
||||
}
|
||||
|
||||
if (!actions.isEmpty()) {
|
||||
String name = getActionName(node.getName());
|
||||
String value = node.getSequence().toString();
|
||||
if (statusField.getType().equals("string")) {
|
||||
value = "'" + value + "'";
|
||||
}
|
||||
String condition = statusField.getName() + " == " + value;
|
||||
if (!wkfService.workflow.getIsJson()) {
|
||||
condition = "$" + wkfService.workflow.getJsonField() + "." + condition;
|
||||
}
|
||||
nodeActions.add(new String[] {name, condition});
|
||||
this.wkfService.updateActionGroup(name, actions);
|
||||
}
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public String getActionName(String node) {
|
||||
|
||||
String name = wkfService.inflector.simplify(node);
|
||||
name = name.toLowerCase().replace(" ", "-");
|
||||
name = "action-group-" + wkfService.wkfId + "-" + name;
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to save MetaModel
|
||||
*
|
||||
* @param metaModel Model to save.
|
||||
* @return Saved MetaModel
|
||||
*/
|
||||
@Transactional
|
||||
public MetaModel saveModel(MetaModel metaModel) {
|
||||
return metaModelRepo.save(metaModel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch MetaSelectItem from MetaSelect according to option.
|
||||
*
|
||||
* @param metaSelect MetaSelect to search for item.
|
||||
* @param option Option to search.
|
||||
* @return MetaSelctItem found or null.
|
||||
*/
|
||||
private MetaSelectItem getMetaSelectItem(MetaSelect metaSelect, String option) {
|
||||
|
||||
for (MetaSelectItem selectItem : metaSelect.getItems()) {
|
||||
if (selectItem.getValue().equals(option)) {
|
||||
return selectItem;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method remove old permission according to name of permission.
|
||||
*
|
||||
* @param name Permission name.
|
||||
*/
|
||||
@Transactional
|
||||
public void clearOldPermissions(String name) {
|
||||
|
||||
Permission permission = permissionRepo.findByName(name);
|
||||
|
||||
if (permission != null) {
|
||||
List<Role> oldRoleList =
|
||||
wkfService.roleRepo.all().filter("self.permissions.id = ?1", permission.getId()).fetch();
|
||||
for (Role role : oldRoleList) {
|
||||
role.removePermission(permission);
|
||||
wkfService.roleRepo.save(role);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,531 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.studio.service.wkf;
|
||||
|
||||
import com.axelor.auth.db.repo.RoleRepository;
|
||||
import com.axelor.common.Inflector;
|
||||
import com.axelor.meta.MetaStore;
|
||||
import com.axelor.meta.db.MetaJsonField;
|
||||
import com.axelor.meta.db.MetaJsonModel;
|
||||
import com.axelor.meta.db.MetaJsonRecord;
|
||||
import com.axelor.meta.db.MetaSelect;
|
||||
import com.axelor.meta.db.repo.MetaJsonFieldRepository;
|
||||
import com.axelor.meta.db.repo.MetaJsonModelRepository;
|
||||
import com.axelor.meta.db.repo.MetaSelectRepository;
|
||||
import com.axelor.meta.loader.XMLViews;
|
||||
import com.axelor.meta.schema.actions.ActionGroup;
|
||||
import com.axelor.meta.schema.actions.ActionGroup.ActionItem;
|
||||
import com.axelor.meta.schema.actions.ActionMethod;
|
||||
import com.axelor.meta.schema.actions.ActionMethod.Call;
|
||||
import com.axelor.studio.db.Wkf;
|
||||
import com.axelor.studio.db.WkfNode;
|
||||
import com.axelor.studio.db.repo.WkfRepository;
|
||||
import com.axelor.studio.service.StudioMetaService;
|
||||
import com.axelor.studio.service.filter.FilterGroovyService;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Service class handle workflow processing. It updated related models/views according to update in
|
||||
* workflow. Also remove effects of workflow it some workflow deleted. Call node and transition
|
||||
* service for further processing.
|
||||
*
|
||||
* @author axelor
|
||||
*/
|
||||
public class WkfService {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||
|
||||
protected Wkf workflow = null;
|
||||
|
||||
protected String wkfId = null;
|
||||
|
||||
protected Inflector inflector;
|
||||
|
||||
protected Integer wkfSequence = 0;
|
||||
|
||||
protected String applyCondition = null;
|
||||
|
||||
protected String trackingAction = null;
|
||||
|
||||
@Inject protected RoleRepository roleRepo;
|
||||
|
||||
@Inject private WkfNodeService nodeService;
|
||||
@Inject private WkfTransitionService transitionService;
|
||||
@Inject private StudioMetaService metaService;
|
||||
@Inject private MetaJsonFieldRepository jsonFieldRepo;
|
||||
@Inject private MetaJsonModelRepository jsonModelRepo;
|
||||
@Inject private MetaSelectRepository metaSelectRepo;
|
||||
@Inject private FilterGroovyService filterGroovyService;
|
||||
@Inject private WkfRepository wkfRepository;
|
||||
|
||||
/**
|
||||
* Method to process workflow. It calls node and transition service for nodes and transitions
|
||||
* linked with workflow.
|
||||
*
|
||||
* @param wkf Worklfow to process.
|
||||
* @return Exception string if any issue in processing else null.
|
||||
*/
|
||||
public String process(Wkf wkf) {
|
||||
|
||||
try {
|
||||
initService(wkf);
|
||||
createTrackingAction();
|
||||
setWkfSequence();
|
||||
setView();
|
||||
List<String[]> actions = nodeService.process();
|
||||
actions.addAll(transitionService.process());
|
||||
actions.add(new String[] {"save"});
|
||||
actions.add(new String[] {trackingAction});
|
||||
updateActionGroup("action-group-" + wkfId, actions);
|
||||
MetaStore.clear();
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return e.toString();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void initService(Wkf wkf) {
|
||||
workflow = wkf;
|
||||
inflector = Inflector.getInstance();
|
||||
wkfId = "wkf" + wkf.getId().toString();
|
||||
trackingAction = "action-method-wkf-track-" + wkfId;
|
||||
}
|
||||
|
||||
private void setView() {
|
||||
|
||||
// clearOldStatusField();
|
||||
|
||||
MetaJsonField status = workflow.getStatusField();
|
||||
|
||||
applyCondition =
|
||||
filterGroovyService.getGroovyFilters(workflow.getConditions(), workflow.getJsonField());
|
||||
|
||||
MetaJsonField panel = getJsonField(wkfId + "Panel", "panel");
|
||||
panel.setSequence(wkfSequence - 49);
|
||||
panel.setVisibleInGrid(false);
|
||||
panel.setIsWkf(true);
|
||||
panel.setWidgetAttrs("{\"colSpan\": \"12\"}");
|
||||
saveJsonField(panel);
|
||||
|
||||
status.setSequence(wkfSequence - 48);
|
||||
status.setSelection(getSelectName());
|
||||
status.setWidget(null);
|
||||
status.setIsWkf(true);
|
||||
status.setReadonly(true);
|
||||
status.setShowIf(applyCondition);
|
||||
status.setWidgetAttrs("{\"colSpan\": \"10\"}");
|
||||
if (workflow.getDisplayTypeSelect() == 0) {
|
||||
status.setWidget("NavSelect");
|
||||
}
|
||||
saveJsonField(workflow.getStatusField());
|
||||
|
||||
MetaJsonField trackFlow = getJsonField(wkfId + "TrackFlow", "button");
|
||||
trackFlow.setSequence(wkfSequence - 47);
|
||||
trackFlow.setTitle("Track flow");
|
||||
trackFlow.setWidgetAttrs("{\"colSpan\": \"2\"}");
|
||||
trackFlow.setOnClick(WkfTrackingService.ACTION_OPEN_TRACK);
|
||||
trackFlow.setIsWkf(true);
|
||||
trackFlow.setVisibleInGrid(false);
|
||||
trackFlow.setHidden(!workflow.getIsTrackFlow());
|
||||
saveJsonField(trackFlow);
|
||||
|
||||
MetaJsonField wkfEnd = getJsonField(wkfId + "Separator", "separator");
|
||||
wkfEnd.setSequence(wkfSequence);
|
||||
wkfEnd.setVisibleInGrid(false);
|
||||
wkfEnd.setIsWkf(true);
|
||||
wkfEnd.setWidgetAttrs("{\"colSpan\": \"12\"}");
|
||||
saveJsonField(panel);
|
||||
|
||||
// setTrackOnSave(workflow, false);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void clearOldStatusField() {
|
||||
|
||||
MetaJsonField field = null;
|
||||
if (workflow.getIsJson()) {
|
||||
field =
|
||||
jsonFieldRepo
|
||||
.all()
|
||||
.filter(
|
||||
"self.isWkf = true "
|
||||
+ "and self.jsonModel.name = :workflowModel "
|
||||
+ "and self.type in ('string','integer')")
|
||||
.bind("workflowModel", workflow.getModel())
|
||||
.fetchOne();
|
||||
} else {
|
||||
field =
|
||||
jsonFieldRepo
|
||||
.all()
|
||||
.filter(
|
||||
"self.isWkf = true "
|
||||
+ "and self.model = :workflowModel "
|
||||
+ "and self.modelField = :workflowJsonField "
|
||||
+ "and self.type in ('string','integer')")
|
||||
.bind("workflowModel", workflow.getModel())
|
||||
.bind("workflowJsonField", workflow.getJsonField())
|
||||
.fetchOne();
|
||||
}
|
||||
|
||||
if (field != null) {
|
||||
if (field.getSelection() != null) {
|
||||
log.debug("Cleaning old status field: {}", field);
|
||||
MetaSelect oldSelect = metaSelectRepo.findByName(field.getSelection());
|
||||
if (oldSelect != null) {
|
||||
log.debug("Removing old wkf selection: {}", oldSelect);
|
||||
metaSelectRepo.remove(oldSelect);
|
||||
}
|
||||
}
|
||||
field.setIsWkf(false);
|
||||
field.setSelection(null);
|
||||
field.setSequence(0);
|
||||
field.setReadonly(false);
|
||||
jsonFieldRepo.save(field);
|
||||
}
|
||||
}
|
||||
|
||||
public String getSelectName() {
|
||||
|
||||
if (workflow != null) {
|
||||
MetaJsonField wkfField = workflow.getStatusField();
|
||||
String selectName = "wkf." + inflector.dasherize(workflow.getName()).replace("_", ".");
|
||||
selectName += "." + inflector.dasherize(wkfField.getName()).replace("_", ".") + ".select";
|
||||
|
||||
return selectName;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update xml of MetaAction with xml string passed. It creates new MetaAction if no MetaAction not
|
||||
* found.
|
||||
*
|
||||
* @param actionName Name of MetaAction to update.
|
||||
* @param actionType Type of MetaAction.
|
||||
* @param xml Xml to update in MetaAction.
|
||||
*/
|
||||
protected ActionGroup updateActionGroup(String name, List<String[]> actions) {
|
||||
|
||||
ActionGroup actionGroup = new ActionGroup();
|
||||
actionGroup.setName(name);
|
||||
List<ActionItem> actionItems = new ArrayList<>();
|
||||
|
||||
for (String[] action : actions) {
|
||||
ActionItem actionItem = new ActionItem();
|
||||
actionItem.setName(action[0]);
|
||||
if (action.length > 1) {
|
||||
actionItem.setCondition(action[1]);
|
||||
}
|
||||
actionItems.add(actionItem);
|
||||
}
|
||||
|
||||
actionGroup.setActions(actionItems);
|
||||
|
||||
String xml = XMLViews.toXml(actionGroup, true);
|
||||
|
||||
metaService.updateMetaAction(name, "action-group", xml, null);
|
||||
|
||||
return actionGroup;
|
||||
}
|
||||
|
||||
public MetaJsonField getJsonField(String name, String type) {
|
||||
|
||||
MetaJsonField field = null;
|
||||
if (workflow.getIsJson()) {
|
||||
field =
|
||||
jsonFieldRepo
|
||||
.all()
|
||||
.filter(
|
||||
"self.isWkf = true "
|
||||
+ "and self.jsonModel.name = ?1 "
|
||||
+ "and self.name = ?2 and self.type = ?3",
|
||||
workflow.getModel(),
|
||||
name,
|
||||
type)
|
||||
.fetchOne();
|
||||
if (field == null) {
|
||||
field = new MetaJsonField();
|
||||
field.setModel(MetaJsonRecord.class.getName());
|
||||
field.setModelField("attrs");
|
||||
field.setJsonModel(jsonModelRepo.findByName(workflow.getModel()));
|
||||
}
|
||||
} else {
|
||||
field =
|
||||
jsonFieldRepo
|
||||
.all()
|
||||
.filter(
|
||||
"self.isWkf = true "
|
||||
+ "and self.model = :workflowModel "
|
||||
+ "and self.modelField = :workflowJsonField "
|
||||
+ "and self.name = :name and self.type = :type")
|
||||
.bind("workflowModel", workflow.getModel())
|
||||
.bind("workflowJsonField", workflow.getJsonField())
|
||||
.bind("name", name)
|
||||
.bind("type", type)
|
||||
.fetchOne();
|
||||
|
||||
log.debug(
|
||||
"Searching json field with model: {}, field: {}, name: {}, type: {}",
|
||||
workflow.getModel(),
|
||||
workflow.getJsonField(),
|
||||
name,
|
||||
type);
|
||||
if (field == null) {
|
||||
field = new MetaJsonField();
|
||||
field.setModel(workflow.getModel());
|
||||
field.setModelField(workflow.getJsonField());
|
||||
field.setName(name);
|
||||
}
|
||||
}
|
||||
|
||||
field.setType(type);
|
||||
field.setName(name);
|
||||
field.setIsWkf(true);
|
||||
field.setShowIf(applyCondition);
|
||||
|
||||
return saveJsonField(field);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public MetaJsonField saveJsonField(MetaJsonField jsonField) {
|
||||
|
||||
return jsonFieldRepo.save(jsonField);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void clearWkf(Wkf wkf) {
|
||||
|
||||
initService(wkf);
|
||||
|
||||
String actions = "action-" + wkfId + ",action-group" + wkfId;
|
||||
actions = clearFields(wkf, actions);
|
||||
|
||||
StringBuilder builder = new StringBuilder(actions);
|
||||
for (WkfNode node : wkf.getNodes()) {
|
||||
if (!node.getMetaActionSet().isEmpty()) {
|
||||
builder.append("," + nodeService.getActionName(node.getName()));
|
||||
}
|
||||
}
|
||||
builder.append(trackingAction);
|
||||
actions = builder.toString();
|
||||
|
||||
metaService.removeMetaActions(actions);
|
||||
|
||||
String select = getSelectName();
|
||||
MetaSelect metaSelect = metaSelectRepo.findByName(select);
|
||||
if (metaSelect != null) {
|
||||
metaSelectRepo.remove(metaSelect);
|
||||
}
|
||||
|
||||
MetaJsonField status = wkf.getStatusField();
|
||||
status.setWidget(null);
|
||||
status.setSelection(null);
|
||||
status.setWidgetAttrs(null);
|
||||
saveJsonField(status);
|
||||
|
||||
// setTrackOnSave(wkf, true);
|
||||
}
|
||||
|
||||
private String clearFields(Wkf wkf, String actions) {
|
||||
|
||||
List<MetaJsonField> fields = getFields(wkf);
|
||||
|
||||
StringBuilder builder = new StringBuilder(actions);
|
||||
for (MetaJsonField field : fields) {
|
||||
if (field.getIsWkf() && !field.equals(wkf.getStatusField())) {
|
||||
if (field.getOnClick() != null) {
|
||||
builder.append("," + field.getOnClick());
|
||||
}
|
||||
jsonFieldRepo.remove(field);
|
||||
}
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private List<MetaJsonField> getFields(Wkf wkf) {
|
||||
|
||||
List<MetaJsonField> fields;
|
||||
|
||||
String query = "self.isWkf = true and self.name LIKE '" + wkfId + "%' and ";
|
||||
|
||||
if (wkf.getIsJson()) {
|
||||
fields =
|
||||
jsonFieldRepo.all().filter(query + "self.jsonModel.name = ?1", wkf.getModel()).fetch();
|
||||
} else {
|
||||
fields =
|
||||
jsonFieldRepo
|
||||
.all()
|
||||
.filter(
|
||||
query + "self.model = ?1 and self.modelField = ?2",
|
||||
wkf.getModel(),
|
||||
wkf.getJsonField())
|
||||
.fetch();
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public String clearOldButtons(List<String> skipList) {
|
||||
|
||||
log.debug("Cleaning old buttons. Skip list: {}", skipList);
|
||||
if (skipList.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
skipList.add(wkfId + "TrackFlow");
|
||||
|
||||
ArrayList<String> actions = new ArrayList<>();
|
||||
|
||||
List<MetaJsonField> fields = null;
|
||||
if (workflow.getIsJson()) {
|
||||
fields =
|
||||
jsonFieldRepo
|
||||
.all()
|
||||
.filter(
|
||||
"self.type = 'button' "
|
||||
+ "and self.jsonModel.name = ?1 "
|
||||
+ "and self.isWkf = true "
|
||||
+ "and self.name not in (?2) "
|
||||
+ "and self.name LIKE ?3",
|
||||
workflow.getModel(),
|
||||
skipList,
|
||||
wkfId + "%")
|
||||
.fetch();
|
||||
} else {
|
||||
fields =
|
||||
jsonFieldRepo
|
||||
.all()
|
||||
.filter(
|
||||
"self.type = 'button' "
|
||||
+ "and self.model = ?1 "
|
||||
+ "and self.modelField = ?2 "
|
||||
+ "and self.name not in (?3) "
|
||||
+ "and self.name LIKE ?4",
|
||||
workflow.getModel(),
|
||||
workflow.getJsonField(),
|
||||
skipList,
|
||||
wkfId + "%")
|
||||
.fetch();
|
||||
}
|
||||
|
||||
log.debug("Total Buttons to remove: {}", fields.size());
|
||||
|
||||
Iterator<MetaJsonField> buttons = fields.iterator();
|
||||
|
||||
MetaJsonModel jsonModel = jsonModelRepo.findByName(workflow.getModel());
|
||||
while (buttons.hasNext()) {
|
||||
|
||||
MetaJsonField button = buttons.next();
|
||||
String onClick = button.getOnClick();
|
||||
log.debug("Removing button : {}, onClick: {}", button.getName(), onClick);
|
||||
|
||||
if (onClick != null) {
|
||||
for (String action : onClick.split(",")) {
|
||||
if (!action.equals("action-group" + wkfId)) {
|
||||
actions.add(action);
|
||||
}
|
||||
}
|
||||
}
|
||||
buttons.remove();
|
||||
jsonModel.getFields().remove(button);
|
||||
jsonFieldRepo.remove(button);
|
||||
}
|
||||
|
||||
return Joiner.on(",").join(actions);
|
||||
}
|
||||
|
||||
public void clearNodes(Collection<WkfNode> nodes) {
|
||||
|
||||
List<String> actions = new ArrayList<>();
|
||||
|
||||
for (WkfNode node : nodes) {
|
||||
if (workflow == null) {
|
||||
workflow = node.getWkf();
|
||||
inflector = Inflector.getInstance();
|
||||
}
|
||||
if (!node.getMetaActionSet().isEmpty()) {
|
||||
actions.add(nodeService.getActionName(node.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
metaService.removeMetaActions(Joiner.on(",").join(actions));
|
||||
}
|
||||
|
||||
// @Transactional
|
||||
// public void setTrackOnSave(Wkf wkf, boolean remove) {
|
||||
// if (wkf.getIsJson()) {
|
||||
// MetaJsonModel jsonModel = jsonModelRepo.findByName(wkf.getModel());
|
||||
// if (jsonModel != null) {
|
||||
// String onSave =
|
||||
// metaService.updateAction(
|
||||
// jsonModel.getOnSave(), "save," + trackingAction, remove);
|
||||
// jsonModel.setOnSave(onSave);
|
||||
// jsonModelRepo.save(jsonModel);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
@Transactional
|
||||
public void createTrackingAction() {
|
||||
|
||||
ActionMethod actionMethod = new ActionMethod();
|
||||
actionMethod.setName(trackingAction);
|
||||
Call call = new Call();
|
||||
call.setMethod("track(" + workflow.getId() + "," + "__self__)");
|
||||
call.setController("com.axelor.studio.service.wkf.WkfTrackingService");
|
||||
actionMethod.setCall(call);
|
||||
String xml = XMLViews.toXml(actionMethod, true);
|
||||
|
||||
metaService.updateMetaAction(trackingAction, "action-method", xml, null);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void setWkfSequence() {
|
||||
|
||||
Wkf wkf =
|
||||
wkfRepository
|
||||
.all()
|
||||
.filter("self.model = ?1", workflow.getModel())
|
||||
.order("wkfSequence")
|
||||
.fetchOne();
|
||||
|
||||
if (wkf.getId() != workflow.getId() && workflow.getWkfSequence() == 0) {
|
||||
workflow.setWkfSequence(wkf.getWkfSequence() - 50);
|
||||
wkfRepository.save(workflow);
|
||||
} else if (workflow.getWkfSequence() == 0) {
|
||||
workflow.setWkfSequence(-1);
|
||||
wkfRepository.save(workflow);
|
||||
}
|
||||
|
||||
wkfSequence = workflow.getWkfSequence();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,289 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.studio.service.wkf;
|
||||
|
||||
import com.axelor.db.EntityHelper;
|
||||
import com.axelor.db.Model;
|
||||
import com.axelor.meta.CallMethod;
|
||||
import com.axelor.meta.MetaStore;
|
||||
import com.axelor.meta.db.MetaJsonField;
|
||||
import com.axelor.meta.db.MetaJsonRecord;
|
||||
import com.axelor.meta.schema.views.Selection.Option;
|
||||
import com.axelor.rpc.Context;
|
||||
import com.axelor.rpc.JsonContext;
|
||||
import com.axelor.studio.db.Wkf;
|
||||
import com.axelor.studio.db.WkfTracking;
|
||||
import com.axelor.studio.db.WkfTrackingLine;
|
||||
import com.axelor.studio.db.WkfTrackingTime;
|
||||
import com.axelor.studio.db.WkfTrackingTotal;
|
||||
import com.axelor.studio.db.repo.WkfRepository;
|
||||
import com.axelor.studio.db.repo.WkfTrackingLineRepository;
|
||||
import com.axelor.studio.db.repo.WkfTrackingRepository;
|
||||
import com.axelor.studio.db.repo.WkfTrackingTimeRepository;
|
||||
import com.axelor.studio.db.repo.WkfTrackingTotalRepository;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDateTime;
|
||||
import javax.script.SimpleBindings;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Service handle tracking of workflow instance for particular record. Creates WkfTracking,
|
||||
* WkfTrackingLine, WkfTrackingTime and WkfTrackingTotal records.
|
||||
*
|
||||
* @author axelor
|
||||
*/
|
||||
public class WkfTrackingService {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||
|
||||
public static final String ACTION_TRACK = "action-method-wkf-track";
|
||||
|
||||
public static final String ACTION_OPEN_TRACK = "action-wkf-open-wkf-tracking";
|
||||
|
||||
@Inject private WkfRepository wkfRepo;
|
||||
|
||||
@Inject private WkfTrackingRepository wkfTrackingRepo;
|
||||
|
||||
@Inject private WkfTrackingLineRepository trackingLineRepo;
|
||||
|
||||
@Inject private WkfTrackingTotalRepository trackingTotalRepo;
|
||||
|
||||
@Inject private WkfTrackingTimeRepository trackingTimeRepo;
|
||||
|
||||
private BigDecimal durationHrs;
|
||||
|
||||
private String oldStatus;
|
||||
|
||||
/**
|
||||
* Root method to access the service. It creates WkfTracking record. WkfTracking is linked with
|
||||
* record of model and workflow of model.
|
||||
*
|
||||
* @param model Model having workflow.
|
||||
* @param modelId Record id of model to track.
|
||||
* @param status Current wkfStatus of record.
|
||||
* @throws ClassNotFoundException
|
||||
*/
|
||||
@CallMethod
|
||||
public void track(Long wkfId, Object object) {
|
||||
|
||||
if (object != null) {
|
||||
|
||||
SimpleBindings ctx = null;
|
||||
|
||||
object = EntityHelper.getEntity(object);
|
||||
Model model = (Model) object;
|
||||
|
||||
if (object instanceof MetaJsonRecord) {
|
||||
log.debug("Meta json record context");
|
||||
MetaJsonRecord metaJsonRecord = (MetaJsonRecord) object;
|
||||
log.debug(
|
||||
"Json id: {}, Json model: {}", metaJsonRecord.getId(), metaJsonRecord.getJsonModel());
|
||||
ctx = new JsonContext((MetaJsonRecord) object);
|
||||
ctx.put("id", metaJsonRecord.getId());
|
||||
ctx.put("jsonModel", metaJsonRecord.getJsonModel());
|
||||
} else {
|
||||
ctx = new Context(model.getId(), object.getClass());
|
||||
}
|
||||
ctx.put("wkfId", wkfId);
|
||||
WkfTracking wkfTracking = getWorkflowTracking(ctx, object.getClass().getName());
|
||||
|
||||
if (wkfTracking == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
MetaJsonField wkfField = wkfTracking.getWkf().getStatusField();
|
||||
|
||||
Object status = null;
|
||||
status = ctx.get(wkfField.getName());
|
||||
log.debug("Status value: {}", status);
|
||||
|
||||
if (status == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Option item = MetaStore.getSelectionItem(wkfField.getSelection(), status.toString());
|
||||
|
||||
log.debug("Fetching option {} from selection {}", status, wkfField.getSelection());
|
||||
if (item == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
durationHrs = BigDecimal.ZERO;
|
||||
WkfTrackingLine trackingLine = updateTrackingLine(wkfTracking, item.getTitle());
|
||||
if (trackingLine != null) {
|
||||
updateTrackingTotal(wkfTracking, item.getTitle());
|
||||
updateTrackingTime(wkfTracking, item.getTitle());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method find or create WkfTracking for model record.
|
||||
*
|
||||
* @param model Model of record.
|
||||
* @param modelId Id of record.
|
||||
* @return WkfTracking instance created/found.s
|
||||
*/
|
||||
@Transactional
|
||||
public WkfTracking getWorkflowTracking(SimpleBindings ctx, String model) {
|
||||
|
||||
String jsonModel = (String) ctx.get("jsonModel");
|
||||
|
||||
log.debug("Context json model: {}", jsonModel);
|
||||
|
||||
if (jsonModel != null) {
|
||||
model = jsonModel;
|
||||
}
|
||||
|
||||
Wkf wkf = wkfRepo.find((Long) ctx.get("wkfId"));
|
||||
|
||||
WkfTracking wkfTracking =
|
||||
wkfTrackingRepo
|
||||
.all()
|
||||
.filter(
|
||||
"self.wkf = ?1 and self.recordModel = ?2 and self.recordId = ?3",
|
||||
wkf,
|
||||
model,
|
||||
ctx.get("id"))
|
||||
.fetchOne();
|
||||
|
||||
if (wkfTracking == null) {
|
||||
wkfTracking = new WkfTracking();
|
||||
wkfTracking.setWkf(wkf);
|
||||
wkfTracking.setRecordModel(model);
|
||||
wkfTracking.setRecordId((Long) ctx.get("id"));
|
||||
wkfTracking = wkfTrackingRepo.save(wkfTracking);
|
||||
}
|
||||
|
||||
return wkfTracking;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method add new WkfTrackingLine in WkfTracking for given status if that status is not last
|
||||
* status added.
|
||||
*
|
||||
* @param wkfTracking WkfTracking to update with new line.
|
||||
* @param status Status to check for update.
|
||||
* @return WkfTrackingLine created or return null if status not changed.
|
||||
*/
|
||||
@Transactional
|
||||
public WkfTrackingLine updateTrackingLine(WkfTracking wkfTracking, String status) {
|
||||
|
||||
WkfTrackingLine trackingLine =
|
||||
trackingLineRepo.all().filter("self.wkfTracking = ?1", wkfTracking).fetchOne();
|
||||
|
||||
if (trackingLine == null || !trackingLine.getStatus().equals(status)) {
|
||||
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
|
||||
if (trackingLine != null) {
|
||||
oldStatus = trackingLine.getStatus();
|
||||
LocalDateTime lastUpdated = trackingLine.getCreatedOn();
|
||||
long minutes = Duration.between(lastUpdated, now).toMinutes();
|
||||
log.debug("Minutes between {} and {} : {}", lastUpdated, now, minutes);
|
||||
durationHrs = new BigDecimal(minutes).divide(new BigDecimal(60), 2, RoundingMode.HALF_UP);
|
||||
log.debug("Hours between {} and {} : {}", lastUpdated, now, durationHrs);
|
||||
trackingLine.setTimeSpent(durationHrs);
|
||||
trackingLineRepo.save(trackingLine);
|
||||
}
|
||||
|
||||
trackingLine = new WkfTrackingLine();
|
||||
trackingLine.setWkfTracking(wkfTracking);
|
||||
trackingLine.setStatus(status);
|
||||
trackingLine.setWkfTracking(wkfTracking);
|
||||
return trackingLineRepo.save(trackingLine);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update o2m to WkfTrackingTotal in WkfTracking. Create or Update WkfTrackingTotal for given
|
||||
* status with updated count of status.
|
||||
*
|
||||
* @param wkfTracking WkfTracking to update for WkfTrackingTotal.
|
||||
* @param status Status to check for total update.
|
||||
*/
|
||||
@Transactional
|
||||
public void updateTrackingTotal(WkfTracking wkfTracking, String status) {
|
||||
|
||||
WkfTrackingTotal trackingTotal =
|
||||
trackingTotalRepo
|
||||
.all()
|
||||
.filter("self.wkfTracking = :wkfTracking and self.status = :status")
|
||||
.bind("wkfTracking", wkfTracking)
|
||||
.bind("status", status)
|
||||
.fetchOne();
|
||||
|
||||
if (trackingTotal == null) {
|
||||
trackingTotal = new WkfTrackingTotal();
|
||||
trackingTotal.setWkfTracking(wkfTracking);
|
||||
trackingTotal.setTotalCount(0);
|
||||
trackingTotal.setStatus(status);
|
||||
}
|
||||
|
||||
trackingTotal.setTotalCount(trackingTotal.getTotalCount() + 1);
|
||||
|
||||
trackingTotalRepo.save(trackingTotal);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method create or update WkfTrackingTime record for given WkfTracking and status. For
|
||||
* existing WkfTrackingTime it update total time in days and hours.
|
||||
*
|
||||
* @param wkfTracking WkfTracking to update for WkfTrackingTime.
|
||||
* @param status Status to check for WkfTrackingTime.
|
||||
*/
|
||||
@Transactional
|
||||
public void updateTrackingTime(WkfTracking wkfTracking, String status) {
|
||||
|
||||
WkfTrackingTime trackingTime =
|
||||
trackingTimeRepo
|
||||
.all()
|
||||
.filter("self.wkfTracking = ?1 and self.status = ?2", wkfTracking, oldStatus)
|
||||
.fetchOne();
|
||||
|
||||
if (trackingTime != null) {
|
||||
BigDecimal days = durationHrs.divide(new BigDecimal(24), 2, RoundingMode.HALF_UP);
|
||||
BigDecimal totalTimeDays = trackingTime.getTotalTimeDays().add(days);
|
||||
trackingTime.setTotalTimeDays(totalTimeDays);
|
||||
BigDecimal totalTimeHrs = trackingTime.getTotalTimeHours().add(durationHrs);
|
||||
trackingTime.setTotalTimeHours(totalTimeHrs);
|
||||
trackingTimeRepo.save(trackingTime);
|
||||
}
|
||||
|
||||
trackingTime =
|
||||
trackingTimeRepo
|
||||
.all()
|
||||
.filter("self.wkfTracking = ?1 and self.status = ?2", wkfTracking, status)
|
||||
.fetchOne();
|
||||
|
||||
if (trackingTime == null) {
|
||||
trackingTime = new WkfTrackingTime();
|
||||
trackingTime.setWkfTracking(wkfTracking);
|
||||
trackingTime.setStatus(status);
|
||||
trackingTimeRepo.save(trackingTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,392 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.studio.service.wkf;
|
||||
|
||||
import com.axelor.auth.db.Role;
|
||||
import com.axelor.meta.db.MetaJsonField;
|
||||
import com.axelor.meta.db.MetaPermission;
|
||||
import com.axelor.meta.db.MetaPermissionRule;
|
||||
import com.axelor.meta.db.repo.MetaPermissionRepository;
|
||||
import com.axelor.meta.loader.XMLViews;
|
||||
import com.axelor.meta.schema.actions.ActionAttrs;
|
||||
import com.axelor.meta.schema.actions.ActionAttrs.Attribute;
|
||||
import com.axelor.meta.schema.actions.ActionValidate;
|
||||
import com.axelor.meta.schema.actions.ActionValidate.Alert;
|
||||
import com.axelor.meta.schema.actions.ActionValidate.Info;
|
||||
import com.axelor.meta.schema.actions.ActionValidate.Notify;
|
||||
import com.axelor.meta.schema.actions.ActionValidate.Validator;
|
||||
import com.axelor.studio.db.Filter;
|
||||
import com.axelor.studio.db.WkfTransition;
|
||||
import com.axelor.studio.service.StudioMetaService;
|
||||
import com.axelor.studio.service.filter.FilterGroovyService;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Service class handle processing of WkfTransition. It creates buttons and actions from
|
||||
* WkfTransition to change the status.
|
||||
*
|
||||
* @author axelor
|
||||
*/
|
||||
class WkfTransitionService {
|
||||
|
||||
private WkfService wkfService;
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||
|
||||
private List<String> wkfButtonNames;
|
||||
|
||||
@Inject private MetaPermissionRepository metaPermissionRepo;
|
||||
|
||||
@Inject private FilterGroovyService filterGroovyService;
|
||||
|
||||
@Inject private StudioMetaService metaService;
|
||||
|
||||
@Inject
|
||||
protected WkfTransitionService(WkfService wkfService) {
|
||||
this.wkfService = wkfService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Root method to access the service. Method call different method to process transition. Create
|
||||
* wkf action that call on save of model to update status. It save all changes to ViewBuilder
|
||||
* linked with Workflow.
|
||||
*/
|
||||
protected List<String[]> process() {
|
||||
|
||||
log.debug("Processing transitions");
|
||||
List<String[]> actions = new ArrayList<String[]>();
|
||||
|
||||
String action = "action-" + wkfService.wkfId;
|
||||
wkfButtonNames = new ArrayList<String>();
|
||||
|
||||
List<ActionAttrs.Attribute> fields = proccessTransitions();
|
||||
|
||||
if (!fields.isEmpty()) {
|
||||
String xml = getActionXML(action, fields);
|
||||
metaService.updateMetaAction(action, "action-attrs", xml, null);
|
||||
actions.add(new String[] {action});
|
||||
} else {
|
||||
metaService.removeMetaActions(action);
|
||||
}
|
||||
|
||||
String actionsToRemove = wkfService.clearOldButtons(wkfButtonNames);
|
||||
metaService.removeMetaActions(actionsToRemove);
|
||||
|
||||
return actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method process each WkfTransition and create RecordField. RecordField contains status and
|
||||
* condition to assign the status. Based on record fields wkf action will be created. It also add
|
||||
* button for transition if transition executed based on button.
|
||||
*
|
||||
* @return List of RecordField
|
||||
*/
|
||||
private List<ActionAttrs.Attribute> proccessTransitions() {
|
||||
|
||||
List<ActionAttrs.Attribute> fields = new ArrayList<ActionAttrs.Attribute>();
|
||||
|
||||
Integer buttonSeq = wkfService.wkfSequence - 46;
|
||||
|
||||
for (WkfTransition transition : wkfService.workflow.getTransitions()) {
|
||||
|
||||
MetaJsonField status = wkfService.workflow.getStatusField();
|
||||
String condition =
|
||||
status.getName() + " == " + getTyped(transition.getSource().getSequence(), status);
|
||||
|
||||
log.debug(
|
||||
"Processing transition : {}, isButton: {}",
|
||||
transition.getName(),
|
||||
transition.getIsButton());
|
||||
|
||||
String filters = getFilters(transition.getConditions());
|
||||
if (filters != null) {
|
||||
condition += " && (" + filters + ")";
|
||||
}
|
||||
|
||||
if (wkfService.applyCondition != null) {
|
||||
condition += " && " + wkfService.applyCondition;
|
||||
}
|
||||
|
||||
if (transition.getIsButton()) {
|
||||
buttonSeq++;
|
||||
addButton(transition, condition, buttonSeq);
|
||||
continue;
|
||||
}
|
||||
|
||||
log.debug("Conditions : {}", transition.getConditions());
|
||||
|
||||
ActionAttrs.Attribute attrs = new ActionAttrs.Attribute();
|
||||
attrs.setName("value");
|
||||
attrs.setFieldName(status.getName());
|
||||
attrs.setCondition(condition);
|
||||
attrs.setExpression("eval:" + getTyped(transition.getTarget().getSequence(), status));
|
||||
|
||||
fields.add(attrs);
|
||||
}
|
||||
|
||||
return fields;
|
||||
}
|
||||
|
||||
private String getFilters(List<Filter> filterList) {
|
||||
|
||||
String jsonField =
|
||||
wkfService.workflow.getIsJson() ? null : "$" + wkfService.workflow.getJsonField();
|
||||
if (jsonField != null && jsonField.equals("$attrs")) {
|
||||
jsonField = null;
|
||||
}
|
||||
String filters = filterGroovyService.getGroovyFilters(filterList, jsonField);
|
||||
log.debug("Filters : {}", filters);
|
||||
|
||||
return filters;
|
||||
}
|
||||
|
||||
private String getTyped(Integer value, MetaJsonField status) {
|
||||
|
||||
String typeName = status.getType();
|
||||
if (typeName.equals("integer")) {
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
return "'" + value + "'";
|
||||
}
|
||||
|
||||
/**
|
||||
* Create toolbar ViewButton in ViewBuilder from WkfTransition. Method called if WkfTransition is
|
||||
* based on button.
|
||||
*
|
||||
* @param viewBuilder ViewBuilder to update.
|
||||
* @param transition WkfTransition to process.
|
||||
* @param condition Condition to show button
|
||||
* @param sequence Sequence of button to add in toolbar.
|
||||
*/
|
||||
private void addButton(WkfTransition transition, String condition, Integer sequence) {
|
||||
|
||||
// String source = transition.getSource().getName();
|
||||
String title = transition.getButtonTitle();
|
||||
// String name = wkfService.inflector.camelize(source + "-" + title, true);
|
||||
// FIXME:Have to check if its working with import export of workflow.
|
||||
String name = wkfService.wkfId + "Transition" + transition.getId();
|
||||
if (name.equals("save") || name.equals("cancel") || name.equals("back")) {
|
||||
name = "wkf" + name;
|
||||
}
|
||||
wkfButtonNames.add(name);
|
||||
|
||||
MetaJsonField button = wkfService.getJsonField(name, "button");
|
||||
button.setTitle(title);
|
||||
button.setShowIf(condition);
|
||||
button.setSequence(sequence);
|
||||
button.setVisibleInGrid(false);
|
||||
button.setIsWkf(true);
|
||||
button.setWidgetAttrs("{\"colSpan\": \"" + transition.getColSpan() + "\"}");
|
||||
button.setOnClick(addButtonActions(transition, name));
|
||||
|
||||
if (transition.getRoleSet() != null) {
|
||||
Set<Role> buttonRoles = new HashSet<>();
|
||||
buttonRoles.addAll(transition.getRoleSet());
|
||||
button.setRoles(buttonRoles);
|
||||
}
|
||||
|
||||
log.debug("Adding button : {}", button.getName());
|
||||
wkfService.saveJsonField(button);
|
||||
|
||||
// String permName = this.wkfService.moduleName + "."
|
||||
// + wkfService.dasherizeModel.replace("-", ".") + name;
|
||||
// clearOldMetaPermissions(permName);
|
||||
// addButtonPermissions(permName, name, transition.getRoleSet());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Method create action for button from WkfTransition and related destination nodes. It set
|
||||
* onClick of ViewButton with new action created.
|
||||
*
|
||||
* @param viewButton ViewButton to update for onClick.
|
||||
* @param transition WkfTransition from where action created.
|
||||
* @param buttonName Name of button used in creation of action name.
|
||||
*/
|
||||
private String addButtonActions(WkfTransition transition, String buttonName) {
|
||||
|
||||
String actionName = buttonName.toLowerCase().replace(" ", "-");
|
||||
actionName = "action-" + wkfService.wkfId + "-" + actionName;
|
||||
List<String> actions = new ArrayList<String>();
|
||||
String xml = "";
|
||||
Integer alterType = transition.getAlertTypeSelect();
|
||||
String alertMsg = transition.getAlertMsg();
|
||||
if (alterType > 0 && alertMsg != null) {
|
||||
String type = "alert";
|
||||
if (alterType == 2) {
|
||||
type = "info";
|
||||
}
|
||||
String alertAction = actionName + "-alert";
|
||||
xml = getActionValidateXML(alertAction, type, alertMsg, transition.getConditions());
|
||||
metaService.updateMetaAction(alertAction, "action-validate", xml, null);
|
||||
actions.add(alertAction);
|
||||
}
|
||||
|
||||
List<Attribute> attrs = new ArrayList<Attribute>();
|
||||
Attribute attr = new Attribute();
|
||||
MetaJsonField wkfField = wkfService.workflow.getStatusField();
|
||||
attr.setName("value");
|
||||
attr.setFieldName(wkfField.getName());
|
||||
attr.setExpression("eval:" + getTyped(transition.getTarget().getSequence(), wkfField));
|
||||
attrs.add(attr);
|
||||
actions.add(actionName);
|
||||
xml = getActionXML(actionName, attrs);
|
||||
metaService.updateMetaAction(actionName, "action-record", xml, null);
|
||||
// actions.add("save");
|
||||
// actions.add(wkfService.trackingAction);
|
||||
|
||||
String successMsg = transition.getSuccessMsg();
|
||||
if (successMsg != null) {
|
||||
String sucessAction = actionName + "-success";
|
||||
xml = getActionValidateXML(sucessAction, "notify", successMsg, null);
|
||||
metaService.updateMetaAction(sucessAction, "action-validate", xml, null);
|
||||
actions.add(sucessAction);
|
||||
}
|
||||
actions.add("save");
|
||||
actions.add("action-group-" + wkfService.wkfId);
|
||||
// actions.add("save");
|
||||
// actions.add(wkfService.trackingAction);
|
||||
|
||||
return Joiner.on(",").join(actions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method create ActionRecord from given name and list of RecordField. It generate xml from
|
||||
* ActionRecord.
|
||||
*
|
||||
* @param name Name of action.
|
||||
* @param fields List of ActionRecord.
|
||||
* @return Xml of ActionRecord created.
|
||||
*/
|
||||
private String getActionXML(String name, List<Attribute> attrs) {
|
||||
|
||||
log.debug("Creating action attrs: {}", name);
|
||||
ActionAttrs action = new ActionAttrs();
|
||||
action.setName(name);
|
||||
action.setAttributes(attrs);
|
||||
|
||||
return XMLViews.toXml(action, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method create ActionValidate from given name,type and validation message.
|
||||
*
|
||||
* @param name Name of action
|
||||
* @param type Type of validate action ('notify','info' or 'alert').
|
||||
* @param message Message to display for action.
|
||||
* @return Xml generated from ActionValidate.
|
||||
*/
|
||||
private String getActionValidateXML(
|
||||
String name, String type, String message, List<Filter> conditions) {
|
||||
|
||||
ActionValidate actionValidate = new ActionValidate();
|
||||
actionValidate.setName(name);
|
||||
List<Validator> validators = new ArrayList<ActionValidate.Validator>();
|
||||
String condition = getFilters(conditions);
|
||||
switch (type) {
|
||||
case "notify":
|
||||
Notify notify = new Notify();
|
||||
notify.setMessage(message);
|
||||
notify.setCondition(condition);
|
||||
validators.add(notify);
|
||||
break;
|
||||
case "info":
|
||||
Info info = new Info();
|
||||
info.setMessage(message);
|
||||
info.setCondition(condition);
|
||||
validators.add(info);
|
||||
break;
|
||||
default:
|
||||
Alert alert = new Alert();
|
||||
alert.setMessage(message);
|
||||
alert.setCondition(condition);
|
||||
validators.add(alert);
|
||||
break;
|
||||
}
|
||||
|
||||
actionValidate.setValidators(validators);
|
||||
|
||||
return XMLViews.toXml(actionValidate, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create/Update MetaPermission for button and set this permission in roles.
|
||||
*
|
||||
* @param name Name of permission to create/update.
|
||||
* @param buttonName Name of button to add permission.
|
||||
* @param roles Roles to update with permission.
|
||||
*/
|
||||
@Transactional
|
||||
public void addButtonPermissions(String name, String buttonName, Set<Role> roles) {
|
||||
|
||||
if (roles == null || roles.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
MetaPermission permission = metaPermissionRepo.findByName(name);
|
||||
if (permission == null) {
|
||||
permission = new MetaPermission(name);
|
||||
permission.setObject(wkfService.workflow.getModel());
|
||||
MetaPermissionRule rule = new MetaPermissionRule();
|
||||
rule.setCanRead(false);
|
||||
rule.setField(buttonName);
|
||||
permission.addRule(rule);
|
||||
permission = metaPermissionRepo.save(permission);
|
||||
}
|
||||
|
||||
for (Role role : roles) {
|
||||
role.addMetaPermission(permission);
|
||||
wkfService.roleRepo.save(role);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear old button permission from all roles having it.
|
||||
*
|
||||
* @param name Name of permission to clear.
|
||||
*/
|
||||
@Transactional
|
||||
public void clearOldMetaPermissions(String name) {
|
||||
|
||||
MetaPermission permission = metaPermissionRepo.findByName(name);
|
||||
|
||||
if (permission != null) {
|
||||
List<Role> oldRoleList =
|
||||
wkfService
|
||||
.roleRepo
|
||||
.all()
|
||||
.filter("self.metaPermissions.id = ?1", permission.getId())
|
||||
.fetch();
|
||||
for (Role role : oldRoleList) {
|
||||
role.removeMetaPermission(permission);
|
||||
wkfService.roleRepo.save(role);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.studio.translation;
|
||||
|
||||
public interface ITranslation {
|
||||
|
||||
public static final String EDITOR_CHOOSE_APP = /*$$(*/ "Choose App name"; /*)*/
|
||||
public static final String EDITOR_BASE_MODEL = /*$$(*/ "Base model"; /*)*/
|
||||
public static final String EDITOR_CUSTOM_MODEL = /*$$(*/ "Custom Model"; /*)*/
|
||||
public static final String EDITOR_CUSTOM_FIELD = /*$$(*/ "Custom Field"; /*)*/
|
||||
public static final String EDITOR_STRING = /*$$(*/ "String"; /*)*/
|
||||
public static final String EDITOR_INTEGER = /*$$(*/ "Integer"; /*)*/
|
||||
public static final String EDITOR_PANEL = /*$$(*/ "Panel"; /*)*/
|
||||
public static final String EDITOR_BUTTON = /*$$(*/ "Button"; /*)*/
|
||||
public static final String EDITOR_DECIMAL = /*$$(*/ "Decimal"; /*)*/
|
||||
public static final String EDITOR_TIME = /*$$(*/ "Time"; /*)*/
|
||||
public static final String EDITOR_DATE = /*$$(*/ "Date"; /*)*/
|
||||
public static final String EDITOR_DATETIME = /*$$(*/ "Datetime"; /*)*/
|
||||
public static final String EDITOR_SEPARATOR = /*$$(*/ "Separator"; /*)*/
|
||||
public static final String EDITOR_BOOLEAN = /*$$(*/ "Boolean"; /*)*/
|
||||
public static final String EDITOR_M2O = /*$$(*/ "Many To One"; /*)*/
|
||||
public static final String EDITOR_M2M = /*$$(*/ "Many To Many"; /*)*/
|
||||
public static final String EDITOR_JM2M = /*$$(*/ "Json Many To Many"; /*)*/
|
||||
public static final String EDITOR_JM2O = /*$$(*/ "Json Many To One"; /*)*/
|
||||
public static final String EDITOR_JO2M = /*$$(*/ "Json One To Many"; /*)*/
|
||||
public static final String EDITOR_O2M = /*$$(*/ "One To Many"; /*)*/
|
||||
public static final String EDITOR_ONNEW = /*$$(*/ "On New"; /*)*/
|
||||
public static final String EDITOR_ONSAVE = /*$$(*/ "On Save"; /*)*/
|
||||
public static final String EDITOR_DEFAULT = /*$$(*/ "Default Value"; /*)*/
|
||||
public static final String EDITOR_SELECTION = /*$$(*/ "Selection"; /*)*/
|
||||
public static final String EDITOR_WIDGET = /*$$(*/ "Widget"; /*)*/
|
||||
public static final String EDITOR_HELP = /*$$(*/ "Help"; /*)*/
|
||||
public static final String EDITOR_REQUIRED = /*$$(*/ "Required"; /*)*/
|
||||
public static final String EDITOR_MIN_SIZE = /*$$(*/ "Min Size"; /*)*/
|
||||
public static final String EDITOR_MAX_SIZE = /*$$(*/ "Max Size"; /*)*/
|
||||
public static final String EDITOR_REGEX = /*$$(*/ "Regex"; /*)*/
|
||||
public static final String EDITOR_ONCHANGE = /*$$(*/ "On Change"; /*)*/
|
||||
public static final String EDITOR_COLSPAN = /*$$(*/ "Colspan"; /*)*/
|
||||
public static final String EDITOR_NAMEFIELD = /*$$(*/ "Name Field"; /*)*/
|
||||
public static final String EDITOR_ONCLICK = /*$$(*/ "On Click"; /*)*/
|
||||
public static final String EDITOR_HIDDEN_GRID = /*$$(*/ "Hidden In Grid"; /*)*/
|
||||
public static final String EDITOR_SHOW_IF = /*$$(*/ "Show If"; /*)*/
|
||||
public static final String EDITOR_REQUIRED_IF = /*$$(*/ "Required If"; /*)*/
|
||||
public static final String EDITOR_TYPE = /*$$(*/ "Type"; /*)*/
|
||||
public static final String EDITOR_META_MODEL = /*$$(*/ "Meta Model"; /*)*/
|
||||
public static final String EDITOR_DOMAIN = /*$$(*/ "Domain"; /*)*/
|
||||
public static final String EDITOR_TARGET_JSON = /*$$(*/ "Target Json Model"; /*)*/
|
||||
public static final String EDITOR_SELECT_OPT = /*$$(*/ "Select Option"; /*)*/
|
||||
public static final String EDITOR_PROP = /*$$(*/ "Properties"; /*)*/
|
||||
public static final String EDITOR_APP_NAME = /*$$(*/ "App name"; /*)*/
|
||||
public static final String EDITOR_SHOW_TITLE = /*$$(*/ "Show Title"; /*)*/
|
||||
public static final String EDITOR_NAME_COLUMN = /*$$(*/ "Name Column"; /*)*/
|
||||
public static final String EDITOR_CAN_COLLAPSE = /*$$(*/ "Can Collapse"; /*)*/
|
||||
public static final String EDITOR_COLLAPSE_IF = /*$$(*/ "Collapse if"; /*)*/
|
||||
public static final String EDITOR_FIELD_OPTIONS = /*$$(*/ "Field options"; /*)*/
|
||||
public static final String EDITOR_UI_OPTIONS = /*$$(*/ "UI options"; /*)*/
|
||||
public static final String EDITOR_IS_JSON_RELATIONAL_FIELD = /*$$(*/
|
||||
"Is Json Relational Field"; /*)*/
|
||||
|
||||
public static final String WKF_TRACK = /*$$(*/ "Track flow"; /*)*/
|
||||
public static final String WKF_EDIT_NODE = /*$$(*/ "Edit Node"; /*)*/
|
||||
public static final String WKF_EDIT_TRANSITION = /*$$(*/ "Edit Transition"; /*)*/
|
||||
|
||||
public static final String BPM_APP_NAME = /*$$(*/ "value:BPM"; /*)*/
|
||||
public static final String PRODUCT_APP_NAME = /*$$(*/ "value:Product App"; /*)*/
|
||||
}
|
||||
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.studio.web;
|
||||
|
||||
import com.axelor.common.Inflector;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.axelor.meta.db.MetaView;
|
||||
import com.axelor.meta.db.repo.MetaViewRepository;
|
||||
import com.axelor.rpc.ActionRequest;
|
||||
import com.axelor.rpc.ActionResponse;
|
||||
import com.axelor.studio.db.ActionBuilder;
|
||||
import com.axelor.studio.db.ActionBuilderView;
|
||||
import com.axelor.studio.db.repo.ActionBuilderRepository;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ActionBuilderController {
|
||||
|
||||
private Inflector inflector;
|
||||
|
||||
public void setViews(ActionRequest request, ActionResponse response) {
|
||||
|
||||
inflector = Inflector.getInstance();
|
||||
|
||||
ActionBuilder builder = request.getContext().asType(ActionBuilder.class);
|
||||
String model = builder.getModel();
|
||||
|
||||
boolean isJson = false;
|
||||
if (builder.getIsJson() != null) {
|
||||
isJson = builder.getIsJson();
|
||||
}
|
||||
if (builder.getTypeSelect() == ActionBuilderRepository.TYPE_SELECT_VIEW && model != null) {
|
||||
if (!isJson) {
|
||||
model = model.substring(model.lastIndexOf('.') + 1);
|
||||
model = inflector.dasherize(model);
|
||||
}
|
||||
List<ActionBuilderView> views = new ArrayList<>();
|
||||
addActionBuilderView(views, model, "grid", isJson, 0);
|
||||
addActionBuilderView(views, model, "form", isJson, 1);
|
||||
response.setValue("actionBuilderViews", views);
|
||||
}
|
||||
}
|
||||
|
||||
private void addActionBuilderView(
|
||||
List<ActionBuilderView> views, String model, String type, boolean isJson, int sequence) {
|
||||
|
||||
String viewName = model + "-" + type;
|
||||
if (isJson) {
|
||||
viewName = "custom-model-" + model + "-" + type;
|
||||
}
|
||||
|
||||
MetaView view = Beans.get(MetaViewRepository.class).findByName(viewName);
|
||||
if (view == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ActionBuilderView builderView = new ActionBuilderView();
|
||||
builderView.setViewName(view.getName());
|
||||
builderView.setViewType(view.getType());
|
||||
builderView.setSequence(sequence);
|
||||
|
||||
views.add(builderView);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.studio.web;
|
||||
|
||||
import com.axelor.data.Listener;
|
||||
import com.axelor.data.xml.XMLImporter;
|
||||
import com.axelor.db.Model;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.axelor.meta.MetaFiles;
|
||||
import com.axelor.meta.db.MetaFile;
|
||||
import com.axelor.meta.db.repo.MetaFileRepository;
|
||||
import com.axelor.rpc.ActionRequest;
|
||||
import com.axelor.rpc.ActionResponse;
|
||||
import com.google.common.io.Files;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Map;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.xmlbeans.impl.common.IOUtil;
|
||||
|
||||
public class AppBuilderController {
|
||||
|
||||
@Transactional
|
||||
public void importBpm(ActionRequest request, ActionResponse response) {
|
||||
|
||||
String config = "/data-import/import-bpm.xml";
|
||||
|
||||
try {
|
||||
InputStream inputStream = this.getClass().getResourceAsStream(config);
|
||||
File configFile = File.createTempFile("config", ".xml");
|
||||
FileOutputStream fout = new FileOutputStream(configFile);
|
||||
IOUtil.copyCompletely(inputStream, fout);
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
Path path =
|
||||
MetaFiles.getPath((String) ((Map) request.getContext().get("dataFile")).get("filePath"));
|
||||
File tempDir = Files.createTempDir();
|
||||
File importFile = new File(tempDir, "bpm.xml");
|
||||
Files.copy(path.toFile(), importFile);
|
||||
|
||||
XMLImporter importer =
|
||||
new XMLImporter(configFile.getAbsolutePath(), tempDir.getAbsolutePath());
|
||||
final StringBuilder log = new StringBuilder();
|
||||
Listener listner =
|
||||
new Listener() {
|
||||
|
||||
@Override
|
||||
public void imported(Integer imported, Integer total) {
|
||||
// log.append("Total records: " + total + ", Total imported: " + total);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void imported(Model arg0) {}
|
||||
|
||||
@Override
|
||||
public void handle(Model arg0, Exception err) {
|
||||
log.append("Error in import: " + err.getStackTrace().toString());
|
||||
}
|
||||
};
|
||||
|
||||
importer.addListener(listner);
|
||||
|
||||
importer.run();
|
||||
|
||||
FileUtils.forceDelete(configFile);
|
||||
|
||||
FileUtils.forceDelete(tempDir);
|
||||
|
||||
FileUtils.forceDelete(path.toFile());
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Object metaFileId = ((Map<String, Object>) request.getContext().get("dataFile")).get("id");
|
||||
MetaFileRepository metaFileRepository = Beans.get(MetaFileRepository.class);
|
||||
if (metaFileId != null) {
|
||||
MetaFile metaFile = metaFileRepository.find(Long.parseLong(metaFileId.toString()));
|
||||
if (metaFile != null) {
|
||||
metaFileRepository.remove(metaFile);
|
||||
}
|
||||
}
|
||||
|
||||
response.setValue("importLog", log.toString());
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.studio.web;
|
||||
|
||||
import com.axelor.common.Inflector;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.axelor.meta.db.MetaField;
|
||||
import com.axelor.meta.db.MetaJsonField;
|
||||
import com.axelor.meta.db.repo.MetaFieldRepository;
|
||||
import com.axelor.rpc.ActionRequest;
|
||||
import com.axelor.rpc.ActionResponse;
|
||||
import com.axelor.studio.db.Filter;
|
||||
import com.axelor.studio.service.filter.FilterSqlService;
|
||||
import java.util.Map;
|
||||
|
||||
public class FilterController {
|
||||
|
||||
public void updateTargetField(ActionRequest request, ActionResponse response) {
|
||||
|
||||
Filter filter = request.getContext().asType(Filter.class);
|
||||
|
||||
MetaField metaField = filter.getMetaField();
|
||||
MetaJsonField metaJson = filter.getMetaJsonField();
|
||||
|
||||
Boolean isJson = filter.getIsJson() != null ? filter.getIsJson() : false;
|
||||
|
||||
if (!isJson && metaField != null) {
|
||||
String type =
|
||||
metaField.getRelationship() != null
|
||||
? metaField.getRelationship()
|
||||
: metaField.getTypeName();
|
||||
response.setValue("targetType", type);
|
||||
response.setValue("targetField", metaField.getName());
|
||||
response.setValue(
|
||||
"targetTitle",
|
||||
metaField.getLabel() != null && !metaField.getLabel().isEmpty()
|
||||
? metaField.getLabel()
|
||||
: metaField.getName());
|
||||
} else if (isJson && metaJson != null) {
|
||||
response.setValue("targetType", Inflector.getInstance().camelize(metaJson.getType()));
|
||||
response.setValue("targetField", metaJson.getName());
|
||||
} else {
|
||||
response.setValue("targetField", null);
|
||||
response.setValue("targetType", null);
|
||||
}
|
||||
|
||||
response.setValue("operator", null);
|
||||
}
|
||||
|
||||
public void updateTargetType(ActionRequest request, ActionResponse response)
|
||||
throws AxelorException {
|
||||
|
||||
Filter filter = request.getContext().asType(Filter.class);
|
||||
FilterSqlService filterSqlService = Beans.get(FilterSqlService.class);
|
||||
|
||||
if (filter.getTargetField() == null) return;
|
||||
|
||||
StringBuilder parent = new StringBuilder("self");
|
||||
String targetType =
|
||||
filterSqlService.getTargetType(
|
||||
filterSqlService.getTargetField(parent, filter, null, false));
|
||||
|
||||
response.setValue("targetType", targetType);
|
||||
response.setValue("filterOperator", null);
|
||||
}
|
||||
|
||||
public void updateTargetMetaField(ActionRequest request, ActionResponse response) {
|
||||
|
||||
Filter filter = request.getContext().asType(Filter.class);
|
||||
|
||||
if (request.getContext().get("targetMetaField") != null) {
|
||||
Integer id = (Integer) ((Map) request.getContext().get("targetMetaField")).get("id");
|
||||
MetaField targetMetaField = Beans.get(MetaFieldRepository.class).find(Long.valueOf(id));
|
||||
|
||||
String targetTitle =
|
||||
targetMetaField.getLabel() != null && !targetMetaField.getLabel().isEmpty()
|
||||
? targetMetaField.getLabel()
|
||||
: targetMetaField.getName();
|
||||
response.setValue("targetField", filter.getTargetField() + "." + targetMetaField.getName());
|
||||
response.setValue("targetTitle", filter.getTargetTitle() + "." + targetTitle);
|
||||
response.setValue(
|
||||
"targetType",
|
||||
targetMetaField.getRelationship() != null
|
||||
? targetMetaField.getRelationship()
|
||||
: targetMetaField.getTypeName());
|
||||
|
||||
if (targetMetaField.getRelationship() != null) {
|
||||
response.setValue("metaTargetFieldDomain", targetMetaField.getTypeName());
|
||||
response.setValue("targetMetaField", null);
|
||||
}
|
||||
}
|
||||
response.setValue("operator", null);
|
||||
}
|
||||
|
||||
public void clearSelection(ActionRequest request, ActionResponse response) {
|
||||
|
||||
Filter filter = request.getContext().asType(Filter.class);
|
||||
|
||||
if (filter.getMetaField() != null) {
|
||||
response.setValue("targetField", filter.getMetaField().getName());
|
||||
response.setValue(
|
||||
"targetTitle",
|
||||
filter.getMetaField().getLabel() != null && !filter.getMetaField().getLabel().isEmpty()
|
||||
? filter.getMetaField().getLabel()
|
||||
: filter.getMetaField().getName());
|
||||
response.setValue("targetType", filter.getMetaField().getRelationship());
|
||||
}
|
||||
response.setValue("metaTargetFieldDomain", null);
|
||||
response.setValue("targetMetaField", null);
|
||||
response.setValue("operator", null);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.studio.web;
|
||||
|
||||
import com.axelor.inject.Beans;
|
||||
import com.axelor.meta.db.MetaMenu;
|
||||
import com.axelor.meta.db.repo.MetaMenuRepository;
|
||||
import com.axelor.rpc.ActionRequest;
|
||||
import com.axelor.rpc.ActionResponse;
|
||||
import com.axelor.rpc.Context;
|
||||
import com.axelor.studio.db.ActionBuilder;
|
||||
import com.axelor.studio.service.builder.MenuBuilderService;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
public class MenuBuilderController {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void fetchMenu(ActionRequest request, ActionResponse response) {
|
||||
|
||||
Context context = request.getContext();
|
||||
|
||||
Map<String, Object> values = null;
|
||||
Map<String, Object> existingMenu = (Map<String, Object>) context.get("existingMenu");
|
||||
if (existingMenu == null) {
|
||||
values = getEmptyMenu();
|
||||
} else {
|
||||
Long menuId = Long.parseLong(existingMenu.get("id").toString());
|
||||
values = getMenu(Beans.get(MetaMenuRepository.class).find(menuId));
|
||||
}
|
||||
|
||||
response.setValues(values);
|
||||
}
|
||||
|
||||
private Map<String, Object> getMenu(MetaMenu menu) {
|
||||
|
||||
Map<String, Object> values = new HashMap<>();
|
||||
values.put("name", menu.getName());
|
||||
values.put("title", menu.getTitle());
|
||||
values.put("icon", menu.getIcon());
|
||||
values.put("iconBackground", menu.getIconBackground());
|
||||
values.put("order", menu.getOrder());
|
||||
values.put("conditionToCheck", menu.getConditionToCheck());
|
||||
values.put("parentMenu", menu.getParent());
|
||||
values.put("tag", menu.getTag());
|
||||
values.put("tagGet", menu.getTagGet());
|
||||
values.put("tagCount", menu.getTagCount());
|
||||
values.put("tagStyle", menu.getTagStyle());
|
||||
values.put("groups", menu.getGroups());
|
||||
values.put("top", menu.getTop());
|
||||
values.put("roles", menu.getRoles());
|
||||
values.put("conditionTocheck", menu.getConditionToCheck());
|
||||
values.put("link", menu.getLink());
|
||||
values.put("left", menu.getLeft());
|
||||
values.put("mobile", menu.getMobile());
|
||||
values.put("hidden", menu.getHidden());
|
||||
|
||||
if (menu.getAction() != null && menu.getAction().getType().contentEquals("action-view")) {
|
||||
Optional<ActionBuilder> actionBuilderOpt =
|
||||
Beans.get(MenuBuilderService.class).createActionBuilder(menu.getAction());
|
||||
actionBuilderOpt.ifPresent(
|
||||
actionBuilder -> {
|
||||
values.put("actionBuilder", actionBuilder);
|
||||
values.put("showAction", true);
|
||||
});
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
private Map<String, Object> getEmptyMenu() {
|
||||
|
||||
Map<String, Object> values = new HashMap<>();
|
||||
values.put("name", null);
|
||||
values.put("title", null);
|
||||
values.put("icon", null);
|
||||
values.put("iconBackground", null);
|
||||
values.put("order", null);
|
||||
values.put("conditionToCheck", null);
|
||||
values.put("parentMenu", null);
|
||||
values.put("tag", null);
|
||||
values.put("tagGet", null);
|
||||
values.put("tagCount", null);
|
||||
values.put("tagStyle", null);
|
||||
values.put("groups", null);
|
||||
values.put("top", null);
|
||||
values.put("roles", null);
|
||||
values.put("conditionTocheck", null);
|
||||
values.put("link", null);
|
||||
values.put("left", null);
|
||||
values.put("mobile", null);
|
||||
values.put("hidden", null);
|
||||
values.put("actionBuilder", null);
|
||||
values.put("showAction", false);
|
||||
|
||||
return values;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.studio.web;
|
||||
|
||||
import com.axelor.inject.Beans;
|
||||
import com.axelor.meta.db.MetaJsonModel;
|
||||
import com.axelor.meta.schema.actions.ActionView;
|
||||
import com.axelor.meta.schema.actions.ActionView.ActionViewBuilder;
|
||||
import com.axelor.rpc.ActionRequest;
|
||||
import com.axelor.rpc.ActionResponse;
|
||||
import com.axelor.studio.db.Wkf;
|
||||
import com.axelor.studio.db.repo.WkfRepository;
|
||||
|
||||
public class MetaJsonModelController {
|
||||
|
||||
public void openWorkflow(ActionRequest request, ActionResponse response) {
|
||||
|
||||
MetaJsonModel jsonModel = request.getContext().asType(MetaJsonModel.class);
|
||||
|
||||
Wkf wkf =
|
||||
Beans.get(WkfRepository.class)
|
||||
.all()
|
||||
.filter("self.model = ?1", jsonModel.getName())
|
||||
.fetchOne();
|
||||
|
||||
ActionViewBuilder builder =
|
||||
ActionView.define("Workflow").add("form", "wkf-form").model("com.axelor.studio.db.Wkf");
|
||||
|
||||
if (wkf == null) {
|
||||
builder.context("_jsonModel", jsonModel.getName());
|
||||
} else {
|
||||
builder.context("_showRecord", wkf.getId());
|
||||
}
|
||||
|
||||
response.setView(builder.map());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,254 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.studio.web;
|
||||
|
||||
import com.axelor.common.Inflector;
|
||||
import com.axelor.exception.service.TraceBackService;
|
||||
import com.axelor.i18n.I18n;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.axelor.meta.MetaStore;
|
||||
import com.axelor.meta.db.MetaJsonField;
|
||||
import com.axelor.meta.schema.actions.ActionView;
|
||||
import com.axelor.meta.schema.views.Selection.Option;
|
||||
import com.axelor.rpc.ActionRequest;
|
||||
import com.axelor.rpc.ActionResponse;
|
||||
import com.axelor.studio.db.Wkf;
|
||||
import com.axelor.studio.db.WkfNode;
|
||||
import com.axelor.studio.db.WkfTransition;
|
||||
import com.axelor.studio.db.repo.WkfNodeRepository;
|
||||
import com.axelor.studio.db.repo.WkfRepository;
|
||||
import com.axelor.studio.db.repo.WkfTransitionRepository;
|
||||
import com.axelor.studio.exception.IExceptionMessage;
|
||||
import com.axelor.studio.service.wkf.WkfDesignerService;
|
||||
import com.axelor.studio.service.wkf.WkfService;
|
||||
import com.axelor.studio.translation.ITranslation;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
public class WkfController {
|
||||
|
||||
public void processXml(ActionRequest request, ActionResponse response) {
|
||||
try {
|
||||
Wkf workflow = request.getContext().asType(Wkf.class);
|
||||
workflow = Beans.get(WkfRepository.class).find(workflow.getId());
|
||||
Beans.get(WkfDesignerService.class).processXml(workflow);
|
||||
} catch (Exception e) {
|
||||
TraceBackService.trace(response, e);
|
||||
}
|
||||
}
|
||||
|
||||
public void processWkf(ActionRequest request, ActionResponse response) {
|
||||
try {
|
||||
Wkf workflow = request.getContext().asType(Wkf.class);
|
||||
workflow = Beans.get(WkfRepository.class).find(workflow.getId());
|
||||
Beans.get(WkfService.class).process(workflow);
|
||||
response.setReload(true);
|
||||
} catch (Exception e) {
|
||||
TraceBackService.trace(response, e);
|
||||
}
|
||||
}
|
||||
|
||||
public void onNodeEdit(ActionRequest request, ActionResponse response) {
|
||||
try {
|
||||
WkfNodeRepository repo = Beans.get(WkfNodeRepository.class);
|
||||
WkfNode node = request.getContext().asType(WkfNode.class);
|
||||
if (node.getWkf().getId() != null) {
|
||||
WkfNode found =
|
||||
repo.all()
|
||||
.filter(
|
||||
"self.wkf.id = ? and self.xmlId = ?", node.getWkf().getId(), node.getXmlId())
|
||||
.fetchOne();
|
||||
if (found != null) {
|
||||
Map<String, Object> view =
|
||||
ActionView.define(I18n.get(ITranslation.WKF_EDIT_NODE))
|
||||
.add("form", "wkf-node-form")
|
||||
.model(WkfNode.class.getName())
|
||||
.context("_showRecord", found.getId())
|
||||
.param("popup", "true")
|
||||
.param("show-toolbar", "false")
|
||||
.param("forceEdit", "true")
|
||||
.map();
|
||||
response.setView(view);
|
||||
} else {
|
||||
response.setFlash(I18n.get(IExceptionMessage.WKF_1));
|
||||
}
|
||||
} else {
|
||||
response.setFlash(I18n.get(IExceptionMessage.WKF_1));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
TraceBackService.trace(response, e);
|
||||
}
|
||||
}
|
||||
|
||||
public void onTransitionEdit(ActionRequest request, ActionResponse response) {
|
||||
try {
|
||||
WkfTransitionRepository repo = Beans.get(WkfTransitionRepository.class);
|
||||
WkfTransition transition = request.getContext().asType(WkfTransition.class);
|
||||
WkfTransition found = repo.all().filter("self.xmlId = ?", transition.getXmlId()).fetchOne();
|
||||
if (found != null) {
|
||||
|
||||
Map<String, Object> view =
|
||||
ActionView.define(I18n.get(ITranslation.WKF_EDIT_TRANSITION))
|
||||
.add("form", "wkf-transition-form")
|
||||
.model(WkfTransition.class.getName())
|
||||
.context("_showRecord", found.getId())
|
||||
.param("popup", "true")
|
||||
.param("show-toolbar", "false")
|
||||
.param("forceEdit", "true")
|
||||
.map();
|
||||
|
||||
response.setView(view);
|
||||
} else {
|
||||
response.setFlash(I18n.get(IExceptionMessage.WKF_1));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
TraceBackService.trace(response, e);
|
||||
}
|
||||
}
|
||||
|
||||
public void setDefaultNodes(ActionRequest request, ActionResponse response) {
|
||||
|
||||
Wkf wkf = request.getContext().asType(Wkf.class);
|
||||
|
||||
MetaJsonField wkfField = wkf.getStatusField();
|
||||
|
||||
if (wkfField != null) {
|
||||
|
||||
Optional<Pair<String, String>> nodesOpt = getDefaultNodes(wkfField);
|
||||
nodesOpt.ifPresent(
|
||||
nodes -> {
|
||||
String bpmnXml =
|
||||
" <?xml version=\"1.0\" encoding=\"UTF-8\"?> "
|
||||
+ "<definitions xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
|
||||
+ "xmlns=\"http://www.omg.org/spec/BPMN/20100524/MODEL\" "
|
||||
+ "xmlns:x=\"http://axelor.com\" xmlns:bpmndi=\"http://www.omg.org/spec/BPMN/20100524/DI\" "
|
||||
+ "xmlns:dc=\"http://www.omg.org/spec/DD/20100524/DC\" "
|
||||
+ "targetNamespace=\"http://bpmn.io/schema/bpmn\" id=\"Definitions_1\"> "
|
||||
+ "<process id=\"Process_1\" name=\""
|
||||
+ wkf.getName()
|
||||
+ "\" x:id=\""
|
||||
+ wkf.getId()
|
||||
+ "\" isExecutable=\"false\"> "
|
||||
+ nodes.getLeft()
|
||||
+ "</process>"
|
||||
+ "<bpmndi:BPMNDiagram id=\"BPMNDiagram_1\">"
|
||||
+ "<bpmndi:BPMNPlane id=\"BPMNPlane_1\" bpmnElement=\"Process_1\">"
|
||||
+ nodes.getRight()
|
||||
+ "</bpmndi:BPMNPlane>"
|
||||
+ "</bpmndi:BPMNDiagram>"
|
||||
+ "</definitions>";
|
||||
response.setValue("$bpmnDefault", bpmnXml);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private Optional<Pair<String, String>> getDefaultNodes(MetaJsonField statusField) {
|
||||
|
||||
// String[] nodes = new String[] {
|
||||
// "<startEvent id=\"StartEvent_1\" /><task id=\"Task_1\" /><endEvent id=\"EndEvent_1\"/>",
|
||||
// "<bpmndi:BPMNShape id=\"_BPMNShape_StartEvent_2\" bpmnElement=\"StartEvent_1\">"
|
||||
// + "<dc:Bounds x=\"100\" y=\"100\" width=\"36\" height=\"36\"/>"
|
||||
// + "</bpmndi:BPMNShape>"
|
||||
// + "<bpmndi:BPMNShape id=\"_BPMNShape_Task_1\" bpmnElement=\"Task_1\">"
|
||||
// + "<dc:Bounds x=\"250\" y=\"100\" width=\"100\" height=\"80\"/>"
|
||||
// + "</bpmndi:BPMNShape>"
|
||||
// + "<bpmndi:BPMNShape id=\"_BPMNShape_EndEvent_2\" bpmnElement=\"EndEvent_1\">"
|
||||
// + "<dc:Bounds x=\"500\" y=\"100\" width=\"36\" height=\"36\"/>"
|
||||
// + "</bpmndi:BPMNShape>"
|
||||
// };
|
||||
//
|
||||
List<Option> select = getSelect(statusField);
|
||||
|
||||
if (!CollectionUtils.isEmpty(select)) {
|
||||
StringBuilder elements = new StringBuilder();
|
||||
StringBuilder designs = new StringBuilder();
|
||||
int count = 1;
|
||||
int x = 100;
|
||||
int y;
|
||||
for (Option option : select) {
|
||||
String element = null;
|
||||
int width = 100;
|
||||
int height = 80;
|
||||
if (count == 1) {
|
||||
width = 36;
|
||||
height = 36;
|
||||
y = 125;
|
||||
element = "startEvent";
|
||||
} else if (count == select.size()) {
|
||||
width = 36;
|
||||
height = 36;
|
||||
x += 150;
|
||||
y = 125;
|
||||
element = "endEvent";
|
||||
} else {
|
||||
y = 100;
|
||||
x += 150;
|
||||
element = "task";
|
||||
}
|
||||
|
||||
String elementId = Inflector.getInstance().camelize(element, false) + "_" + count;
|
||||
element = "<" + element + " id=\"" + elementId + "\" name=\"" + option.getTitle() + "\" />";
|
||||
elements.append(element);
|
||||
|
||||
String design =
|
||||
"<bpmndi:BPMNShape id=\"_BPMNShape_"
|
||||
+ elementId
|
||||
+ "\" bpmnElement=\""
|
||||
+ elementId
|
||||
+ "\" >"
|
||||
+ "<dc:Bounds x=\""
|
||||
+ x
|
||||
+ "\" y=\""
|
||||
+ y
|
||||
+ "\" width=\""
|
||||
+ width
|
||||
+ "\" height=\""
|
||||
+ height
|
||||
+ "\" />"
|
||||
+ "</bpmndi:BPMNShape>";
|
||||
|
||||
designs.append(design);
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
if (elements.length() > 0) {
|
||||
return Optional.of(Pair.of(elements.toString(), designs.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private List<Option> getSelect(MetaJsonField wkfField) {
|
||||
|
||||
if (wkfField == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
if (wkfField.getSelection() != null) {
|
||||
return MetaStore.getSelectionList(wkfField.getSelection());
|
||||
}
|
||||
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,514 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<bpm>
|
||||
<% allApps = com.axelor.inject.Beans.get('com.axelor.studio.db.repo.AppBuilderRepository' as Class).all()
|
||||
|
||||
allModels = com.axelor.inject.Beans.get('com.axelor.meta.db.repo.MetaJsonModelRepository' as Class).all()
|
||||
|
||||
allFields = com.axelor.inject.Beans.get('com.axelor.meta.db.repo.MetaJsonFieldRepository' as Class).all()
|
||||
|
||||
allSelections = com.axelor.inject.Beans.get('com.axelor.meta.db.repo.MetaSelectRepository' as Class).all()
|
||||
|
||||
allCharts = com.axelor.inject.Beans.get('com.axelor.studio.db.repo.ChartBuilderRepository' as Class).all()
|
||||
|
||||
allDashboards = com.axelor.inject.Beans.get('com.axelor.studio.db.repo.DashboardBuilderRepository' as Class).all()
|
||||
|
||||
allDashlets = com.axelor.inject.Beans.get('com.axelor.studio.db.repo.DashletBuilderRepository' as Class).all()
|
||||
|
||||
allActions = com.axelor.inject.Beans.get('com.axelor.studio.db.repo.ActionBuilderRepository' as Class).all()
|
||||
|
||||
allMenus = com.axelor.inject.Beans.get('com.axelor.studio.db.repo.MenuBuilderRepository' as Class).all()
|
||||
|
||||
allMenusParentMenu = com.axelor.inject.Beans.get('com.axelor.studio.db.repo.MenuBuilderRepository' as Class).all()
|
||||
|
||||
allWkfs = com.axelor.inject.Beans.get('com.axelor.studio.db.repo.WkfRepository' as Class).all()
|
||||
|
||||
if(__ids__ != null) {
|
||||
allApps = allApps.filter('self.id in ?1',__ids__)
|
||||
|
||||
allModels = allModels.filter('self.appBuilder.id in ?1',__ids__)
|
||||
|
||||
allFields = allFields.filter('self.appBuilder.id in ?1 OR (self.appBuilder is null and self.jsonModel.appBuilder.id in ?1)',__ids__)
|
||||
|
||||
allSelections = allSelections.filter('(self.appBuilder.id in ?1 OR self.appBuilder is null) AND self.isCustom = true',__ids__)
|
||||
|
||||
allCharts = allCharts.filter('self.appBuilder.id in ?1',__ids__)
|
||||
|
||||
allDashboards = allDashboards.filter('self.appBuilder.id in ?1',__ids__)
|
||||
|
||||
allDashlets = allDashlets.filter('self.appBuilder.id in ?1 or (self.appBuilder is null and self.dashboardBuilder.appBuilder.id in ?1)',__ids__)
|
||||
|
||||
allActions = allActions.filter('self.appBuilder.id in ?1)',__ids__)
|
||||
|
||||
allMenus = allMenus.filter('self.appBuilder.id in ?1 and self.parentMenu is null)',__ids__).order('-parentMenu')
|
||||
|
||||
allMenusParentMenu = allMenusParentMenu.filter('self.appBuilder.id in ?1 and self.parentMenu is not null',__ids__)
|
||||
|
||||
allWkfs = allWkfs.filter('self.appBuilder.id in ?1)',__ids__)
|
||||
} else {
|
||||
allSelections = allSelections.filter('self.isCustom = true')
|
||||
|
||||
allMenus = allMenus.filter('self.parentMenu is null')
|
||||
|
||||
allMenusParentMenu = allMenusParentMenu.filter('self.parentMenu is not null')
|
||||
}
|
||||
|
||||
apps = ""
|
||||
allApps.fetch().each({
|
||||
depends = ""
|
||||
it.dependsOnSet?.each({ depend -> depends +="${depend.code}," })
|
||||
|
||||
apps += """\n\t<appBuilder>
|
||||
<name>${it.name}</name>
|
||||
<code>${it.code}</code>
|
||||
<description>${it.description}</description>
|
||||
<depends>$depends</depends>
|
||||
<image name=\"${it.image?.fileName}\">${com.axelor.studio.service.ExportService.getImage(it.image)}</image>
|
||||
<sequence>${it.sequence}</sequence>
|
||||
\n\t</appBuilder>"""
|
||||
})
|
||||
|
||||
models = ""
|
||||
allModels.fetch().each({
|
||||
model -> models += """\n\t\t<model>
|
||||
\n\t\t\t<name>${model.name}</name>
|
||||
\n\t\t\t<title>${model.title}</title>
|
||||
\n\t\t\t<onNew>${model.onNew}</onNew>
|
||||
\n\t\t\t<onSave>${model.onSave}</onSave>
|
||||
\n\t\t\t<menuTitle>${model.menuTitle}</menuTitle>
|
||||
\n\t\t\t<menuIcon>${model.menuIcon}</menuIcon>
|
||||
\n\t\t\t<menuBackground>${model.menuBackground}</menuBackground>
|
||||
\n\t\t\t<menuOrder>${model.menuOrder}</menuOrder>
|
||||
\n\t\t\t<menuTop>${model.menuTop}</menuTop>
|
||||
\n\t\t\t<menuParent>${model.menuParent?.id}</menuParent>
|
||||
\n\t\t\t<appBuilder>${model.appBuilder?.code}</appBuilder>
|
||||
\n\t\t</model>"""
|
||||
})
|
||||
|
||||
fields = ""
|
||||
allFields.fetch().each({
|
||||
field -> fields += """\n\t\t<field>
|
||||
\n\t\t\t<name>${field.name}</name>
|
||||
\n\t\t\t<title>${field.title}</title>
|
||||
\n\t\t\t<type>${field.type}</type>
|
||||
\n\t\t\t<defaultValue>${field.defaultValue}</defaultValue>
|
||||
\n\t\t\t<domain>${field.domain}</domain>
|
||||
\n\t\t\t<enumType>${field.enumType}</enumType>
|
||||
\n\t\t\t<help>${field.help}</help>
|
||||
\n\t\t\t<formView>${field.formView}</formView>
|
||||
\n\t\t\t<gridView>${field.gridView}</gridView>
|
||||
\n\t\t\t<hidden>${field.hidden}</hidden>
|
||||
\n\t\t\t<visibleInGrid>${field.visibleInGrid}</visibleInGrid>
|
||||
\n\t\t\t<hideIf>${field.hideIf}</hideIf>
|
||||
\n\t\t\t<isWkf>${field.isWkf}</isWkf>
|
||||
\n\t\t\t<maxSize>${field.maxSize}</maxSize>
|
||||
\n\t\t\t<minSize>${field.minSize}</minSize>
|
||||
\n\t\t\t<model>${field.model}</model>
|
||||
\n\t\t\t<modelField>${field.modelField}</modelField>
|
||||
\n\t\t\t<nameField>${field.nameField}</nameField>
|
||||
\n\t\t\t<onChange>${field.onChange}</onChange>
|
||||
\n\t\t\t<onClick>${field.onClick}</onClick>
|
||||
\n\t\t\t<precision>${field.precision}</precision>
|
||||
\n\t\t\t<regex>${field.regex}</regex>
|
||||
\n\t\t\t<required>${field.required}</required>
|
||||
\n\t\t\t<requiredIf>${field.requiredIf}</requiredIf>
|
||||
\n\t\t\t<readonly>${field.readonly}</readonly>
|
||||
\n\t\t\t<scale>${field.scale}</scale>
|
||||
\n\t\t\t<selection>${field.selection}</selection>
|
||||
\n\t\t\t<sequence>${field.sequence}</sequence>
|
||||
\n\t\t\t<showIf>${field.showIf}</showIf>
|
||||
\n\t\t\t<targetModel>${field.targetModel}</targetModel>
|
||||
\n\t\t\t<widget>${field.widget}</widget>
|
||||
\n\t\t\t<widgetAttrs>""" + field.widgetAttrs + """</widgetAttrs>
|
||||
\n\t\t\t<valueExpr>${field.valueExpr != null ? """ + field.valueExpr + """ : ""}</valueExpr>
|
||||
\n\t\t\t<jsonModel>${field.jsonModel?.name}</jsonModel>
|
||||
\n\t\t\t<targetJsonModel>${field.targetJsonModel?.name}</targetJsonModel>
|
||||
\n\t\t\t<appBuilder>${field.appBuilder?.code}</appBuilder>
|
||||
\n\t\t\t<modelAppBuilder>${field.jsonModel?.appBuilder?.code}</modelAppBuilder>
|
||||
\n\t\t</field>"""
|
||||
})
|
||||
|
||||
selections = ""
|
||||
allSelections.fetch().each({
|
||||
selection ->
|
||||
options = ""
|
||||
selection.items.each{
|
||||
option -> options += """\n\t\t\t\t<option>
|
||||
\n\t\t\t\t\t<title>${option.title}</title>
|
||||
\n\t\t\t\t\t<value>${option.value}</value>
|
||||
\n\t\t\t\t\t<icon>${option.icon}</icon>
|
||||
\n\t\t\t\t\t<data>${option.data}</data>
|
||||
\n\t\t\t\t\t<order>${option.order}</order>
|
||||
\n\t\t\t\t\t<hidden>${option.hidden}</hidden>
|
||||
\n\t\t\t\t\t<select>${option.select?.name}</select>
|
||||
\n\t\t\t\t</option>"""
|
||||
}
|
||||
|
||||
selections += """\n\t\t<selection>
|
||||
\n\t\t\t<name>${selection.name}</name>
|
||||
\n\t\t\t<module>${selection.module}</module>
|
||||
\n\t\t\t<priority>${selection.priority}</priority>
|
||||
\n\t\t\t<items>$options
|
||||
\n\t\t\t</items>
|
||||
\n\t\t\t<isCustom>${selection.isCustom}</isCustom>
|
||||
\n\t\t\t<appBuilder>${selection.appBuilder?.code}</appBuilder>
|
||||
\n\t\t</selection>"""
|
||||
})
|
||||
|
||||
charts = ""
|
||||
allCharts.fetch().each({
|
||||
chart ->
|
||||
filters = ""
|
||||
chart.filterList.each{
|
||||
filter->filters += """\n\t\t\t\t<filter>
|
||||
\n\t\t\t\t\t<metaField>${filter.metaField?.name}</metaField>
|
||||
\n\t\t\t\t\t<metaJsonField>${filter.metaJsonField?.name}</metaJsonField>
|
||||
\n\t\t\t\t\t<operator>${filter.operator}</operator>
|
||||
\n\t\t\t\t\t<targetField>${filter.targetField}</targetField>
|
||||
\n\t\t\t\t\t<targetType>${filter.targetType}</targetType>
|
||||
\n\t\t\t\t\t<value>${filter.value}</value>
|
||||
\n\t\t\t\t\t<defaultValue>${filter.defaultValue}</defaultValue>
|
||||
\n\t\t\t\t\t<isParameter>${filter.isParameter}</isParameter>
|
||||
\n\t\t\t\t\t<isJson>${filter.isJson}</isJson>
|
||||
\n\t\t\t\t\t<isTargetJson>${filter.isTargetJson}</isTargetJson>
|
||||
\n\t\t\t\t\t<logicOp>${filter.logicOp}</logicOp>
|
||||
\n\t\t\t\t</filter>"""
|
||||
}
|
||||
|
||||
charts += """\n\t\t<chartBuilder>
|
||||
\n\t\t\t<name>${chart.name}</name>
|
||||
\n\t\t\t<title>${chart.title}</title>
|
||||
\n\t\t\t<chartType>${chart.chartType}</chartType>
|
||||
\n\t\t\t<isJson>${chart.isJson}</isJson>
|
||||
\n\t\t\t<model>${chart.model}</model>
|
||||
\n\t\t\t<groupOn>${chart.groupOn?.name}</groupOn>
|
||||
\n\t\t\t<groupOnJson>${chart.groupOnJson?.name}</groupOnJson>
|
||||
\n\t\t\t<groupDateType>${chart.groupDateType}</groupDateType>
|
||||
\n\t\t\t<groupOnTarget>${chart.groupOnTarget}</groupOnTarget>
|
||||
\n\t\t\t<groupOnTargetType>${chart.groupOnTargetType}</groupOnTargetType>
|
||||
\n\t\t\t<isJsonGroupOn>${chart.isJsonGroupOn}</isJsonGroupOn>
|
||||
\n\t\t\t<isJsonAggregateOn>${chart.isJsonAggregateOn}</isJsonAggregateOn>
|
||||
\n\t\t\t<isJsonDisplayField>${chart.isJsonDisplayField}</isJsonDisplayField>
|
||||
\n\t\t\t<aggregateOnJson>${chart.aggregateOnJson?.name}</aggregateOnJson>
|
||||
\n\t\t\t<aggregateOn>${chart.aggregateOn?.name}</aggregateOn>
|
||||
\n\t\t\t<aggregateOnTarget>${chart.aggregateOnTarget}</aggregateOnTarget>
|
||||
\n\t\t\t<aggregateDateType>${chart.aggregateDateType}</aggregateDateType>
|
||||
\n\t\t\t<aggregateOnTargetType>${chart.aggregateOnTargetType}</aggregateOnTargetType>
|
||||
\n\t\t\t<displayField>${chart.displayField?.name}</displayField>
|
||||
\n\t\t\t<displayFieldJson>${chart.displayFieldJson?.name}</displayFieldJson>
|
||||
\n\t\t\t<displayType>${chart.displayType}</displayType>
|
||||
\n\t\t\t<filters>$filters
|
||||
\n\t\t\t</filters>
|
||||
\n\t\t\t<appBuilder>${chart.appBuilder?.code}</appBuilder>
|
||||
\n\t\t</chartBuilder>"""
|
||||
})
|
||||
|
||||
dashboards = ""
|
||||
allDashboards.fetch().each({
|
||||
dashboard ->
|
||||
dashboards += """\n\t\t<dashboardBuilder>
|
||||
\n\t\t\t<name>${dashboard.name}</name>
|
||||
\n\t\t\t<title>${dashboard.title}</title>
|
||||
\n\t\t\t<model>${dashboard.model}</model>
|
||||
\n\t\t\t<appBuilder>${dashboard.appBuilder?.code}</appBuilder>
|
||||
\n\t\t</dashboardBuilder>"""
|
||||
|
||||
})
|
||||
|
||||
dashlets = ""
|
||||
allDashlets.fetch().each({
|
||||
dashlet ->
|
||||
dashlets += """\n\t\t<dashletBuilder>
|
||||
\n\t\t\t<name>${dashlet.name}</name>
|
||||
\n\t\t\t<metaView>${dashlet.metaView?.name}</metaView>
|
||||
\n\t\t\t<action>${dashlet.action?.name}</action>
|
||||
\n\t\t\t<dashboardBuilder>${dashlet.dashboardBuilder?.name}</dashboardBuilder>
|
||||
\n\t\t\t<sequence>${dashlet.sequence}</sequence>
|
||||
\n\t\t\t<viewType>${dashlet.viewType}</viewType>
|
||||
\n\t\t\t<colspan>${dashlet.colspan}</colspan>
|
||||
\n\t\t\t<paginationLimit>${dashlet.paginationLimit}</paginationLimit>
|
||||
\n\t\t\t<appBuilder>${dashlet.appBuilder?.code}</appBuilder>
|
||||
\n\t\t\t<parentAppBuilder>${dashlet.dashboardBuilder.appBuilder?.code}</parentAppBuilder>
|
||||
\n\t\t</dashletBuilder>"""
|
||||
|
||||
})
|
||||
|
||||
actions = ""
|
||||
allActions.fetch().each({
|
||||
action ->
|
||||
lines = com.axelor.studio.service.ExportService.exportActionBuilderLines(action.lines, 4)
|
||||
|
||||
viewParams = com.axelor.studio.service.ExportService.exportActionBuilderLines(action.viewParams, 4)
|
||||
|
||||
views = ""
|
||||
action.actionBuilderViews.each{
|
||||
view->views += """\n\t\t\t\t<view>
|
||||
\n\t\t\t\t\t<viewType>${view.viewType}</viewType>
|
||||
\n\t\t\t\t\t<viewName>${view.viewName}</viewName>
|
||||
\n\t\t\t\t\t<sequence>${view.sequence}</sequence>
|
||||
\n\t\t\t\t</view>"""
|
||||
}
|
||||
|
||||
actions += """\n\t\t<actionBuilder>
|
||||
\n\t\t\t<name>${action.name}</name>
|
||||
\n\t\t\t<typeSelect>${action.typeSelect}</typeSelect>
|
||||
\n\t\t\t<model>${action.model}</model>
|
||||
\n\t\t\t<targetModel>${action.targetModel}</targetModel>
|
||||
\n\t\t\t<lines>$lines
|
||||
\n\t\t\t</lines>
|
||||
\n\t\t\t<title>${action.title}</title>
|
||||
\n\t\t\t<transactional>${action.transactional}</transactional>
|
||||
\n\t\t\t<scriptType>${action.scriptType}</scriptType>
|
||||
\n\t\t\t<scriptText>${action.scriptText}</scriptText>
|
||||
\n\t\t\t<actionBuilderViews>$views
|
||||
\n\t\t\t</actionBuilderViews>
|
||||
\n\t\t\t<isJson>${action.isJson}</isJson>
|
||||
\n\t\t\t<domainCondition>${action.domainCondition}</domainCondition>
|
||||
\n\t\t\t<viewParams>$viewParams
|
||||
\n\t\t\t</viewParams>
|
||||
\n\t\t\t<menuAction>${action.menuAction}</menuAction>
|
||||
\n\t\t\t<appBuilder>${action.appBuilder?.code}</appBuilder>
|
||||
\n\t\t</actionBuilder>"""
|
||||
|
||||
})
|
||||
|
||||
menus = ""
|
||||
allMenus.fetch().each({
|
||||
menu ->
|
||||
groups = ""
|
||||
menu.groups.each{
|
||||
group -> groups += """\n\t\t\t\t<group>${group.code}</group>"""
|
||||
}
|
||||
|
||||
roles = ""
|
||||
menu.roles.each{
|
||||
role -> roles += """\n\t\t\t\t<role>${role.name}</role>"""
|
||||
}
|
||||
|
||||
menus += """\n\t\t<menuBuilder>
|
||||
\n\t\t\t<name>${menu.name}</name>
|
||||
\n\t\t\t<title>${menu.title}</title>
|
||||
\n\t\t\t<icon>${menu.icon}</icon>
|
||||
\n\t\t\t<iconBackground>${menu.iconBackground}</iconBackground>
|
||||
\n\t\t\t<order>${menu.order}</order>
|
||||
\n\t\t\t<tag>${menu.tag}</tag>
|
||||
\n\t\t\t<tagGet>${menu.tagGet}</tagGet>
|
||||
\n\t\t\t<tagCount>${menu.tagCount}</tagCount>
|
||||
\n\t\t\t<tagStyle>${menu.tagStyle}</tagStyle>
|
||||
\n\t\t\t<top>${menu.top}</top>
|
||||
\n\t\t\t<left>${menu.left}</left>
|
||||
\n\t\t\t<mobile>${menu.mobile}</mobile>
|
||||
\n\t\t\t<hidden>${menu.hidden}</hidden>
|
||||
\n\t\t\t<link>${menu.link}</link>
|
||||
\n\t\t\t<conditionToCheck>${menu.conditionToCheck}</conditionToCheck>
|
||||
\n\t\t\t<moduleToCheck>${menu.moduleToCheck}</moduleToCheck>
|
||||
\n\t\t\t<showAction>${menu.showAction}</showAction>
|
||||
\n\t\t\t<groups>$groups
|
||||
\n\t\t\t</groups>
|
||||
\n\t\t\t<roles>$roles
|
||||
\n\t\t\t</roles>
|
||||
\n\t\t\t<parentMenu>${menu.parentMenu?.name}</parentMenu>
|
||||
\n\t\t\t<actionBuilder>${menu.actionBuilder?.name}</actionBuilder>
|
||||
\n\t\t\t<appBuilder>${menu.appBuilder?.code}</appBuilder>
|
||||
\n\t\t</menuBuilder>"""
|
||||
|
||||
})
|
||||
|
||||
allMenusParentMenu.fetch().each({
|
||||
menu ->
|
||||
groups = ""
|
||||
menu.groups.each{
|
||||
group -> groups += """\n\t\t\t\t<group>${group.code}</group>"""
|
||||
}
|
||||
|
||||
roles = ""
|
||||
menu.roles.each{
|
||||
role -> roles += """\n\t\t\t\t<role>${role.name}</role>"""
|
||||
}
|
||||
|
||||
menus += """\n\t\t<menuBuilder>
|
||||
\n\t\t\t<name>${menu.name}</name>
|
||||
\n\t\t\t<title>${menu.title}</title>
|
||||
\n\t\t\t<icon>${menu.icon}</icon>
|
||||
\n\t\t\t<iconBackground>${menu.iconBackground}</iconBackground>
|
||||
\n\t\t\t<order>${menu.order}</order>
|
||||
\n\t\t\t<tag>${menu.tag}</tag>
|
||||
\n\t\t\t<tagGet>${menu.tagGet}</tagGet>
|
||||
\n\t\t\t<tagCount>${menu.tagCount}</tagCount>
|
||||
\n\t\t\t<tagStyle>${menu.tagStyle}</tagStyle>
|
||||
\n\t\t\t<top>${menu.top}</top>
|
||||
\n\t\t\t<left>${menu.left}</left>
|
||||
\n\t\t\t<mobile>${menu.mobile}</mobile>
|
||||
\n\t\t\t<hidden>${menu.hidden}</hidden>
|
||||
\n\t\t\t<link>${menu.link}</link>
|
||||
\n\t\t\t<conditionToCheck>${menu.conditionToCheck}</conditionToCheck>
|
||||
\n\t\t\t<moduleToCheck>${menu.moduleToCheck}</moduleToCheck>
|
||||
\n\t\t\t<showAction>${menu.showAction}</showAction>
|
||||
\n\t\t\t<groups>$groups
|
||||
\n\t\t\t</groups>
|
||||
\n\t\t\t<roles>$roles
|
||||
\n\t\t\t</roles>
|
||||
\n\t\t\t<parentMenu>${menu.parentMenu?.name}</parentMenu>
|
||||
\n\t\t\t<actionBuilder>${menu.actionBuilder?.name}</actionBuilder>
|
||||
\n\t\t\t<appBuilder>${menu.appBuilder?.code}</appBuilder>
|
||||
\n\t\t</menuBuilder>"""
|
||||
|
||||
})
|
||||
|
||||
wkfs = ""
|
||||
nodes = ""
|
||||
transitions = ""
|
||||
allWkfs.fetch().each({
|
||||
wkf ->
|
||||
wkf.nodes.each{
|
||||
node ->
|
||||
node = com.axelor.inject.Beans.get('com.axelor.studio.db.repo.WkfNodeRepository' as Class).find(node.id)
|
||||
incoming = ""
|
||||
node.incoming.each{
|
||||
incom -> incoming += """\n\t\t\t<incoming>${incom.name}</incoming>"""
|
||||
}
|
||||
|
||||
outgoing = ""
|
||||
node.outgoing.each{
|
||||
outg -> outgoing += """\n\t\t\t\t<outgoing>${outg.name}</outgoing>"""
|
||||
}
|
||||
|
||||
roles = ""
|
||||
node.roleSet.each{
|
||||
role -> roles += """\n\t\t\t<role>${role.name}</role>"""
|
||||
}
|
||||
|
||||
metaActions = ""
|
||||
node.metaActionSet.each{
|
||||
action -> metaActions += """\n\t\t\t<action>${action.name}</action>"""
|
||||
}
|
||||
|
||||
nodes += """\n\t\t\t<node>
|
||||
\n\t\t\t<wkf>${node.wkf.name}</wkf>
|
||||
\n\t\t\t<name>${node.name}</name>
|
||||
\n\t\t\t<title>${node.title}</title>
|
||||
\n\t\t\t<xmlId>${node.xmlId}</xmlId>
|
||||
\n\t\t\t<metaField>${node.metaField?.name}</metaField>
|
||||
\n\t\t\t<metaFieldModel>${node.metaField?.metaModel?.name}</metaFieldModel>
|
||||
\n\t\t\t<incomings>$incoming
|
||||
\n\t\t\t</incomings>
|
||||
\n\t\t\t<outgoings>$outgoing
|
||||
\n\t\t\t</outgoings>
|
||||
\n\t\t\t<roleSet>$roles
|
||||
\n\t\t\t</roleSet>
|
||||
\n\t\t\t<metaActionSet>$metaActions
|
||||
\n\t\t\t</metaActionSet>
|
||||
\n\t\t\t<sequence>${node.sequence}</sequence>
|
||||
\n\t\t\t<nodeType>${node.nodeType}</nodeType>
|
||||
\n\t\t\t</node>"""
|
||||
}
|
||||
|
||||
wkf.transitions.each{
|
||||
transition ->
|
||||
conditions = ""
|
||||
transition = com.axelor.inject.Beans.get('com.axelor.studio.db.repo.WkfTransitionRepository' as Class).find(transition.id)
|
||||
transition.conditions.each{
|
||||
condition-> conditions += """\n\t\t\t<condition>
|
||||
\n\t\t\t\t<metaField>${condition.metaField?.name}</metaField>
|
||||
\n\t\t\t\t<metaModel>${condition.metaField?.metaModel?.name}</metaModel>
|
||||
\n\t\t\t\t<metaJsonField>${condition.metaJsonField?.name}</metaJsonField>
|
||||
\n\t\t\t\t<jsonModel>${condition.metaJsonField?.jsonModel?.name}</jsonModel>
|
||||
\n\t\t\t\t<operator>${condition.operator}</operator>
|
||||
\n\t\t\t\t<targetField>${condition.targetField}</targetField>
|
||||
\n\t\t\t\t<targetType>${condition.targetType}</targetType>
|
||||
\n\t\t\t\t<value>${condition.value}</value>
|
||||
\n\t\t\t\t<isTargetJson>${condition.isTargetJson}</isTargetJson>
|
||||
\n\t\t\t\t<logicOp>${condition.logicOp}</logicOp>
|
||||
\n\t\t\t\t<model>${condition.metaJsonField?.model}</model>
|
||||
\n\t\t\t\t<modelField>${condition.metaJsonField?.modelField}</modelField>
|
||||
\n\t\t\t</condition>"""
|
||||
}
|
||||
|
||||
roles = ""
|
||||
transition.roleSet.each{
|
||||
role -> roles += """\n\t\t\t\t<role>${role.name}</role>"""
|
||||
}
|
||||
|
||||
|
||||
transitions += """\n\t\t\t<transition>
|
||||
\n\t\t\t<wkf>${transition.wkf.name}</wkf>
|
||||
\n\t\t\t<name>${transition.name}</name>
|
||||
\n\t\t\t<xmlId>${transition.xmlId}</xmlId>
|
||||
\n\t\t\t<isButton>${transition.isButton}</isButton>
|
||||
\n\t\t\t<buttonTitle>${transition.buttonTitle}</buttonTitle>
|
||||
\n\t\t\t<roleSet>$roles
|
||||
\n\t\t\t</roleSet>
|
||||
\n\t\t\t<conditions>$conditions
|
||||
\n\t\t\t</conditions>
|
||||
\n\t\t\t<source>${transition.source?.name}</source>
|
||||
\n\t\t\t<target>${transition.target?.name}</target>
|
||||
\n\t\t\t<alertTypeSelect>${transition.alertTypeSelect}</alertTypeSelect>
|
||||
\n\t\t\t<alertMsg>${transition.alertMsg}</alertMsg>
|
||||
\n\t\t\t<successMsg>${transition.successMsg}</successMsg>
|
||||
\n\t\t\t</transition>"""
|
||||
}
|
||||
|
||||
wkfs += """\n\t\t<wkf>
|
||||
\n\t\t\t<name>${wkf.name}</name>
|
||||
\n\t\t\t<model>${wkf.model}</model>
|
||||
\n\t\t\t<jsonField>${wkf.jsonField}</jsonField>
|
||||
\n\t\t\t<isJson>${wkf.isJson}</isJson>
|
||||
\n\t\t\t<isTrackFlow>${wkf.isTrackFlow}</isTrackFlow>
|
||||
\n\t\t\t<statusField>${wkf.statusField?.name}</statusField>
|
||||
\n\t\t\t<displayTypeSelect>${wkf.displayTypeSelect}</displayTypeSelect>
|
||||
\n\t\t\t<bpmnXml><![CDATA[""" + wkf.bpmnXml + """]]></bpmnXml>
|
||||
\n\t\t\t<appBuilder>${wkf.appBuilder.code}</appBuilder>
|
||||
\n\t\t</wkf>"""
|
||||
|
||||
})
|
||||
|
||||
out <<
|
||||
"""
|
||||
$apps
|
||||
|
||||
<models>
|
||||
$models
|
||||
</models>
|
||||
|
||||
<fields>
|
||||
$fields
|
||||
</fields>
|
||||
|
||||
<selections>
|
||||
$selections
|
||||
</selections>
|
||||
|
||||
<chartBuilders>
|
||||
$charts
|
||||
</chartBuilders>
|
||||
|
||||
<actionBuilders>
|
||||
$actions
|
||||
</actionBuilders>
|
||||
|
||||
<dashboardBuilders>
|
||||
$dashboards
|
||||
</dashboardBuilders>
|
||||
|
||||
<dashletBuilders>
|
||||
$dashlets
|
||||
</dashletBuilders>
|
||||
|
||||
<menuBuilders>
|
||||
$menus
|
||||
</menuBuilders>
|
||||
|
||||
<wkfs>
|
||||
$wkfs
|
||||
</wkfs>
|
||||
|
||||
<nodes>
|
||||
$nodes
|
||||
</nodes>
|
||||
|
||||
<transitions>
|
||||
$transitions
|
||||
</transitions>
|
||||
|
||||
"""
|
||||
%>
|
||||
</bpm>
|
||||
@ -0,0 +1,409 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xml-inputs xmlns="http://axelor.com/xml/ns/data-import"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://axelor.com/xml/ns/data-import http://axelor.com/xml/ns/data-import/data-import_5.2.xsd">
|
||||
|
||||
<input file="bpm.xml" root="bpm" >
|
||||
<bind node="appBuilder" type="com.axelor.studio.db.AppBuilder" search="self.code = :code" update="true" call="com.axelor.studio.service.ImportService:importAppBuilderImg">
|
||||
<bind node="name" to="name" />
|
||||
<bind node="code" to="code" />
|
||||
<bind node="description" to="description" />
|
||||
<bind node="sequence" to="sequence" />
|
||||
<bind node="image/@name" alias="fileName"/>
|
||||
<bind node="image" alias="imageData" />
|
||||
</bind>
|
||||
<bind node="appBuilder" type="com.axelor.studio.db.AppBuilder" search="self.code = :code" create="false" update="true" call="com.axelor.studio.service.ImportService:importAppBuilder">
|
||||
<bind node="code" to="code" />
|
||||
<bind node="depends" alias="depends" />
|
||||
<bind to="dependsOnSet" alias="deps" search="self.code in :deps" eval="depends != null ? depends.split(',') as List : []" create="false"/>
|
||||
</bind>
|
||||
<bind node="models/model" type="com.axelor.meta.db.MetaJsonModel" search="self.name = :name" update="true">
|
||||
<bind node="name" to="name" />
|
||||
<bind node="title" to="title" />
|
||||
<bind node="onNew" to="onNew" />
|
||||
<bind node="onSave" to="onSave" />
|
||||
<bind node="menuTitle" to="menuTitle" />
|
||||
<bind node="menuIcon" to="menuIcon" />
|
||||
<bind node="menuBackground" to="menuBackground" />
|
||||
<bind node="menuOrder" to="menuOrder" />
|
||||
<bind node="menuTop" to="menuTop" />
|
||||
<bind node="menuParent" to="menuParent" search="self.id = :menuParent" create="false" />
|
||||
<bind node="appBuilder" to="appBuilder" search="self.code = :appBuilder" create="false" />
|
||||
</bind>
|
||||
<bind node="fields/field" type="com.axelor.meta.db.MetaJsonField" if="jsonModel != null && !jsonModel.empty"
|
||||
search="self.name = :name and self.model = :model and self.modelField = :modelField and self.jsonModel.name = :jsonModel"
|
||||
call="com.axelor.studio.service.ImportService:importJsonModelField" update="true">
|
||||
<bind node="name" to="name" />
|
||||
<bind node="title" to="title" />
|
||||
<bind node="type" to="type" />
|
||||
<bind node="defaultValue" to="defaultValue" />
|
||||
<bind node="domain" to="domain" />
|
||||
<bind node="enumType" to="enumType" />
|
||||
<bind node="help" to="help" />
|
||||
<bind node="formView" to="formView" />
|
||||
<bind node="gridView" to="gridView" />
|
||||
<bind node="hidden" to="hidden" />
|
||||
<bind node="visibleInGrid" to="visibleInGrid" />
|
||||
<bind node="hideIf" to="hideIf" />
|
||||
<bind node="isWkf" to="isWkf" />
|
||||
<bind node="maxSize" to="maxSize" />
|
||||
<bind node="minSize" to="minSize" />
|
||||
<bind node="model" to="model" />
|
||||
<bind node="modelField" to="modelField" />
|
||||
<bind node="nameField" to="nameField" />
|
||||
<bind node="onChange" to="onChange" />
|
||||
<bind node="onClick" to="onClick" />
|
||||
<bind node="precision" to="precision" />
|
||||
<bind node="regex" to="regex" />
|
||||
<bind node="required" to="required" />
|
||||
<bind node="requiredIf" to="requiredIf" />
|
||||
<bind node="readonly" to="readonly" />
|
||||
<bind node="scale" to="scale" />
|
||||
<bind node="selection" to="selection" />
|
||||
<bind node="sequence" to="sequence" />
|
||||
<bind node="showIf" to="showIf" />
|
||||
<bind node="targetModel" to="targetModel" />
|
||||
<bind node="widget" to="widget" />
|
||||
<bind node="widgetAttrs" to="widgetAttrs" />
|
||||
<bind node="valueExpr" to="valueExpr"/>
|
||||
<bind node="jsonModel" to="jsonModel" search="self.name = :jsonModel" update="true" alias="jsonModel" create="false" />
|
||||
<bind node="targetJsonModel" to="targetJsonModel" search="self.name = :targetJsonModel" update="true" create="false" />
|
||||
<bind node="appBuilder" to="appBuilder" search="self.code = :appBuilder" create="false" />
|
||||
<bind node="modelAppBuilder" alias="modelAppBuilder" />
|
||||
</bind>
|
||||
|
||||
<bind node="fields/field" type="com.axelor.meta.db.MetaJsonField" if="jsonModel == null"
|
||||
search="self.name = :name and self.model = :model and self.modelField = :modelField and self.jsonModel is null"
|
||||
call="com.axelor.studio.service.ImportService:importJsonField" update="true">
|
||||
<bind node="name" to="name" />
|
||||
<bind node="title" to="title" />
|
||||
<bind node="type" to="type" />
|
||||
<bind node="defaultValue" to="defaultValue" />
|
||||
<bind node="domain" to="domain" />
|
||||
<bind node="enumType" to="enumType" />
|
||||
<bind node="help" to="help" />
|
||||
<bind node="formView" to="formView" />
|
||||
<bind node="gridView" to="gridView" />
|
||||
<bind node="hidden" to="hidden" />
|
||||
<bind node="visibleInGrid" to="visibleInGrid" />
|
||||
<bind node="hideIf" to="hideIf" />
|
||||
<bind node="isWkf" to="isWkf" />
|
||||
<bind node="maxSize" to="maxSize" />
|
||||
<bind node="minSize" to="minSize" />
|
||||
<bind node="model" to="model" />
|
||||
<bind node="modelField" to="modelField" />
|
||||
<bind node="nameField" to="nameField" />
|
||||
<bind node="onChange" to="onChange" />
|
||||
<bind node="onClick" to="onClick" />
|
||||
<bind node="precision" to="precision" />
|
||||
<bind node="regex" to="regex" />
|
||||
<bind node="required" to="required" />
|
||||
<bind node="requiredIf" to="requiredIf" />
|
||||
<bind node="readonly" to="readonly" />
|
||||
<bind node="scale" to="scale" />
|
||||
<bind node="selection" to="selection" />
|
||||
<bind node="sequence" to="sequence" />
|
||||
<bind node="showIf" to="showIf" />
|
||||
<bind node="targetModel" to="targetModel" />
|
||||
<bind node="widget" to="widget" />
|
||||
<bind node="widgetAttrs" to="widgetAttrs" />
|
||||
<bind node="valueExpr" to="valueExpr"/>
|
||||
<bind node="jsonModel" to="jsonModel" search="self.name = :jsonModel" update="true" create="false" />
|
||||
<bind node="targetJsonModel" to="targetJsonModel" search="self.name = :targetJsonModel" update="true" create="false" />
|
||||
<bind node="appBuilder" to="appBuilder" search="self.code = :appBuilder" create="false"/>
|
||||
<bind node="modelAppBuilder" alias="modelAppBuilder" create="false"/>
|
||||
</bind>
|
||||
|
||||
</input>
|
||||
|
||||
<input file="bpm.xml" root="bpm" >
|
||||
|
||||
<bind node="models/model" type="com.axelor.meta.db.MetaJsonModel" search="self.name = :name" create="false" call="com.axelor.studio.service.ImportService:importAppMetaJsonModel" update="true">
|
||||
<bind node="name" to="name" />
|
||||
</bind>
|
||||
|
||||
</input>
|
||||
|
||||
<input file="bpm.xml" root="bpm" >
|
||||
|
||||
<bind node="selections/selection" type="com.axelor.meta.db.MetaSelect" search="self.name = :name" update="true">
|
||||
<bind node="name" to="name"/>
|
||||
<bind node="module" to="module"/>
|
||||
<bind node="priority" to="priority"/>
|
||||
<bind node="items/option" to="items">
|
||||
<bind node="title" to="title"/>
|
||||
<bind node="value" to="value"/>
|
||||
<bind node="icon" to="icon"/>
|
||||
<bind node="data" to="data"/>
|
||||
<bind node="order" to="order"/>
|
||||
<bind node="hidden" to="hidden"/>
|
||||
<bind node="select" to="select" search="self.name = :select" create="false"/>
|
||||
</bind>
|
||||
<bind node="isCustom" to="isCustom"/>
|
||||
<bind node="appBuilder" to="appBuilder" search="self.code = :appBuilder" create="false" />
|
||||
</bind>
|
||||
|
||||
<bind node="chartBuilders/chartBuilder" type="com.axelor.studio.db.ChartBuilder" search="self.name = :name" call="com.axelor.studio.service.ImportService:importChartBuilder" update="true">
|
||||
<bind node="name" to="name" />
|
||||
<bind node="title" to="title" />
|
||||
<bind node="chartType" to="chartType" />
|
||||
<bind node="isJson" to="isJson" />
|
||||
<bind node="model" to="model" alias="_model"/>
|
||||
<bind node="groupOn" to="groupOn" search="self.name = :groupOn and self.metaModel.fullName = :_model" />
|
||||
<bind node="groupOnJson" to="groupOnJson" search="self.name = :groupOnJson and self.jsonModel.name = :_model" />
|
||||
<bind node="groupDateType" to="groupDateType" />
|
||||
<bind node="groupOnTarget" to="groupOnTarget" />
|
||||
<bind node="groupOnTargetType" to="groupOnTargetType" />
|
||||
<bind node="isJsonGroupOn" to="isJsonGroupOn" />
|
||||
<bind node="isJsonAggregateOn" to="isJsonAggregateOn" />
|
||||
<bind node="isJsonDisplayField" to="isJsonDisplayField" />
|
||||
<bind node="aggregateOnJson" to="aggregateOnJson" search="self.name = :aggregateOnJson and self.jsonModel.name = :_model" create="false" />
|
||||
<bind node="aggregateOn" to="aggregateOn" search="self.name = :aggregateOn and self.metaModel.fullName = :_model" create="false" />
|
||||
<bind node="aggregateOnTarget" to="aggregateOnTarget" />
|
||||
<bind node="aggregateDateType" to="aggregateDateType" />
|
||||
<bind node="aggregateOnTargetType" to="aggregateOnTargetType" />
|
||||
<bind node="displayField" to="displayField" search="self.name = :displayField and self.metaModel.fullName = :_model" create="false"/>
|
||||
<bind node="displayFieldJson" to="displayFieldJson" search="self.name = :displayFieldJson and self.jsonModel.name = :_model" create="false" />
|
||||
<bind node="displayType" to="displayType" />
|
||||
<bind node="filters/filter" to="filterList">
|
||||
<bind node="metaField" to="metaField" search="self.name = :metaField and self.metaModel.fullName = :_model" create="false" />
|
||||
<bind node="metaJsonField" to="metaJsonField" search="self.name = :metaJsonField and self.jsonModel.name = :_model" create="false" />
|
||||
<bind node="operator" to="operator" />
|
||||
<bind node="targetField" to="targetField"/>
|
||||
<bind node="targetType" to="targetType"/>
|
||||
<bind node="value" to="value"/>
|
||||
<bind node="defaultValue" to="defaultValue"/>
|
||||
<bind node="isParameter" to="isParameter"/>
|
||||
<bind node="isJson" to="isJson" />
|
||||
<bind node="isTargetJson" to="isTargetJson" />
|
||||
<bind node="logicOp" to="logicOp" />
|
||||
</bind>
|
||||
<bind node="appBuilder" to="appBuilder" search="self.code = :appBuilder" create="false" />
|
||||
</bind>
|
||||
|
||||
<bind node="dashboardBuilders/dashboardBuilder" type="com.axelor.studio.db.DashboardBuilder" search="self.name = :name" update="true">
|
||||
<bind node="name" to="name" />
|
||||
<bind node="title" to="title" />
|
||||
<bind node="model" to="model" />
|
||||
<bind node="appBuilder" to="appBuilder" search="self.code = :appBuilder" create="false" />
|
||||
</bind>
|
||||
|
||||
<bind node="dashletBuilders/dashletBuilder" type="com.axelor.studio.db.DashletBuilder"
|
||||
search="self.name = :name and self.dashboardBuilder.name = :dashboardBuilder and (self.appBuilder.code = :appBuilder OR self.dashboardBuilder.appBuilder.code = :parentAppBuilder)" update="true">
|
||||
<bind node="name" to="name" />
|
||||
<bind node="metaView" to="metaView" search="self.name = :metaView" />
|
||||
<bind node="dashboardBuilder" to="dashboardBuilder" search="self.name = :dashboardBuilder" create="false" />
|
||||
<bind node="action" to="action" search="self.name = :action" create="false" />
|
||||
<bind node="sequence" to="sequence" />
|
||||
<bind node="viewType" to="viewType" />
|
||||
<bind node="colspan" to="colspan" />
|
||||
<bind node="paginationLimit" to="paginationLimit" />
|
||||
<bind node="appBuilder" to="appBuilder" search="self.code = :appBuilder" create="false" />
|
||||
<bind node="parentAppBuilder" alias="parentAppBuilder" />
|
||||
</bind>
|
||||
|
||||
</input>
|
||||
|
||||
<input file="bpm.xml" root="bpm" >
|
||||
|
||||
<bind node="dashboardBuilders/dashboardBuilder" type="com.axelor.studio.db.DashboardBuilder" search="self.name = :name" create="false" call="com.axelor.studio.service.ImportService:importAppDashboardBuilder" update="true">
|
||||
<bind node="name" to="name" />
|
||||
</bind>
|
||||
|
||||
</input>
|
||||
|
||||
<input file="bpm.xml" root="bpm" >
|
||||
|
||||
<bind node="actionBuilders/actionBuilder" type="com.axelor.studio.db.ActionBuilder" search="self.name = :name" call="com.axelor.studio.service.ImportService:importActionBuilder" update="true">
|
||||
<bind node="name" to="name" />
|
||||
<bind node="typeSelect" to="typeSelect" alias="_type" />
|
||||
<bind node="model" to="model" alias="_model"/>
|
||||
<bind node="targetModel" to="targetModel" alias="_targetModel" />
|
||||
<bind node="title" to="title" />
|
||||
<bind node="transactional" to="transactional" />
|
||||
<bind node="scriptType" to="scriptType" />
|
||||
<bind node="scriptText" to="scriptText" />
|
||||
<bind node="actionBuilderViews/view" to="actionBuilderViews">
|
||||
<bind node="viewType" to="viewType" />
|
||||
<bind node="viewName" to="viewName" />
|
||||
<bind node="sequence" to="sequence" />
|
||||
</bind>
|
||||
<bind node="isJson" to="isJson" alias="_isJson" />
|
||||
<bind node="domainCondition" to="domainCondition" />
|
||||
<bind node="viewParams/line" to="viewParams">
|
||||
<bind node="name" to="name"/>
|
||||
<bind node="value" to="value"/>
|
||||
</bind>
|
||||
<bind node="menuAction" to="menuAction"/>
|
||||
<bind node="lines/line" to="lines">
|
||||
<bind node="target" alias="target" />
|
||||
<bind node="source" alias="source" />
|
||||
<bind node="metaJsonField" to="metaJsonField" search="self.name = :metaJsonField and self.jsonModel.name = :target" create="false"/>
|
||||
<bind node="metaField" to="metaField" search="self.name = :metaField and self.metaModel.fullName = :target" create="false"/>
|
||||
<bind node="valueJson" to="valueJson" search="self.name = :valueJson and self.jsonModel.name = :source" create="false" />
|
||||
<bind node="valueField" to="valueField" search="self.name = :valueField and self.metaModel.fullName = :source" create="false" />
|
||||
<bind node="value" to="value"/>
|
||||
<bind node="conditionText" to="conditionText"/>
|
||||
<bind node="filter" to="filter"/>
|
||||
<bind node="validationTypeSelect" to="validationTypeSelect"/>
|
||||
<bind node="validationMsg" to="validationMsg"/>
|
||||
<bind node="name" to="name"/>
|
||||
<bind node="dummy" to="dummy"/>
|
||||
<bind node="subLines/line" to="subLines">
|
||||
<bind node="target" alias="target" />
|
||||
<bind node="source" alias="source" />
|
||||
<bind node="metaJsonField" to="metaJsonField" search="self.name = :metaJsonField and self.jsonModel.name = :target" create="false"/>
|
||||
<bind node="metaField" to="metaField" search="self.name = :metaField and (self.metaModel.fullName = :target OR self.metaModel.name = :target)" create="false" />
|
||||
<bind node="valueJson" to="valueJson" search="self.name = :valueJson and self.jsonModel.name = :source" create="false" />
|
||||
<bind node="valueField" to="valueField" search="self.name = :valueField and (self.metaModel.fullName = :source OR self.metaModel.fullName = :source)" create="false" />
|
||||
<bind node="value" to="value"/>
|
||||
<bind node="conditionText" to="conditionText"/>
|
||||
<bind node="filter" to="filter"/>
|
||||
<bind node="validationTypeSelect" to="validationTypeSelect"/>
|
||||
<bind node="validationMsg" to="validationMsg"/>
|
||||
<bind node="name" to="name"/>
|
||||
<bind node="dummy" to="dummy"/>
|
||||
<bind node="subLines/line" to="subLines">
|
||||
<bind node="target" alias="target" />
|
||||
<bind node="source" alias="source" />
|
||||
<bind node="metaJsonField" to="metaJsonField" search="self.name = :metaJsonField and self.jsonModel.name = :target" create="false"/>
|
||||
<bind node="metaField" to="metaField" search="self.name = :metaField and (self.metaModel.fullName = :target OR self.metaModel.name = :target)" create="false" />
|
||||
<bind node="valueJson" to="valueJson" search="self.name = :valueJson and self.jsonModel.name = :source" create="false"/>
|
||||
<bind node="valueField" to="valueField" search="self.name = :valueField and (self.metaModel.fullName = :source OR self.metaModel.fullName = :source)" create="false" />
|
||||
<bind node="value" to="value"/>
|
||||
<bind node="conditionText" to="conditionText"/>
|
||||
<bind node="filter" to="filter"/>
|
||||
<bind node="validationTypeSelect" to="validationTypeSelect"/>
|
||||
<bind node="validationMsg" to="validationMsg"/>
|
||||
<bind node="name" to="name"/>
|
||||
<bind node="dummy" to="dummy"/>
|
||||
</bind>
|
||||
</bind>
|
||||
</bind>
|
||||
<bind node="appBuilder" to="appBuilder" search="self.code = :appBuilder" create="false" />
|
||||
</bind>
|
||||
|
||||
<bind node="menuBuilders/menuBuilder" type="com.axelor.studio.db.MenuBuilder" search="self.name = :name" call="com.axelor.studio.service.ImportService:importMenuBuilder" update="true">
|
||||
<bind node="name" to="name" />
|
||||
<bind node="title" to="title" />
|
||||
<bind node="icon" to="icon" />
|
||||
<bind node="iconBackground" to="iconBackground" />
|
||||
<bind node="order" to="order" />
|
||||
<bind node="tag" to="tag" />
|
||||
<bind node="tagCount" to="tagCount" />
|
||||
<bind node="tagStyle" to="tagStyle" />
|
||||
<bind node="top" to="top" />
|
||||
<bind node="left" to="left" />
|
||||
<bind node="mobile" to="mobile" />
|
||||
<bind node="hidden" to="hidden" />
|
||||
<bind node="link" to="link" />
|
||||
<bind node="conditionToCheck" to="conditionToCheck" />
|
||||
<bind node="moduleToCheck" to="moduleToCheck" />
|
||||
<bind node="showAction" to="showAction" />
|
||||
<bind node="parentMenu" to="parentMenu" search="self.name = :parentMenu" />
|
||||
<bind node="actionBuilder" to="actionBuilder" search="self.name = :actionBuilder"/>
|
||||
<bind node="groups/group" to="groups" search="self.code = :groupCode" update="true" create="false" >
|
||||
<bind node="text()" to="code" alias="groupCode"/>
|
||||
</bind>
|
||||
<bind node="roles/role" to="roles" search="self.name = :roleName" update="true" create="false">
|
||||
<bind node="text()" to="name" alias="roleName"/>
|
||||
</bind>
|
||||
<bind node="appBuilder" to="appBuilder" search="self.code = :appBuilder" create="false"/>
|
||||
</bind>
|
||||
|
||||
<bind node="wkfs/wkf" type="com.axelor.studio.db.Wkf" search="self.name = :name" update="true">
|
||||
<bind node="name" to="name" />
|
||||
<bind node="model" to="model" />
|
||||
<bind node="isJson" to="isJson" alias="_isJson"/>
|
||||
<bind node="jsonField" to="jsonField" />
|
||||
<bind node="isTrackFlow" to="isTrackFlow"/>
|
||||
<bind node="statusField" to="statusField" search="self.jsonModel.name = :model and self.name = :statusField" if="_isJson == 'true'" create="false" />
|
||||
<bind node="statusField" to="statusField" search="self.model = :model and self.modelField = :jsonField and self.name = :statusField and self.jsonModel is null" if="_isJson == 'false'" create="false" />
|
||||
<bind node="displayTypeSelect" to="displayTypeSelect" />
|
||||
<bind node="bpmnXml" to="bpmnXml" />
|
||||
<bind node="appBuilder" to="appBuilder" search="self.code = :appBuilder" create="false"/>
|
||||
</bind>
|
||||
|
||||
<bind node="nodes/node" type="com.axelor.studio.db.WkfNode" search="self.name = :name and self.wkf.name = :wkf" update="true">
|
||||
<bind node="wkf" to="wkf" search="self.name = :wkf" create="false"/>
|
||||
<bind node="name" to="name" />
|
||||
<bind node="title" to="title" />
|
||||
<bind node="xmlId" to="xmlId" />
|
||||
<bind node="sequence" to="sequence" />
|
||||
<bind node="nodeType" to="nodeType" />
|
||||
<bind node="metaFieldModel" alias="metaFieldModel" />
|
||||
<bind node="metaField" to="metaField" search="self.name = :metaField and self.metaModel.name = :metaFieldModel" create="false"/>
|
||||
<bind node="roleSet/role" to="roleSet" search="self.name = :roleName" update="false" create="false">
|
||||
<bind node="text()" to="name" alias="roleName"/>
|
||||
</bind>
|
||||
<bind node="metaActionSet/action" to="metaActionSet" search="self.name = :actionName" update="false" create="false">
|
||||
<bind node="text()" to="name" alias="actionName"/>
|
||||
</bind>
|
||||
</bind>
|
||||
|
||||
<bind node="nodes/node" type="com.axelor.studio.db.WkfNode" search="self.name = :name and self.wkf.name = :wkf" update="true" create="false">
|
||||
<bind node="wkf" to="wkf" search="self.name = :wkf" create="false"/>
|
||||
<bind node="name" to="name" />
|
||||
<bind node="title" to="title" />
|
||||
<bind node="xmlId" to="xmlId" />
|
||||
<bind node="sequence" to="sequence" />
|
||||
<bind node="nodeType" to="nodeType" />
|
||||
<bind node="metaFieldModel" alias="metaFieldModel" />
|
||||
<bind node="metaField" to="metaField" search="self.name = :metaField and self.metaModel.name = :metaFieldModel" />
|
||||
<bind node="roleSet/role" to="roleSet" search="self.name = :roleName" update="false" create="false">
|
||||
<bind node="text()" to="name" alias="roleName"/>
|
||||
</bind>
|
||||
<bind node="metaActionSet/action" to="metaActionSet" search="self.name = :actionName" update="false" create="false">
|
||||
<bind node="text()" to="name" alias="actionName"/>
|
||||
</bind>
|
||||
</bind>
|
||||
|
||||
<bind node="transitions/transition" type="com.axelor.studio.db.WkfTransition" search="self.name = :name and self.wkf.name = :wkf" update="true">
|
||||
<bind node="wkf" to="wkf" search="self.name = :wkf" update="true" create="false"/>
|
||||
<bind node="name" to="name" />
|
||||
<bind node="xmlId" to="xmlId" />
|
||||
<bind node="isButton" to="isButton" />
|
||||
<bind node="buttonTitle" to="buttonTitle" />
|
||||
<bind node="roleSet/role" to="roleSet" search="self.name = :roleName" create="false">
|
||||
<bind node="text()" to="name" alias="roleName"/>
|
||||
</bind>
|
||||
<bind node="conditions/condition" to="conditions">
|
||||
<bind node="metaModel" alias="metaModel" />
|
||||
<bind node="jsonModel" alias="jsonModel" />
|
||||
<bind node="metaField" to="metaField" search="self.name = :metaField and self.metaModel.fullName = :metaModel" create="false"/>
|
||||
<bind node="metaJsonField" to="metaJsonField" search="self.name = :metaJsonField and self.jsonModel.name = :jsonModel" create="false" if="jsonModel != null"/>
|
||||
<bind node="metaJsonField" to="metaJsonField" search="self.name = :metaJsonField and self.model = :model and self.modelField = :modelField" create="false" if="jsonModel == null"/>
|
||||
<bind node="operator" to="operator" />
|
||||
<bind node="targetField" to="targetField"/>
|
||||
<bind node="targetType" to="targetType"/>
|
||||
<bind node="value" to="value"/>
|
||||
<bind node="isJson" to="isJson" />
|
||||
<bind node="isTargetJson" to="isTargetJson" />
|
||||
<bind node="logicOp" to="logicOp" />
|
||||
</bind>
|
||||
<bind node="source" to="source" search="self.name = :source and self.wkf.name = :wkf" update="false" create="false" />
|
||||
<bind node="target" to="target" search="self.name = :target and self.wkf.name = :wkf" update="false" create="false" />
|
||||
<bind node="alertTypeSelect" to="alertTypeSelect" />
|
||||
<bind node="alertMsg" to="alertMsg" />
|
||||
<bind node="successMsg" to="successMsg" />
|
||||
</bind>
|
||||
|
||||
<bind node="nodes/node" type="com.axelor.studio.db.WkfNode" search="self.name = :nodeName and self.wkf.name = :wkf" update="true" create="false">
|
||||
<bind node="wkf" to="wkf" search="self.name = :wkf" update="true" create="false" />
|
||||
<bind node="name" to="name" alias="nodeName" />
|
||||
<bind node="incomings/incoming" to="incoming" search="self.name = :inNode and self.wkf.name = :wkf" update="false" create="false">
|
||||
<bind node="text()" to="name" alias="inNode" />
|
||||
</bind>
|
||||
<bind node="outgoings/outgoing" to="outgoings" search="self.name = :outNode and self.wkf.name = :wkf" update="false" create="false">
|
||||
<bind node="text()" to="name" alias="outNode" />
|
||||
</bind>
|
||||
</bind>
|
||||
</input>
|
||||
|
||||
<input file="bpm.xml" root="bpm" >
|
||||
<bind node="wkfs/wkf" type="com.axelor.studio.db.Wkf" search="self.name = :name" create="false" call="com.axelor.studio.service.ImportService:importAppWkf">
|
||||
<bind node="name" to="name" />
|
||||
</bind>
|
||||
</input>
|
||||
|
||||
</xml-inputs>
|
||||
@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<csv-inputs xmlns="http://axelor.com/xml/ns/data-import"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://axelor.com/xml/ns/data-import http://axelor.com/xml/ns/data-import/data-import_5.2.xsd">
|
||||
|
||||
<input file="auth_permission.csv" separator=";" type="com.axelor.auth.db.Permission" search="self.name = :name" call="com.axelor.csv.script.ImportPermission:importPermissionToRole">
|
||||
<bind to="canRead" eval="can_read == 'x' ? 'true' : 'false'"/>
|
||||
<bind to="canWrite" eval="can_write == 'x' ? 'true' : 'false'"/>
|
||||
<bind to="canCreate" eval="can_create == 'x' ? 'true' : 'false'"/>
|
||||
<bind to="canRemove" eval="can_remove == 'x' ? 'true' : 'false'"/>
|
||||
<bind to="canExport" eval="can_export == 'x' ? 'true' : 'false'"/>
|
||||
</input>
|
||||
|
||||
<input file="base_appBpm.csv" separator=";" type="com.axelor.apps.base.db.AppBpm" call="com.axelor.csv.script.ImportApp:importApp">
|
||||
<bind column="dependsOn" to="dependsOnSet" search="self.code in :dependsOn" eval="dependsOn.split(',') as List"/>
|
||||
</input>
|
||||
|
||||
<input file="meta_metaMenu.csv" separator=";" type="com.axelor.meta.db.MetaMenu" search="self.name = :name" update="true" />
|
||||
|
||||
</csv-inputs>
|
||||
@ -0,0 +1,2 @@
|
||||
"name";"object";"can_read";"can_write";"can_create";"can_remove";"can_export";"condition";"conditionParams";"roleName"
|
||||
"perm.studio.all";"com.axelor.studio.db.*";"x";"x";"x";"x";"x";;;"Admin"
|
||||
|
@ -0,0 +1,2 @@
|
||||
"importId";"name";"code";"installOrder";"description";"imagePath";"modules";"dependsOn";"sequence"
|
||||
50;"BPM";"bpm";28;"Business Process Modeling";"app-bpm.png";"axelor-studio";;29
|
||||
|
Binary file not shown.
|
After Width: | Height: | Size: 7.8 KiB |
@ -0,0 +1,15 @@
|
||||
"name";"roles.name"
|
||||
"app-builder-root";"Admin"
|
||||
"app-builder-models-views";"Admin"
|
||||
"app-builder-models-views-model-studio";"Admin"
|
||||
"app-builder-models-views-custom-models";"Admin"
|
||||
"app-builder-models-views-custom-fields";"Admin"
|
||||
"app-builder-bpm";"Admin"
|
||||
"app-builder-bpm-process-studio";"Admin"
|
||||
"app-builder-bpm-process-tracking";"Admin"
|
||||
"app-builder-bpm-actions-reporting";"Admin"
|
||||
"app-builder-bpm-actions-reporting-chart-builders";"Admin"
|
||||
"app-builder-bpm-actions-reporting-dashboard-builders";"Admin"
|
||||
"app-builder-bpm-actions-reporting-action-builders";"Admin"
|
||||
"app-builder-bpm-actions-reporting-menu-builders";"Admin"
|
||||
"app-builder-bpm-apps-configurator";"Admin"
|
||||
|
@ -0,0 +1,235 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xml-inputs xmlns="http://axelor.com/xml/ns/data-import"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://axelor.com/xml/ns/data-import http://axelor.com/xml/ns/data-import/data-import_5.2.xsd">
|
||||
|
||||
<input file="bpm_appBuilder.xml" root="app-builders">
|
||||
<bind node="app-builder" type="com.axelor.studio.db.AppBuilder" call="com.axelor.studio.service.ImportService:importAppBuilderImg">
|
||||
<bind node="name" to="name" />
|
||||
<bind node="code" to="code" />
|
||||
<bind node="description" to="description" />
|
||||
<bind node="sequence" to="sequence" />
|
||||
<bind node="depends" alias="depends" />
|
||||
<bind to="dependsOnSet" alias="deps" search="self.code in :deps" eval="depends.split(',') as List" update="true" />
|
||||
<bind node="image/@name" alias="fileName"/>
|
||||
<bind node="image" alias="imageData" />
|
||||
</bind>
|
||||
</input>
|
||||
|
||||
<input file="bpm_metaJsonModel.xml" root="json-models">
|
||||
<bind node="json-model" type="com.axelor.meta.db.MetaJsonModel" call="com.axelor.studio.service.ImportService:importMetaJsonModel">
|
||||
<bind node="@name" to="name" />
|
||||
<bind node="@title" to="title" />
|
||||
<bind node="@appBuilder" to="appBuilder" search="self.code = :appBuilder" />
|
||||
<bind node="fields/field" to="fields">
|
||||
<bind node="@name" to="name"/>
|
||||
<bind node="@title" to="title" />
|
||||
<bind node="@type" to="type" />
|
||||
<bind node="@target-model" to="targetModel"/>
|
||||
<bind node="@target-json-model" alias="targetJsonModel" to="targetJsonModel" search="self.name = :targetJsonModel" update="true"/>
|
||||
<bind node="@required" to="required"/>
|
||||
<bind node="@domain" to="domain"/>
|
||||
<bind to="model" eval="'com.axelor.meta.db.MetaJsonRecord'" />
|
||||
<bind to="modelField" eval="'attrs'" />
|
||||
<bind node="@sequence" to="sequence"/>
|
||||
<bind node="@onChange" to="onChange" />
|
||||
<bind node="@visibleInGrid" to="visibleInGrid" />
|
||||
</bind>
|
||||
</bind>
|
||||
|
||||
<bind node="json-field" type="com.axelor.meta.db.MetaJsonField" call="com.axelor.studio.service.ImportService:importMetaJsonField">
|
||||
<bind node="@name" to="name" />
|
||||
<bind node="@title" to="title" />
|
||||
<bind node="@type" to="type" />
|
||||
<bind node="@model" to="model" />
|
||||
<bind node="@modelField" to="modelField" />
|
||||
<bind node="@onClick" to="onClick" />
|
||||
<bind node="@target-json-model" alias="targetJsonModel" to="targetJsonModel" search="self.name = :targetJsonModel" update="true"/>
|
||||
<bind node="@jsonModel" to="jsonModel" search="self.name = :jsonModel" update="true" />
|
||||
<bind node="@sequence" to="sequence"/>
|
||||
<bind node="@onChange" to="onChange" />
|
||||
<bind node="@appBuilder" to="appBuilder" search="self.code = :appBuilder" />
|
||||
<bind node="@showIf" to="showIf" />
|
||||
</bind>
|
||||
</input>
|
||||
|
||||
<input file="bpm_chartBuilder.xml" root="chart-builders">
|
||||
<bind node="chart-builder" type="com.axelor.studio.db.ChartBuilder" call="com.axelor.studio.service.ImportService:importChartBuilder">
|
||||
<bind node="@name" to="name" />
|
||||
<bind node="@title" to="title" />
|
||||
<bind node="@type" to="chartType" />
|
||||
<bind node="@json" to="isJson" />
|
||||
<bind node="@model" to="model" alias="_model"/>
|
||||
<bind node="@appBuilder" to="appBuilder" search="self.code = :appBuilder" />
|
||||
<bind node="@groupOnJson" to="groupOnJson" search="self.name = :groupOnJson and self.jsonModel.name = :_model" />
|
||||
<bind node="@groupOn" to="groupOn" search="self.name = :groupOn and self.metaModel.fullName = :_model" />
|
||||
<bind node="@groupDateType" to="groupDateType" />
|
||||
<bind node="@groupOnTarget" to="groupOnTarget" />
|
||||
<bind node="@groupOnTargetType" to="groupOnTargetType" />
|
||||
<bind node="@isJsonGroupOn" to="isJsonGroupOn" />
|
||||
<bind node="@isJsonAggregateOn" to="isJsonAggregateOn" />
|
||||
<bind node="@isJsonDisplayField" to="isJsonDisplayField" />
|
||||
<bind node="@aggregateOnJson" to="aggregateOnJson" search="self.name = :aggregateOnJson and self.jsonModel.name = :_model" />
|
||||
<bind node="@aggregateOn" to="aggregateOn" search="self.name = :aggregateOn and self.metaModel.fullName = :_model" />
|
||||
<bind node="@aggregateOnTarget" to="aggregateOnTarget" />
|
||||
<bind node="@aggregateOnTargetType" to="aggregateOnTargetType" />
|
||||
<bind node="@displayFieldJson" to="displayFieldJson" search="self.name = :displayFieldJson and self.jsonModel.name = :_model" />
|
||||
<bind node="@displayField" to="displayField" search="self.name = :displayField and self.metaModel.fullName = :_model" />
|
||||
<bind node="filters/filter" to="filterList">
|
||||
<bind node="@json" to="isJson" />
|
||||
<bind node="@targetType" to="targetType" />
|
||||
<bind node="@operator" to="operator" />
|
||||
<bind node="@targetField" to="targetField"/>
|
||||
<bind node="@jsonField" to="metaJsonField" search="self.name = :metaJsonField and self.jsonModel.name = :_model" />
|
||||
<bind node="@field" to="metaField" search="self.name = :metaField and self.metaModel.fullName = :_model" />
|
||||
<bind node="@value" to="value"/>
|
||||
<bind node="@isParameter" to="isParameter"/>
|
||||
</bind>
|
||||
</bind>
|
||||
</input>
|
||||
|
||||
|
||||
<input file="bpm_dashboardBuilder.xml" root="dashboard-builders">
|
||||
<bind node="dashboard-builder" type="com.axelor.studio.db.DashboardBuilder" call="com.axelor.studio.service.ImportService:importDashboardBuilder">
|
||||
<bind node="@name" to="name" />
|
||||
<bind node="@title" to="title" />
|
||||
<bind node="@appBuilder" to="appBuilder" search="self.code = :appBuilder" />
|
||||
<bind node="dashlets/dashlet" to="dashletBuilderList">
|
||||
<bind node="@name" to="name" />
|
||||
<bind node="@sequence" to="sequence" />
|
||||
<bind node="@viewType" to="viewType" />
|
||||
<bind node="@colspan" to="colspan" />
|
||||
<bind node="@view" to="metaView" search="self.name = :metaView" />
|
||||
</bind>
|
||||
</bind>
|
||||
</input>
|
||||
|
||||
<input file="bpm_menuBuilder.xml" root="menu-builders">
|
||||
<bind node="menu-builder" type="com.axelor.studio.db.MenuBuilder" call="com.axelor.studio.service.ImportService:importMenuBuilder">
|
||||
<bind node="@name" to="name" />
|
||||
<bind node="@title" to="title" />
|
||||
<bind node="@icon" to="icon" />
|
||||
<bind node="@background" to="iconBackground" />
|
||||
<bind node="@parent" to="parentMenu" search="self.name = :parentMenu" />
|
||||
<bind node="@show-action" to="showAction" />
|
||||
<bind node="@appBuilder" to="appBuilder" search="self.code = :appBuilder" />
|
||||
<bind node="action" to="actionBuilder" if="actionName != null">
|
||||
<bind node="@name" to="name" alias="actionName" />
|
||||
<bind node="@model" to="model" />
|
||||
<bind node="@isJson" to="isJson" />
|
||||
<bind node="@title" to="title" />
|
||||
<bind to="typeSelect" eval="3"/>
|
||||
<bind node="views/view" to="actionBuilderViews">
|
||||
<bind node="@type" to="viewType" />
|
||||
<bind node="@name" to="viewName" />
|
||||
<bind node="@sequence" to="sequence" />
|
||||
</bind>
|
||||
<bind node="@domain" to="domainCondition" />
|
||||
<bind node="context/ctx" to="lines">
|
||||
<bind node="@value" to="value" />
|
||||
<bind node="@name" to="name" />
|
||||
</bind>
|
||||
</bind>
|
||||
</bind>
|
||||
</input>
|
||||
|
||||
<input file="bpm_actionBuilder.xml" root="action-builders">
|
||||
<bind node="action-builder" type="com.axelor.studio.db.ActionBuilder" call="com.axelor.studio.service.ImportService:importActionBuilder">
|
||||
<bind node="@name" to="name" />
|
||||
<bind node="@isJson" to="isJson" />
|
||||
<bind node="@typeSelect" to="typeSelect" />
|
||||
<bind node="@model" to="model" />
|
||||
<bind node="@targetModel" to="targetModel" />
|
||||
<bind node="@appBuilder" to="appBuilder" search="self.code = :appBuilder" />
|
||||
<bind node="lines/line" to="lines">
|
||||
<bind node="@metaModel" to="metaModel" />
|
||||
<bind node="@valueModel" to="valueModel" />
|
||||
<bind node="@jsonModel" to="jsonModel" />
|
||||
<bind node="@valueJsonModel" to="valueJsonModel" />
|
||||
<bind node="@metaField" to="metaField" search="self.name = :metaField and self.metaModel.name = :metaModel" />
|
||||
<bind node="@valueField" to="valueField" search="self.name = :valueField and self.metaModel.name = :valueModel" />
|
||||
<bind node="@jsonField" to="metaJsonField" search="self.name = :metaJsonField and self.jsonModel.name = :jsonModel" />
|
||||
<bind node="@valueJsonField" to="valueJson" search="self.name = :valueJson and self.jsonModel.name = :valueJsonModel" />
|
||||
<bind node="@name" to="name" if="metaField == null && metaJsonField == null"/>
|
||||
<bind node="@metaField" to="name" if="metaField != null"/>
|
||||
<bind node="@jsonField" to="name" if="metaJsonField != null"/>
|
||||
<bind node="@value" to="value"/>
|
||||
<bind node="@filter" to="filter"/>
|
||||
<bind node="@dummy" to="dummy"/>
|
||||
<bind node="subLines/line" to="subLines">
|
||||
<bind node="@metaModel" to="metaModel" />
|
||||
<bind node="@valueModel" to="valueModel" />
|
||||
<bind node="@jsonModel" to="jsonModel" />
|
||||
<bind node="@valueJsonModel" to="valueJsonModel" />
|
||||
<bind node="@metaField" to="metaField" search="self.name = :metaField and self.metaModel.name = :metaModel" />
|
||||
<bind node="@valueField" to="valueField" search="self.name = :valueField and self.metaModel.name = :valueModel" />
|
||||
<bind node="@jsonField" to="metaJsonField" search="self.name = :metaJsonField and self.jsonModel.name = :jsonModel" />
|
||||
<bind node="@valueJsonField" to="valueJson" search="self.name = :valueJson and self.jsonModel.name = :valueJsonModel" />
|
||||
<bind node="@name" to="name" if="metaField == null && metaJsonField == null"/>
|
||||
<bind node="@metaField" to="name" if="metaField != null"/>
|
||||
<bind node="@jsonField" to="name" if="metaJsonField != null"/>
|
||||
<bind node="@value" to="value"/>
|
||||
<bind node="@filter" to="filter"/>
|
||||
<bind node="@dummy" to="dummy"/>
|
||||
</bind>
|
||||
</bind>
|
||||
</bind>
|
||||
</input>
|
||||
|
||||
<input file="bpm_workflow.xml" root="wkfs" >
|
||||
<bind node="wkf" type="com.axelor.studio.db.Wkf">
|
||||
<bind node="@appBuilder" to="appBuilder" search="self.code = :appBuilder" />
|
||||
<bind node="@name" to="name" />
|
||||
<bind node="@isJson" to="isJson" />
|
||||
<bind node="@model" to="model" />
|
||||
<bind node="@statusField" to="statusField" search="self.jsonModel.name = :model and self.name = :statusField" update="true" />
|
||||
<bind node="@displayTypeSelect" to="displayTypeSelect" />
|
||||
<bind node="xml" to="bpmnXml" />
|
||||
</bind>
|
||||
<bind node="wkfNode" type="com.axelor.studio.db.WkfNode">
|
||||
<bind node="@name" to="name" />
|
||||
<bind node="@title" to="title" />
|
||||
<bind node="@wkf" to="wkf" search="self.name = :wkf" update="true"/>
|
||||
<bind node="@sequence" to="sequence" />
|
||||
<bind node="@nodeType" to="nodeType" />
|
||||
<bind node="@xmlId" to="xmlId" />
|
||||
</bind>
|
||||
<bind node="transition" type="com.axelor.studio.db.WkfTransition">
|
||||
<bind node="@name" to="name" />
|
||||
<bind node="@wkf" to="wkf" search="self.name = :wkf" update="true"/>
|
||||
<bind node="@source" to="source" search="self.name = :source and self.wkf.name = :wkf" update="true"/>
|
||||
<bind node="@target" to="target" search="self.name = :target and self.wkf.name = :wkf" update="true"/>
|
||||
<bind node="@isButton" to="isButton" />
|
||||
<bind node="@buttonTitle" to="buttonTitle" />
|
||||
<bind node="@alertTypeSelect" to="alertTypeSelect" />
|
||||
<bind node="@alertMsg" to="alertMsg" />
|
||||
<bind node="@successMsg" to="successMsg" />
|
||||
<bind node="@xmlId" to="xmlId" />
|
||||
</bind>
|
||||
<bind node="node" type="com.axelor.studio.db.WkfNode" search="self.name = :nodeName and self.wkf.name = :wkf" update="true">
|
||||
<bind node="@wkf" to="wkf" search="self.name = :wkf" update="true" />
|
||||
<bind node="@name" to="name" alias="nodeName" />
|
||||
<bind node="incomings/incoming" to="incoming" search="self.name = :name and self.wkf.name = :wkf" update="true">
|
||||
<bind node="@name" to="name" />
|
||||
</bind>
|
||||
<bind node="outgoings/outgoing" to="outgoings" search="self.name = :name and self.wkf.name = :wkf" update="true">
|
||||
<bind node="@name" to="name" />
|
||||
</bind>
|
||||
</bind>
|
||||
</input>
|
||||
|
||||
<input file="bpm_workflow.xml" root="wkfs" >
|
||||
<bind node="workflow" type="com.axelor.studio.db.Wkf" search="self.name = :name" update="true" call="com.axelor.studio.service.ImportService:importWkf">
|
||||
<bind node="@name" to="name" />
|
||||
</bind>
|
||||
</input>
|
||||
|
||||
<input file="bpm_translation.xml" root="meta-translations" >
|
||||
<bind node="meta-translation" type="com.axelor.meta.db.MetaTranslation" search="self.key = :key and self.language = :language">
|
||||
<bind node="@key" to="key" />
|
||||
<bind node="@message" to="message" />
|
||||
<bind node="@language" to="language"/>
|
||||
</bind>
|
||||
</input>
|
||||
|
||||
</xml-inputs>
|
||||
@ -0,0 +1,102 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<action-builders xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
|
||||
<action-builder name="action-create-invoice-from-timesheet"
|
||||
isJson="false"
|
||||
typeSelect="0"
|
||||
appBuilder="PRD"
|
||||
model="com.axelor.apps.hr.db.Timesheet"
|
||||
targetModel="com.axelor.apps.account.db.Invoice">
|
||||
<lines>
|
||||
<line metaField="partner" metaModel="Invoice" valueField="company" valueModel="Timesheet" value="$.company.partner" />
|
||||
<line metaField="company" metaModel="Invoice" valueField="company" valueModel="Timesheet" value="$.company" />
|
||||
<line metaField="currency" metaModel="Invoice" valueField="company" valueModel="Timesheet" value="$.company.currency" />
|
||||
<line metaField="operationTypeSelect" metaModel="Invoice" value="3"/>
|
||||
<line metaField="paymentCondition" metaModel="Invoice" filter="self.code = '15D_EOM'"/>
|
||||
<line metaField="paymentMode" metaModel="Invoice" filter="self.code = 'OUT_WT'"/>
|
||||
<line name="total" value="$.timesheetLineList.sum($.hoursDuration*$$.user.employee.hourlyRate)" dummy="true"/>
|
||||
<line metaField="exTaxTotal" metaModel="Invoice" value="_$.total" />
|
||||
<line metaField="inTaxTotal" metaModel="Invoice" value="_$.total" />
|
||||
<line metaField="invoiceLineList" metaModel="Invoice" valueField="timesheetLineList" valueModel="Timesheet" value="$.timesheetLineList">
|
||||
<subLines>
|
||||
<line metaField="exTaxTotal" metaModel="InvoiceLine" value="$.hoursDuration*$$.user.employee.hourlyRate" />
|
||||
<line metaField="price" metaModel="InvoiceLine" value="$$.user.employee.hourlyRate" />
|
||||
<line metaField="product" metaModel="InvoiceLine" valueModel="TimesheetLine" valueField="product" value="$.product" />
|
||||
<line metaField="productName" metaModel="InvoiceLine" valueModel="TimesheetLine" valueField="product" value="$.product.name" />
|
||||
<line metaField="qty" metaModel="InvoiceLine" valueModel="TimesheetLine" valueField="hoursDuration" value="$.hoursDuration" />
|
||||
<line metaField="unit" metaModel="InvoiceLine" filter="self.name = 'Hour'"/>
|
||||
</subLines>
|
||||
</line>
|
||||
</lines>
|
||||
</action-builder>
|
||||
|
||||
<action-builder name="action-timesheet-line-invert-to-invoice"
|
||||
isJson="false"
|
||||
typeSelect="1"
|
||||
appBuilder="PRD"
|
||||
model="com.axelor.apps.hr.db.Timesheet">
|
||||
<lines>
|
||||
<line metaField="timesheetLineList" metaModel="Timesheet" value="$.timesheetLineList" valueModel="Timesheet" valueField="timesheetLineList">
|
||||
<subLines>
|
||||
<line metaField="toInvoice" metaModel="TimesheetLine" value="!$.toInvoice" valueModel="TimesheetLine" valueField="toInvoice" />
|
||||
</subLines>
|
||||
</line>
|
||||
</lines>
|
||||
</action-builder>
|
||||
|
||||
<action-builder name="action-create-product-order-from-category"
|
||||
isJson="true"
|
||||
typeSelect="0"
|
||||
appBuilder="PRD"
|
||||
model="ProductCategory"
|
||||
targetModel="ProductOrder">
|
||||
<lines>
|
||||
<line jsonField="customer" jsonModel="ProductOrder" filter="self.name = 'Axelor'" />
|
||||
<line jsonField="status" jsonModel="ProductOrder" value="1" />
|
||||
<line jsonField="total" jsonModel="ProductOrder" value="$.products.sum($.price)" />
|
||||
<line jsonField="lines" jsonModel="ProductOrder" value="$.products" valueJsonModel="ProductCategory" valueJsonField="products">
|
||||
<subLines>
|
||||
<line jsonField="product" jsonModel="ProductOrderLine" value="$" />
|
||||
<line jsonField="price" jsonModel="ProductOrderLine" value="$.price" valueJsonModel="Product" valueJsonField="price" />
|
||||
<line jsonField="qty" jsonModel="ProductOrderLine" value="1" />
|
||||
<line jsonField="total" jsonModel="ProductOrderLine" value="$.price" valueJsonModel="Product" valueJsonField="price" />
|
||||
</subLines>
|
||||
</line>
|
||||
</lines>
|
||||
</action-builder>
|
||||
|
||||
<action-builder name="action-product-order-line-update-total"
|
||||
isJson="true"
|
||||
typeSelect="1"
|
||||
appBuilder="PRD"
|
||||
model="ProductOrderLine"
|
||||
targetModel="ProductOrderLine">
|
||||
<lines>
|
||||
<line jsonField="total" jsonModel="ProductOrderLine" value="$.price*$.qty" />
|
||||
</lines>
|
||||
</action-builder>
|
||||
|
||||
<action-builder name="action-product-order-line-get-product-details"
|
||||
isJson="true"
|
||||
typeSelect="1"
|
||||
appBuilder="PRD"
|
||||
model="ProductOrderLine"
|
||||
targetModel="ProductOrderLine">
|
||||
<lines>
|
||||
<line jsonField="price" jsonModel="ProductOrderLine" valueJson="Product" valueJsonModel="ProductOrderLine" valueJsonField="product" value="$.product.price" />
|
||||
</lines>
|
||||
</action-builder>
|
||||
|
||||
<action-builder name="action-product-order-update-total"
|
||||
isJson="true"
|
||||
typeSelect="1"
|
||||
appBuilder="PRD"
|
||||
model="ProductOrder"
|
||||
targetModel="ProductOrder">
|
||||
<lines>
|
||||
<line jsonField="total" jsonModel="ProductOrder" valueJson="Product" valueJsonModel="ProductOrder" valueJsonField="lines" value="$.lines.sum($.total)" />
|
||||
</lines>
|
||||
</action-builder>
|
||||
|
||||
</action-builders>
|
||||
File diff suppressed because one or more lines are too long
@ -0,0 +1,46 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<chart-builders xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
|
||||
|
||||
<chart-builder name="product-order-chart" title="Product orders per month" appBuilder="PRD"
|
||||
type="bar" model="ProductOrder" json="true" groupOnJson="orderDate" groupOnTarget="orderDate" groupOnTargetType="Date" groupDateType="month"
|
||||
isJsonGroupOn="true" isJsonAggregateOn="true" isJsonDisplayField="true"
|
||||
aggregateOnJson="customer" aggregateOnTarget="customer.fullName" aggregateOnTargetType="String" displayFieldJson="total">
|
||||
<filters>
|
||||
<filter json="true" targetType="many-to-one" operator="notNull" targetField="customer" jsonField="customer" />
|
||||
<filter json="true" targetType="date" operator="<=" targetField="orderDate" value="$date" jsonField="orderDate" />
|
||||
</filters>
|
||||
</chart-builder>
|
||||
|
||||
<chart-builder name="product-order-per-author-per-category" title="Product orders per supplier per category" appBuilder="PRD"
|
||||
type="pie" model="ProductOrderLine" json="true" groupOnJson="product"
|
||||
isJsonGroupOn="true" isJsonAggregateOn="true" isJsonDisplayField="true"
|
||||
groupOnTarget="product.supplier.name" groupOnTargetType="String" displayFieldJson="total">
|
||||
<filters>
|
||||
<filter json="true" targetType="json-many-to-one" operator="=" targetField="product.category" isParameter="true" jsonField="product" />
|
||||
</filters>
|
||||
</chart-builder>
|
||||
|
||||
|
||||
<!-- <chart-builder name="sal" title="Product sale per category" -->
|
||||
<!-- type="pie" model="com.axelor.apps.sale.db.SaleOrderLine" groupOn="product" -->
|
||||
<!-- groupOnTarget="product.productCategory.name" displayField="exTaxTotal"> -->
|
||||
<!-- <filters> -->
|
||||
<!-- <filter targetType="many-to-one" operator="=" targetField="product.productFamily" isParameter="true" field="product" /> -->
|
||||
<!-- <filter targetType="Integer" operator="in" targetField="saleOrder.statusSelect" field="saleOrder" value="3,4" /> -->
|
||||
<!-- </filters> -->
|
||||
<!-- </chart-builder> -->
|
||||
|
||||
<!-- <chart-builder name="products-order-per-month-per-customer" title="Product sale per month per customer" -->
|
||||
<!-- type="bar" model="com.axelor.apps.sale.db.SaleOrderLine" groupOn="saleOrder" groupOnTarget="saleOrder.orderDate" groupOnTargetType="LocalDate" groupDateType="month" -->
|
||||
<!-- aggregateOn="saleOrder" aggregateOnTarget="saleOrder.clientPartner.fullName" displayField="exTaxTotal"> -->
|
||||
<!-- <filters> -->
|
||||
<!-- <filter targetType="Integer" operator="in" targetField="saleOrder.statusSelect" value="3,4" field="saleOrder" /> -->
|
||||
<!-- <filter targetType="LocalDate" operator="notNull" targetField="saleOrder.orderDate" field="saleOrder" /> -->
|
||||
<!-- <filter targetType="many-to-one" operator="=" targetField="product" isParameter="true" field="product" /> -->
|
||||
<!-- </filters> -->
|
||||
<!-- </chart-builder> -->
|
||||
|
||||
|
||||
</chart-builders>
|
||||
@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<dashboard-builders xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
|
||||
<dashboard-builder name="product-dashboard" title="Product dashboard" appBuilder="PRD">
|
||||
<dashlets>
|
||||
<dashlet name="Product orders" sequence="0" viewType="grid" colspan="12" view="custom-model-ProductOrder-grid" />
|
||||
<dashlet name="Product orders per month" sequence="1" viewType="chart" colspan="6" view="product-order-chart" />
|
||||
<dashlet name="Product orders per supplier per category" sequence="2" viewType="chart" colspan="6" view="product-order-per-author-per-category" />
|
||||
</dashlets>
|
||||
</dashboard-builder>
|
||||
|
||||
<!-- <dashboard-builder name="product-order-dashboard" title="Product dashboard"> -->
|
||||
<!-- <dashlets> -->
|
||||
<!-- <dashlet name="All products" sequence="0" viewType="grid" colspan="12" view="product-grid" /> -->
|
||||
<!-- <dashlet name="Product sale per category" sequence="1" viewType="chart" colspan="6" view="products-order-per-category" /> -->
|
||||
<!-- <dashlet name="Product sale per month per customer" sequence="2" viewType="chart" colspan="6" view="products-order-per-month-per-customer" /> -->
|
||||
<!-- </dashlets> -->
|
||||
<!-- </dashboard-builder> -->
|
||||
|
||||
|
||||
</dashboard-builders>
|
||||
@ -0,0 +1,76 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu-builders xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
|
||||
<menu-builder name="bpm-product-root" title="Products" icon="fa-cube" background="red" appBuilder="PRD" />
|
||||
|
||||
<menu-builder name="menu-json-model-ProductCategory" title="Product category" parent="bpm-product-root" show-action="true" appBuilder="PRD">
|
||||
<action name="all.json.ProductCategory" title="Product category" model="com.axelor.meta.db.MetaJsonRecord"
|
||||
domain="self.jsonModel = :jsonModel" isJson="true">
|
||||
<views>
|
||||
<view type="grid" name="custom-model-ProductCategory-grid" sequence="1" />
|
||||
<view type="form" name="custom-model-ProductCategory-form" sequence="2" />
|
||||
</views>
|
||||
<context>
|
||||
<ctx name="jsonModel" value="'ProductCategory'" />
|
||||
</context>
|
||||
</action>
|
||||
</menu-builder>
|
||||
|
||||
<menu-builder name="menu-json-model-Product" title="Product" parent="bpm-product-root" show-action="true" appBuilder="PRD">
|
||||
<action name="all.json.Product" title="Product" model="com.axelor.meta.db.MetaJsonRecord"
|
||||
domain="self.jsonModel = :jsonModel" isJson="true">
|
||||
<views>
|
||||
<view type="grid" name="custom-model-Product-grid" sequence="1" />
|
||||
<view type="form" name="custom-model-Product-form" sequence="2" />
|
||||
</views>
|
||||
<context>
|
||||
<ctx name="jsonModel" value="'Product'" />
|
||||
</context>
|
||||
</action>
|
||||
</menu-builder>
|
||||
|
||||
<menu-builder name="menu-json-model-ProductOrder" title="Product order" parent="bpm-product-root" show-action="true" appBuilder="PRD">
|
||||
<action name="all.json.ProductOrder" title="Product order" model="com.axelor.meta.db.MetaJsonRecord"
|
||||
domain="self.jsonModel = :jsonModel" isJson="true">
|
||||
<views>
|
||||
<view type="grid" name="custom-model-ProductOrder-grid" sequence="1" />
|
||||
<view type="form" name="custom-model-ProductOrder-form" sequence="2" />
|
||||
</views>
|
||||
<context>
|
||||
<ctx name="jsonModel" value="'ProductOrder'" />
|
||||
</context>
|
||||
</action>
|
||||
</menu-builder>
|
||||
|
||||
<menu-builder name="menu-json-model-ProductOrderLine" title="Product order line" parent="bpm-product-root" show-action="true" appBuilder="PRD" >
|
||||
<action name="all.json.ProductOrderLine" title="Product order line" model="com.axelor.meta.db.MetaJsonRecord"
|
||||
domain="self.jsonModel = :jsonModel" isJson="true">
|
||||
<views>
|
||||
<view type="grid" name="custom-model-ProductOrderLine-grid" sequence="1" />
|
||||
<view type="form" name="custom-model-ProductOrderLine-form" sequence="2" />
|
||||
</views>
|
||||
<context>
|
||||
<ctx name="jsonModel" value="'ProductOrderLine'" />
|
||||
</context>
|
||||
</action>
|
||||
</menu-builder>
|
||||
|
||||
<menu-builder name="bpm-dashboard-product-dashboard" title="Product dashboard" parent="bpm-product-root" show-action="true" appBuilder="PRD">
|
||||
<action name="bpm.dashboard.product.dashboard" title="Product dashboard" isJson="true">
|
||||
<views>
|
||||
<view type="dashboard" name="product-dashboard" sequence="1" />
|
||||
</views>
|
||||
</action>
|
||||
</menu-builder>
|
||||
|
||||
<!-- <menu-builder name="bpm-dashboard-crm-dashboard" title="Crm dashboard" parent="bpm-dashboard-root" show-action="true"> -->
|
||||
<!-- <action name="bpm.dashboard.sales.dashboard" title="Sales dashboard"> -->
|
||||
<!-- <views> -->
|
||||
<!-- <view type="dashboard" name="sales-order-dashboard" /> -->
|
||||
<!-- </views> -->
|
||||
<!-- </action> -->
|
||||
<!-- </menu-builder> -->
|
||||
|
||||
|
||||
</menu-builders>
|
||||
@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<json-models xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
|
||||
<json-model name="ProductCategory" title="Product category" appBuilder="PRD">
|
||||
<fields>
|
||||
<field name="name" title="Name" required="true" type="string" sequence="1" visibleInGrid="true"/>
|
||||
<field name="code" title="Code" type="string" sequence="2" visibleInGrid="true"/>
|
||||
</fields>
|
||||
</json-model>
|
||||
|
||||
<json-model name="Product" title="Product" appBuilder="PRD">
|
||||
<fields>
|
||||
<field name="name" title="Name" required="true" type="string" sequence="1" visibleInGrid="true"/>
|
||||
<field name="code" title="Code" type="string" sequence="2" visibleInGrid="true"/>
|
||||
<field name="price" title="Price" type="decimal" sequence="3" visibleInGrid="true"/>
|
||||
<field name="launchDate" title="Launch Date" type="date" sequence="4"/>
|
||||
<field name="supplier" title="Supplier" type="many-to-one" target-model="com.axelor.apps.base.db.Partner" sequence="5"/>
|
||||
<field name="category" title="Main Category" type="json-many-to-one" target-json-model="ProductCategory" sequence="6" visibleInGrid="true"/>
|
||||
</fields>
|
||||
</json-model>
|
||||
|
||||
<json-model name="ProductOrderLine" title="Product order line" appBuilder="PRD">
|
||||
<fields>
|
||||
<field name="product" title="Product" type="json-many-to-one" target-json-model="Product" sequence="1" onChange="action-product-order-line-get-product-details,action-product-order-line-update-total" visibleInGrid="true"/>
|
||||
<field name="price" title="Price" type="decimal" sequence="2" onChange="action-product-order-line-update-total" visibleInGrid="true"/>
|
||||
<field name="qty" title="Qty" type="integer" sequence="3" onChange="action-product-order-line-update-total" visibleInGrid="true"/>
|
||||
<field name="total" title="Total" type="decimal" sequence="4" visibleInGrid="true"/>
|
||||
</fields>
|
||||
</json-model>
|
||||
|
||||
<json-model name="ProductOrder" title="Product order" appBuilder="PRD">
|
||||
<fields>
|
||||
<field name="reference" title="Ref" type="string" sequence="1" visibleInGrid="true"/>
|
||||
<field name="customer" title="Customer" type="many-to-one" target-model="com.axelor.apps.base.db.Partner" domain="isCustomer = true" sequence="2" visibleInGrid="true"/>
|
||||
<field name="orderDate" title="Order Date" type="date" sequence="3" visibleInGrid="true"/>
|
||||
<field name="total" title="Total" type="decimal" sequence="4" visibleInGrid="true"/>
|
||||
<field name="lines" title="Lines" type="json-one-to-many" target-json-model="ProductOrderLine" sequence="5" onChange="action-product-order-update-total"/>
|
||||
<field name="status" title="Status" type="integer" sequence="6" visibleInGrid="true"/>
|
||||
</fields>
|
||||
</json-model>
|
||||
|
||||
<json-field name="createInvoice" type="button"
|
||||
model="com.axelor.apps.hr.db.Timesheet" modelField="attrs"
|
||||
onClick="action-create-invoice-from-timesheet" sequence="1"
|
||||
appBuilder="PRD" showIf="$record.user.employee"
|
||||
title="Create invoice"/>
|
||||
|
||||
<json-field name="createPlanning" type="button"
|
||||
model="com.axelor.apps.project.db.Project" modelField="attrs"
|
||||
onClick="action-create-project-planning" sequence="1" appBuilder="PRD"
|
||||
title="Create planning"/>
|
||||
|
||||
<json-field name="invertToInvoice" title="Check/Uncheck 'to invoice'" type="button" model="com.axelor.apps.hr.db.Timesheet" modelField="attrs" onClick="action-timesheet-line-invert-to-invoice" sequence="2" appBuilder="PRD"/>
|
||||
|
||||
<json-field name="products" title="Products" type="json-many-to-many" target-json-model="Product" model="com.axelor.meta.db.MetaJsonRecord" modelField="attrs" jsonModel="ProductCategory" sequence="3" appBuilder="PRD"/>
|
||||
|
||||
<json-field name="createProduct" title="Create product order" type="button" onClick="action-create-product-order-from-category" model="com.axelor.meta.db.MetaJsonRecord" modelField="attrs" jsonModel="ProductCategory" sequence="4" appBuilder="PRD"/>
|
||||
|
||||
</json-models>
|
||||
@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<meta-translations xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
|
||||
<meta-translation key="Launch Date" message="Date de lancement" language="fr"/>
|
||||
<meta-translation key="Main Category" message="Catégorie principale" language="fr"/>
|
||||
<meta-translation key="Product order line" message="Ligne de commande produit" language="fr"/>
|
||||
<meta-translation key="Product order" message="Commande produit" language="fr"/>
|
||||
<meta-translation key="Create product order" message="Créer commande produit" language="fr"/>
|
||||
<meta-translation key="Product dashboard" message="Tableau de bord produit" language="fr"/>
|
||||
<meta-translation key="Product orders per month" message="Commandes produit par mois" language="fr"/>
|
||||
<meta-translation key="Product orders per supplier per category" message="Commandes produit par fournisseurs et catégorie" language="fr"/>
|
||||
<meta-translation key="Reset" message="Réinitialiser" language="fr"/>
|
||||
<meta-translation key="Are you sure wants to validate." message="Êtes-vous sûr de vouloir valider cette commande?" language="fr"/>
|
||||
<meta-translation key="Order validated" message="Commande validée" language="fr"/>
|
||||
<meta-translation key="Are you sure wants to cancel ?" message="Êtes-vous sûr de vouloir annuler cette commande??" language="fr"/>
|
||||
<meta-translation key="Order finished." message="Commande terminée" language="fr"/>
|
||||
<meta-translation key="Check/Uncheck 'to invoice'" message="Cocher/Décocher 'A facturer'" language="fr"/>
|
||||
|
||||
</meta-translations>
|
||||
|
||||
|
||||
@ -0,0 +1,157 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<wkfs xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
|
||||
<wkf name="Product Order Flow" isJson="true" model="ProductOrder" statusField="status" displayTypeSelect="0" appBuilder="PRD">
|
||||
<xml>
|
||||
<![CDATA[
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:x="http://axelor.com" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn">
|
||||
<process id="Process_1" name="undefined" isExecutable="false" x:id="undefined">
|
||||
<endEvent id="EndEvent_062urgf" name="Finished">
|
||||
<incoming>SequenceFlow_18u3b2a</incoming>
|
||||
</endEvent>
|
||||
<startEvent id="StartEvent_07npy19" name="Draft">
|
||||
<incoming>SequenceFlow_1yn5orr</incoming>
|
||||
<outgoing>SequenceFlow_0qljt6y</outgoing>
|
||||
</startEvent>
|
||||
<task id="Task_07my1i6" name="Confirmed">
|
||||
<incoming>SequenceFlow_0qljt6y</incoming>
|
||||
<outgoing>SequenceFlow_10bvr21</outgoing>
|
||||
<outgoing>SequenceFlow_02m6a90</outgoing>
|
||||
</task>
|
||||
<sequenceFlow id="SequenceFlow_0qljt6y" name="Confirm" sourceRef="StartEvent_07npy19" targetRef="Task_07my1i6" />
|
||||
<task id="Task_0k79fbo" name="Validated">
|
||||
<incoming>SequenceFlow_10bvr21</incoming>
|
||||
<outgoing>SequenceFlow_18u3b2a</outgoing>
|
||||
</task>
|
||||
<sequenceFlow id="SequenceFlow_10bvr21" name="Validate" sourceRef="Task_07my1i6" targetRef="Task_0k79fbo" />
|
||||
<task id="Task_069h0a2" name="Canceled">
|
||||
<incoming>SequenceFlow_02m6a90</incoming>
|
||||
<outgoing>SequenceFlow_1yn5orr</outgoing>
|
||||
</task>
|
||||
<sequenceFlow id="SequenceFlow_02m6a90" name="Cancel" sourceRef="Task_07my1i6" targetRef="Task_069h0a2" />
|
||||
<sequenceFlow id="SequenceFlow_18u3b2a" name="Finish" sourceRef="Task_0k79fbo" targetRef="EndEvent_062urgf" />
|
||||
<sequenceFlow id="SequenceFlow_1yn5orr" name="Reset" sourceRef="Task_069h0a2" targetRef="StartEvent_07npy19" />
|
||||
</process>
|
||||
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
||||
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1">
|
||||
<bpmndi:BPMNShape id="EndEvent_062urgf_di" bpmnElement="EndEvent_062urgf">
|
||||
<dc:Bounds x="747" y="120" width="36" height="36" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="720" y="156" width="90" height="20" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="StartEvent_07npy19_di" bpmnElement="StartEvent_07npy19">
|
||||
<dc:Bounds x="133" y="120" width="36" height="36" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="87" y="168" width="90" height="20" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Task_07my1i6_di" bpmnElement="Task_07my1i6">
|
||||
<dc:Bounds x="291" y="98" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_0qljt6y_di" bpmnElement="SequenceFlow_0qljt6y">
|
||||
<di:waypoint xsi:type="dc:Point" x="169" y="138" />
|
||||
<di:waypoint xsi:type="dc:Point" x="291" y="138" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="190" y="117" width="90" height="20" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNShape id="Task_0k79fbo_di" bpmnElement="Task_0k79fbo">
|
||||
<dc:Bounds x="492" y="98" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_10bvr21_di" bpmnElement="SequenceFlow_10bvr21">
|
||||
<di:waypoint xsi:type="dc:Point" x="391" y="138" />
|
||||
<di:waypoint xsi:type="dc:Point" x="492" y="138" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="392" y="105" width="90" height="20" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNShape id="Task_069h0a2_di" bpmnElement="Task_069h0a2">
|
||||
<dc:Bounds x="500" y="239" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_02m6a90_di" bpmnElement="SequenceFlow_02m6a90">
|
||||
<di:waypoint xsi:type="dc:Point" x="341" y="178" />
|
||||
<di:waypoint xsi:type="dc:Point" x="341" y="279" />
|
||||
<di:waypoint xsi:type="dc:Point" x="500" y="279" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="373" y="253.5" width="90" height="20" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_18u3b2a_di" bpmnElement="SequenceFlow_18u3b2a">
|
||||
<di:waypoint xsi:type="dc:Point" x="592" y="138" />
|
||||
<di:waypoint xsi:type="dc:Point" x="747" y="138" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="625" y="112" width="90" height="20" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_1yn5orr_di" bpmnElement="SequenceFlow_1yn5orr">
|
||||
<di:waypoint xsi:type="dc:Point" x="550" y="319" />
|
||||
<di:waypoint xsi:type="dc:Point" x="550" y="356" />
|
||||
<di:waypoint xsi:type="dc:Point" x="151" y="356" />
|
||||
<di:waypoint xsi:type="dc:Point" x="151" y="156" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="266" y="330.5" width="90" height="20" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNEdge>
|
||||
</bpmndi:BPMNPlane>
|
||||
</bpmndi:BPMNDiagram>
|
||||
</definitions>
|
||||
]]>
|
||||
</xml>
|
||||
</wkf>
|
||||
|
||||
<wkfNode wkf="Product Order Flow" name="Draft" title="Draft" nodeType="0" sequence="1" xmlId="StartEvent_07npy19"/>
|
||||
<wkfNode wkf="Product Order Flow" name="Confirmed" title="Confirmed" nodeType="1" sequence="2" xmlId="Task_07my1i6" />
|
||||
<wkfNode wkf="Product Order Flow" name="Validated" title="Validated" nodeType="1" sequence="3" xmlId="Task_0k79fbo" />
|
||||
<wkfNode wkf="Product Order Flow" name="Canceled" title="Canceled" nodeType="1" sequence="4" xmlId="Task_069h0a2"/>
|
||||
<wkfNode wkf="Product Order Flow" name="Finished" title="Finished" nodeType="2" sequence="5" xmlId="EndEvent_062urgf"/>
|
||||
|
||||
<transition wkf="Product Order Flow" name="Confirm" source="Draft" target="Confirmed" isButton="true" buttonTitle="Confirm" xmlId="SequenceFlow_0qljt6y"/>
|
||||
<transition wkf="Product Order Flow" name="Validate" source="Confirmed" target="Validated" isButton="true" buttonTitle="Validate" xmlId="SequenceFlow_10bvr21" alertTypeSelect="1" alertMsg="Are you sure wants to validate." successMsg="Order validated" />
|
||||
<transition wkf="Product Order Flow" name="Cancel" source="Confirmed" target="Canceled" isButton="true" buttonTitle="Cancel" xmlId="SequenceFlow_02m6a90" alertTypeSelect="1" alertMsg="Are you sure wants to cancel ?" />
|
||||
<transition wkf="Product Order Flow" name="Finish" source="Validated" target="Finished" isButton="true" buttonTitle="Finish" xmlId="SequenceFlow_18u3b2a" alertTypeSelect="2" alertMsg="Order finished." />
|
||||
<transition wkf="Product Order Flow" name="Reset" source="Canceled" target="Draft" isButton="true" buttonTitle="Reset" xmlId="SequenceFlow_1yn5orr" />
|
||||
|
||||
<node wkf="Product Order Flow" name="Draft">
|
||||
<incomings>
|
||||
<incoming name="Reset" />
|
||||
</incomings>
|
||||
<outgoings>
|
||||
<outgoing name="Confirm" />
|
||||
</outgoings>
|
||||
</node>
|
||||
<node wkf="Product Order Flow" name="Confirmed">
|
||||
<incomings>
|
||||
<incoming name="Confirm" />
|
||||
</incomings>
|
||||
<outgoings>
|
||||
<outgoing name="Validate" />
|
||||
<outgoing name="Cancel" />
|
||||
</outgoings>
|
||||
</node>
|
||||
<node wkf="Product Order Flow" name="Validated">
|
||||
<incomings>
|
||||
<incoming name="Validate" />
|
||||
</incomings>
|
||||
<outgoings>
|
||||
<outgoing name="Finish" />
|
||||
</outgoings>
|
||||
</node>
|
||||
<node wkf="Product Order Flow" name="Canceled">
|
||||
<incomings>
|
||||
<incoming name="Cancel" />
|
||||
</incomings>
|
||||
<outgoings>
|
||||
<outgoing name="Reset" />
|
||||
</outgoings>
|
||||
</node>
|
||||
<node wkf="Product Order Flow" name="Finished">
|
||||
<incomings>
|
||||
<incoming name="Finish" />
|
||||
</incomings>
|
||||
</node>
|
||||
|
||||
<workflow name="Product Order Flow" />
|
||||
</wkfs>
|
||||
@ -0,0 +1,102 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<action-builders xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
|
||||
<action-builder name="action-create-invoice-from-timesheet"
|
||||
isJson="false"
|
||||
typeSelect="0"
|
||||
appBuilder="PRD"
|
||||
model="com.axelor.apps.hr.db.Timesheet"
|
||||
targetModel="com.axelor.apps.account.db.Invoice">
|
||||
<lines>
|
||||
<line metaField="partner" metaModel="Invoice" valueField="company" valueModel="Timesheet" value="$.company.partner" />
|
||||
<line metaField="company" metaModel="Invoice" valueField="company" valueModel="Timesheet" value="$.company" />
|
||||
<line metaField="currency" metaModel="Invoice" valueField="company" valueModel="Timesheet" value="$.company.currency" />
|
||||
<line metaField="operationTypeSelect" metaModel="Invoice" value="3"/>
|
||||
<line metaField="paymentCondition" metaModel="Invoice" filter="self.code = '15D_EOM'"/>
|
||||
<line metaField="paymentMode" metaModel="Invoice" filter="self.code = 'OUT_WT'"/>
|
||||
<line name="total" value="$.timesheetLineList.sum($.hoursDuration*$$.user.employee.hourlyRate)" dummy="true"/>
|
||||
<line metaField="exTaxTotal" metaModel="Invoice" value="_$.total" />
|
||||
<line metaField="inTaxTotal" metaModel="Invoice" value="_$.total" />
|
||||
<line metaField="invoiceLineList" metaModel="Invoice" valueField="timesheetLineList" valueModel="Timesheet" value="$.timesheetLineList">
|
||||
<subLines>
|
||||
<line metaField="exTaxTotal" metaModel="InvoiceLine" value="$.hoursDuration*$$.user.employee.hourlyRate" />
|
||||
<line metaField="price" metaModel="InvoiceLine" value="$$.user.employee.hourlyRate" />
|
||||
<line metaField="product" metaModel="InvoiceLine" valueModel="TimesheetLine" valueField="product" value="$.product" />
|
||||
<line metaField="productName" metaModel="InvoiceLine" valueModel="TimesheetLine" valueField="product" value="$.product.name" />
|
||||
<line metaField="qty" metaModel="InvoiceLine" valueModel="TimesheetLine" valueField="hoursDuration" value="$.hoursDuration" />
|
||||
<line metaField="unit" metaModel="InvoiceLine" filter="self.name = 'Hour'"/>
|
||||
</subLines>
|
||||
</line>
|
||||
</lines>
|
||||
</action-builder>
|
||||
|
||||
<action-builder name="action-timesheet-line-invert-to-invoice"
|
||||
isJson="false"
|
||||
typeSelect="1"
|
||||
appBuilder="PRD"
|
||||
model="com.axelor.apps.hr.db.Timesheet">
|
||||
<lines>
|
||||
<line metaField="timesheetLineList" metaModel="Timesheet" value="$.timesheetLineList" valueModel="Timesheet" valueField="timesheetLineList">
|
||||
<subLines>
|
||||
<line metaField="toInvoice" metaModel="TimesheetLine" value="!$.toInvoice" valueModel="TimesheetLine" valueField="toInvoice" />
|
||||
</subLines>
|
||||
</line>
|
||||
</lines>
|
||||
</action-builder>
|
||||
|
||||
<action-builder name="action-create-product-order-from-category"
|
||||
isJson="true"
|
||||
typeSelect="0"
|
||||
appBuilder="PRD"
|
||||
model="ProductCategory"
|
||||
targetModel="ProductOrder">
|
||||
<lines>
|
||||
<line jsonField="customer" jsonModel="ProductOrder" filter="self.name = 'Axelor'" />
|
||||
<line jsonField="status" jsonModel="ProductOrder" value="1" />
|
||||
<line jsonField="total" jsonModel="ProductOrder" value="$.products.sum($.price)" />
|
||||
<line jsonField="lines" jsonModel="ProductOrder" value="$.products" valueJsonModel="ProductCategory" valueJsonField="products">
|
||||
<subLines>
|
||||
<line jsonField="product" jsonModel="ProductOrderLine" value="$" />
|
||||
<line jsonField="price" jsonModel="ProductOrderLine" value="$.price" valueJsonModel="Product" valueJsonField="price" />
|
||||
<line jsonField="qty" jsonModel="ProductOrderLine" value="1" />
|
||||
<line jsonField="total" jsonModel="ProductOrderLine" value="$.price" valueJsonModel="Product" valueJsonField="price" />
|
||||
</subLines>
|
||||
</line>
|
||||
</lines>
|
||||
</action-builder>
|
||||
|
||||
<action-builder name="action-product-order-line-update-total"
|
||||
isJson="true"
|
||||
typeSelect="1"
|
||||
appBuilder="PRD"
|
||||
model="ProductOrderLine"
|
||||
targetModel="ProductOrderLine">
|
||||
<lines>
|
||||
<line jsonField="total" jsonModel="ProductOrderLine" value="$.price*$.qty" />
|
||||
</lines>
|
||||
</action-builder>
|
||||
|
||||
<action-builder name="action-product-order-line-get-product-details"
|
||||
isJson="true"
|
||||
typeSelect="1"
|
||||
appBuilder="PRD"
|
||||
model="ProductOrderLine"
|
||||
targetModel="ProductOrderLine">
|
||||
<lines>
|
||||
<line jsonField="price" jsonModel="ProductOrderLine" valueJson="Product" valueJsonModel="ProductOrderLine" valueJsonField="product" value="$.product.price" />
|
||||
</lines>
|
||||
</action-builder>
|
||||
|
||||
<action-builder name="action-product-order-update-total"
|
||||
isJson="true"
|
||||
typeSelect="1"
|
||||
appBuilder="PRD"
|
||||
model="ProductOrder"
|
||||
targetModel="ProductOrder">
|
||||
<lines>
|
||||
<line jsonField="total" jsonModel="ProductOrder" valueJson="Product" valueJsonModel="ProductOrder" valueJsonField="lines" value="$.lines.sum($.total)" />
|
||||
</lines>
|
||||
</action-builder>
|
||||
|
||||
</action-builders>
|
||||
File diff suppressed because one or more lines are too long
@ -0,0 +1,46 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<chart-builders xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
|
||||
|
||||
<chart-builder name="product-order-chart" title="Commandes produit par mois" appBuilder="PRD"
|
||||
type="bar" model="ProductOrder" json="true" groupOnJson="orderDate" groupOnTarget="orderDate" groupOnTargetType="Date" groupDateType="month"
|
||||
isJsonGroupOn="true" isJsonAggregateOn="true" isJsonDisplayField="true"
|
||||
aggregateOnJson="customer" aggregateOnTarget="customer.fullName" aggregateOnTargetType="String" displayFieldJson="total">
|
||||
<filters>
|
||||
<filter json="true" targetType="many-to-one" operator="notNull" targetField="customer" jsonField="customer" />
|
||||
<filter json="true" targetType="date" operator="<=" targetField="orderDate" value="$date" jsonField="orderDate" />
|
||||
</filters>
|
||||
</chart-builder>
|
||||
|
||||
<chart-builder name="product-order-per-author-per-category" title="Commandes produit par fournisseurs et catégorie" appBuilder="PRD"
|
||||
type="pie" model="ProductOrderLine" json="true" groupOnJson="product"
|
||||
isJsonGroupOn="true" isJsonAggregateOn="true" isJsonDisplayField="true"
|
||||
groupOnTarget="product.supplier.name" groupOnTargetType="String" displayFieldJson="total">
|
||||
<filters>
|
||||
<filter json="true" targetType="json-many-to-one" operator="=" targetField="product.category" isParameter="true" jsonField="product" />
|
||||
</filters>
|
||||
</chart-builder>
|
||||
|
||||
|
||||
<!-- <chart-builder name="sal" title="Ventes de produit par catégorie" -->
|
||||
<!-- type="pie" model="com.axelor.apps.sale.db.SaleOrderLine" groupOn="product" -->
|
||||
<!-- groupOnTarget="product.productCategory.name" displayField="exTaxTotal"> -->
|
||||
<!-- <filters> -->
|
||||
<!-- <filter targetType="many-to-one" operator="=" targetField="product.productFamily" isParameter="true" field="product" /> -->
|
||||
<!-- <filter targetType="Integer" operator="in" targetField="saleOrder.statusSelect" field="saleOrder" value="3,4" /> -->
|
||||
<!-- </filters> -->
|
||||
<!-- </chart-builder> -->
|
||||
|
||||
<!-- <chart-builder name="products-order-per-month-per-customer" title="Ventes de produit par mois et par client" -->
|
||||
<!-- type="bar" model="com.axelor.apps.sale.db.SaleOrderLine" groupOn="saleOrder" groupOnTarget="saleOrder.orderDate" groupOnTargetType="LocalDate" groupDateType="month" -->
|
||||
<!-- aggregateOn="saleOrder" aggregateOnTarget="saleOrder.clientPartner.fullName" displayField="exTaxTotal"> -->
|
||||
<!-- <filters> -->
|
||||
<!-- <filter targetType="Integer" operator="in" targetField="saleOrder.statusSelect" value="3,4" field="saleOrder" /> -->
|
||||
<!-- <filter targetType="LocalDate" operator="notNull" targetField="saleOrder.orderDate" field="saleOrder" /> -->
|
||||
<!-- <filter targetType="many-to-one" operator="=" targetField="product" isParameter="true" field="product" /> -->
|
||||
<!-- </filters> -->
|
||||
<!-- </chart-builder> -->
|
||||
|
||||
|
||||
</chart-builders>
|
||||
@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<dashboard-builders xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
|
||||
<dashboard-builder name="product-dashboard" title="Tableau de bord produit" appBuilder="PRD">
|
||||
<dashlets>
|
||||
<dashlet name="Commande produit" sequence="0" viewType="grid" colspan="12" view="custom-model-ProductOrder-grid" />
|
||||
<dashlet name="Commandes produit par mois" sequence="1" viewType="chart" colspan="6" view="product-order-chart" />
|
||||
<dashlet name="Commandes produit par fournisseurs et catégorie" sequence="2" viewType="chart" colspan="6" view="product-order-per-author-per-category" />
|
||||
</dashlets>
|
||||
</dashboard-builder>
|
||||
|
||||
<!-- <dashboard-builder name="product-order-dashboard" title="Tableau de bord produit"> -->
|
||||
<!-- <dashlets> -->
|
||||
<!-- <dashlet name="Tous les produits" sequence="0" viewType="grid" colspan="12" view="product-grid" /> -->
|
||||
<!-- <dashlet name="Ventes de produit par catégorie" sequence="1" viewType="chart" colspan="6" view="products-order-per-category" /> -->
|
||||
<!-- <dashlet name="Ventes de produit par mois et par client" sequence="2" viewType="chart" colspan="6" view="products-order-per-month-per-customer" /> -->
|
||||
<!-- </dashlets> -->
|
||||
<!-- </dashboard-builder> -->
|
||||
|
||||
|
||||
</dashboard-builders>
|
||||
@ -0,0 +1,76 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu-builders xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
|
||||
<menu-builder name="bpm-product-root" title="Produits" icon="fa-cube" background="red" appBuilder="PRD" />
|
||||
|
||||
<menu-builder name="menu-json-model-ProductCategory" title="Catégorie de produit" parent="bpm-product-root" appBuilder="PRD" show-action="true">
|
||||
<action name="all.json.ProductCategory" title="Catégorie de produit" model="com.axelor.meta.db.MetaJsonRecord"
|
||||
domain="self.jsonModel = :jsonModel" isJson="true">
|
||||
<views>
|
||||
<view type="grid" name="custom-model-ProductCategory-grid" sequence="1" />
|
||||
<view type="form" name="custom-model-ProductCategory-form" sequence="2" />
|
||||
</views>
|
||||
<context>
|
||||
<ctx name="jsonModel" value="'ProductCategory'" />
|
||||
</context>
|
||||
</action>
|
||||
</menu-builder>
|
||||
|
||||
<menu-builder name="menu-json-model-Product" title="Produits" parent="bpm-product-root" show-action="true" appBuilder="PRD">
|
||||
<action name="all.json.Product" title="Produits" model="com.axelor.meta.db.MetaJsonRecord"
|
||||
domain="self.jsonModel = :jsonModel" isJson="true">
|
||||
<views>
|
||||
<view type="grid" name="custom-model-Product-grid" sequence="1" />
|
||||
<view type="form" name="custom-model-Product-form" sequence="2" />
|
||||
</views>
|
||||
<context>
|
||||
<ctx name="jsonModel" value="'Product'" />
|
||||
</context>
|
||||
</action>
|
||||
</menu-builder>
|
||||
|
||||
<menu-builder name="menu-json-model-ProductOrder" title="Commande produit" parent="bpm-product-root" show-action="true" appBuilder="PRD">
|
||||
<action name="all.json.ProductOrder" title="Commande produit" model="com.axelor.meta.db.MetaJsonRecord"
|
||||
domain="self.jsonModel = :jsonModel" isJson="true">
|
||||
<views>
|
||||
<view type="grid" name="custom-model-ProductOrder-grid" sequence="1" />
|
||||
<view type="form" name="custom-model-ProductOrder-form" sequence="2" />
|
||||
</views>
|
||||
<context>
|
||||
<ctx name="jsonModel" value="'ProductOrder'" />
|
||||
</context>
|
||||
</action>
|
||||
</menu-builder>
|
||||
|
||||
<menu-builder name="menu-json-model-ProductOrderLine" title="Ligne de commande produit" parent="bpm-product-root" show-action="true" appBuilder="PRD">
|
||||
<action name="all.json.ProductOrderLine" title="Ligne de commande produit" model="com.axelor.meta.db.MetaJsonRecord"
|
||||
domain="self.jsonModel = :jsonModel" isJson="true">
|
||||
<views>
|
||||
<view type="grid" name="custom-model-ProductOrderLine-grid" sequence="1" />
|
||||
<view type="form" name="custom-model-ProductOrderLine-form" sequence="2" />
|
||||
</views>
|
||||
<context>
|
||||
<ctx name="jsonModel" value="'ProductOrderLine'" />
|
||||
</context>
|
||||
</action>
|
||||
</menu-builder>
|
||||
|
||||
<menu-builder name="bpm-dashboard-product-dashboard" title="Tableau de bord produit" parent="bpm-product-root" show-action="true" appBuilder="PRD">
|
||||
<action name="bpm.dashboard.product.dashboard" title="Tableau de bord produit" isJson="true">
|
||||
<views>
|
||||
<view type="dashboard" name="product-dashboard" sequence="1" />
|
||||
</views>
|
||||
</action>
|
||||
</menu-builder>
|
||||
|
||||
<!-- <menu-builder name="bpm-dashboard-crm-dashboard" title="Crm dashboard" parent="bpm-dashboard-root" show-action="true"> -->
|
||||
<!-- <action name="bpm.dashboard.sales.dashboard" title="Sales dashboard"> -->
|
||||
<!-- <views> -->
|
||||
<!-- <view type="dashboard" name="sales-order-dashboard" /> -->
|
||||
<!-- </views> -->
|
||||
<!-- </action> -->
|
||||
<!-- </menu-builder> -->
|
||||
|
||||
|
||||
</menu-builders>
|
||||
@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<json-models xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
|
||||
<json-model name="ProductCategory" title="Catégorie de produit" appBuilder="PRD">
|
||||
<fields>
|
||||
<field name="name" title="Nom" required="true" type="string" sequence="1" visibleInGrid="true"/>
|
||||
<field name="code" title="Code" type="string" sequence="2" visibleInGrid="true"/>
|
||||
</fields>
|
||||
</json-model>
|
||||
|
||||
<json-model name="Product" title="Produit" appBuilder="PRD">
|
||||
<fields>
|
||||
<field name="name" title="Nom" required="true" type="string" sequence="1" visibleInGrid="true"/>
|
||||
<field name="code" title="Code" type="string" sequence="2" visibleInGrid="true"/>
|
||||
<field name="price" title="Prix" type="decimal" sequence="3" visibleInGrid="true"/>
|
||||
<field name="launchDate" title="Date de lancement" type="date" sequence="4"/>
|
||||
<field name="supplier" title="Fournisseur" type="many-to-one" target-model="com.axelor.apps.base.db.Partner" sequence="5"/>
|
||||
<field name="category" title="Catégorie principale" type="json-many-to-one" target-json-model="ProductCategory" sequence="6" visibleInGrid="true"/>
|
||||
</fields>
|
||||
</json-model>
|
||||
|
||||
<json-model name="ProductOrderLine" title="Ligne de commande produit" appBuilder="PRD">
|
||||
<fields>
|
||||
<field name="product" title="Produit" type="json-many-to-one" target-json-model="Product" sequence="1" onChange="action-product-order-line-get-product-details,action-product-order-line-update-total" visibleInGrid="true"/>
|
||||
<field name="price" title="Prix" type="decimal" sequence="2" onChange="action-product-order-line-update-total" visibleInGrid="true"/>
|
||||
<field name="qty" title="Qté" type="integer" sequence="3" onChange="action-product-order-line-update-total" visibleInGrid="true"/>
|
||||
<field name="total" title="Total" type="decimal" sequence="4" visibleInGrid="true"/>
|
||||
</fields>
|
||||
</json-model>
|
||||
|
||||
<json-model name="ProductOrder" title="Commande produit" appBuilder="PRD">
|
||||
<fields>
|
||||
<field name="reference" title="Réf" type="string" sequence="1" visibleInGrid="true"/>
|
||||
<field name="customer" title="Client" type="many-to-one" target-model="com.axelor.apps.base.db.Partner" domain="isCustomer = true" sequence="2" visibleInGrid="true"/>
|
||||
<field name="orderDate" title="Date de commande" type="date" sequence="3" visibleInGrid="true"/>
|
||||
<field name="total" title="Total" type="decimal" sequence="4" visibleInGrid="true"/>
|
||||
<field name="lines" title="Lignes" type="json-one-to-many" target-json-model="ProductOrderLine" sequence="5" onChange="action-product-order-update-total"/>
|
||||
<field name="status" title="Statut" type="integer" sequence="6" visibleInGrid="true"/>
|
||||
</fields>
|
||||
</json-model>
|
||||
|
||||
<json-field name="createInvoice" type="button"
|
||||
model="com.axelor.apps.hr.db.Timesheet" modelField="attrs"
|
||||
onClick="action-create-invoice-from-timesheet" sequence="1"
|
||||
appBuilder="PRD" showIf="$record.user.employee"
|
||||
title="Créer facture"/>
|
||||
|
||||
<json-field name="createPlanning" type="button"
|
||||
model="com.axelor.apps.project.db.Project" modelField="attrs"
|
||||
onClick="action-create-project-planning" sequence="1" appBuilder="PRD"
|
||||
title="Créer planning"/>
|
||||
|
||||
<json-field name="invertToInvoice" title="Cocher/Décocher 'A facturer'" type="button" model="com.axelor.apps.hr.db.Timesheet" modelField="attrs" onClick="action-timesheet-line-invert-to-invoice" sequence="2" appBuilder="PRD"/>
|
||||
|
||||
<json-field name="products" title="Produit" type="json-many-to-many" target-json-model="Product" model="com.axelor.meta.db.MetaJsonRecord" modelField="attrs" jsonModel="ProductCategory" sequence="3" appBuilder="PRD"/>
|
||||
|
||||
<json-field name="createProduct" title="Créer commande produit" type="button" onClick="action-create-product-order-from-category" model="com.axelor.meta.db.MetaJsonRecord" modelField="attrs" jsonModel="ProductCategory" sequence="4" appBuilder="PRD"/>
|
||||
|
||||
</json-models>
|
||||
@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<meta-translations xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
|
||||
<meta-translation key="Date de lancement" message="Launch Date" language="en"/>
|
||||
<meta-translation key="Catégorie de produit" message="Product category" language="en"/>
|
||||
<meta-translation key="Produit" message="Product" language="en"/>
|
||||
<meta-translation key="Produits" message="Products" language="en"/>
|
||||
<meta-translation key="Catégorie principale" message="Main Category" language="en"/>
|
||||
<meta-translation key="Ligne de commande produit" message="Product order line" language="en"/>
|
||||
<meta-translation key="Commande produit" message="Product order" language="en"/>
|
||||
<meta-translation key="Créer commande produit" message="Create product order" language="en"/>
|
||||
<meta-translation key="Tableau de bord produit" message="Product dashboard" language="en"/>
|
||||
<meta-translation key="Commandes produit par mois" message="Product orders per month" language="en"/>
|
||||
<meta-translation key="Commandes produit par fournisseurs et catégorie" message="Product orders per supplier per category" language="en"/>
|
||||
<meta-translation key="Réinitialiser" message="Reset" language="en"/>
|
||||
<meta-translation key="Êtes-vous sûr de vouloir valider cette commande?" message="Are you sure wants to validate." language="en"/>
|
||||
<meta-translation key="Commande validée" message="Order validated" language="en"/>
|
||||
<meta-translation key="Êtes-vous sûr de vouloir annuler cette commande??" message="Are you sure wants to cancel ?" language="en"/>
|
||||
<meta-translation key="Commande terminée" message="Order finished." language="en"/>
|
||||
<meta-translation key="Cocher/Décocher 'A facturer'" message="Check/Uncheck 'to invoice'" language="en"/>
|
||||
|
||||
</meta-translations>
|
||||
@ -0,0 +1,157 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<wkfs xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
|
||||
<wkf name="Commande produit" isJson="true" model="ProductOrder" statusField="status" displayTypeSelect="0" appBuilder="PRD">
|
||||
<xml>
|
||||
<![CDATA[
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:x="http://axelor.com" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn">
|
||||
<process id="Process_1" name="undefined" isExecutable="false" x:id="undefined">
|
||||
<endEvent id="EndEvent_062urgf" name="Terminé">
|
||||
<incoming>SequenceFlow_18u3b2a</incoming>
|
||||
</endEvent>
|
||||
<startEvent id="StartEvent_07npy19" name="Brouillon">
|
||||
<incoming>SequenceFlow_1yn5orr</incoming>
|
||||
<outgoing>SequenceFlow_0qljt6y</outgoing>
|
||||
</startEvent>
|
||||
<task id="Task_07my1i6" name="Confirmé">
|
||||
<incoming>SequenceFlow_0qljt6y</incoming>
|
||||
<outgoing>SequenceFlow_10bvr21</outgoing>
|
||||
<outgoing>SequenceFlow_02m6a90</outgoing>
|
||||
</task>
|
||||
<sequenceFlow id="SequenceFlow_0qljt6y" name="Confirmer" sourceRef="StartEvent_07npy19" targetRef="Task_07my1i6" />
|
||||
<task id="Task_0k79fbo" name="Validé">
|
||||
<incoming>SequenceFlow_10bvr21</incoming>
|
||||
<outgoing>SequenceFlow_18u3b2a</outgoing>
|
||||
</task>
|
||||
<sequenceFlow id="SequenceFlow_10bvr21" name="Valider" sourceRef="Task_07my1i6" targetRef="Task_0k79fbo" />
|
||||
<task id="Task_069h0a2" name="Annulé">
|
||||
<incoming>SequenceFlow_02m6a90</incoming>
|
||||
<outgoing>SequenceFlow_1yn5orr</outgoing>
|
||||
</task>
|
||||
<sequenceFlow id="SequenceFlow_02m6a90" name="Annuler" sourceRef="Task_07my1i6" targetRef="Task_069h0a2" />
|
||||
<sequenceFlow id="SequenceFlow_18u3b2a" name="Terminer" sourceRef="Task_0k79fbo" targetRef="EndEvent_062urgf" />
|
||||
<sequenceFlow id="SequenceFlow_1yn5orr" name="Réinitialiser" sourceRef="Task_069h0a2" targetRef="StartEvent_07npy19" />
|
||||
</process>
|
||||
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
||||
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1">
|
||||
<bpmndi:BPMNShape id="EndEvent_062urgf_di" bpmnElement="EndEvent_062urgf">
|
||||
<dc:Bounds x="747" y="120" width="36" height="36" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="720" y="156" width="90" height="20" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="StartEvent_07npy19_di" bpmnElement="StartEvent_07npy19">
|
||||
<dc:Bounds x="133" y="120" width="36" height="36" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="87" y="168" width="90" height="20" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Task_07my1i6_di" bpmnElement="Task_07my1i6">
|
||||
<dc:Bounds x="291" y="98" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_0qljt6y_di" bpmnElement="SequenceFlow_0qljt6y">
|
||||
<di:waypoint xsi:type="dc:Point" x="169" y="138" />
|
||||
<di:waypoint xsi:type="dc:Point" x="291" y="138" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="190" y="117" width="90" height="20" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNShape id="Task_0k79fbo_di" bpmnElement="Task_0k79fbo">
|
||||
<dc:Bounds x="492" y="98" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_10bvr21_di" bpmnElement="SequenceFlow_10bvr21">
|
||||
<di:waypoint xsi:type="dc:Point" x="391" y="138" />
|
||||
<di:waypoint xsi:type="dc:Point" x="492" y="138" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="392" y="105" width="90" height="20" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNShape id="Task_069h0a2_di" bpmnElement="Task_069h0a2">
|
||||
<dc:Bounds x="500" y="239" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_02m6a90_di" bpmnElement="SequenceFlow_02m6a90">
|
||||
<di:waypoint xsi:type="dc:Point" x="341" y="178" />
|
||||
<di:waypoint xsi:type="dc:Point" x="341" y="279" />
|
||||
<di:waypoint xsi:type="dc:Point" x="500" y="279" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="373" y="253.5" width="90" height="20" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_18u3b2a_di" bpmnElement="SequenceFlow_18u3b2a">
|
||||
<di:waypoint xsi:type="dc:Point" x="592" y="138" />
|
||||
<di:waypoint xsi:type="dc:Point" x="747" y="138" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="625" y="112" width="90" height="20" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_1yn5orr_di" bpmnElement="SequenceFlow_1yn5orr">
|
||||
<di:waypoint xsi:type="dc:Point" x="550" y="319" />
|
||||
<di:waypoint xsi:type="dc:Point" x="550" y="356" />
|
||||
<di:waypoint xsi:type="dc:Point" x="151" y="356" />
|
||||
<di:waypoint xsi:type="dc:Point" x="151" y="156" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="266" y="330.5" width="90" height="20" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNEdge>
|
||||
</bpmndi:BPMNPlane>
|
||||
</bpmndi:BPMNDiagram>
|
||||
</definitions>
|
||||
]]>
|
||||
</xml>
|
||||
</wkf>
|
||||
|
||||
<wkfNode wkf="Commande produit" name="Brouillon" title="Brouillon" nodeType="0" sequence="1" xmlId="StartEvent_07npy19"/>
|
||||
<wkfNode wkf="Commande produit" name="Confirmé" title="Confirmé" nodeType="1" sequence="2" xmlId="Task_07my1i6" />
|
||||
<wkfNode wkf="Commande produit" name="Validé" title="Validé" nodeType="1" sequence="3" xmlId="Task_0k79fbo" />
|
||||
<wkfNode wkf="Commande produit" name="Annulé" title="Annulé" nodeType="1" sequence="4" xmlId="Task_069h0a2"/>
|
||||
<wkfNode wkf="Commande produit" name="Terminé" title="Terminé" nodeType="2" sequence="5" xmlId="EndEvent_062urgf"/>
|
||||
|
||||
<transition wkf="Commande produit" name="Confirmer" source="Brouillon" target="Confirmé" isButton="true" buttonTitle="Confirmer" xmlId="SequenceFlow_0qljt6y"/>
|
||||
<transition wkf="Commande produit" name="Valider" source="Confirmé" target="Validé" isButton="true" buttonTitle="Valider" xmlId="SequenceFlow_10bvr21" alertTypeSelect="1" alertMsg="Êtes-vous sûr de vouloir valider cette commande?" successMsg="Commande validée" />
|
||||
<transition wkf="Commande produit" name="Annuler" source="Confirmé" target="Annulé" isButton="true" buttonTitle="Annuler" xmlId="SequenceFlow_02m6a90" alertTypeSelect="1" alertMsg="Êtes-vous sûr de vouloir annuler cette commande??" />
|
||||
<transition wkf="Commande produit" name="Terminer" source="Validé" target="Terminé" isButton="true" buttonTitle="Terminer" xmlId="SequenceFlow_18u3b2a" alertTypeSelect="2" alertMsg="Commande terminée" />
|
||||
<transition wkf="Commande produit" name="Réinitialiser" source="Annulé" target="Brouillon" isButton="true" buttonTitle="Réinitialiser" xmlId="SequenceFlow_1yn5orr" />
|
||||
|
||||
<node wkf="Commande produit" name="Brouillon">
|
||||
<incomings>
|
||||
<incoming name="Réinitialiser" />
|
||||
</incomings>
|
||||
<outgoings>
|
||||
<outgoing name="Confirmer" />
|
||||
</outgoings>
|
||||
</node>
|
||||
<node wkf="Commande produit" name="Confirmé">
|
||||
<incomings>
|
||||
<incoming name="Confirmer" />
|
||||
</incomings>
|
||||
<outgoings>
|
||||
<outgoing name="Valider" />
|
||||
<outgoing name="Annuler" />
|
||||
</outgoings>
|
||||
</node>
|
||||
<node wkf="Commande produit" name="Validé">
|
||||
<incomings>
|
||||
<incoming name="Valider" />
|
||||
</incomings>
|
||||
<outgoings>
|
||||
<outgoing name="Terminer" />
|
||||
</outgoings>
|
||||
</node>
|
||||
<node wkf="Commande produit" name="Annulé">
|
||||
<incomings>
|
||||
<incoming name="Annuler" />
|
||||
</incomings>
|
||||
<outgoings>
|
||||
<outgoing name="Réinitialiser" />
|
||||
</outgoings>
|
||||
</node>
|
||||
<node wkf="Commande produit" name="Terminé">
|
||||
<incomings>
|
||||
<incoming name="Terminer" />
|
||||
</incomings>
|
||||
</node>
|
||||
|
||||
<workflow name="Commande produit" />
|
||||
</wkfs>
|
||||
@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<domain-models xmlns="http://axelor.com/xml/ns/domain-models"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://axelor.com/xml/ns/domain-models http://axelor.com/xml/ns/domain-models/domain-models_5.2.xsd">
|
||||
|
||||
<module name="studio" package="com.axelor.studio.db" />
|
||||
|
||||
<entity name="ActionBuilder" cacheable="true">
|
||||
<string name="name" title="Name" unique="true"/>
|
||||
<integer name="typeSelect" title="Type" selection="studio.action.builder.type.select" />
|
||||
<string name="model" title="Object" />
|
||||
<string name="targetModel" title="Target object" />
|
||||
<one-to-many name="lines" ref="ActionBuilderLine" title="Fields" mappedBy="actionBuilder"/>
|
||||
<many-to-one name="assignValueTo" title="Assign value to" ref="com.axelor.meta.db.MetaField" />
|
||||
<string name="firstGroupBy" title="First group by"/>
|
||||
<string name="secondGroupBy" title="Second group by"/>
|
||||
<string name="title" title="Title" />
|
||||
<many-to-one name="emailTemplate" ref="com.axelor.apps.message.db.Template" title="Template" />
|
||||
<one-to-many name="filters" ref="Filter" title="Filters"/>
|
||||
<boolean name="transactional" title="Transactional" />
|
||||
<integer name="scriptType" title="Script type" selection="studio.action.builder.script.type.select"/>
|
||||
<string name="scriptText" title="Script" large="true"/>
|
||||
<boolean name="openRecord" title="Open record" />
|
||||
<string name="displayMsg" title="Display message" />
|
||||
<integer name="emailSendOptionSelect" title="Send option" selection="studio.action.builder.email.send.option.select"/>
|
||||
|
||||
<!-- Action view fields -->
|
||||
<one-to-many name="actionBuilderViews" title="Views" ref="ActionBuilderView" mappedBy="actionBuilder" orderBy="sequence"/>
|
||||
<boolean name="isJson" title="Json" />
|
||||
|
||||
<string name="domainCondition" title="Domain" />
|
||||
<one-to-many name="viewParams" title="View params" ref="ActionBuilderLine" orphanRemoval="true" />
|
||||
<boolean name="menuAction" />
|
||||
|
||||
<many-to-one name="appBuilder" ref="AppBuilder" title="App builder" />
|
||||
|
||||
<many-to-one name="metaModule" ref="com.axelor.meta.db.MetaModule" />
|
||||
|
||||
<extra-code><![CDATA[
|
||||
public static final int TYPE_SELECT_CREATE = 0;
|
||||
public static final int TYPE_SELECT_UPDATE = 1;
|
||||
public static final int TYPE_SELECT_SCRIPT = 2;
|
||||
public static final int TYPE_SELECT_VIEW= 3;
|
||||
public static final int TYPE_SELECT_EMAIL = 4;
|
||||
public static final int TYPE_SELECT_REPORT = 5;
|
||||
]]></extra-code>
|
||||
|
||||
</entity>
|
||||
|
||||
</domain-models>
|
||||
@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<domain-models xmlns="http://axelor.com/xml/ns/domain-models"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://axelor.com/xml/ns/domain-models http://axelor.com/xml/ns/domain-models/domain-models_5.2.xsd">
|
||||
|
||||
<module name="studio" package="com.axelor.studio.db" />
|
||||
|
||||
<entity name="ActionBuilderLine" cacheable="true">
|
||||
<many-to-one name="actionBuilder" ref="ActionBuilder" title="Action builder" />
|
||||
<many-to-one name="metaJsonField" ref="com.axelor.meta.db.MetaJsonField" title="Target field" />
|
||||
<many-to-one name="metaField" ref="com.axelor.meta.db.MetaField" title="Target field" />
|
||||
<many-to-one name="valueJson" ref="com.axelor.meta.db.MetaJsonField" title="Source field" />
|
||||
<many-to-one name="valueField" ref="com.axelor.meta.db.MetaField" title="Source field" />
|
||||
<string name="value" title="Value expr"/>
|
||||
<string name="conditionText" title="Condition" />
|
||||
<string name="filter" title="Filter" />
|
||||
<string name="validationTypeSelect" title="Validation type"/>
|
||||
<string name="validationMsg" title="Message" />
|
||||
<one-to-many name="subLines" ref="ActionBuilderLine" mappedBy="parent"/>
|
||||
<many-to-one name="parent" ref="ActionBuilderLine" />
|
||||
<string name="name" title="Target field" />
|
||||
<boolean name="dummy" title="Dummy" />
|
||||
</entity>
|
||||
|
||||
</domain-models>
|
||||
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<domain-models xmlns="http://axelor.com/xml/ns/domain-models"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://axelor.com/xml/ns/domain-models http://axelor.com/xml/ns/domain-models/domain-models_5.2.xsd">
|
||||
|
||||
<module name="studio" package="com.axelor.studio.db" />
|
||||
|
||||
<entity name="ActionBuilderView" cacheable="true">
|
||||
<string name="viewType" title="Type" required="true" selection="view.type.selection"/>
|
||||
<string name="viewName" title="Name" required="true"/>
|
||||
<many-to-one name="actionBuilder" ref="ActionBuilder" />
|
||||
<integer name="sequence" title="Sequence" />
|
||||
<string name="viewConditionToCheck" title="If"/>
|
||||
</entity>
|
||||
|
||||
</domain-models>
|
||||
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<domain-models xmlns="http://axelor.com/xml/ns/domain-models" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://axelor.com/xml/ns/domain-models http://axelor.com/xml/ns/domain-models/domain-models_5.2.xsd">
|
||||
|
||||
<module name="base" package="com.axelor.apps.base.db"/>
|
||||
|
||||
<entity name="AppBpm" lang="java" cacheable="true" extends="App" />
|
||||
|
||||
</domain-models>
|
||||
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<domain-models xmlns="http://axelor.com/xml/ns/domain-models"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://axelor.com/xml/ns/domain-models http://axelor.com/xml/ns/domain-models/domain-models_5.2.xsd">
|
||||
|
||||
<module name="studio" package="com.axelor.studio.db" />
|
||||
|
||||
<entity name="AppBuilder" cacheable="true">
|
||||
<string name="name" title="Name" required="true" translatable="true"/>
|
||||
<string name="code" title="Code" required="true" unique="true" />
|
||||
<string name="description" title="Description" large="true" translatable="true"/>
|
||||
<many-to-many name="dependsOnSet" title="Depends on" ref="App"/>
|
||||
<many-to-one name="image" ref="com.axelor.meta.db.MetaFile" title="Image"/>
|
||||
<integer name="sequence" title="Sequence" />
|
||||
<many-to-one name="generatedApp" ref="com.axelor.apps.base.db.App" />
|
||||
</entity>
|
||||
|
||||
</domain-models>
|
||||
@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<domain-models xmlns="http://axelor.com/xml/ns/domain-models"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://axelor.com/xml/ns/domain-models http://axelor.com/xml/ns/domain-models/domain-models_5.2.xsd">
|
||||
|
||||
<module name="studio" package="com.axelor.studio.db" />
|
||||
|
||||
<entity name="ChartBuilder" cacheable="true">
|
||||
<string name="title" title="Title" required="true" />
|
||||
<string name="name" title="Name" required="true" unique="true"/>
|
||||
<string name="model" title="Model" />
|
||||
<boolean name="isJson" title="Json" />
|
||||
<one-to-many name="filterList" title="Filters" ref="com.axelor.studio.db.Filter" mappedBy="chartBuilder" />
|
||||
<many-to-one name="aggregateOn" title="Aggregate On" ref="com.axelor.meta.db.MetaField"/>
|
||||
<boolean name="isJsonAggregateOn" title="Json" />
|
||||
<many-to-one name="aggregateOnJson" title="Aggregate On" ref="com.axelor.meta.db.MetaJsonField"/>
|
||||
<string name="aggregateOnTarget" title="Target" />
|
||||
<string name="aggregateOnTargetType" title="Aggregate On type" />
|
||||
<string name="aggregateDateType" selection="studio.chart.builder.date.type" />
|
||||
<many-to-one name="groupOn" title="Group By" ref="com.axelor.meta.db.MetaField" />
|
||||
<boolean name="isJsonGroupOn" title="Json" />
|
||||
<many-to-one name="groupOnJson" title="Group By" ref="com.axelor.meta.db.MetaJsonField" />
|
||||
<string name="groupOnTarget" title="Target" />
|
||||
<string name="groupOnTargetType" title="Group on type" />
|
||||
<string name="groupDateType" selection="studio.chart.builder.date.type" />
|
||||
<many-to-one name="displayField" title="Display" ref="com.axelor.meta.db.MetaField" />
|
||||
<integer name="displayType" selection="studio.chart.builder.display.type" />
|
||||
<boolean name="isJsonDisplayField" title="Json" />
|
||||
<many-to-one name="displayFieldJson" title="Display" ref="com.axelor.meta.db.MetaJsonField" />
|
||||
<string name="chartType" selection="studio.chart.builder.chart.type" default="bar"/>
|
||||
<many-to-one name="metaViewGenerated" title="View generated" ref="com.axelor.meta.db.MetaView" />
|
||||
<many-to-one name="appBuilder" ref="AppBuilder" title="App builder" />
|
||||
</entity>
|
||||
|
||||
|
||||
</domain-models>
|
||||
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<domain-models xmlns="http://axelor.com/xml/ns/domain-models"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://axelor.com/xml/ns/domain-models http://axelor.com/xml/ns/domain-models/domain-models_5.2.xsd">
|
||||
|
||||
<module name="studio" package="com.axelor.studio.db" />
|
||||
|
||||
<entity name="DashboardBuilder" cacheable="true">
|
||||
<string name="title" title="Title" required="true" />
|
||||
<string name="name" title="Name" required="true" unique="true"/>
|
||||
<string name="model" title="Model" />
|
||||
<one-to-many name="dashletBuilderList" ref="com.axelor.studio.db.DashletBuilder" mappedBy="dashboardBuilder" orderBy="sequence"/>
|
||||
<many-to-one name="metaViewGenerated" title="View generated" ref="com.axelor.meta.db.MetaView" />
|
||||
<one-to-many name="generatedActions" ref="com.axelor.meta.db.MetaAction" title="Generated Actions" orphanRemoval="true" />
|
||||
<many-to-one name="appBuilder" ref="AppBuilder" title="App builder" />
|
||||
</entity>
|
||||
|
||||
|
||||
</domain-models>
|
||||
@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<domain-models xmlns="http://axelor.com/xml/ns/domain-models"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://axelor.com/xml/ns/domain-models http://axelor.com/xml/ns/domain-models/domain-models_5.2.xsd">
|
||||
|
||||
<module name="studio" package="com.axelor.studio.db" />
|
||||
|
||||
<entity name="DashletBuilder" cacheable="true">
|
||||
<![CDATA[
|
||||
It represents a custom dashlet. It contains fields required to generate a Axelor Open Platform supported dashlet xml.
|
||||
]]>
|
||||
<string name="name" title="Name" required="true" />
|
||||
<many-to-one name="metaView" ref="com.axelor.meta.db.MetaView" title="View" />
|
||||
<many-to-one name="dashboardBuilder" ref="DashboardBuilder"/>
|
||||
<many-to-one name="action" ref="com.axelor.meta.db.MetaAction" title="Action" />
|
||||
<integer name="sequence" title="Sequence" />
|
||||
<string name="viewType" title="Type" selection="view.type.selection" />
|
||||
<integer name="colspan" title="Colspan" />
|
||||
<integer name="paginationLimit" title="Pagination limit" />
|
||||
<many-to-one name="appBuilder" ref="AppBuilder" title="App builder" />
|
||||
<unique-constraint columns="name,dashboardBuilder"/>
|
||||
</entity>
|
||||
|
||||
</domain-models>
|
||||
@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<domain-models xmlns="http://axelor.com/xml/ns/domain-models"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://axelor.com/xml/ns/domain-models http://axelor.com/xml/ns/domain-models/domain-models_5.2.xsd">
|
||||
|
||||
<module name="studio" package="com.axelor.studio.db" />
|
||||
|
||||
<entity name="Filter" cacheable="true">
|
||||
<![CDATA[
|
||||
Filter represents a condition to evaluate. It stores condition components like operand, operator and value.
|
||||
A sql or groovy condition will be created by using this.
|
||||
]]>
|
||||
<string name="moduleName" title="Module" />
|
||||
<many-to-one name="chartBuilder" ref="com.axelor.studio.db.ChartBuilder" />
|
||||
<many-to-one name="metaField" title="Field" ref="com.axelor.meta.db.MetaField"/>
|
||||
<many-to-one name="metaJsonField" title="Json Field" ref="com.axelor.meta.db.MetaJsonField"/>
|
||||
<many-to-one name="wkfTransition" ref="com.axelor.studio.db.WkfTransition" />
|
||||
<many-to-one name="wkf" ref="com.axelor.studio.db.Wkf" />
|
||||
<string name="operator" title="Operator" selection="studio.filter.operator" required="true" />
|
||||
<many-to-one name="actionBuilder" ref="com.axelor.studio.db.ActionBuilder" />
|
||||
<string name="targetField" title="Target field"/>
|
||||
<string name="targetType" title="Target type"/>
|
||||
<string name="value" title="Value" />
|
||||
<string name="defaultValue" title="Default Value" />
|
||||
<string name="targetTitle" title="Target title"/>
|
||||
<boolean name="isParameter" title="Is parameter" />
|
||||
<boolean name="isJson" title="Is json" />
|
||||
<boolean name="isTargetJson" title="Target json" />
|
||||
<integer name="logicOp" title="Logic operator" selection="studio.filter.logic.operator" default="0"/>
|
||||
</entity>
|
||||
|
||||
</domain-models>
|
||||
@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<domain-models xmlns="http://axelor.com/xml/ns/domain-models"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://axelor.com/xml/ns/domain-models http://axelor.com/xml/ns/domain-models/domain-models_5.2.xsd">
|
||||
|
||||
<module name="studio" package="com.axelor.studio.db" />
|
||||
|
||||
<entity name="MenuBuilder" cacheable="true">
|
||||
<string name="name" title="Name" unique="true"/>
|
||||
<string name="title" title="Title" required="true" />
|
||||
<string name="icon" title="Icon" />
|
||||
<string name="iconBackground" title="Background" />
|
||||
<integer name="order" title="MenuBuilder.Order" column="order_seq" />
|
||||
<string name="tag" title="Tag label"/>
|
||||
<string name="tagGet" title="Tag method"/>
|
||||
<boolean name="tagCount" title="Tag count"/>
|
||||
<string name="tagStyle" selection="label.style.selection" title="Tag style"/>
|
||||
<boolean name="top" column="top_menu" title="Top menu"/>
|
||||
<boolean name="left" column="left_menu" default="true" title="Left menu"/>
|
||||
<boolean name="mobile" column="mobile_menu" title="Mobile menu"/>
|
||||
<boolean name="hidden" title="Hidden menu"/>
|
||||
<string name="link" />
|
||||
<many-to-many name="groups" ref="com.axelor.auth.db.Group"/>
|
||||
<many-to-many name="roles" ref="com.axelor.auth.db.Role"/>
|
||||
<string name="conditionToCheck" max="1024" title="If" help="Only use this menu-item if the given expression is true."/>
|
||||
<string name="moduleToCheck" title="If-module" help="Only use this menu-item if the given module is installed."/>
|
||||
|
||||
<many-to-one name="metaMenu" title="MetaMenu" ref="com.axelor.meta.db.MetaMenu"/>
|
||||
<many-to-one name="parentMenu" title="Parent" ref="com.axelor.meta.db.MetaMenu"/>
|
||||
<many-to-one name="actionBuilder" ref="ActionBuilder" title="Action"/>
|
||||
<boolean name="showAction" title="Object"/>
|
||||
<many-to-one name="appBuilder" ref="AppBuilder" title="App builder" />
|
||||
<many-to-one name="metaModule" ref="com.axelor.meta.db.MetaModule" />
|
||||
|
||||
<finder-method name="findByParentMenu" using="parentMenu" all="true"/>
|
||||
</entity>
|
||||
|
||||
</domain-models>
|
||||
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<domain-models xmlns="http://axelor.com/xml/ns/domain-models"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://axelor.com/xml/ns/domain-models http://axelor.com/xml/ns/domain-models/domain-models_5.2.xsd">
|
||||
|
||||
<module name="meta" package="com.axelor.meta.db" />
|
||||
|
||||
<entity name="MetaAction" cacheable="true">
|
||||
<integer name="sequence" title="Sequence" />
|
||||
</entity>
|
||||
|
||||
|
||||
</domain-models>
|
||||
@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<domain-models xmlns="http://axelor.com/xml/ns/domain-models"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://axelor.com/xml/ns/domain-models http://axelor.com/xml/ns/domain-models/domain-models_5.2.xsd">
|
||||
|
||||
<module name="meta" package="com.axelor.meta.db" />
|
||||
|
||||
<entity name="MetaJsonField" table="META_JSON_FIELD">
|
||||
<boolean name="isWkf" />
|
||||
<many-to-one name="appBuilder" ref="com.axelor.studio.db.AppBuilder"
|
||||
title="App builder" />
|
||||
</entity>
|
||||
|
||||
</domain-models>
|
||||
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<domain-models xmlns="http://axelor.com/xml/ns/domain-models"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://axelor.com/xml/ns/domain-models http://axelor.com/xml/ns/domain-models/domain-models_5.2.xsd">
|
||||
|
||||
<module name="meta" package="com.axelor.meta.db" />
|
||||
|
||||
<entity name="MetaJsonModel" table="META_JSON_MODEL">
|
||||
<many-to-one name="appBuilder" ref="com.axelor.studio.db.AppBuilder" title="App builder" />
|
||||
<boolean name="showProcessTracking" title="Show process tracking" />
|
||||
</entity>
|
||||
|
||||
</domain-models>
|
||||
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<domain-models xmlns="http://axelor.com/xml/ns/domain-models"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://axelor.com/xml/ns/domain-models http://axelor.com/xml/ns/domain-models/domain-models_5.2.xsd">
|
||||
|
||||
<module name="meta" package="com.axelor.meta.db" />
|
||||
|
||||
<entity name="MetaSelect" table="META_SELECT" cacheable="true">
|
||||
<many-to-one name="appBuilder" ref="com.axelor.studio.db.AppBuilder" title="App builder"/>
|
||||
<boolean name="isCustom" title="Custom"/>
|
||||
</entity>
|
||||
|
||||
</domain-models>
|
||||
@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<domain-models xmlns="http://axelor.com/xml/ns/domain-models"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://axelor.com/xml/ns/domain-models http://axelor.com/xml/ns/domain-models/domain-models_5.2.xsd">
|
||||
|
||||
<module name="studio" package="com.axelor.studio.db" />
|
||||
|
||||
<entity name="Wkf" cacheable="true">
|
||||
<![CDATA[
|
||||
This class is a root class used to store the workflow. A workflow is linked with a model and a form view of that model.
|
||||
Wkf stores the bpmn xml of the worklfow diagram. The nodes and transitions of a wkf will be created by using the bpmn xml.
|
||||
]]>
|
||||
<string name="name" title="Name" required="true" />
|
||||
<string name="model" title="Object" required="true" />
|
||||
<string name="jsonField" title="Json Field"/>
|
||||
<boolean name="isJson" title="Custom" default="true" />
|
||||
<many-to-one name="statusField" ref="com.axelor.meta.db.MetaJsonField" title="Wkf field" required="true"/>
|
||||
<one-to-many name="nodes" ref="WkfNode" mappedBy="wkf" orderBy="sequence"/>
|
||||
<one-to-many name="transitions" ref="WkfTransition" mappedBy="wkf"/>
|
||||
<one-to-many name="wkfTrackings" ref="WkfTracking" mappedBy="wkf"/>
|
||||
<integer name="displayTypeSelect" title="Process display type" selection="studio.business.wkf.display.type.select"/>
|
||||
<string name="bpmnXml" title="Bpmn xml" large="true" />
|
||||
<many-to-one name="appBuilder" ref="AppBuilder" title="App builder" required="true" />
|
||||
<string name="description" title="Description" large="true"/>
|
||||
<one-to-many name="conditions" ref="Filter" title="Apply if" mappedBy="wkf"/>
|
||||
<integer name="wkfSequence" title="Wkf sequence" />
|
||||
<boolean name="isTrackFlow" title="Track flow"/>
|
||||
</entity>
|
||||
|
||||
</domain-models>
|
||||
@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<domain-models xmlns="http://axelor.com/xml/ns/domain-models"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://axelor.com/xml/ns/domain-models http://axelor.com/xml/ns/domain-models/domain-models_5.2.xsd">
|
||||
|
||||
<module name="studio" package="com.axelor.studio.db" />
|
||||
|
||||
<entity name="WkfNode" cacheable="true">
|
||||
<![CDATA[
|
||||
WkfNode represents a state of the workflow. A workflow must contain at least two states.
|
||||
It is also used to generate a menu entry based on state.
|
||||
]]>
|
||||
<string name="name" title="Name" required="true"/>
|
||||
<string name="title" title="Title" required="true" />
|
||||
<string name="xmlId" title="xmlId" />
|
||||
<many-to-one name="wkf" ref="Wkf" />
|
||||
<many-to-one name="metaField" ref="com.axelor.meta.db.MetaField" title="Field for 'My menu'" />
|
||||
<many-to-many name="incoming" ref="WkfTransition" title="Incoming" />
|
||||
<many-to-many name="outgoing" ref="WkfTransition" title="Outgoing" />
|
||||
<many-to-many name="roleSet" ref="com.axelor.auth.db.Role" title="ReadOnly for"/>
|
||||
<integer name="sequence" title="Sequence" />
|
||||
<integer name="nodeType" title="Node type" selection="studio.node.type.select" default="1" />
|
||||
<many-to-many name="metaActionSet" ref="com.axelor.meta.db.MetaAction" title="Actions" orderBy="sequence"/>
|
||||
<unique-constraint columns="wkf,sequence"/>
|
||||
|
||||
<extra-code>
|
||||
<![CDATA[
|
||||
public static final Integer START_NODE = 0;
|
||||
public static final Integer TASK_NODE = 1;
|
||||
public static final Integer END_NODE = 2;
|
||||
]]>
|
||||
</extra-code>
|
||||
</entity>
|
||||
|
||||
</domain-models>
|
||||
@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<domain-models xmlns="http://axelor.com/xml/ns/domain-models"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://axelor.com/xml/ns/domain-models http://axelor.com/xml/ns/domain-models/domain-models_5.2.xsd">
|
||||
|
||||
<module name="studio" package="com.axelor.studio.db" />
|
||||
|
||||
<entity name="WkfTracking" cacheable="true">
|
||||
<![CDATA[
|
||||
WkfTracking stores the information related to the workflow instance for an object.
|
||||
The information like number of time some status changed, the user who changed the state, date and time when state is changed.
|
||||
]]>
|
||||
<many-to-one name="wkf" ref="Wkf" required="true"/>
|
||||
<string name="recordModel" title="Record model" required="true"/>
|
||||
<long name="recordId" required="true" title="Record Id"/>
|
||||
<string name="recordName" title="Record name"/>
|
||||
<one-to-many name="wkfTrackingLines" title="Tracking lines" ref="WkfTrackingLine" mappedBy="wkfTracking"/>
|
||||
<one-to-many name="totalLines" title="Nb of passes per status" ref="WkfTrackingTotal" mappedBy="wkfTracking" />
|
||||
<one-to-many name="totalTimeLines" title="Time spent (hours/days)" ref="WkfTrackingTime" mappedBy="wkfTracking" />
|
||||
</entity>
|
||||
|
||||
</domain-models>
|
||||
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<domain-models xmlns="http://axelor.com/xml/ns/domain-models"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://axelor.com/xml/ns/domain-models http://axelor.com/xml/ns/domain-models/domain-models_5.2.xsd">
|
||||
|
||||
<module name="studio" package="com.axelor.studio.db" />
|
||||
|
||||
<entity name="WkfTrackingLine" cacheable="true">
|
||||
<![CDATA[
|
||||
This object stores the sub details of the {@link WkfTracking} class.
|
||||
The details like status and time spent on particular status.
|
||||
]]>
|
||||
<many-to-one name="wkfTracking" ref="WkfTracking" required="true"/>
|
||||
<string name="status" title="Status" required="true"/>
|
||||
<decimal name="timeSpent" title="Time spent" />
|
||||
</entity>
|
||||
|
||||
</domain-models>
|
||||
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<domain-models xmlns="http://axelor.com/xml/ns/domain-models"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://axelor.com/xml/ns/domain-models http://axelor.com/xml/ns/domain-models/domain-models_5.2.xsd">
|
||||
|
||||
<module name="studio" package="com.axelor.studio.db" />
|
||||
|
||||
<entity name="WkfTrackingTime" cacheable="true">
|
||||
<![CDATA[
|
||||
It stores the total time spent on particular status.
|
||||
]]>
|
||||
<many-to-one name="wkfTracking" ref="WkfTracking" required="true"/>
|
||||
<string name="status" title="Status" required="true"/>
|
||||
<decimal name="totalTimeHours" title="Status time(hours)"/>
|
||||
<decimal name="totalTimeDays" title="Status time(days)" />
|
||||
</entity>
|
||||
|
||||
</domain-models>
|
||||
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<domain-models xmlns="http://axelor.com/xml/ns/domain-models"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://axelor.com/xml/ns/domain-models http://axelor.com/xml/ns/domain-models/domain-models_5.2.xsd">
|
||||
|
||||
<module name="studio" package="com.axelor.studio.db" />
|
||||
|
||||
<entity name="WkfTrackingTotal" cacheable="true">
|
||||
<![CDATA[
|
||||
It stores the number times a particular status used by an object.
|
||||
]]>
|
||||
<many-to-one name="wkfTracking" ref="WkfTracking" required="true"/>
|
||||
<string name="status" title="Status" required="true"/>
|
||||
<integer name="totalCount" title="Nb of passes"/>
|
||||
</entity>
|
||||
|
||||
</domain-models>
|
||||
@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<domain-models xmlns="http://axelor.com/xml/ns/domain-models"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://axelor.com/xml/ns/domain-models http://axelor.com/xml/ns/domain-models/domain-models_5.2.xsd">
|
||||
|
||||
<module name="studio" package="com.axelor.studio.db" />
|
||||
|
||||
<entity name="WkfTransition" cacheable="true">
|
||||
<![CDATA[
|
||||
WkfTransition stores the transition information for the nodes(state) of a workflow.
|
||||
It contains source and destination nodes. The transition can be done on button click or on satisfaction of some conditions.
|
||||
It is used to generate the buttons and actions required to call a transition.
|
||||
]]>
|
||||
<string name="name" title="Name" required="true" />
|
||||
<string name="xmlId" title="xmlId" />
|
||||
<boolean name="isButton" title="Button" />
|
||||
<string name="buttonTitle" title="Button title" />
|
||||
<integer name="colSpan" title="Colspan" default="3" min="1" max="12"/>
|
||||
<many-to-many name="roleSet" ref="com.axelor.auth.db.Role" title="Roles" />
|
||||
<one-to-many name="conditions" ref="Filter" title="Conditions" mappedBy="wkfTransition"/>
|
||||
<many-to-one name="wkf" ref="Wkf" />
|
||||
<many-to-one name="source" ref="WkfNode" title="From" />
|
||||
<many-to-one name="target" ref="WkfNode" title="To" />
|
||||
<integer name="alertTypeSelect" title="Alert or Blocking condition" selection="studio.condition.alert.type.select" />
|
||||
<string name="alertMsg" title="Message on alert or blocking" />
|
||||
<string name="successMsg" title="Message on success" />
|
||||
</entity>
|
||||
|
||||
</domain-models>
|
||||
@ -0,0 +1,292 @@
|
||||
"key","message","comment","context"
|
||||
"<b>Tags:</b> $user: Current user, $date: Today's date, $time: Current time",,,
|
||||
"AND",,,
|
||||
"Action",,,
|
||||
"Action builder",,,
|
||||
"Action builders",,,
|
||||
"Actions",,,
|
||||
"Activate the hand tool",,,
|
||||
"Aggregate",,,
|
||||
"Aggregate On",,,
|
||||
"Aggregate On type",,,
|
||||
"Aggregate date type",,,
|
||||
"Alert",,,
|
||||
"Alert or Blocking condition",,,
|
||||
"App builder",,,
|
||||
"App builders",,,
|
||||
"App name",,,
|
||||
"Append end node",,,
|
||||
"Append intermediate node",,,
|
||||
"Apply if",,,
|
||||
"Area",,,
|
||||
"Assign value to",,,
|
||||
"BPM",,,
|
||||
"Background",,,
|
||||
"Bar",,,
|
||||
"Base model",,,
|
||||
"Blocking",,,
|
||||
"Boolean",,,
|
||||
"Bpmn xml",,,
|
||||
"Button",,,
|
||||
"Button title",,,
|
||||
"Can Collapse",,,
|
||||
"Chart builder",,,
|
||||
"Chart builders",,,
|
||||
"Chart type",,,
|
||||
"ChartBuilder.Group",,,
|
||||
"Choose App name",,,
|
||||
"Code",,,
|
||||
"Collapse if",,,
|
||||
"Colspan",,,
|
||||
"Condition",,,
|
||||
"Conditions",,,
|
||||
"Configuration",,,
|
||||
"Connect using transition",,,
|
||||
"Context",,,
|
||||
"Create",,,
|
||||
"Create end node",,,
|
||||
"Create intermediate node",,,
|
||||
"Create start node",,,
|
||||
"Custom",,,
|
||||
"Custom Field",,,
|
||||
"Custom Model",,,
|
||||
"Custom field",,,
|
||||
"Custom fields",,,
|
||||
"Custom model",,,
|
||||
"Custom models",,,
|
||||
"Dashboard",,,
|
||||
"Dashboard builder",,,
|
||||
"Dashboard builders",,,
|
||||
"Dashlet builder",,,
|
||||
"Dashlet builder list",,,
|
||||
"Dashlet builders",,,
|
||||
"Data file",,,
|
||||
"Date",,,
|
||||
"Datetime",,,
|
||||
"Day",,,
|
||||
"Decimal",,,
|
||||
"Default Value",,,
|
||||
"Depends on",,,
|
||||
"Description",,,
|
||||
"Display",,,
|
||||
"Display message",,,
|
||||
"Display type",,,
|
||||
"Do you want to reset workflow ?",,,
|
||||
"Domain",,,
|
||||
"Donut",,,
|
||||
"Dummy",,,
|
||||
"Edit Node",,,
|
||||
"Edit Transition",,,
|
||||
"Edit before send",,,
|
||||
"Email",,,
|
||||
"End node",,,
|
||||
"Existing menu",,,
|
||||
"Export",,,
|
||||
"Extra",,,
|
||||
"Field",,,
|
||||
"Field for 'My menu'",,,
|
||||
"Field options",,,
|
||||
"Fields",,,
|
||||
"Filter",,,
|
||||
"Filters",,,
|
||||
"First group by",,,
|
||||
"From",,,
|
||||
"Funnel",,,
|
||||
"Gauge",,,
|
||||
"Generated Actions",,,
|
||||
"Generated app",,,
|
||||
"Groovy",,,
|
||||
"Group By",,,
|
||||
"Group date type",,,
|
||||
"Group on type",,,
|
||||
"Groups",,,
|
||||
"Help",,,
|
||||
"Hidden In Grid",,,
|
||||
"Hidden menu",,,
|
||||
"Horizontal bar",,,
|
||||
"Icon",,,
|
||||
"If",,,
|
||||
"If-module",,,
|
||||
"Image",,,
|
||||
"Import",,,
|
||||
"Import BPM",,,
|
||||
"Import log",,,
|
||||
"Incoming",,,
|
||||
"Integer",,,
|
||||
"Is Json Relational Field",,,
|
||||
"Is json",,,
|
||||
"Is parameter",,,
|
||||
"Is wkf",,,
|
||||
"Javascript",,,
|
||||
"Json",,,
|
||||
"Json Field",,,
|
||||
"Json Many To Many",,,
|
||||
"Json Many To One",,,
|
||||
"Json One To Many",,,
|
||||
"Left menu",,,
|
||||
"Line",,,
|
||||
"Link",,,
|
||||
"Logic operator",,,
|
||||
"Many To Many",,,
|
||||
"Many To One",,,
|
||||
"Max Size",,,
|
||||
"Menu action",,,
|
||||
"Menu builder",,,
|
||||
"Menu builders",,,
|
||||
"MenuBuilder.Order",,,
|
||||
"Message",,,
|
||||
"Message on alert or blocking",,,
|
||||
"Message on success",,,
|
||||
"Meta Model",,,
|
||||
"Meta module",,,
|
||||
"MetaMenu",,,
|
||||
"Min Size",,,
|
||||
"Mobile menu",,,
|
||||
"Model",,,
|
||||
"Module",,,
|
||||
"Month",,,
|
||||
"Name",,,
|
||||
"Name Column",,,
|
||||
"Name Field",,,
|
||||
"Name must not contains space",,,
|
||||
"Nav Select",,,
|
||||
"Nb of passes",,,
|
||||
"Nb of passes per status",,,
|
||||
"Node",,,
|
||||
"Node type",,,
|
||||
"Nodes",,,
|
||||
"None",,,
|
||||
"OR",,,
|
||||
"Object",,,
|
||||
"On Change",,,
|
||||
"On Click",,,
|
||||
"On New",,,
|
||||
"On Save",,,
|
||||
"One To Many",,,
|
||||
"Only use this menu-item if the given expression is true.",,,
|
||||
"Only use this menu-item if the given module is installed.",,,
|
||||
"Open record",,,
|
||||
"Open workflow",,,
|
||||
"Operator",,,
|
||||
"Outgoing",,,
|
||||
"Overview",,,
|
||||
"Pagination limit",,,
|
||||
"Panel",,,
|
||||
"Parent",,,
|
||||
"Percentage(%)",,,
|
||||
"Permissions",,,
|
||||
"Pie Chart",,,
|
||||
"Please correct the workflow diagram.",,,
|
||||
"Please input value bind with single quotation.",,,
|
||||
"Please provide unique code. The code '%s' is already used",,,
|
||||
"Process",,,
|
||||
"Process display type",,,
|
||||
"Process studio",,,
|
||||
"Process tracking",,,
|
||||
"Properties",,,
|
||||
"Radar",,,
|
||||
"ReadOnly for",,,
|
||||
"Record Id",,,
|
||||
"Record model",,,
|
||||
"Record name",,,
|
||||
"Regex",,,
|
||||
"Report",,,
|
||||
"Reporting",,,
|
||||
"Required",,,
|
||||
"Required If",,,
|
||||
"Roles",,,
|
||||
"Scatter",,,
|
||||
"Script",,,
|
||||
"Script type",,,
|
||||
"Second group by",,,
|
||||
"Select Option",,,
|
||||
"Selection",,,
|
||||
"Selections",,,
|
||||
"Send directly",,,
|
||||
"Send option",,,
|
||||
"Separator",,,
|
||||
"Sequence",,,
|
||||
"Show If",,,
|
||||
"Show Title",,,
|
||||
"Show process tracking",,,
|
||||
"Simple Select",,,
|
||||
"Source field",,,
|
||||
"Start node",,,
|
||||
"Status",,,
|
||||
"Status per day",,,
|
||||
"Status per month",,,
|
||||
"Status time(days)",,,
|
||||
"Status time(hours)",,,
|
||||
"String",,,
|
||||
"Studio",,,
|
||||
"Sub lines",,,
|
||||
"Tag count",,,
|
||||
"Tag label",,,
|
||||
"Tag method",,,
|
||||
"Tag style",,,
|
||||
"Target",,,
|
||||
"Target Json Model",,,
|
||||
"Target field",,,
|
||||
"Target json",,,
|
||||
"Target object",,,
|
||||
"Target title",,,
|
||||
"Target type",,,
|
||||
"Task node",,,
|
||||
"Template",,,
|
||||
"Text",,,
|
||||
"Time",,,
|
||||
"Time spent",,,
|
||||
"Time spent (hours/days)",,,
|
||||
"Time spent per status (hours)",,,
|
||||
"Time spent per status per user (hours)",,,
|
||||
"Title",,,
|
||||
"To",,,
|
||||
"Top menu",,,
|
||||
"Total time per status",,,
|
||||
"Track flow",,,
|
||||
"Track workflow",,,
|
||||
"Tracking line",,,
|
||||
"Tracking lines",,,
|
||||
"Transactional",,,
|
||||
"Transition",,,
|
||||
"Transitions",,,
|
||||
"Type",,,
|
||||
"UI options",,,
|
||||
"Update",,,
|
||||
"User",,,
|
||||
"Validation type",,,
|
||||
"Value",,,
|
||||
"Value expr",,,
|
||||
"View",,,
|
||||
"View generated",,,
|
||||
"View params",,,
|
||||
"Views",,,
|
||||
"Widget",,,
|
||||
"Wkf",,,
|
||||
"Wkf field",,,
|
||||
"Wkf sequence",,,
|
||||
"Wkf tracking",,,
|
||||
"Wkf trackings",,,
|
||||
"Wkf transition",,,
|
||||
"Workflow dashboard",,,
|
||||
"Workflow is not saved",,,
|
||||
"Year",,,
|
||||
"contains",,,
|
||||
"doesn't contains",,,
|
||||
"equal",,,
|
||||
"greater or equal",,,
|
||||
"greater than",,,
|
||||
"in",,,
|
||||
"include",,,
|
||||
"is false",,,
|
||||
"is not null",,,
|
||||
"is null",,,
|
||||
"is true",,,
|
||||
"less or equal",,,
|
||||
"less than",,,
|
||||
"not equal",,,
|
||||
"not in",,,
|
||||
"not include",,,
|
||||
"value:BPM",,,
|
||||
"value:Product App",,,
|
||||
"xmlId",,,
|
||||
|
@ -0,0 +1,292 @@
|
||||
"key","message","comment","context"
|
||||
"<b>Tags:</b> $user: Current user, $date: Today's date, $time: Current time","<b>Tags:</b> $user: Aktueller Benutzer, $Datum: Heutiges Datum, $Zeit: Aktuelle Zeit",,
|
||||
"AND","UND",,
|
||||
"Action","Aktion",,
|
||||
"Action builder","Action Builder",,
|
||||
"Action builders","Aktionsbauer",,
|
||||
"Actions","Aktionen",,
|
||||
"Activate the hand tool","Aktivieren Sie das Handwerkzeug.",,
|
||||
"Aggregate","Aggregat",,
|
||||
"Aggregate On","Aggregat ein",,
|
||||
"Aggregate On type","Aggregat Nach Typ",,
|
||||
"Aggregate date type","Datumstyp aggregieren",,
|
||||
"Alert","Warnung",,
|
||||
"Alert or Blocking condition","Alarm- oder Sperrbedingung",,
|
||||
"App builder","App Builder",,
|
||||
"App builders",,,
|
||||
"App name",,,
|
||||
"Append end node","Endknoten anhängen",,
|
||||
"Append intermediate node","Zwischenknoten anhängen",,
|
||||
"Apply if",,,
|
||||
"Area","Bereich",,
|
||||
"Assign value to","Wert zuweisen an",,
|
||||
"BPM","BPM",,
|
||||
"Background","Hintergrund",,
|
||||
"Bar","Bar",,
|
||||
"Base model",,,
|
||||
"Blocking","Blockierung",,
|
||||
"Boolean","Boolesch",,
|
||||
"Bpmn xml","Bpmn xml",,
|
||||
"Button","Taste",,
|
||||
"Button title","Titel der Schaltfläche",,
|
||||
"Can Collapse",,,
|
||||
"Chart builder","Diagrammgenerator",,
|
||||
"Chart builders","Diagramm-Ersteller",,
|
||||
"Chart type","Diagrammtyp",,
|
||||
"ChartBuilder.Group","Gruppe",,
|
||||
"Choose App name",,,
|
||||
"Code","Code",,
|
||||
"Collapse if",,,
|
||||
"Colspan","Colspan",,
|
||||
"Condition","Bedingung",,
|
||||
"Conditions","Bedingungen",,
|
||||
"Configuration",,,
|
||||
"Connect using transition","Verbindung über Übergang",,
|
||||
"Context","Kontext",,
|
||||
"Create","Erstellen",,
|
||||
"Create end node","Endknoten anlegen",,
|
||||
"Create intermediate node","Zwischenknoten anlegen",,
|
||||
"Create start node","Startknoten anlegen",,
|
||||
"Custom","Benutzerdefiniert",,
|
||||
"Custom Field","Benutzerdefiniertes Feld",,
|
||||
"Custom Model","Benutzerdefiniertes Modell",,
|
||||
"Custom field","Benutzerdefiniertes Feld",,
|
||||
"Custom fields","Benutzerdefinierte Felder",,
|
||||
"Custom model","Benutzerdefiniertes Modell",,
|
||||
"Custom models","Kundenspezifische Modelle",,
|
||||
"Dashboard","Dashboard",,
|
||||
"Dashboard builder","Dashboard-Builder",,
|
||||
"Dashboard builders","Dashboard-Bauer",,
|
||||
"Dashlet builder","Dashlet Erbauer",,
|
||||
"Dashlet builder list","Liste der Dashlet-Builder",,
|
||||
"Dashlet builders","Dashlet Erbauer",,
|
||||
"Data file","Datendatei",,
|
||||
"Date","Datum",,
|
||||
"Datetime","Datum/Uhrzeit",,
|
||||
"Day","Tag",,
|
||||
"Decimal","Dezimal",,
|
||||
"Default Value","Standardwert",,
|
||||
"Depends on","Abhängig von",,
|
||||
"Description","Beschreibung",,
|
||||
"Display","Display",,
|
||||
"Display message","Display-Meldung",,
|
||||
"Display type","Anzeigeart",,
|
||||
"Do you want to reset workflow ?",,,
|
||||
"Domain","Domain",,
|
||||
"Donut","Donut",,
|
||||
"Dummy","Dummy",,
|
||||
"Edit Node","Knoten bearbeiten",,
|
||||
"Edit Transition","Übergang bearbeiten",,
|
||||
"Edit before send","Bearbeiten vor dem Senden",,
|
||||
"Email","E-Mail",,
|
||||
"End node","Endknoten",,
|
||||
"Existing menu","Vorhandenes Menü",,
|
||||
"Export","Exportieren",,
|
||||
"Extra","Extra",,
|
||||
"Field","Feld",,
|
||||
"Field for 'My menu'","Feld für'Mein Menü'.",,
|
||||
"Field options",,,
|
||||
"Fields","Felder",,
|
||||
"Filter","Filter",,
|
||||
"Filters","Filter",,
|
||||
"First group by","Erste Gruppe nach",,
|
||||
"From","Von",,
|
||||
"Funnel","Trichter",,
|
||||
"Gauge","Manometer",,
|
||||
"Generated Actions","Generierte Aktionen",,
|
||||
"Generated app","Generierte App",,
|
||||
"Groovy","Groovy",,
|
||||
"Group By","Gruppieren nach",,
|
||||
"Group date type","Gruppendatumstyp",,
|
||||
"Group on type","Gruppe nach Typ",,
|
||||
"Groups","Gruppen",,
|
||||
"Help","Hilfe",,
|
||||
"Hidden In Grid","Im Raster versteckt",,
|
||||
"Hidden menu","Verstecktes Menü",,
|
||||
"Horizontal bar","Horizontale Stange",,
|
||||
"Icon","Icon",,
|
||||
"If","Wenn",,
|
||||
"If-module","Wenn-Modul",,
|
||||
"Image","Bild",,
|
||||
"Import","Importieren",,
|
||||
"Import BPM","BPM importieren",,
|
||||
"Import log","Importprotokoll",,
|
||||
"Incoming","Ankommend",,
|
||||
"Integer","Ganzzahl",,
|
||||
"Is Json Relational Field",,,
|
||||
"Is json","Ist json",,
|
||||
"Is parameter","Ist Parameter",,
|
||||
"Is wkf","Ist wkf",,
|
||||
"Javascript","Javascript",,
|
||||
"Json","Json",,
|
||||
"Json Field","Json Feld",,
|
||||
"Json Many To Many","Json Viele Zu Viele Zu Viele",,
|
||||
"Json Many To One","Json viele zu eins",,
|
||||
"Json One To Many","Json Einer zu viele",,
|
||||
"Left menu","Linkes Menü",,
|
||||
"Line","Linie",,
|
||||
"Link","Link",,
|
||||
"Logic operator","Verknüpfungsoperator",,
|
||||
"Many To Many","Viele Zu Viele Zu Viele",,
|
||||
"Many To One","Viele zu einem",,
|
||||
"Max Size","Maximale Größe",,
|
||||
"Menu action","Menü-Aktion",,
|
||||
"Menu builder","Menü-Builder",,
|
||||
"Menu builders","Menü-Erstellung",,
|
||||
"MenuBuilder.Order","Ordnung",,
|
||||
"Message","Nachricht",,
|
||||
"Message on alert or blocking","Nachricht bei Alarm oder Sperrung",,
|
||||
"Message on success","Meldung über den Erfolg",,
|
||||
"Meta Model","Metamodell",,
|
||||
"Meta module","Metamodul",,
|
||||
"MetaMenu","MetaMenü",,
|
||||
"Min Size","Min. Größe",,
|
||||
"Mobile menu","Mobiles Menü",,
|
||||
"Model","Modell",,
|
||||
"Module","Modul",,
|
||||
"Month","Monat",,
|
||||
"Name","Name",,
|
||||
"Name Column",,,
|
||||
"Name Field","Namensfeld",,
|
||||
"Name must not contains space","Der Name darf kein Leerzeichen enthalten.",,
|
||||
"Nav Select","Nav-Auswahl",,
|
||||
"Nb of passes","Anzahl der Durchgänge",,
|
||||
"Nb of passes per status","Anzahl der Durchläufe pro Status",,
|
||||
"Node","Knoten",,
|
||||
"Node type",,,
|
||||
"Nodes","Knoten",,
|
||||
"None",,,
|
||||
"OR","ODER",,
|
||||
"Object","Objekt",,
|
||||
"On Change","Bei Änderung",,
|
||||
"On Click","Auf Klick",,
|
||||
"On New","Bei Neu",,
|
||||
"On Save","Beim Speichern",,
|
||||
"One To Many","Einer zu vielen",,
|
||||
"Only use this menu-item if the given expression is true.","Verwenden Sie diesen Menüpunkt nur, wenn der angegebene Ausdruck wahr ist.",,
|
||||
"Only use this menu-item if the given module is installed.","Verwenden Sie diesen Menüpunkt nur, wenn das angegebene Modul installiert ist.",,
|
||||
"Open record","Datensatz öffnen",,
|
||||
"Open workflow","Offener Workflow",,
|
||||
"Operator","Bediener",,
|
||||
"Outgoing","Ausgehend",,
|
||||
"Overview","Übersicht",,
|
||||
"Pagination limit","Seitenumbruchgrenze",,
|
||||
"Panel","Panel",,
|
||||
"Parent","Elternteil",,
|
||||
"Percentage(%)","Prozentsatz(%)",,
|
||||
"Permissions","Berechtigungen",,
|
||||
"Pie Chart","Kreisdiagramm",,
|
||||
"Please correct the workflow diagram.","Bitte korrigieren Sie das Arbeitsablaufdiagramm.",,
|
||||
"Please input value bind with single quotation.","Bitte geben Sie den Wert binden mit einem einfachen Angebot ein.",,
|
||||
"Please provide unique code. The code '%s' is already used","Bitte geben Sie einen eindeutigen Code an. Der Code'%s' ist bereits verwendet.",,
|
||||
"Process",,,
|
||||
"Process display type","Prozessanzeigetyp",,
|
||||
"Process studio","Prozessstudio",,
|
||||
"Process tracking","Prozessverfolgung",,
|
||||
"Properties","Eigenschaften",,
|
||||
"Radar","Radar",,
|
||||
"ReadOnly for",,,
|
||||
"Record Id","Aufzeichnungs-ID",,
|
||||
"Record model","Aktenmodell",,
|
||||
"Record name","Datensatzname",,
|
||||
"Regex","Regex",,
|
||||
"Report","Bericht",,
|
||||
"Reporting",,,
|
||||
"Required","Erforderlich",,
|
||||
"Required If","Erforderlich bei",,
|
||||
"Roles","Rollen",,
|
||||
"Scatter","Streuung",,
|
||||
"Script","Skript",,
|
||||
"Script type","Skript-Typ",,
|
||||
"Second group by","Zweite Gruppe nach",,
|
||||
"Select Option","Option auswählen",,
|
||||
"Selection","Auswahl",,
|
||||
"Selections",,,
|
||||
"Send directly","Direkt versenden",,
|
||||
"Send option","Sendeoption",,
|
||||
"Separator","Separator",,
|
||||
"Sequence","Sequenz",,
|
||||
"Show If","Anzeigen ob",,
|
||||
"Show Title",,,
|
||||
"Show process tracking","Prozessverfolgung anzeigen",,
|
||||
"Simple Select","Einfache Auswahl",,
|
||||
"Source field","Quellfeld",,
|
||||
"Start node","Startknoten",,
|
||||
"Status","Status",,
|
||||
"Status per day","Status pro Tag",,
|
||||
"Status per month","Status pro Monat",,
|
||||
"Status time(days)","Statuszeit (Tage)",,
|
||||
"Status time(hours)","Statuszeit (Stunden)",,
|
||||
"String","Zeichenkette",,
|
||||
"Studio",,,
|
||||
"Sub lines","Unterzeilen",,
|
||||
"Tag count","Tag-Anzahl",,
|
||||
"Tag label","Tag-Etikett",,
|
||||
"Tag method","Tag-Verfahren",,
|
||||
"Tag style","Tag-Stil",,
|
||||
"Target","Ziel",,
|
||||
"Target Json Model","Ziel Json Modell",,
|
||||
"Target field","Zielfeld",,
|
||||
"Target json","Ziel json",,
|
||||
"Target object","Zielobjekt",,
|
||||
"Target title",,,
|
||||
"Target type","Zielart",,
|
||||
"Task node",,,
|
||||
"Template","Vorlage",,
|
||||
"Text","Text",,
|
||||
"Time","Zeit",,
|
||||
"Time spent","Zeitaufwand",,
|
||||
"Time spent (hours/days)","Verweildauer (Stunden/Tage)",,
|
||||
"Time spent per status (hours)","Verweildauer pro Status (Stunden)",,
|
||||
"Time spent per status per user (hours)","Zeitaufwand pro Status pro Benutzer (Stunden)",,
|
||||
"Title","Titel",,
|
||||
"To","An",,
|
||||
"Top menu","Top-Menü",,
|
||||
"Total time per status","Gesamtzeit pro Status",,
|
||||
"Track flow","Schienenfluss",,
|
||||
"Track workflow","Verfolgung des Arbeitsablaufs",,
|
||||
"Tracking line","Tracking-Linie",,
|
||||
"Tracking lines","Tracking-Linien",,
|
||||
"Transactional","Transaktionale",,
|
||||
"Transition","Übergang",,
|
||||
"Transitions","Übergänge",,
|
||||
"Type","Typ",,
|
||||
"UI options",,,
|
||||
"Update","Update",,
|
||||
"User","Benutzer",,
|
||||
"Validation type","Validierungsart",,
|
||||
"Value","Wert",,
|
||||
"Value expr","Wert Ausdruck",,
|
||||
"View","Ansicht",,
|
||||
"View generated","Ansicht generiert",,
|
||||
"View params","Parameter anzeigen",,
|
||||
"Views","Ansichten",,
|
||||
"Widget","Widget",,
|
||||
"Wkf","Wkf",,
|
||||
"Wkf field","Wkf-Feld",,
|
||||
"Wkf sequence",,,
|
||||
"Wkf tracking","Wkf-Tracking",,
|
||||
"Wkf trackings","Wkf-Tracking",,
|
||||
"Wkf transition","Wkf-Übergang",,
|
||||
"Workflow dashboard","Workflow-Dashboard",,
|
||||
"Workflow is not saved","Workflow wird nicht gespeichert",,
|
||||
"Year","Jahr",,
|
||||
"contains","enthält",,
|
||||
"doesn't contains","enthält nicht",,
|
||||
"equal","gleich",,
|
||||
"greater or equal","größer oder gleich",,
|
||||
"greater than","größer als",,
|
||||
"in","in",,
|
||||
"include","einbeziehen",,
|
||||
"is false","ist falsch",,
|
||||
"is not null","ist nicht Null",,
|
||||
"is null","ist Null",,
|
||||
"is true","ist wahr",,
|
||||
"less or equal","kleiner oder gleich",,
|
||||
"less than","weniger als",,
|
||||
"not equal","nicht gleich",,
|
||||
"not in","nicht in",,
|
||||
"not include","nicht enthalten",,
|
||||
"value:BPM","Wert:BPM",,
|
||||
"value:Product App","Wert:Produkt-App",,
|
||||
"xmlId","xmlId",,
|
||||
|
@ -0,0 +1,292 @@
|
||||
"key","message","comment","context"
|
||||
"<b>Tags:</b> $user: Current user, $date: Today's date, $time: Current time",,,
|
||||
"AND",,,
|
||||
"Action",,,
|
||||
"Action builder",,,
|
||||
"Action builders",,,
|
||||
"Actions",,,
|
||||
"Activate the hand tool",,,
|
||||
"Aggregate",,,
|
||||
"Aggregate On",,,
|
||||
"Aggregate On type",,,
|
||||
"Aggregate date type",,,
|
||||
"Alert",,,
|
||||
"Alert or Blocking condition",,,
|
||||
"App builder",,,
|
||||
"App builders",,,
|
||||
"App name","Application",,
|
||||
"Append end node",,,
|
||||
"Append intermediate node",,,
|
||||
"Apply if",,,
|
||||
"Area",,,
|
||||
"Assign value to",,,
|
||||
"BPM",,,
|
||||
"Background",,,
|
||||
"Bar",,,
|
||||
"Base model",,,
|
||||
"Blocking",,,
|
||||
"Boolean",,,
|
||||
"Bpmn xml",,,
|
||||
"Button",,,
|
||||
"Button title",,,
|
||||
"Can Collapse",,,
|
||||
"Chart builder",,,
|
||||
"Chart builders",,,
|
||||
"Chart type",,,
|
||||
"ChartBuilder.Group","Group",,
|
||||
"Choose App name",,,
|
||||
"Code",,,
|
||||
"Collapse if",,,
|
||||
"Colspan",,,
|
||||
"Condition",,,
|
||||
"Conditions",,,
|
||||
"Configuration",,,
|
||||
"Connect using transition",,,
|
||||
"Context",,,
|
||||
"Create",,,
|
||||
"Create end node",,,
|
||||
"Create intermediate node",,,
|
||||
"Create start node",,,
|
||||
"Custom",,,
|
||||
"Custom Field",,,
|
||||
"Custom Model",,,
|
||||
"Custom field",,,
|
||||
"Custom fields",,,
|
||||
"Custom model",,,
|
||||
"Custom models",,,
|
||||
"Dashboard",,,
|
||||
"Dashboard builder",,,
|
||||
"Dashboard builders",,,
|
||||
"Dashlet builder",,,
|
||||
"Dashlet builder list",,,
|
||||
"Dashlet builders",,,
|
||||
"Data file",,,
|
||||
"Date",,,
|
||||
"Datetime",,,
|
||||
"Day",,,
|
||||
"Decimal",,,
|
||||
"Default Value",,,
|
||||
"Depends on",,,
|
||||
"Description",,,
|
||||
"Display",,,
|
||||
"Display message",,,
|
||||
"Display type",,,
|
||||
"Do you want to reset workflow ?",,,
|
||||
"Domain",,,
|
||||
"Donut",,,
|
||||
"Dummy",,,
|
||||
"Edit Node",,,
|
||||
"Edit Transition",,,
|
||||
"Edit before send",,,
|
||||
"Email",,,
|
||||
"End node",,,
|
||||
"Existing menu",,,
|
||||
"Export",,,
|
||||
"Extra",,,
|
||||
"Field",,,
|
||||
"Field for 'My menu'",,,
|
||||
"Field options",,,
|
||||
"Fields",,,
|
||||
"Filter",,,
|
||||
"Filters",,,
|
||||
"First group by",,,
|
||||
"From",,,
|
||||
"Funnel",,,
|
||||
"Gauge",,,
|
||||
"Generated Actions",,,
|
||||
"Generated app",,,
|
||||
"Groovy",,,
|
||||
"Group By",,,
|
||||
"Group date type",,,
|
||||
"Group on type",,,
|
||||
"Groups",,,
|
||||
"Help",,,
|
||||
"Hidden In Grid",,,
|
||||
"Hidden menu",,,
|
||||
"Horizontal bar",,,
|
||||
"Icon",,,
|
||||
"If",,,
|
||||
"If-module",,,
|
||||
"Image",,,
|
||||
"Import",,,
|
||||
"Import BPM",,,
|
||||
"Import log",,,
|
||||
"Incoming",,,
|
||||
"Integer",,,
|
||||
"Is Json Relational Field",,,
|
||||
"Is json",,,
|
||||
"Is parameter",,,
|
||||
"Is wkf",,,
|
||||
"Javascript",,,
|
||||
"Json",,,
|
||||
"Json Field",,,
|
||||
"Json Many To Many",,,
|
||||
"Json Many To One",,,
|
||||
"Json One To Many",,,
|
||||
"Left menu",,,
|
||||
"Line",,,
|
||||
"Link",,,
|
||||
"Logic operator",,,
|
||||
"Many To Many",,,
|
||||
"Many To One",,,
|
||||
"Max Size",,,
|
||||
"Menu action",,,
|
||||
"Menu builder",,,
|
||||
"Menu builders",,,
|
||||
"MenuBuilder.Order","Order",,
|
||||
"Message",,,
|
||||
"Message on alert or blocking",,,
|
||||
"Message on success",,,
|
||||
"Meta Model",,,
|
||||
"Meta module",,,
|
||||
"MetaMenu",,,
|
||||
"Min Size",,,
|
||||
"Mobile menu",,,
|
||||
"Model",,,
|
||||
"Module",,,
|
||||
"Month",,,
|
||||
"Name",,,
|
||||
"Name Column",,,
|
||||
"Name Field",,,
|
||||
"Name must not contains space",,,
|
||||
"Nav Select",,,
|
||||
"Nb of passes",,,
|
||||
"Nb of passes per status",,,
|
||||
"Node",,,
|
||||
"Node type",,,
|
||||
"Nodes",,,
|
||||
"None",,,
|
||||
"OR",,,
|
||||
"Object",,,
|
||||
"On Change",,,
|
||||
"On Click",,,
|
||||
"On New",,,
|
||||
"On Save",,,
|
||||
"One To Many",,,
|
||||
"Only use this menu-item if the given expression is true.",,,
|
||||
"Only use this menu-item if the given module is installed.",,,
|
||||
"Open record",,,
|
||||
"Open workflow",,,
|
||||
"Operator",,,
|
||||
"Outgoing",,,
|
||||
"Overview",,,
|
||||
"Pagination limit",,,
|
||||
"Panel",,,
|
||||
"Parent",,,
|
||||
"Percentage(%)",,,
|
||||
"Permissions",,,
|
||||
"Pie Chart",,,
|
||||
"Please correct the workflow diagram.",,,
|
||||
"Please input value bind with single quotation.",,,
|
||||
"Please provide unique code. The code '%s' is already used",,,
|
||||
"Process",,,
|
||||
"Process display type",,,
|
||||
"Process studio",,,
|
||||
"Process tracking",,,
|
||||
"Properties",,,
|
||||
"Radar",,,
|
||||
"ReadOnly for",,,
|
||||
"Record Id",,,
|
||||
"Record model",,,
|
||||
"Record name",,,
|
||||
"Regex",,,
|
||||
"Report",,,
|
||||
"Reporting",,,
|
||||
"Required",,,
|
||||
"Required If",,,
|
||||
"Roles",,,
|
||||
"Scatter",,,
|
||||
"Script",,,
|
||||
"Script type",,,
|
||||
"Second group by",,,
|
||||
"Select Option",,,
|
||||
"Selection",,,
|
||||
"Selections",,,
|
||||
"Send directly",,,
|
||||
"Send option",,,
|
||||
"Separator",,,
|
||||
"Sequence",,,
|
||||
"Show If",,,
|
||||
"Show Title",,,
|
||||
"Show process tracking",,,
|
||||
"Simple Select",,,
|
||||
"Source field",,,
|
||||
"Start node",,,
|
||||
"Status",,,
|
||||
"Status per day",,,
|
||||
"Status per month",,,
|
||||
"Status time(days)",,,
|
||||
"Status time(hours)",,,
|
||||
"String",,,
|
||||
"Studio",,,
|
||||
"Sub lines",,,
|
||||
"Tag count",,,
|
||||
"Tag label",,,
|
||||
"Tag method",,,
|
||||
"Tag style",,,
|
||||
"Target",,,
|
||||
"Target Json Model",,,
|
||||
"Target field",,,
|
||||
"Target json",,,
|
||||
"Target object",,,
|
||||
"Target title",,,
|
||||
"Target type",,,
|
||||
"Task node",,,
|
||||
"Template",,,
|
||||
"Text",,,
|
||||
"Time",,,
|
||||
"Time spent",,,
|
||||
"Time spent (hours/days)",,,
|
||||
"Time spent per status (hours)",,,
|
||||
"Time spent per status per user (hours)",,,
|
||||
"Title",,,
|
||||
"To",,,
|
||||
"Top menu",,,
|
||||
"Total time per status",,,
|
||||
"Track flow",,,
|
||||
"Track workflow",,,
|
||||
"Tracking line",,,
|
||||
"Tracking lines",,,
|
||||
"Transactional",,,
|
||||
"Transition",,,
|
||||
"Transitions",,,
|
||||
"Type",,,
|
||||
"UI options",,,
|
||||
"Update",,,
|
||||
"User",,,
|
||||
"Validation type",,,
|
||||
"Value",,,
|
||||
"Value expr",,,
|
||||
"View",,,
|
||||
"View generated",,,
|
||||
"View params",,,
|
||||
"Views",,,
|
||||
"Widget",,,
|
||||
"Wkf",,,
|
||||
"Wkf field",,,
|
||||
"Wkf sequence",,,
|
||||
"Wkf tracking",,,
|
||||
"Wkf trackings",,,
|
||||
"Wkf transition",,,
|
||||
"Workflow dashboard",,,
|
||||
"Workflow is not saved",,,
|
||||
"Year",,,
|
||||
"contains",,,
|
||||
"doesn't contains",,,
|
||||
"equal",,,
|
||||
"greater or equal",,,
|
||||
"greater than",,,
|
||||
"in",,,
|
||||
"include",,,
|
||||
"is false",,,
|
||||
"is not null",,,
|
||||
"is null",,,
|
||||
"is true",,,
|
||||
"less or equal",,,
|
||||
"less than",,,
|
||||
"not equal",,,
|
||||
"not in",,,
|
||||
"not include",,,
|
||||
"value:BPM",,,
|
||||
"value:Product App",,,
|
||||
"xmlId",,,
|
||||
|
@ -0,0 +1,292 @@
|
||||
"key","message","comment","context"
|
||||
"<b>Tags:</b> $user: Current user, $date: Today's date, $time: Current time","<b>Etiquetas:</b> $usuario: Usuario actual, $date: Fecha de hoy, $time: Hora actual",,
|
||||
"AND","Y",,
|
||||
"Action","Acción",,
|
||||
"Action builder","Constructor de acciones",,
|
||||
"Action builders","Constructores de acciones",,
|
||||
"Actions","Acciones",,
|
||||
"Activate the hand tool","Activar la herramienta manual",,
|
||||
"Aggregate","Agregado",,
|
||||
"Aggregate On","Agregado en",,
|
||||
"Aggregate On type","Tipo Aggregate On",,
|
||||
"Aggregate date type","Agregar clase de fecha",,
|
||||
"Alert","Alerta",,
|
||||
"Alert or Blocking condition","Alerta o condición de bloqueo",,
|
||||
"App builder","Constructor de aplicaciones",,
|
||||
"App builders",,,
|
||||
"App name",,,
|
||||
"Append end node","Añadir nodo final",,
|
||||
"Append intermediate node","Añadir nodo intermedio",,
|
||||
"Apply if",,,
|
||||
"Area","Área",,
|
||||
"Assign value to","Asignar valor a",,
|
||||
"BPM","BPM",,
|
||||
"Background","Antecedentes",,
|
||||
"Bar","Bar",,
|
||||
"Base model",,,
|
||||
"Blocking","Bloqueo",,
|
||||
"Boolean","booleano",,
|
||||
"Bpmn xml","Bpmn xml",,
|
||||
"Button","Botón",,
|
||||
"Button title","Título del botón",,
|
||||
"Can Collapse",,,
|
||||
"Chart builder","Constructor de gráficos",,
|
||||
"Chart builders","Constructores de cartas",,
|
||||
"Chart type","Tipo de gráfico",,
|
||||
"ChartBuilder.Group","Grupo",,
|
||||
"Choose App name",,,
|
||||
"Code","Código",,
|
||||
"Collapse if",,,
|
||||
"Colspan","Colspan",,
|
||||
"Condition","Condición",,
|
||||
"Conditions","Condiciones",,
|
||||
"Configuration",,,
|
||||
"Connect using transition","Conectar usando la transición",,
|
||||
"Context","Contexto",,
|
||||
"Create","Crear",,
|
||||
"Create end node","Crear nodo final",,
|
||||
"Create intermediate node","Crear nodo intermedio",,
|
||||
"Create start node","Crear nodo de inicio",,
|
||||
"Custom","A medida",,
|
||||
"Custom Field","Campo personalizado",,
|
||||
"Custom Model","Modelo personalizado",,
|
||||
"Custom field","Campo personalizado",,
|
||||
"Custom fields","Campos personalizados",,
|
||||
"Custom model","Modelo personalizado",,
|
||||
"Custom models","Modelos personalizados",,
|
||||
"Dashboard","Tablero de mandos",,
|
||||
"Dashboard builder","Constructor de cuadros de mando",,
|
||||
"Dashboard builders","Constructores de cuadros de mando",,
|
||||
"Dashlet builder","Constructor de dashlets",,
|
||||
"Dashlet builder list","Lista de constructores de dashlets",,
|
||||
"Dashlet builders","Constructores de dashlets",,
|
||||
"Data file","Archivo de datos",,
|
||||
"Date","Fecha",,
|
||||
"Datetime","Fecha y hora",,
|
||||
"Day","Día",,
|
||||
"Decimal","Decimal",,
|
||||
"Default Value","Valor de propuesta",,
|
||||
"Depends on","Depende de",,
|
||||
"Description","Descripción",,
|
||||
"Display","Pantalla",,
|
||||
"Display message","Mostrar mensaje",,
|
||||
"Display type","Tipo de pantalla",,
|
||||
"Do you want to reset workflow ?",,,
|
||||
"Domain","Dominio",,
|
||||
"Donut","Donut",,
|
||||
"Dummy","Maniquí",,
|
||||
"Edit Node","Tratar nodo",,
|
||||
"Edit Transition","Editar transición",,
|
||||
"Edit before send","Modificar antes de enviar",,
|
||||
"Email","Correo electrónico",,
|
||||
"End node","Nodo final",,
|
||||
"Existing menu","Menú existente",,
|
||||
"Export","Exportación",,
|
||||
"Extra","Extra",,
|
||||
"Field","Campo",,
|
||||
"Field for 'My menu'","Campo para `Mi menú'.",,
|
||||
"Field options",,,
|
||||
"Fields","Campos",,
|
||||
"Filter","Filtro",,
|
||||
"Filters","Filtros",,
|
||||
"First group by","Primer grupo por",,
|
||||
"From","Desde",,
|
||||
"Funnel","Embudo",,
|
||||
"Gauge","Calibrador",,
|
||||
"Generated Actions","Acciones generadas",,
|
||||
"Generated app","Generado app",,
|
||||
"Groovy","Groovy",,
|
||||
"Group By","Agrupar por",,
|
||||
"Group date type","Clase de fecha de grupo",,
|
||||
"Group on type","Grupo sobre el tipo",,
|
||||
"Groups","Grupos",,
|
||||
"Help","Ayuda",,
|
||||
"Hidden In Grid","Oculto en la cuadrícula",,
|
||||
"Hidden menu","Menú oculto",,
|
||||
"Horizontal bar","Barra horizontal",,
|
||||
"Icon","Icono",,
|
||||
"If","Si",,
|
||||
"If-module","Módulo If",,
|
||||
"Image","Imagen",,
|
||||
"Import","Importar",,
|
||||
"Import BPM","Importación BPM",,
|
||||
"Import log","Log de importación",,
|
||||
"Incoming","Entrante",,
|
||||
"Integer","Entero",,
|
||||
"Is Json Relational Field",,,
|
||||
"Is json","Es json",,
|
||||
"Is parameter","Es parámetro",,
|
||||
"Is wkf","Es wkf",,
|
||||
"Javascript","Javascript",,
|
||||
"Json","Json",,
|
||||
"Json Field","Campo Json",,
|
||||
"Json Many To Many","Json Many To Many",,
|
||||
"Json Many To One","Json Muchos a Uno",,
|
||||
"Json One To Many","Json One to Many",,
|
||||
"Left menu","Menú de la izquierda",,
|
||||
"Line","Línea",,
|
||||
"Link","Enlace",,
|
||||
"Logic operator","Operador lógico",,
|
||||
"Many To Many","Muchos a muchos",,
|
||||
"Many To One","Muchos a uno",,
|
||||
"Max Size","Tamaño Máximo",,
|
||||
"Menu action","Acción del menú",,
|
||||
"Menu builder","Constructor de menús",,
|
||||
"Menu builders","Constructores de menús",,
|
||||
"MenuBuilder.Order","Orden",,
|
||||
"Message","Mensaje",,
|
||||
"Message on alert or blocking","Mensaje de alerta o bloqueo",,
|
||||
"Message on success","Mensaje sobre el éxito",,
|
||||
"Meta Model","Meta Modelo",,
|
||||
"Meta module","Meta módulo",,
|
||||
"MetaMenu","MetaMenú",,
|
||||
"Min Size","Tamaño mínimo",,
|
||||
"Mobile menu","Menú Móvil",,
|
||||
"Model","Modelo",,
|
||||
"Module","Módulo",,
|
||||
"Month","Mes",,
|
||||
"Name","Nombre",,
|
||||
"Name Column",,,
|
||||
"Name Field","Nombre Campo",,
|
||||
"Name must not contains space","El nombre no debe contener espacio",,
|
||||
"Nav Select","Selección de Navegación",,
|
||||
"Nb of passes","Número de pases",,
|
||||
"Nb of passes per status","Número de pases por estado",,
|
||||
"Node","Nodo",,
|
||||
"Node type","Type de nœud",,
|
||||
"Nodes","Nodos",,
|
||||
"None",,,
|
||||
"OR","O",,
|
||||
"Object","Objeto",,
|
||||
"On Change","Sobre el cambio",,
|
||||
"On Click","En Click",,
|
||||
"On New","En Nuevo",,
|
||||
"On Save","En Guardar",,
|
||||
"One To Many","Uno a muchos",,
|
||||
"Only use this menu-item if the given expression is true.","Utilice este elemento de menú sólo si la expresión dada es verdadera.",,
|
||||
"Only use this menu-item if the given module is installed.","Utilice este elemento de menú sólo si el módulo está instalado.",,
|
||||
"Open record","Registro abierto",,
|
||||
"Open workflow","Flujo de trabajo abierto",,
|
||||
"Operator","Operador",,
|
||||
"Outgoing","Saliente",,
|
||||
"Overview","Panorama general",,
|
||||
"Pagination limit","Límite de paginación",,
|
||||
"Panel","Panel",,
|
||||
"Parent","Padre",,
|
||||
"Percentage(%)","Porcentaje (%)",,
|
||||
"Permissions","Permisos",,
|
||||
"Pie Chart","Gráfico de tarta",,
|
||||
"Please correct the workflow diagram.","Por favor, corrija el diagrama de flujo de trabajo.",,
|
||||
"Please input value bind with single quotation.","Por favor, introduzca el valor de encuadernar con una sola cita.",,
|
||||
"Please provide unique code. The code '%s' is already used","Por favor, proporcione un código único. El código '%s' ya se utiliza",,
|
||||
"Process",,,
|
||||
"Process display type","Tipo de visualización del proceso",,
|
||||
"Process studio","Estudio de procesos",,
|
||||
"Process tracking","Seguimiento del proceso",,
|
||||
"Properties","Propiedades",,
|
||||
"Radar","Radar",,
|
||||
"ReadOnly for","Lecture seule pour",,
|
||||
"Record Id","Id. de registro",,
|
||||
"Record model","Modelo de registro",,
|
||||
"Record name","Nombre del registro",,
|
||||
"Regex","Regex",,
|
||||
"Report","Informe",,
|
||||
"Reporting",,,
|
||||
"Required","Requerido",,
|
||||
"Required If","Requerido Si",,
|
||||
"Roles","Roles",,
|
||||
"Scatter","Esparcir",,
|
||||
"Script","Guión",,
|
||||
"Script type","Tipo de guión",,
|
||||
"Second group by","Segundo grupo por",,
|
||||
"Select Option","Seleccione la opción",,
|
||||
"Selection","Selección",,
|
||||
"Selections",,,
|
||||
"Send directly","Enviar directamente",,
|
||||
"Send option","Opción de envío",,
|
||||
"Separator","Separador",,
|
||||
"Sequence","Secuencia",,
|
||||
"Show If","Mostrar Si",,
|
||||
"Show Title",,,
|
||||
"Show process tracking","Mostrar seguimiento de procesos",,
|
||||
"Simple Select","Selección simple",,
|
||||
"Source field","Campo fuente",,
|
||||
"Start node","Nodo de inicio",,
|
||||
"Status","Estado",,
|
||||
"Status per day","Estado por día",,
|
||||
"Status per month","Estado por mes",,
|
||||
"Status time(days)","Tiempo de status (días)",,
|
||||
"Status time(hours)","Tiempo de estado (horas)",,
|
||||
"String","Cadena",,
|
||||
"Studio",,,
|
||||
"Sub lines","Líneas secundarias",,
|
||||
"Tag count","Conteo de etiquetas",,
|
||||
"Tag label","Etiqueta",,
|
||||
"Tag method","Método de la etiqueta",,
|
||||
"Tag style","Estilo de etiqueta",,
|
||||
"Target","Objetivo",,
|
||||
"Target Json Model","Modelo Json objetivo",,
|
||||
"Target field","Campo de destino",,
|
||||
"Target json","Objetivo json",,
|
||||
"Target object","Objeto de destino",,
|
||||
"Target title",,,
|
||||
"Target type","Clase de destino",,
|
||||
"Task node","Noeud intermédiaire",,
|
||||
"Template","Plantilla",,
|
||||
"Text","Texto",,
|
||||
"Time","Tiempo",,
|
||||
"Time spent","Tiempo de permanencia",,
|
||||
"Time spent (hours/days)","Tiempo empleado (horas/días)",,
|
||||
"Time spent per status (hours)","Tiempo empleado por estado (horas)",,
|
||||
"Time spent per status per user (hours)","Tiempo empleado por estado por usuario (horas)",,
|
||||
"Title","Título",,
|
||||
"To","Para",,
|
||||
"Top menu","Menú principal",,
|
||||
"Total time per status","Tiempo total por status",,
|
||||
"Track flow","Flujo de la pista",,
|
||||
"Track workflow","Seguimiento del flujo de trabajo",,
|
||||
"Tracking line","Línea de seguimiento",,
|
||||
"Tracking lines","Líneas de seguimiento",,
|
||||
"Transactional","Transaccional",,
|
||||
"Transition","Transición",,
|
||||
"Transitions","Transiciones",,
|
||||
"Type","Tipo",,
|
||||
"UI options",,,
|
||||
"Update","Actualización",,
|
||||
"User","Usuario",,
|
||||
"Validation type","Tipo de validación",,
|
||||
"Value","Valor",,
|
||||
"Value expr","Valor Expr",,
|
||||
"View","Ver",,
|
||||
"View generated","Vista generada",,
|
||||
"View params","Ver parámetros",,
|
||||
"Views","Vistas",,
|
||||
"Widget","Widget",,
|
||||
"Wkf","Wkf",,
|
||||
"Wkf field","Campo Wkf",,
|
||||
"Wkf sequence",,,
|
||||
"Wkf tracking","Seguimiento de Wkf",,
|
||||
"Wkf trackings","Seguimiento de Wkf",,
|
||||
"Wkf transition","Transición Wkf",,
|
||||
"Workflow dashboard","Panel de control del flujo de trabajo",,
|
||||
"Workflow is not saved","No se graba el workflow",,
|
||||
"Year","Año",,
|
||||
"contains","contiene",,
|
||||
"doesn't contains","no contiene",,
|
||||
"equal","idénticas",,
|
||||
"greater or equal","mayor o igual",,
|
||||
"greater than","mayor que",,
|
||||
"in","en",,
|
||||
"include","contener",,
|
||||
"is false","es falso",,
|
||||
"is not null","no es nula",,
|
||||
"is null","es nulo",,
|
||||
"is true","es cierto",,
|
||||
"less or equal","menor o igual",,
|
||||
"less than","menos de",,
|
||||
"not equal","no es igual",,
|
||||
"not in","no en",,
|
||||
"not include","no incluye",,
|
||||
"value:BPM","valor:BPM",,
|
||||
"value:Product App","valor:Producto App",,
|
||||
"xmlId","xmlId",,
|
||||
|
@ -0,0 +1,292 @@
|
||||
"key","message","comment","context"
|
||||
"<b>Tags:</b> $user: Current user, $date: Today's date, $time: Current time","<b>Libellé:</b> $user: Utilisateur actuel, $date: Date d'aujourd'hui, $time: Heure actuelle",,
|
||||
"AND","ET",,
|
||||
"Action","Action",,
|
||||
"Action builder","Constructeur d'action",,
|
||||
"Action builders","Constructeurs d'action",,
|
||||
"Actions","Actions",,
|
||||
"Activate the hand tool","Activer l'outil manuel",,
|
||||
"Aggregate","Agréger",,
|
||||
"Aggregate On","Agréger sur",,
|
||||
"Aggregate On type","Agréger sur un type",,
|
||||
"Aggregate date type","Type de date agrégée",,
|
||||
"Alert","Alerte",,
|
||||
"Alert or Blocking condition","Condition d'alerte ou de blocage",,
|
||||
"App builder","Constructeur d'app",,
|
||||
"App builders","Constructeurs d'apps",,
|
||||
"App name","Application",,
|
||||
"Append end node","Ajouter un nœud terminal",,
|
||||
"Append intermediate node","Ajouter un nœud intermédiaire",,
|
||||
"Apply if",,,
|
||||
"Area","Zone",,
|
||||
"Assign value to","Affecter valeur à",,
|
||||
"BPM","BPM",,
|
||||
"Background","Background",,
|
||||
"Bar","Bar",,
|
||||
"Base model","Modèle de base",,
|
||||
"Blocking","Blocage",,
|
||||
"Boolean","Booléen",,
|
||||
"Bpmn xml","Bpmn xml",,
|
||||
"Button","Bouton",,
|
||||
"Button title","Titre du bouton",,
|
||||
"Can Collapse","Repliable",,
|
||||
"Chart builder","Constructeur de graphique",,
|
||||
"Chart builders","Constructeurs de graphiques",,
|
||||
"Chart type","Type de graphique",,
|
||||
"ChartBuilder.Group","Regrouper",,
|
||||
"Choose App name","Choisir application",,
|
||||
"Code",,,
|
||||
"Collapse if","Replier si",,
|
||||
"Colspan","Colspan",,
|
||||
"Condition","Condition",,
|
||||
"Conditions","Conditions",,
|
||||
"Configuration",,,
|
||||
"Connect using transition","Connecter en utilisant la transition",,
|
||||
"Context","Contexte",,
|
||||
"Create","Créer",,
|
||||
"Create end node","Créer un nœud terminal",,
|
||||
"Create intermediate node","Créer un nœud intermédiaire",,
|
||||
"Create start node","Créer un nœud de départ",,
|
||||
"Custom","Personnaliser",,
|
||||
"Custom Field","Champ personnalisé",,
|
||||
"Custom Model","Modèle personnalisé",,
|
||||
"Custom field","Champ personnalisé",,
|
||||
"Custom fields","Champs personnalisés",,
|
||||
"Custom model","Modèle personnalisé",,
|
||||
"Custom models","Modèles personnalisés",,
|
||||
"Dashboard",,,
|
||||
"Dashboard builder","Constructeur de tableaux de bord",,
|
||||
"Dashboard builders","Constructeurs de tableaux de bord",,
|
||||
"Dashlet builder","Constructeur de dashlet",,
|
||||
"Dashlet builder list","Liste des constructeurs de dashlet",,
|
||||
"Dashlet builders","Constructeurs de dashlet",,
|
||||
"Data file","Fichier de données",,
|
||||
"Date","Date",,
|
||||
"Datetime","Date et heure",,
|
||||
"Day","Jour",,
|
||||
"Decimal","Décimal",,
|
||||
"Default Value","Valeur par défaut",,
|
||||
"Depends on","Dépend de",,
|
||||
"Description",,,
|
||||
"Display","Affichage",,
|
||||
"Display message","Message affiché",,
|
||||
"Display type","Type d'affichage",,
|
||||
"Do you want to reset workflow ?","Voulez-vous réinitialiser le workflow ?",,
|
||||
"Domain","Domaine",,
|
||||
"Donut","Donut",,
|
||||
"Dummy","Factice",,
|
||||
"Edit Node","Modifier un nœud",,
|
||||
"Edit Transition","Modifier une transition",,
|
||||
"Edit before send","Editer avant d’envoyer",,
|
||||
"Email",,,
|
||||
"End node","Nœud terminal",,
|
||||
"Existing menu","Menu existant",,
|
||||
"Export","Exporter",,
|
||||
"Extra","Extra",,
|
||||
"Field","Champ",,
|
||||
"Field for 'My menu'","Champ pour 'Mon menu'",,
|
||||
"Field options","Options du champ",,
|
||||
"Fields","Champs",,
|
||||
"Filter","Filtre",,
|
||||
"Filters","Filtres",,
|
||||
"First group by","Premier groupe par",,
|
||||
"From","De",,
|
||||
"Funnel","Entonnoir",,
|
||||
"Gauge","Jauge",,
|
||||
"Generated Actions","Actions générées",,
|
||||
"Generated app","App générée",,
|
||||
"Groovy","Groovy",,
|
||||
"Group By","Regrouper par",,
|
||||
"Group date type","Type de date de groupe",,
|
||||
"Group on type","Regrouper sur type",,
|
||||
"Groups","Groupes",,
|
||||
"Help","Aide",,
|
||||
"Hidden In Grid","Caché dans la grille",,
|
||||
"Hidden menu","Menu caché",,
|
||||
"Horizontal bar","Barre horizontale",,
|
||||
"Icon","Icône",,
|
||||
"If","Si",,
|
||||
"If-module","Si-module",,
|
||||
"Image",,,
|
||||
"Import","Import",,
|
||||
"Import BPM",,,
|
||||
"Import log",,,
|
||||
"Incoming","Entrant",,
|
||||
"Integer","Nombre entier",,
|
||||
"Is Json Relational Field","Champ relationnel JSON",,
|
||||
"Is json","Est JSON",,
|
||||
"Is parameter","Est paramètre",,
|
||||
"Is wkf","Est wkf",,
|
||||
"Javascript","Javascript",,
|
||||
"Json",,,
|
||||
"Json Field","Champ Json",,
|
||||
"Json Many To Many","Json N à N",,
|
||||
"Json Many To One","Json N à 1",,
|
||||
"Json One To Many","Json 1 à N",,
|
||||
"Left menu","Menu de gauche",,
|
||||
"Line","Ligne",,
|
||||
"Link","Lien",,
|
||||
"Logic operator","Opérateur logique",,
|
||||
"Many To Many","N à N",,
|
||||
"Many To One","N à 1",,
|
||||
"Max Size","Taille max",,
|
||||
"Menu action","Constructeur de menu",,
|
||||
"Menu builder","Constructeur de menu",,
|
||||
"Menu builders","Constructeurs de menus",,
|
||||
"MenuBuilder.Order","Ordre",,
|
||||
"Message","Message",,
|
||||
"Message on alert or blocking","Message sur les alertes ou blocages",,
|
||||
"Message on success","Message de succès",,
|
||||
"Meta Model","Modèle Meta",,
|
||||
"Meta module",,,
|
||||
"MetaMenu",,,
|
||||
"Min Size","Taille min",,
|
||||
"Mobile menu","Menu mobile",,
|
||||
"Model","Modèle",,
|
||||
"Module","Module",,
|
||||
"Month","Mois",,
|
||||
"Name","Nom",,
|
||||
"Name Column","Colonne nominative",,
|
||||
"Name Field","Champ nom",,
|
||||
"Name must not contains space","Le nom ne doit pas contenir d'espace",,
|
||||
"Nav Select","Nav Select",,
|
||||
"Nb of passes","Nb de passages",,
|
||||
"Nb of passes per status","Nb de passages par statut",,
|
||||
"Node","Nœud",,
|
||||
"Node type","Type de nœud",,
|
||||
"Nodes","Nœuds",,
|
||||
"None",,,
|
||||
"OR","OU",,
|
||||
"Object","Objet",,
|
||||
"On Change","Au changement",,
|
||||
"On Click","Au clic",,
|
||||
"On New","À la création",,
|
||||
"On Save","À la sauvegarde",,
|
||||
"One To Many","1 à N",,
|
||||
"Only use this menu-item if the given expression is true.","N'utilisez cet élément de menu que si l'expression donnée est vraie.",,
|
||||
"Only use this menu-item if the given module is installed.","N'utilisez cet élément de menu que si le module concerné est installé.",,
|
||||
"Open record","Ouvrir enregistrement",,
|
||||
"Open workflow","Ouvrir le processus",,
|
||||
"Operator","Opérateur",,
|
||||
"Outgoing","Sortant",,
|
||||
"Overview","Vue d'ensemble",,
|
||||
"Pagination limit","Limite de pagination",,
|
||||
"Panel","Panel",,
|
||||
"Parent","Parent",,
|
||||
"Percentage(%)","Pourcentage(%)",,
|
||||
"Permissions","Permissions",,
|
||||
"Pie Chart","Diagramme circulaire",,
|
||||
"Please correct the workflow diagram.","Veuillez corriger le diagramme de workflow.",,
|
||||
"Please input value bind with single quotation.","Veuillez entrer les valeurs liées avec une seule guillemet",,
|
||||
"Please provide unique code. The code '%s' is already used","Veuillez indiquer un code unique. Le code '%s' est déjà utilisé",,
|
||||
"Process",,,
|
||||
"Process display type","Type d'affichage du processus",,
|
||||
"Process studio","Studio Processus",,
|
||||
"Process tracking","Suivi processus",,
|
||||
"Properties","Propriétés",,
|
||||
"Radar","Radar",,
|
||||
"ReadOnly for","Lecture seule pour",,
|
||||
"Record Id","Identifiant",,
|
||||
"Record model","Objet",,
|
||||
"Record name","Nom de l'objet",,
|
||||
"Regex","Regex",,
|
||||
"Report","Rapport",,
|
||||
"Reporting",,,
|
||||
"Required","Requis",,
|
||||
"Required If","Requis si",,
|
||||
"Roles","Rôles",,
|
||||
"Scatter","Disperser",,
|
||||
"Script","Script",,
|
||||
"Script type","Type de script",,
|
||||
"Second group by","Deuxième groupe par",,
|
||||
"Select Option","Sélectionner option",,
|
||||
"Selection","Sélection",,
|
||||
"Selections","Sélections",,
|
||||
"Send directly","Envoyer directement",,
|
||||
"Send option","Option d’envoi",,
|
||||
"Separator","Séparateur",,
|
||||
"Sequence","Séquence",,
|
||||
"Show If","Montrer si",,
|
||||
"Show Title","Montrer le titre",,
|
||||
"Show process tracking","Afficher le suivi du processus",,
|
||||
"Simple Select","Sélection simple",,
|
||||
"Source field","Champ source",,
|
||||
"Start node","Nœud de départ",,
|
||||
"Status","Statut",,
|
||||
"Status per day","Statut par jour",,
|
||||
"Status per month","Statut par mois",,
|
||||
"Status time(days)","Temps du status (en heures)",,
|
||||
"Status time(hours)","Temps du status (en jours)",,
|
||||
"String","Chaîne de caractères",,
|
||||
"Studio",,,
|
||||
"Sub lines","Sous-lignes",,
|
||||
"Tag count","Compteur",,
|
||||
"Tag label","Libellé du tag",,
|
||||
"Tag method","Méthode de calcul",,
|
||||
"Tag style","Style de tag",,
|
||||
"Target","Cible",,
|
||||
"Target Json Model","Modèle de cible JSON",,
|
||||
"Target field","Champ cible",,
|
||||
"Target json","JSON cible",,
|
||||
"Target object","Objet cible",,
|
||||
"Target title","Titre de la cible",,
|
||||
"Target type","Type cible",,
|
||||
"Task node","Noeud intermédiaire",,
|
||||
"Template","Modèle",,
|
||||
"Text","Texte",,
|
||||
"Time","Heure",,
|
||||
"Time spent","Temps passé",,
|
||||
"Time spent (hours/days)","Temps passé (heures/jours)",,
|
||||
"Time spent per status (hours)","Temps passé par statut (heures)",,
|
||||
"Time spent per status per user (hours)","Temps passé par statut par utilisateur (heures)",,
|
||||
"Title","Titre",,
|
||||
"To","À",,
|
||||
"Top menu","Menu supérieur",,
|
||||
"Total time per status","Temps total par status",,
|
||||
"Track flow","Suivi processus",,
|
||||
"Track workflow","Suivre le workflow",,
|
||||
"Tracking line","Suivi de la ligne",,
|
||||
"Tracking lines","Suivi des lignes",,
|
||||
"Transactional","Transactionnel",,
|
||||
"Transition","Transition",,
|
||||
"Transitions","Transitions",,
|
||||
"Type","Type",,
|
||||
"UI options","Options UI",,
|
||||
"Update","Mise à jour",,
|
||||
"User","Utilisateur",,
|
||||
"Validation type","Type de validation",,
|
||||
"Value","Valeur",,
|
||||
"Value expr","Expression évaluée",,
|
||||
"View","Vue",,
|
||||
"View generated","Vue générée",,
|
||||
"View params","Afficher les paramètres",,
|
||||
"Views","Vues",,
|
||||
"Widget","Widget",,
|
||||
"Wkf","Processus",,
|
||||
"Wkf field","Champ wkf",,
|
||||
"Wkf sequence",,,
|
||||
"Wkf tracking","Suivi wkf",,
|
||||
"Wkf trackings","Suivis wkf",,
|
||||
"Wkf transition","Transition wkf",,
|
||||
"Workflow dashboard","Tableau de bord workflow",,
|
||||
"Workflow is not saved","Le workflow n'est pas sauvegardé",,
|
||||
"Year","Année",,
|
||||
"contains","Contient",,
|
||||
"doesn't contains","Ne contient pas",,
|
||||
"equal","égal",,
|
||||
"greater or equal","Supérieur ou égal à",,
|
||||
"greater than","Supérieur à",,
|
||||
"in","dans",,
|
||||
"include","inclus",,
|
||||
"is false","est faux",,
|
||||
"is not null","n'est pas nul",,
|
||||
"is null","est nul",,
|
||||
"is true","est vrai",,
|
||||
"less or equal","inférieur ou égal",,
|
||||
"less than","inférieur à",,
|
||||
"not equal","n'est pas égal",,
|
||||
"not in","pas dans",,
|
||||
"not include","n'est pas inclus",,
|
||||
"value:BPM","BPM",,
|
||||
"value:Product App",,,
|
||||
"xmlId","xmlId",,
|
||||
|
@ -0,0 +1,292 @@
|
||||
"key","message","comment","context"
|
||||
"<b>Tags:</b> $user: Current user, $date: Today's date, $time: Current time","<b>Tags:</b> $user: Utente corrente, $date: data di oggi, $time: Ora corrente",,
|
||||
"AND","E",,
|
||||
"Action","Azione",,
|
||||
"Action builder","Costruttore di azioni",,
|
||||
"Action builders","Costruttori di azioni",,
|
||||
"Actions","Azioni",,
|
||||
"Activate the hand tool","Attivare lo strumento manuale",,
|
||||
"Aggregate","Aggregato",,
|
||||
"Aggregate On","Aggregato su",,
|
||||
"Aggregate On type","Aggregato Su tipo",,
|
||||
"Aggregate date type","Tipo di data aggregata",,
|
||||
"Alert","Allarme",,
|
||||
"Alert or Blocking condition","Allarme o condizione di blocco",,
|
||||
"App builder","Costruttore di applicazioni",,
|
||||
"App builders",,,
|
||||
"App name",,,
|
||||
"Append end node","Append end nodo di fine",,
|
||||
"Append intermediate node","Aggiungete un nodo intermedio",,
|
||||
"Apply if",,,
|
||||
"Area","Area",,
|
||||
"Assign value to","Assegnare il valore a",,
|
||||
"BPM","BPM",,
|
||||
"Background","Sfondo",,
|
||||
"Bar","Bar",,
|
||||
"Base model",,,
|
||||
"Blocking","Blocco",,
|
||||
"Boolean","booleano",,
|
||||
"Bpmn xml","Bpmn xml",,
|
||||
"Button","Pulsante",,
|
||||
"Button title","Titolo del pulsante",,
|
||||
"Can Collapse",,,
|
||||
"Chart builder","Costruttore di grafici",,
|
||||
"Chart builders","Costruttori di carte nautiche",,
|
||||
"Chart type","Tipo di grafico",,
|
||||
"ChartBuilder.Group","Gruppo",,
|
||||
"Choose App name",,,
|
||||
"Code","Codice",,
|
||||
"Collapse if",,,
|
||||
"Colspan","Colspan",,
|
||||
"Condition","Condizione",,
|
||||
"Conditions","Condizioni",,
|
||||
"Configuration",,,
|
||||
"Connect using transition","Connettiti usando la transizione",,
|
||||
"Context","Contesto",,
|
||||
"Create","Creare",,
|
||||
"Create end node","Crea nodo finale",,
|
||||
"Create intermediate node","Creare un nodo intermedio",,
|
||||
"Create start node","Crea nodo di partenza",,
|
||||
"Custom","Personalizzato",,
|
||||
"Custom Field","Campo personalizzato",,
|
||||
"Custom Model","Modello personalizzato",,
|
||||
"Custom field","Campo personalizzato",,
|
||||
"Custom fields","Campi personalizzati",,
|
||||
"Custom model","Modello personalizzato",,
|
||||
"Custom models","Modelli personalizzati",,
|
||||
"Dashboard","Cruscotto",,
|
||||
"Dashboard builder","Costruttore di cruscotti",,
|
||||
"Dashboard builders","Costruttori di cruscotti",,
|
||||
"Dashlet builder","Costruttore di cruscotti",,
|
||||
"Dashlet builder list","Elenco dei costruttori di cruscotti",,
|
||||
"Dashlet builders","Costruttori di cruscotti",,
|
||||
"Data file","File di dati",,
|
||||
"Date","Data",,
|
||||
"Datetime","Data e ora",,
|
||||
"Day","Giorno",,
|
||||
"Decimal","Decimale",,
|
||||
"Default Value","Valore predefinito",,
|
||||
"Depends on","Dipende",,
|
||||
"Description","Descrizione",,
|
||||
"Display","Display",,
|
||||
"Display message","Messaggio sul display",,
|
||||
"Display type","Tipo di display",,
|
||||
"Do you want to reset workflow ?",,,
|
||||
"Domain","Dominio",,
|
||||
"Donut","Ciambella",,
|
||||
"Dummy","Manichino",,
|
||||
"Edit Node","Modifica nodo",,
|
||||
"Edit Transition","Modifica Transizione",,
|
||||
"Edit before send","Modifica prima dell'invio",,
|
||||
"Email","Email eMail",,
|
||||
"End node","Nodo finale",,
|
||||
"Existing menu","Menu esistente",,
|
||||
"Export","Esportazione",,
|
||||
"Extra","Extra",,
|
||||
"Field","Campo",,
|
||||
"Field for 'My menu'","Campo per 'Il mio menu'.",,
|
||||
"Field options",,,
|
||||
"Fields","I campi",,
|
||||
"Filter","Filtro",,
|
||||
"Filters","Filtri",,
|
||||
"First group by","Primo gruppo per",,
|
||||
"From","Da",,
|
||||
"Funnel","Imbuto",,
|
||||
"Gauge","Calibro",,
|
||||
"Generated Actions","Azioni generate",,
|
||||
"Generated app","App generata",,
|
||||
"Groovy","Groovy",,
|
||||
"Group By","Gruppo per",,
|
||||
"Group date type","Tipo di data di gruppo",,
|
||||
"Group on type","Gruppo per tipo",,
|
||||
"Groups","Gruppi",,
|
||||
"Help","Aiuto",,
|
||||
"Hidden In Grid","Nascosto nella griglia",,
|
||||
"Hidden menu","Menu nascosto",,
|
||||
"Horizontal bar","Barra orizzontale",,
|
||||
"Icon","Icona",,
|
||||
"If","Se",,
|
||||
"If-module","Modulo If",,
|
||||
"Image","Immagine",,
|
||||
"Import","Importazione",,
|
||||
"Import BPM","Importazione BPM",,
|
||||
"Import log","Importa log",,
|
||||
"Incoming","Arrivo",,
|
||||
"Integer","Intero",,
|
||||
"Is Json Relational Field",,,
|
||||
"Is json","E' Json",,
|
||||
"Is parameter","È parametro",,
|
||||
"Is wkf","È wkf",,
|
||||
"Javascript","Javascript",,
|
||||
"Json","Json",,
|
||||
"Json Field","Campo Json",,
|
||||
"Json Many To Many","Json molti a molti a molti",,
|
||||
"Json Many To One","Json molti a uno",,
|
||||
"Json One To Many","Json uno a molti",,
|
||||
"Left menu","Menu di sinistra",,
|
||||
"Line","Linea",,
|
||||
"Link","Collegamento",,
|
||||
"Logic operator","Operatore logico",,
|
||||
"Many To Many","Molti a molti a molti",,
|
||||
"Many To One","Molti a uno",,
|
||||
"Max Size","Dimensione massima",,
|
||||
"Menu action","Azione del menu",,
|
||||
"Menu builder","Costruttore di menu",,
|
||||
"Menu builders","Costruttori di menu",,
|
||||
"MenuBuilder.Order","Ordine",,
|
||||
"Message","Messaggio",,
|
||||
"Message on alert or blocking","Messaggio in caso di allarme o blocco",,
|
||||
"Message on success","Messaggio sul successo",,
|
||||
"Meta Model","Meta Modello",,
|
||||
"Meta module","Meta modulo",,
|
||||
"MetaMenu","MetaMenu",,
|
||||
"Min Size","Dimensione minima",,
|
||||
"Mobile menu","Menu mobile",,
|
||||
"Model","Modello",,
|
||||
"Module","Modulo",,
|
||||
"Month","Mese",,
|
||||
"Name","Nome",,
|
||||
"Name Column",,,
|
||||
"Name Field","Nome Campo",,
|
||||
"Name must not contains space","Il nome non deve contenere spazio",,
|
||||
"Nav Select","Seleziona Nav",,
|
||||
"Nb of passes","Numero di passaggi",,
|
||||
"Nb of passes per status","Nb di pass per stato",,
|
||||
"Node","Nodo",,
|
||||
"Node type",,,
|
||||
"Nodes","Nodi",,
|
||||
"None",,,
|
||||
"OR","OPPURE",,
|
||||
"Object","Oggetto",,
|
||||
"On Change","In Cambia",,
|
||||
"On Click","Su Click",,
|
||||
"On New","Su Nuovo",,
|
||||
"On Save","Su salvare",,
|
||||
"One To Many","Uno a molti",,
|
||||
"Only use this menu-item if the given expression is true.","Utilizzare questa voce di menu solo se l'espressione data è vera.",,
|
||||
"Only use this menu-item if the given module is installed.","Utilizzare questa voce di menu solo se il modulo in questione è installato.",,
|
||||
"Open record","Apri record",,
|
||||
"Open workflow","Flusso di lavoro aperto",,
|
||||
"Operator","Operatore",,
|
||||
"Outgoing","In uscita",,
|
||||
"Overview","Panoramica",,
|
||||
"Pagination limit","Limite di impaginazione",,
|
||||
"Panel","Pannello",,
|
||||
"Parent","Genitore",,
|
||||
"Percentage(%)","Percentuale (%)",,
|
||||
"Permissions","Autorizzazioni",,
|
||||
"Pie Chart","Grafico a torta",,
|
||||
"Please correct the workflow diagram.","Si prega di correggere il diagramma del flusso di lavoro.",,
|
||||
"Please input value bind with single quotation.","Si prega di inserire il valore da associare alla quotazione singola.",,
|
||||
"Please provide unique code. The code '%s' is already used","Si prega di fornire un codice univoco. Il codice %s è già utilizzato",,
|
||||
"Process",,,
|
||||
"Process display type","Tipo di visualizzazione del processo",,
|
||||
"Process studio","Studio di processo",,
|
||||
"Process tracking","Tracciabilità del processo",,
|
||||
"Properties","Proprietà",,
|
||||
"Radar","Radar",,
|
||||
"ReadOnly for",,,
|
||||
"Record Id","Id record",,
|
||||
"Record model","Modello di record",,
|
||||
"Record name","Nome del record",,
|
||||
"Regex","Regex",,
|
||||
"Report","Segnala",,
|
||||
"Reporting",,,
|
||||
"Required","Richiesto",,
|
||||
"Required If","Richiesto Se",,
|
||||
"Roles","Ruoli",,
|
||||
"Scatter","Spargimento",,
|
||||
"Script","Sceneggiatura",,
|
||||
"Script type","Tipo di script",,
|
||||
"Second group by","Secondo gruppo per",,
|
||||
"Select Option","Selezionare l'opzione",,
|
||||
"Selection","Selezione",,
|
||||
"Selections",,,
|
||||
"Send directly","Inviare direttamente",,
|
||||
"Send option","Opzione Invio",,
|
||||
"Separator","Separatore",,
|
||||
"Sequence","Sequenza",,
|
||||
"Show If","Mostra se",,
|
||||
"Show Title",,,
|
||||
"Show process tracking","Mostra il monitoraggio del processo",,
|
||||
"Simple Select","Selezione semplice",,
|
||||
"Source field","Fonte Campo",,
|
||||
"Start node","Nodo di partenza",,
|
||||
"Status","Stato",,
|
||||
"Status per day","Stato al giorno",,
|
||||
"Status per month","Stato al mese",,
|
||||
"Status time(days)","Tempo di stato (giorni)",,
|
||||
"Status time(hours)","Tempo di stato (ore)",,
|
||||
"String","Stringa",,
|
||||
"Studio",,,
|
||||
"Sub lines","Linee secondarie",,
|
||||
"Tag count","Numero di tag",,
|
||||
"Tag label","Etichetta dell'etichetta",,
|
||||
"Tag method","Metodo dei tag",,
|
||||
"Tag style","Stile dell'etichetta",,
|
||||
"Target","Obiettivo",,
|
||||
"Target Json Model","Obiettivo Json modello",,
|
||||
"Target field","Campo target",,
|
||||
"Target json","Json bersaglio",,
|
||||
"Target object","Oggetto target",,
|
||||
"Target title",,,
|
||||
"Target type","Tipo di target",,
|
||||
"Task node",,,
|
||||
"Template","Modello",,
|
||||
"Text","Testo",,
|
||||
"Time","Tempo",,
|
||||
"Time spent","Tempo trascorso",,
|
||||
"Time spent (hours/days)","Tempo di permanenza (ore/giorni)",,
|
||||
"Time spent per status (hours)","Tempo trascorso per stato (ore)",,
|
||||
"Time spent per status per user (hours)","Tempo di permanenza per stato per utente (ore)",,
|
||||
"Title","Titolo",,
|
||||
"To","A",,
|
||||
"Top menu","Menu principale",,
|
||||
"Total time per status","Tempo totale per stato",,
|
||||
"Track flow","Flusso della pista",,
|
||||
"Track workflow","Traccia il flusso di lavoro",,
|
||||
"Tracking line","Linea di monitoraggio",,
|
||||
"Tracking lines","Linee di tracciamento",,
|
||||
"Transactional","Transazionale",,
|
||||
"Transition","Transizione",,
|
||||
"Transitions","Transizioni",,
|
||||
"Type","Tipo",,
|
||||
"UI options",,,
|
||||
"Update","Aggiorna",,
|
||||
"User","Utente",,
|
||||
"Validation type","Tipo di convalida",,
|
||||
"Value","Valore",,
|
||||
"Value expr","Valore",,
|
||||
"View","Vista",,
|
||||
"View generated","Vista generata",,
|
||||
"View params","Visualizza i parametri",,
|
||||
"Views","Viste",,
|
||||
"Widget","Widget",,
|
||||
"Wkf","Wkf",,
|
||||
"Wkf field","Campo Wkf",,
|
||||
"Wkf sequence",,,
|
||||
"Wkf tracking","Inseguimento di Wkf",,
|
||||
"Wkf trackings","Tracciati Wkf",,
|
||||
"Wkf transition","Transizione Wkf",,
|
||||
"Workflow dashboard","Flusso di lavoro cruscotto",,
|
||||
"Workflow is not saved","Il flusso di lavoro non viene salvato",,
|
||||
"Year","Anno",,
|
||||
"contains","contiene",,
|
||||
"doesn't contains","non contiene",,
|
||||
"equal","paritario",,
|
||||
"greater or equal","maggiore o uguale",,
|
||||
"greater than","maggiore di",,
|
||||
"in","in",,
|
||||
"include","comprendere",,
|
||||
"is false","è falso",,
|
||||
"is not null","non è nullo",,
|
||||
"is null","è nullo",,
|
||||
"is true","è vero",,
|
||||
"less or equal","inferiore o uguale",,
|
||||
"less than","meno di",,
|
||||
"not equal","non uguale",,
|
||||
"not in","non in",,
|
||||
"not include","non includere",,
|
||||
"value:BPM","valore:BPM",,
|
||||
"value:Product App","valore:Prodotto App",,
|
||||
"xmlId","xmlId",,
|
||||
|
@ -0,0 +1,292 @@
|
||||
"key","message","comment","context"
|
||||
"<b>Tags:</b> $user: Current user, $date: Today's date, $time: Current time","<b>Tags:</b> $user: Huidige gebruiker, $date: datum van vandaag, $time: Huidige tijd",,
|
||||
"AND","EN",,
|
||||
"Action","Actie",,
|
||||
"Action builder","Actie bouwer",,
|
||||
"Action builders","Actiebouwers",,
|
||||
"Actions","Acties",,
|
||||
"Activate the hand tool","Activeer het handgereedschap",,
|
||||
"Aggregate","Geaggregeerd",,
|
||||
"Aggregate On","Geaggregeerd op",,
|
||||
"Aggregate On type","Geaggregeerd Op type",,
|
||||
"Aggregate date type","Geaggregeerde datum type",,
|
||||
"Alert","Alarm",,
|
||||
"Alert or Blocking condition","Waarschuwing of blokkeringstoestand",,
|
||||
"App builder","App bouwer",,
|
||||
"App builders",,,
|
||||
"App name",,,
|
||||
"Append end node","Eindknooppunt toevoegen",,
|
||||
"Append intermediate node","Voeg tussenliggende knoop toe",,
|
||||
"Apply if",,,
|
||||
"Area","Gebied",,
|
||||
"Assign value to","Wijs waarde toe aan",,
|
||||
"BPM","BPM",,
|
||||
"Background","Achtergrond",,
|
||||
"Bar","Bar",,
|
||||
"Base model",,,
|
||||
"Blocking","Blokkeren",,
|
||||
"Boolean","Booleaans",,
|
||||
"Bpmn xml","Bpmn xml",,
|
||||
"Button","Knop",,
|
||||
"Button title","Titel van de knop",,
|
||||
"Can Collapse",,,
|
||||
"Chart builder","Grafiekbouwer",,
|
||||
"Chart builders","Grafiekbouwers",,
|
||||
"Chart type","Grafiektype",,
|
||||
"ChartBuilder.Group","Groep",,
|
||||
"Choose App name",,,
|
||||
"Code","Code",,
|
||||
"Collapse if",,,
|
||||
"Colspan","Colspan",,
|
||||
"Condition","Voorwaarde",,
|
||||
"Conditions","Voorwaarden",,
|
||||
"Configuration",,,
|
||||
"Connect using transition","Aansluiten met behulp van de overgang",,
|
||||
"Context","Context",,
|
||||
"Create","Creëer",,
|
||||
"Create end node","Eindknoop maken",,
|
||||
"Create intermediate node","Creëer tussenliggende knoop",,
|
||||
"Create start node","Startknooppunt maken",,
|
||||
"Custom","Douane",,
|
||||
"Custom Field","Aangepast veld",,
|
||||
"Custom Model","Aangepast model",,
|
||||
"Custom field","Aangepast veld",,
|
||||
"Custom fields","Aangepaste velden",,
|
||||
"Custom model","Aangepast model",,
|
||||
"Custom models","Aangepaste modellen",,
|
||||
"Dashboard","Dashboard",,
|
||||
"Dashboard builder","Dashboard bouwer",,
|
||||
"Dashboard builders","Dashboard bouwers",,
|
||||
"Dashlet builder","Dashlet bouwer",,
|
||||
"Dashlet builder list","Dashlet bouwer lijst",,
|
||||
"Dashlet builders","Dashlet bouwers",,
|
||||
"Data file","Gegevensbestand",,
|
||||
"Date","Datum",,
|
||||
"Datetime","Datetime",,
|
||||
"Day","Dag",,
|
||||
"Decimal","Decimaal",,
|
||||
"Default Value","Standaardwaarde",,
|
||||
"Depends on","Afhankelijk van",,
|
||||
"Description","Beschrijving",,
|
||||
"Display","Vertoning",,
|
||||
"Display message","Weergave bericht",,
|
||||
"Display type","Type display",,
|
||||
"Do you want to reset workflow ?",,,
|
||||
"Domain","Domein",,
|
||||
"Donut","Donut",,
|
||||
"Dummy","Dummy",,
|
||||
"Edit Node","Knooppunt bewerken",,
|
||||
"Edit Transition","Overgang bewerken",,
|
||||
"Edit before send","Bewerken voor verzending",,
|
||||
"Email","E-mail",,
|
||||
"End node","Eindknoop",,
|
||||
"Existing menu","Bestaand menu",,
|
||||
"Export","Exporteren",,
|
||||
"Extra","Extra",,
|
||||
"Field","Veld",,
|
||||
"Field for 'My menu'","Veld voor 'Mijn menu'",,
|
||||
"Field options",,,
|
||||
"Fields","Velden",,
|
||||
"Filter","Filter",,
|
||||
"Filters","Filters",,
|
||||
"First group by","Eerste groep door",,
|
||||
"From","Van",,
|
||||
"Funnel","Trechter",,
|
||||
"Gauge","Meter",,
|
||||
"Generated Actions","Gegenereerde acties",,
|
||||
"Generated app","Gegenereerde app",,
|
||||
"Groovy","Groovy",,
|
||||
"Group By","Groep Per",,
|
||||
"Group date type","Groepsdatum type",,
|
||||
"Group on type","Groep op type",,
|
||||
"Groups","Groepen",,
|
||||
"Help","Hulp",,
|
||||
"Hidden In Grid","Verborgen in raster",,
|
||||
"Hidden menu","Verborgen menu",,
|
||||
"Horizontal bar","Horizontale balk",,
|
||||
"Icon","Pictogram",,
|
||||
"If","Indien",,
|
||||
"If-module","Als-module",,
|
||||
"Image","Beeld",,
|
||||
"Import","Importeren",,
|
||||
"Import BPM","Importeren BPM",,
|
||||
"Import log","Logboek importeren",,
|
||||
"Incoming","Inkomend",,
|
||||
"Integer","Geheel getal",,
|
||||
"Is Json Relational Field",,,
|
||||
"Is json","Is json",,
|
||||
"Is parameter","Is parameter",,
|
||||
"Is wkf","Is wkf",,
|
||||
"Javascript","Javascript",,
|
||||
"Json","Json",,
|
||||
"Json Field","Json veld",,
|
||||
"Json Many To Many","Json veel te veel voor veel",,
|
||||
"Json Many To One","Json Vele aan Één",,
|
||||
"Json One To Many","Json een voor veel",,
|
||||
"Left menu","Menu links",,
|
||||
"Line","Lijn",,
|
||||
"Link","Link",,
|
||||
"Logic operator","Logische operator",,
|
||||
"Many To Many","Veel te veel voor veel",,
|
||||
"Many To One","Veel naar een",,
|
||||
"Max Size","Maximum Grootte",,
|
||||
"Menu action","Menu actie",,
|
||||
"Menu builder","Menu bouwer",,
|
||||
"Menu builders","Menu bouwers",,
|
||||
"MenuBuilder.Order","Orde",,
|
||||
"Message","Bericht",,
|
||||
"Message on alert or blocking","Bericht over waarschuwing of blokkering",,
|
||||
"Message on success","Bericht over succes",,
|
||||
"Meta Model","Metamodel",,
|
||||
"Meta module","Metamodule",,
|
||||
"MetaMenu","MetaMenu",,
|
||||
"Min Size","Min. grootte",,
|
||||
"Mobile menu","Mobiel menu",,
|
||||
"Model","Model",,
|
||||
"Module","Module",,
|
||||
"Month","Maand",,
|
||||
"Name","Naam",,
|
||||
"Name Column",,,
|
||||
"Name Field","Naam Veld",,
|
||||
"Name must not contains space","Naam mag geen ruimte bevatten",,
|
||||
"Nav Select","Navigatie Kiezen",,
|
||||
"Nb of passes","Aantal passen",,
|
||||
"Nb of passes per status","Aantal passen per status",,
|
||||
"Node","Knooppunt",,
|
||||
"Node type","Type de nœud",,
|
||||
"Nodes","Knooppunten",,
|
||||
"None",,,
|
||||
"OR","OF",,
|
||||
"Object","Voorwerp",,
|
||||
"On Change","Over verandering",,
|
||||
"On Click","Op Klik",,
|
||||
"On New","Op Nieuw",,
|
||||
"On Save","Op Opslaan",,
|
||||
"One To Many","Een naar veel",,
|
||||
"Only use this menu-item if the given expression is true.","Gebruik dit menu-item alleen als de gegeven uitdrukking waar is.",,
|
||||
"Only use this menu-item if the given module is installed.","Gebruik dit menu-item alleen als de gegeven module is geïnstalleerd.",,
|
||||
"Open record","Open record",,
|
||||
"Open workflow","Open workflow",,
|
||||
"Operator","Exploitant",,
|
||||
"Outgoing","Uitgaand",,
|
||||
"Overview","Overzicht",,
|
||||
"Pagination limit","Paginatiegrens",,
|
||||
"Panel","Paneel",,
|
||||
"Parent","Ouder",,
|
||||
"Percentage(%)","Percentage (%)",,
|
||||
"Permissions","Toestemmingen",,
|
||||
"Pie Chart","Taartdiagram",,
|
||||
"Please correct the workflow diagram.","Corrigeer het workflow diagram.",,
|
||||
"Please input value bind with single quotation.","Gelieve de invoerwaarde te binden met één offerte.",,
|
||||
"Please provide unique code. The code '%s' is already used","Geef een unieke code op. De code %s wordt reeds gebruikt",,
|
||||
"Process",,,
|
||||
"Process display type","Type procesweergave",,
|
||||
"Process studio","Processtudio",,
|
||||
"Process tracking","Proces het volgen",,
|
||||
"Properties","Eigenschappen",,
|
||||
"Radar","Radar",,
|
||||
"ReadOnly for","Lecture seule pour",,
|
||||
"Record Id","Verslag Id",,
|
||||
"Record model","Record model",,
|
||||
"Record name","Naam record",,
|
||||
"Regex","Regex",,
|
||||
"Report","Verslag",,
|
||||
"Reporting",,,
|
||||
"Required","Vereist",,
|
||||
"Required If","Vereist indien",,
|
||||
"Roles","Rollen",,
|
||||
"Scatter","Verstrooien",,
|
||||
"Script","Script",,
|
||||
"Script type","Scripttype",,
|
||||
"Second group by","Tweede groep door",,
|
||||
"Select Option","Selecteer optie",,
|
||||
"Selection","Selectie",,
|
||||
"Selections",,,
|
||||
"Send directly","Direct verzenden",,
|
||||
"Send option","Verzend optie",,
|
||||
"Separator","Scheider",,
|
||||
"Sequence","Volgorde",,
|
||||
"Show If","Toon als",,
|
||||
"Show Title",,,
|
||||
"Show process tracking","Toon procesvolgsysteem",,
|
||||
"Simple Select","Eenvoudig selecteren",,
|
||||
"Source field","Bronveld",,
|
||||
"Start node","Startknoop",,
|
||||
"Status","Status",,
|
||||
"Status per day","Status per dag",,
|
||||
"Status per month","Status per maand",,
|
||||
"Status time(days)","Status tijd (dagen)",,
|
||||
"Status time(hours)","Status tijd (uren)",,
|
||||
"String","Snaar",,
|
||||
"Studio",,,
|
||||
"Sub lines","Onderlijnen",,
|
||||
"Tag count","Tagtelling",,
|
||||
"Tag label","Markeringsetiket",,
|
||||
"Tag method","Tag methode",,
|
||||
"Tag style","Tag stijl",,
|
||||
"Target","Doel",,
|
||||
"Target Json Model","Doel Json Model",,
|
||||
"Target field","Doelveld",,
|
||||
"Target json","Doelgroep json",,
|
||||
"Target object","Doelobject",,
|
||||
"Target title",,,
|
||||
"Target type","Doeltype",,
|
||||
"Task node","Noeud intermédiaire",,
|
||||
"Template","Sjabloon",,
|
||||
"Text","Tekst",,
|
||||
"Time","Tijd",,
|
||||
"Time spent","Doorgebrachte tijd",,
|
||||
"Time spent (hours/days)","bestede tijd (uren/dagen)",,
|
||||
"Time spent per status (hours)","bestede tijd per status (uren)",,
|
||||
"Time spent per status per user (hours)","bestede tijd per status per gebruiker (uren)",,
|
||||
"Title","Titel",,
|
||||
"To","Naar",,
|
||||
"Top menu","Hoofdmenu",,
|
||||
"Total time per status","Totale tijd per status",,
|
||||
"Track flow","Spoorstroom",,
|
||||
"Track workflow","Traceer de workflow",,
|
||||
"Tracking line","Het volgen van lijn",,
|
||||
"Tracking lines","Het volgen van lijnen",,
|
||||
"Transactional","Transactioneel",,
|
||||
"Transition","Overgang",,
|
||||
"Transitions","Overgangen",,
|
||||
"Type","Type",,
|
||||
"UI options",,,
|
||||
"Update","Update",,
|
||||
"User","Gebruiker",,
|
||||
"Validation type","Type validatie",,
|
||||
"Value","Waarde",,
|
||||
"Value expr",,,
|
||||
"View","Bekijk",,
|
||||
"View generated","Weergave gegenereerd",,
|
||||
"View params","Bekijk params",,
|
||||
"Views","Uitzicht",,
|
||||
"Widget","Widget",,
|
||||
"Wkf","Wkf",,
|
||||
"Wkf field","Wkf veld",,
|
||||
"Wkf sequence",,,
|
||||
"Wkf tracking","Wkf het volgen",,
|
||||
"Wkf trackings","Wkf rupsbanden",,
|
||||
"Wkf transition","Wkf overgang",,
|
||||
"Workflow dashboard","Workflow dashboard",,
|
||||
"Workflow is not saved","Workflow wordt niet opgeslagen",,
|
||||
"Year","Jaar",,
|
||||
"contains","bevat",,
|
||||
"doesn't contains","bevat niet",,
|
||||
"equal","gelijk",,
|
||||
"greater or equal","groter of gelijk",,
|
||||
"greater than","groter dan",,
|
||||
"in","naar binnen",,
|
||||
"include","behelzen",,
|
||||
"is false","vals is",,
|
||||
"is not null","niet ongeldig is",,
|
||||
"is null","is ongeldig",,
|
||||
"is true","waar is",,
|
||||
"less or equal","minder of gelijk",,
|
||||
"less than","minder dan",,
|
||||
"not equal","niet gelijk",,
|
||||
"not in","niet in",,
|
||||
"not include","niet omvatten",,
|
||||
"value:BPM","waarde: BPM",,
|
||||
"value:Product App","waarde: Product App",,
|
||||
"xmlId","xmlId",,
|
||||
|
@ -0,0 +1,292 @@
|
||||
"key","message","comment","context"
|
||||
"<b>Tags:</b> $user: Current user, $date: Today's date, $time: Current time","<b>Tagi:</b> $user: Aktualny użytkownik, $date: Dzisiejsza data, $time: Czas bieżący.",,
|
||||
"AND","ORAZ",,
|
||||
"Action","Działanie",,
|
||||
"Action builder","Kreator działań",,
|
||||
"Action builders","Osoby budujące działania",,
|
||||
"Actions","Działania",,
|
||||
"Activate the hand tool","Aktywuj narzędzie ręczne",,
|
||||
"Aggregate","Agregat",,
|
||||
"Aggregate On","Aggregate On",,
|
||||
"Aggregate On type","Agregat na typ",,
|
||||
"Aggregate date type","Typ daty zbiorczej",,
|
||||
"Alert","Alert",,
|
||||
"Alert or Blocking condition","Stan alarmu lub blokady",,
|
||||
"App builder","Konstruktor aplikacji",,
|
||||
"App builders",,,
|
||||
"App name",,,
|
||||
"Append end node","Dodaj węzeł końcowy",,
|
||||
"Append intermediate node","Dodaj węzeł pośredni",,
|
||||
"Apply if",,,
|
||||
"Area","Powierzchnia",,
|
||||
"Assign value to","Przypisz wartość do",,
|
||||
"BPM","BPM",,
|
||||
"Background","Kontekst",,
|
||||
"Bar","Bar",,
|
||||
"Base model",,,
|
||||
"Blocking","Blokowanie",,
|
||||
"Boolean","luksemburski",,
|
||||
"Bpmn xml","Bpmn xml",,
|
||||
"Button","Przycisk",,
|
||||
"Button title","Tytuł przycisku",,
|
||||
"Can Collapse",,,
|
||||
"Chart builder","Konstruktor wykresów",,
|
||||
"Chart builders","Producenci wykresów",,
|
||||
"Chart type","Typ wykresu",,
|
||||
"ChartBuilder.Group","Grupa",,
|
||||
"Choose App name",,,
|
||||
"Code","Kod",,
|
||||
"Collapse if",,,
|
||||
"Colspan","Kolspan",,
|
||||
"Condition","Warunek",,
|
||||
"Conditions","Warunki",,
|
||||
"Configuration",,,
|
||||
"Connect using transition","Łączenie przy użyciu przejścia",,
|
||||
"Context","Kontekst",,
|
||||
"Create","Utworzyć",,
|
||||
"Create end node","Utwórz węzeł końcowy",,
|
||||
"Create intermediate node","Utwórz węzeł pośredni",,
|
||||
"Create start node","Utwórz węzeł startowy",,
|
||||
"Custom","Niestandardowe",,
|
||||
"Custom Field","Pole niestandardowe",,
|
||||
"Custom Model","Model niestandardowy",,
|
||||
"Custom field","Pole niestandardowe",,
|
||||
"Custom fields","Pola niestandardowe",,
|
||||
"Custom model","Model niestandardowy",,
|
||||
"Custom models","Modele niestandardowe",,
|
||||
"Dashboard","Tablica rozdzielcza",,
|
||||
"Dashboard builder","Konstruktor deski rozdzielczej",,
|
||||
"Dashboard builders","Producenci desek rozdzielczych",,
|
||||
"Dashlet builder","Konstruktor desek rozdzielczych",,
|
||||
"Dashlet builder list","Lista konstruktorów kreski",,
|
||||
"Dashlet builders","Producenci desek rozdzielczych",,
|
||||
"Data file","Plik danych",,
|
||||
"Date","Data",,
|
||||
"Datetime","Okres przydatności do spożycia",,
|
||||
"Day","Dzień",,
|
||||
"Decimal","dziesiętny",,
|
||||
"Default Value","Wartość domyślna",,
|
||||
"Depends on","W zależności od",,
|
||||
"Description","Opis",,
|
||||
"Display","Wyświetlacz",,
|
||||
"Display message","Wyświetlanie komunikatu",,
|
||||
"Display type","Typ wyświetlacza",,
|
||||
"Do you want to reset workflow ?",,,
|
||||
"Domain","Dziedzina",,
|
||||
"Donut","Pączek",,
|
||||
"Dummy","Dumia",,
|
||||
"Edit Node","Edytuj węzeł",,
|
||||
"Edit Transition","Edycja Przejścia",,
|
||||
"Edit before send","Edytuj przed wysłaniem",,
|
||||
"Email","Poczta elektroniczna",,
|
||||
"End node","Węzeł końcowy",,
|
||||
"Existing menu","Istniejące menu",,
|
||||
"Export","Eksportowanie",,
|
||||
"Extra","Ekstra",,
|
||||
"Field","Pole",,
|
||||
"Field for 'My menu'","Pole Moje menu",,
|
||||
"Field options",,,
|
||||
"Fields","Pola",,
|
||||
"Filter","Filtr",,
|
||||
"Filters","Filtry",,
|
||||
"First group by","Pierwsza grupa przez",,
|
||||
"From","Od",,
|
||||
"Funnel","Lejek",,
|
||||
"Gauge","Manometr",,
|
||||
"Generated Actions","Działania wygenerowane",,
|
||||
"Generated app","Generowana aplikacja",,
|
||||
"Groovy","Groovy",,
|
||||
"Group By","Grupa Według",,
|
||||
"Group date type","Typ daty grupy",,
|
||||
"Group on type","Grupa na typie",,
|
||||
"Groups","Grupy",,
|
||||
"Help","Pomoc",,
|
||||
"Hidden In Grid","Ukryte w siatce",,
|
||||
"Hidden menu","Ukryte menu",,
|
||||
"Horizontal bar","Listwa pozioma",,
|
||||
"Icon","Ikona",,
|
||||
"If","Jeżeli",,
|
||||
"If-module","Moduł If",,
|
||||
"Image","Obrazek",,
|
||||
"Import","Przywóz",,
|
||||
"Import BPM","Przywóz BPM",,
|
||||
"Import log","Dziennik przywozowy",,
|
||||
"Incoming","Incoming",,
|
||||
"Integer","Integer",,
|
||||
"Is Json Relational Field",,,
|
||||
"Is json","Jest json",,
|
||||
"Is parameter","Parametr jest parametrem",,
|
||||
"Is wkf","Jest fajerwerkiem",,
|
||||
"Javascript","JavaScript",,
|
||||
"Json","Json",,
|
||||
"Json Field","Pole Jsona",,
|
||||
"Json Many To Many","Json wielu do wielu",,
|
||||
"Json Many To One","Json Many To One",,
|
||||
"Json One To Many","Json Jeden do wielu",,
|
||||
"Left menu","Menu lewe",,
|
||||
"Line","Linia",,
|
||||
"Link","Łącze",,
|
||||
"Logic operator","Operator logiczny",,
|
||||
"Many To Many","Wiele do wielu",,
|
||||
"Many To One","Wiele do jednego",,
|
||||
"Max Size","Maksymalna wielkość",,
|
||||
"Menu action","Akcja menu",,
|
||||
"Menu builder","Konstruktor menu",,
|
||||
"Menu builders","Konstruktorzy menu",,
|
||||
"MenuBuilder.Order",,,
|
||||
"Message","Wiadomość",,
|
||||
"Message on alert or blocking","Komunikat w sprawie alarmu lub blokady",,
|
||||
"Message on success","Przesłanie o sukcesie",,
|
||||
"Meta Model","Model meta",,
|
||||
"Meta module","Moduł Meta",,
|
||||
"MetaMenu","MetaMenu",,
|
||||
"Min Size","Rozmiar min.",,
|
||||
"Mobile menu","Menu mobilne",,
|
||||
"Model","Model",,
|
||||
"Module","Moduł",,
|
||||
"Month","Miesiąc",,
|
||||
"Name","Nazwa",,
|
||||
"Name Column",,,
|
||||
"Name Field","Nazwa Nazwa Pole",,
|
||||
"Name must not contains space","Nazwa nie może zawierać spacji",,
|
||||
"Nav Select","Wybierz nawigację nawigację",,
|
||||
"Nb of passes","Nb przepustek",,
|
||||
"Nb of passes per status","Nb przepustek na status",,
|
||||
"Node","Węzeł",,
|
||||
"Node type",,,
|
||||
"Nodes","Węzły",,
|
||||
"None",,,
|
||||
"OR","LUB",,
|
||||
"Object","Obiekt",,
|
||||
"On Change","W sprawie zmian",,
|
||||
"On Click","Kliknij na Click",,
|
||||
"On New","Na temat nowego",,
|
||||
"On Save","świeci się Zapisz.",,
|
||||
"One To Many","Jeden do wielu",,
|
||||
"Only use this menu-item if the given expression is true.","Używaj tego menu-punktu menu tylko wtedy, gdy dane wyrażenie jest prawdziwe.",,
|
||||
"Only use this menu-item if the given module is installed.","Z tego menu - punktu menu należy korzystać tylko wtedy, gdy dany moduł jest zainstalowany.",,
|
||||
"Open record","Otwarty rekord",,
|
||||
"Open workflow","Otwarty przepływ pracy",,
|
||||
"Operator","Operator",,
|
||||
"Outgoing","Wychodzący",,
|
||||
"Overview","Przegląd",,
|
||||
"Pagination limit","Granica numerowania stron",,
|
||||
"Panel","Panel",,
|
||||
"Parent","Rodzic",,
|
||||
"Percentage(%)","Procent (%)",,
|
||||
"Permissions","Pozwolenia",,
|
||||
"Pie Chart","Wykres kołowy",,
|
||||
"Please correct the workflow diagram.","Proszę skorygować diagram przepływu pracy.",,
|
||||
"Please input value bind with single quotation.","Proszę wpisać wartość powiązaną z pojedynczym cudzysłowem.",,
|
||||
"Please provide unique code. The code '%s' is already used","Proszę podać niepowtarzalny kod. Kod %s jest już stosowany",,
|
||||
"Process",,,
|
||||
"Process display type","Typ wyświetlania procesu",,
|
||||
"Process studio","Studio procesowe",,
|
||||
"Process tracking","Śledzenie procesu",,
|
||||
"Properties","Właściwości",,
|
||||
"Radar","radar",,
|
||||
"ReadOnly for",,,
|
||||
"Record Id","Numer rekordu",,
|
||||
"Record model","Model rekordu",,
|
||||
"Record name","Nazwa rekordu",,
|
||||
"Regex","Regex",,
|
||||
"Report","Sprawozdanie",,
|
||||
"Reporting",,,
|
||||
"Required","Wymagane",,
|
||||
"Required If","Wymagane, jeżeli",,
|
||||
"Roles","Role",,
|
||||
"Scatter","Rozproszenie",,
|
||||
"Script","Skrypt",,
|
||||
"Script type","Typ skryptu",,
|
||||
"Second group by","Druga grupa przez",,
|
||||
"Select Option","Wybór opcji",,
|
||||
"Selection","Wybór",,
|
||||
"Selections",,,
|
||||
"Send directly","Wyślij bezpośrednio",,
|
||||
"Send option","Opcja wysyłania",,
|
||||
"Separator","Separator",,
|
||||
"Sequence","Kolejność",,
|
||||
"Show If","Pokaż, jeśli",,
|
||||
"Show Title",,,
|
||||
"Show process tracking","Wyświetlanie śledzenia procesu",,
|
||||
"Simple Select","Prosty wybór",,
|
||||
"Source field","Źródło: Pole źródłowe",,
|
||||
"Start node","Węzeł startowy",,
|
||||
"Status","Status",,
|
||||
"Status per day","Status na dzień",,
|
||||
"Status per month","Status miesięcznie",,
|
||||
"Status time(days)","Czas statusu (dni)",,
|
||||
"Status time(hours)","Czas statusu (godziny)",,
|
||||
"String","String",,
|
||||
"Studio",,,
|
||||
"Sub lines","Podlinie",,
|
||||
"Tag count","Liczba znaczników",,
|
||||
"Tag label","Etykieta znacznika",,
|
||||
"Tag method","Metoda znacznikowa",,
|
||||
"Tag style","Styl Tagów",,
|
||||
"Target","Cel",,
|
||||
"Target Json Model","Model Target Jsona",,
|
||||
"Target field","Pole docelowe",,
|
||||
"Target json","Cel json docelowy",,
|
||||
"Target object","Obiekt docelowy",,
|
||||
"Target title",,,
|
||||
"Target type","Typ celu",,
|
||||
"Task node",,,
|
||||
"Template","Szablon",,
|
||||
"Text","Tekst",,
|
||||
"Time","Czas",,
|
||||
"Time spent","Czas spędzony na pracy",,
|
||||
"Time spent (hours/days)","Czas spędzony (godziny/dni)",,
|
||||
"Time spent per status (hours)","Czas spędzony na statusie (godziny)",,
|
||||
"Time spent per status per user (hours)","Czas spędzony na statusie na użytkownika (godziny)",,
|
||||
"Title","Tytuł",,
|
||||
"To","Do",,
|
||||
"Top menu","Menu górne",,
|
||||
"Total time per status","Łączny czas na status",,
|
||||
"Track flow","Przepływ po torze",,
|
||||
"Track workflow","Ścieżka przepływu pracy",,
|
||||
"Tracking line","Linia monitorowania",,
|
||||
"Tracking lines","Linie śledzące",,
|
||||
"Transactional","Transakcyjny",,
|
||||
"Transition","Przejście do nowego systemu",,
|
||||
"Transitions","Transformacje",,
|
||||
"Type","Typ",,
|
||||
"UI options",,,
|
||||
"Update","Aktualizacja",,
|
||||
"User","Użytkownik",,
|
||||
"Validation type","Typ walidacji",,
|
||||
"Value","Wartość",,
|
||||
"Value expr","Wyrażenie wartości",,
|
||||
"View","Widok",,
|
||||
"View generated","Wygenerowany widok",,
|
||||
"View params","Przeglądaj paramy",,
|
||||
"Views","Widoki",,
|
||||
"Widget","Widżet",,
|
||||
"Wkf","Wkf",,
|
||||
"Wkf field","Pole fajerwerków",,
|
||||
"Wkf sequence",,,
|
||||
"Wkf tracking","Śledzenie chmur punktów na sekundę",,
|
||||
"Wkf trackings","Śledzenie chmur punktów",,
|
||||
"Wkf transition","Przejście na żakiety",,
|
||||
"Workflow dashboard","Deska rozdzielcza przepływu pracy",,
|
||||
"Workflow is not saved","Przepływ pracy nie jest zapisywany",,
|
||||
"Year","Rok",,
|
||||
"contains","zawiera",,
|
||||
"doesn't contains","nie zawiera",,
|
||||
"equal","jednakowy",,
|
||||
"greater or equal","większy lub równy",,
|
||||
"greater than","więcej niż",,
|
||||
"in","na miejscu",,
|
||||
"include","zawierać",,
|
||||
"is false","jest nieprawdziwy",,
|
||||
"is not null","nie jest nieważny",,
|
||||
"is null","jest nieważny",,
|
||||
"is true","jest prawdą",,
|
||||
"less or equal","mniejsza lub równa",,
|
||||
"less than","mniej niż",,
|
||||
"not equal","nierówny",,
|
||||
"not in","nie wewnątrz",,
|
||||
"not include","nie obejmują",,
|
||||
"value:BPM","wartość: BPM",,
|
||||
"value:Product App","wartość: Produkt App",,
|
||||
"xmlId","xmlId",,
|
||||
|
@ -0,0 +1,292 @@
|
||||
"key","message","comment","context"
|
||||
"<b>Tags:</b> $user: Current user, $date: Today's date, $time: Current time","B>Tags:<b>Tags:</b> $user: Usuário atual, $date: Data de hoje, $time: Hora atual.",,
|
||||
"AND","E",,
|
||||
"Action","Ação",,
|
||||
"Action builder","Construtor de ações",,
|
||||
"Action builders","Construtores de acções",,
|
||||
"Actions","Ações",,
|
||||
"Activate the hand tool","Ativar a ferramenta manual",,
|
||||
"Aggregate","Agregado",,
|
||||
"Aggregate On","Agregar em",,
|
||||
"Aggregate On type","Agregar no tipo",,
|
||||
"Aggregate date type","Tipo de data agregada",,
|
||||
"Alert","Alerta",,
|
||||
"Alert or Blocking condition","Alerta ou condição de bloqueio",,
|
||||
"App builder","Construtor de aplicações",,
|
||||
"App builders",,,
|
||||
"App name",,,
|
||||
"Append end node","Anexar nó final",,
|
||||
"Append intermediate node","Anexar nó intermediário",,
|
||||
"Apply if",,,
|
||||
"Area","Área",,
|
||||
"Assign value to","Atribuir valor a",,
|
||||
"BPM","BPM",,
|
||||
"Background","Antecedentes",,
|
||||
"Bar","Bar",,
|
||||
"Base model",,,
|
||||
"Blocking","Bloqueio",,
|
||||
"Boolean","booleano",,
|
||||
"Bpmn xml","Bpmn xml",,
|
||||
"Button","Botão",,
|
||||
"Button title","Título do botão",,
|
||||
"Can Collapse",,,
|
||||
"Chart builder","Construtor de gráficos",,
|
||||
"Chart builders","Construtores de gráficos",,
|
||||
"Chart type","Tipo de gráfico",,
|
||||
"ChartBuilder.Group","Grupo (Grupo)",,
|
||||
"Choose App name",,,
|
||||
"Code","Código",,
|
||||
"Collapse if",,,
|
||||
"Colspan","Colspan",,
|
||||
"Condition","Condição",,
|
||||
"Conditions","Condições de utilização",,
|
||||
"Configuration",,,
|
||||
"Connect using transition","Conectar-se usando a transição",,
|
||||
"Context","Contexto",,
|
||||
"Create","Criar",,
|
||||
"Create end node","Criar nó final",,
|
||||
"Create intermediate node","Criar nó intermediário",,
|
||||
"Create start node","Criar nó inicial",,
|
||||
"Custom","Personalizado",,
|
||||
"Custom Field","Campo personalizado",,
|
||||
"Custom Model","Modelo Personalizado",,
|
||||
"Custom field","Campo personalizado",,
|
||||
"Custom fields","Campos personalizados",,
|
||||
"Custom model","Modelo personalizado",,
|
||||
"Custom models","Modelos personalizados",,
|
||||
"Dashboard","Painel de instrumentos",,
|
||||
"Dashboard builder","Construtor de painéis de instrumentos",,
|
||||
"Dashboard builders","Construtores de painéis de instrumentos",,
|
||||
"Dashlet builder","Construtor de Dashlet",,
|
||||
"Dashlet builder list","Lista de construtores de Dashlet",,
|
||||
"Dashlet builders","Construtores de Dashlet",,
|
||||
"Data file","Arquivo de dados",,
|
||||
"Date","Data",,
|
||||
"Datetime","Data/hora",,
|
||||
"Day","Dia da semana",,
|
||||
"Decimal","Decimal",,
|
||||
"Default Value","Valor proposto",,
|
||||
"Depends on","Depende de",,
|
||||
"Description","Descrição do produto",,
|
||||
"Display","Exibição",,
|
||||
"Display message","Exibir mensagem",,
|
||||
"Display type","Tipo de exibição",,
|
||||
"Do you want to reset workflow ?",,,
|
||||
"Domain","Domínios",,
|
||||
"Donut","Donut",,
|
||||
"Dummy","Dummy",,
|
||||
"Edit Node","Editar nó",,
|
||||
"Edit Transition","Editar Transição",,
|
||||
"Edit before send","Editar antes de enviar",,
|
||||
"Email","Email",,
|
||||
"End node","Nó final",,
|
||||
"Existing menu","Menu Existente",,
|
||||
"Export","Exportação",,
|
||||
"Extra","Extra",,
|
||||
"Field","Campo",,
|
||||
"Field for 'My menu'","Campo para 'Meu menu",,
|
||||
"Field options",,,
|
||||
"Fields","Campos",,
|
||||
"Filter","Filtro",,
|
||||
"Filters","Filtros",,
|
||||
"First group by","Primeiro grupo por",,
|
||||
"From","De",,
|
||||
"Funnel","Funil",,
|
||||
"Gauge","Bitola",,
|
||||
"Generated Actions","Ações geradas",,
|
||||
"Generated app","Aplicativo gerado",,
|
||||
"Groovy","Groovy",,
|
||||
"Group By","Agrupar por",,
|
||||
"Group date type","Tipo de data de grupo",,
|
||||
"Group on type","Grupo por tipo",,
|
||||
"Groups","Grupos",,
|
||||
"Help","Ajudar",,
|
||||
"Hidden In Grid","Escondido na Grelha",,
|
||||
"Hidden menu","Menu oculto",,
|
||||
"Horizontal bar","Barra horizontal",,
|
||||
"Icon","Ícone",,
|
||||
"If","Se",,
|
||||
"If-module","Se-módulo",,
|
||||
"Image","Imagem",,
|
||||
"Import","Importação",,
|
||||
"Import BPM","Importar BPM",,
|
||||
"Import log","Log de importação",,
|
||||
"Incoming","Incoming",,
|
||||
"Integer","Inteiro",,
|
||||
"Is Json Relational Field",,,
|
||||
"Is json","É o Json.",,
|
||||
"Is parameter","É parâmetro",,
|
||||
"Is wkf","É wkf",,
|
||||
"Javascript","Javascript",,
|
||||
"Json","Json",,
|
||||
"Json Field","Campo de Json",,
|
||||
"Json Many To Many","Json Muitos para muitos",,
|
||||
"Json Many To One","Json Muitos para um",,
|
||||
"Json One To Many","Json um para muitos",,
|
||||
"Left menu","Menu esquerdo",,
|
||||
"Line","Linha",,
|
||||
"Link","Link",,
|
||||
"Logic operator","Operador lógico",,
|
||||
"Many To Many","Muitos para muitos",,
|
||||
"Many To One","Muitos para um",,
|
||||
"Max Size","Tamanho máximo",,
|
||||
"Menu action","Ação do menu",,
|
||||
"Menu builder","Construtor de menus",,
|
||||
"Menu builders","Construtores de menus",,
|
||||
"MenuBuilder.Order","Ordem",,
|
||||
"Message","Mensagem",,
|
||||
"Message on alert or blocking","Mensagem em alerta ou bloqueio",,
|
||||
"Message on success","Mensagem sobre o sucesso",,
|
||||
"Meta Model","Meta Modelo",,
|
||||
"Meta module","Meta módulo",,
|
||||
"MetaMenu","MetaMenu",,
|
||||
"Min Size","Tamanho Mínimo",,
|
||||
"Mobile menu","Menu móvel",,
|
||||
"Model","Modelo",,
|
||||
"Module","Módulo",,
|
||||
"Month","Mês",,
|
||||
"Name","Nome e Sobrenome",,
|
||||
"Name Column",,,
|
||||
"Name Field","Nome Campo",,
|
||||
"Name must not contains space","O nome não deve conter espaço",,
|
||||
"Nav Select","Selecção do Nav",,
|
||||
"Nb of passes","Nb de passagens",,
|
||||
"Nb of passes per status","Nb de passes por status",,
|
||||
"Node","Nó",,
|
||||
"Node type","Type de nœud",,
|
||||
"Nodes","Nós",,
|
||||
"None",,,
|
||||
"OR","OU",,
|
||||
"Object","Objeto",,
|
||||
"On Change","Em Mudança",,
|
||||
"On Click","Clicar em",,
|
||||
"On New","Em Novo",,
|
||||
"On Save","Em Salvar",,
|
||||
"One To Many","De um para muitos",,
|
||||
"Only use this menu-item if the given expression is true.","Só use este item de menu se a expressão dada for verdadeira.",,
|
||||
"Only use this menu-item if the given module is installed.","Utilize este menu apenas se o módulo em questão estiver instalado.",,
|
||||
"Open record","Abrir registro",,
|
||||
"Open workflow","Fluxo de trabalho aberto",,
|
||||
"Operator","Operador",,
|
||||
"Outgoing","Saída",,
|
||||
"Overview","Visão Geral",,
|
||||
"Pagination limit","Limite de Paginação",,
|
||||
"Panel","Painel",,
|
||||
"Parent","Pais",,
|
||||
"Percentage(%)","Porcentagem (%)",,
|
||||
"Permissions","Permissões",,
|
||||
"Pie Chart","Gráfico de Pizza",,
|
||||
"Please correct the workflow diagram.","Por favor, corrija o diagrama de fluxo de trabalho.",,
|
||||
"Please input value bind with single quotation.","Por favor, introduza um valor de encadernação com uma única cotação.",,
|
||||
"Please provide unique code. The code '%s' is already used","Por favor, forneça um código único. O código %s já é utilizado",,
|
||||
"Process",,,
|
||||
"Process display type","Tipo de exibição do processo",,
|
||||
"Process studio","Estúdio de processo",,
|
||||
"Process tracking","Acompanhamento do processo",,
|
||||
"Properties","Imóveis",,
|
||||
"Radar","Radar",,
|
||||
"ReadOnly for","Lecture seule pour",,
|
||||
"Record Id","Registrar Id",,
|
||||
"Record model","Modelo de registro",,
|
||||
"Record name","Nome do registro",,
|
||||
"Regex","Regex",,
|
||||
"Report","Relatório",,
|
||||
"Reporting",,,
|
||||
"Required","Necessário",,
|
||||
"Required If","Necessário se",,
|
||||
"Roles","Funções",,
|
||||
"Scatter","Dispersão",,
|
||||
"Script","Roteiro",,
|
||||
"Script type","Tipo de script",,
|
||||
"Second group by","Segundo grupo por",,
|
||||
"Select Option","Selecione Opção",,
|
||||
"Selection","Selecção",,
|
||||
"Selections",,,
|
||||
"Send directly","Enviar diretamente",,
|
||||
"Send option","Enviar opção",,
|
||||
"Separator","Separador",,
|
||||
"Sequence","Seqüência",,
|
||||
"Show If","Mostrar se",,
|
||||
"Show Title",,,
|
||||
"Show process tracking","Mostrar acompanhamento do processo",,
|
||||
"Simple Select","Seleção simples",,
|
||||
"Source field","Campo de origem",,
|
||||
"Start node","Nó inicial",,
|
||||
"Status","Estado",,
|
||||
"Status per day","Status por dia",,
|
||||
"Status per month","Status por mês",,
|
||||
"Status time(days)","Tempo de status (dias)",,
|
||||
"Status time(hours)","Tempo de status (horas)",,
|
||||
"String","Corda",,
|
||||
"Studio",,,
|
||||
"Sub lines","Sub-linhas",,
|
||||
"Tag count","Contagem de tags",,
|
||||
"Tag label","Etiqueta de etiqueta",,
|
||||
"Tag method","Método Tag",,
|
||||
"Tag style","Estilo de etiqueta",,
|
||||
"Target","Alvo",,
|
||||
"Target Json Model","Modelo Target Json",,
|
||||
"Target field","Campo de destino",,
|
||||
"Target json","Alvo json",,
|
||||
"Target object","Objeto de destino",,
|
||||
"Target title",,,
|
||||
"Target type","Tipo de destino",,
|
||||
"Task node","Noeud intermédiaire",,
|
||||
"Template","Modelo",,
|
||||
"Text","Texto",,
|
||||
"Time","Tempo",,
|
||||
"Time spent","Tempo gasto",,
|
||||
"Time spent (hours/days)","Tempo gasto (horas/dia)",,
|
||||
"Time spent per status (hours)","Tempo gasto por status (horas)",,
|
||||
"Time spent per status per user (hours)","Tempo gasto por status por usuário (horas)",,
|
||||
"Title","Título",,
|
||||
"To","Para",,
|
||||
"Top menu","Menu superior",,
|
||||
"Total time per status","Tempo total por status",,
|
||||
"Track flow","Fluxo da via",,
|
||||
"Track workflow","Acompanhe o fluxo de trabalho",,
|
||||
"Tracking line","Linha de rastreamento",,
|
||||
"Tracking lines","Linhas de rastreamento",,
|
||||
"Transactional","Transaccional",,
|
||||
"Transition","Transição",,
|
||||
"Transitions","Transições",,
|
||||
"Type","Tipo de",,
|
||||
"UI options",,,
|
||||
"Update","Atualização",,
|
||||
"User","Usuário",,
|
||||
"Validation type","Tipo de validação",,
|
||||
"Value","Valor",,
|
||||
"Value expr","Valor Expr",,
|
||||
"View","Ver",,
|
||||
"View generated","Visualização gerada",,
|
||||
"View params","Ver parâmetros",,
|
||||
"Views","Vistas",,
|
||||
"Widget","Widget",,
|
||||
"Wkf","Wkf",,
|
||||
"Wkf field","Campo Wkf",,
|
||||
"Wkf sequence",,,
|
||||
"Wkf tracking","Tracking Wkf",,
|
||||
"Wkf trackings","Rastreamentos Wkf",,
|
||||
"Wkf transition","Transição de Wkf",,
|
||||
"Workflow dashboard","Painel de fluxo de trabalho",,
|
||||
"Workflow is not saved","Workflow não é gravado",,
|
||||
"Year","Ano",,
|
||||
"contains","contém",,
|
||||
"doesn't contains","não contém",,
|
||||
"equal","igualitária",,
|
||||
"greater or equal","maior ou igual",,
|
||||
"greater than","superior a",,
|
||||
"in","em",,
|
||||
"include","incluir",,
|
||||
"is false","é falso",,
|
||||
"is not null","não é nulo",,
|
||||
"is null","é nulo",,
|
||||
"is true","é verdade",,
|
||||
"less or equal","menor ou igual",,
|
||||
"less than","inferior a",,
|
||||
"not equal","não igual",,
|
||||
"not in","não em",,
|
||||
"not include","não incluir",,
|
||||
"value:BPM","valor:BPM",,
|
||||
"value:Product App","value:Produto App",,
|
||||
"xmlId","xmlId",,
|
||||
|
@ -0,0 +1,292 @@
|
||||
"key","message","comment","context"
|
||||
"<b>Tags:</b> $user: Current user, $date: Today's date, $time: Current time","<b>Тэги:</b>Пользователь. Текущий пользователь, $date: Текущая дата, $time: Текущее время",,
|
||||
"AND","И",,
|
||||
"Action","Действие",,
|
||||
"Action builder","Строитель боев",,
|
||||
"Action builders","Строители боев",,
|
||||
"Actions","Действия",,
|
||||
"Activate the hand tool","Активировать ручной инструмент",,
|
||||
"Aggregate","Совокупность",,
|
||||
"Aggregate On","Агрегировать Вкл.",,
|
||||
"Aggregate On type","Агрегировать по типу Вкл.",,
|
||||
"Aggregate date type","Тип агрегированной даты",,
|
||||
"Alert","Тревога",,
|
||||
"Alert or Blocking condition","Предупреждение или состояние блокировки",,
|
||||
"App builder","Создатель приложений",,
|
||||
"App builders",,,
|
||||
"App name",,,
|
||||
"Append end node","Добавить конечный узел",,
|
||||
"Append intermediate node","Добавить промежуточный узел",,
|
||||
"Apply if",,,
|
||||
"Area","Площадь",,
|
||||
"Assign value to","Присвоить значение",,
|
||||
"BPM","BPM",,
|
||||
"Background","Предыстория",,
|
||||
"Bar","Бар",,
|
||||
"Base model",,,
|
||||
"Blocking","Блокировка",,
|
||||
"Boolean","булев",,
|
||||
"Bpmn xml","Bpmn xml",,
|
||||
"Button","Кнопка",,
|
||||
"Button title","Название кнопки",,
|
||||
"Can Collapse",,,
|
||||
"Chart builder","Создатель диаграмм",,
|
||||
"Chart builders","Составители карт",,
|
||||
"Chart type","Тип графика",,
|
||||
"ChartBuilder.Group","Группа",,
|
||||
"Choose App name",,,
|
||||
"Code","Код",,
|
||||
"Collapse if",,,
|
||||
"Colspan","Колспан",,
|
||||
"Condition","Условие",,
|
||||
"Conditions","Условия",,
|
||||
"Configuration",,,
|
||||
"Connect using transition","Подключение с помощью перехода",,
|
||||
"Context","Контекст",,
|
||||
"Create","Создать",,
|
||||
"Create end node","Создать конечный узел",,
|
||||
"Create intermediate node","Создать промежуточный узел",,
|
||||
"Create start node","Создать стартовый узел",,
|
||||
"Custom","Пользовательский",,
|
||||
"Custom Field","Настраиваемое поле",,
|
||||
"Custom Model","Пользовательская модель",,
|
||||
"Custom field","Настраиваемое поле",,
|
||||
"Custom fields","Дополнительные поля",,
|
||||
"Custom model","Индивидуальная модель",,
|
||||
"Custom models","Индивидуальные модели",,
|
||||
"Dashboard","Приборная панель",,
|
||||
"Dashboard builder","Изготовитель приборной панели",,
|
||||
"Dashboard builders","Производители приборных панелей",,
|
||||
"Dashlet builder","Изготовитель приборных панелей",,
|
||||
"Dashlet builder list","Список разработчиков черточек",,
|
||||
"Dashlet builders","Производители приборов Dashlet",,
|
||||
"Data file","Файл данных",,
|
||||
"Date","Дата",,
|
||||
"Datetime","Дата",,
|
||||
"Day","День",,
|
||||
"Decimal","Десятичная дробь",,
|
||||
"Default Value","Значение по умолчанию",,
|
||||
"Depends on","Зависит от",,
|
||||
"Description","Описание",,
|
||||
"Display","дисплей",,
|
||||
"Display message","Отобразить сообщение",,
|
||||
"Display type","Тип дисплея",,
|
||||
"Do you want to reset workflow ?",,,
|
||||
"Domain","Домен",,
|
||||
"Donut","пончик",,
|
||||
"Dummy","Кукла",,
|
||||
"Edit Node","Редактировать узел",,
|
||||
"Edit Transition","Редактирование перехода",,
|
||||
"Edit before send","Изменить перед отправкой",,
|
||||
"Email","Электронная почта",,
|
||||
"End node","Конечный узел",,
|
||||
"Existing menu","Существующее меню",,
|
||||
"Export","Экспорт",,
|
||||
"Extra","Дополнительная информация",,
|
||||
"Field","Поле",,
|
||||
"Field for 'My menu'","Поле для Мое меню.",,
|
||||
"Field options",,,
|
||||
"Fields","Поля",,
|
||||
"Filter","Фильтр",,
|
||||
"Filters","Фильтры",,
|
||||
"First group by","Первая группа по",,
|
||||
"From","От",,
|
||||
"Funnel","Воронка",,
|
||||
"Gauge","Измеритель",,
|
||||
"Generated Actions","Сгенерированные действия",,
|
||||
"Generated app","Созданное приложение",,
|
||||
"Groovy","Клёвый",,
|
||||
"Group By","Сгруппировать по",,
|
||||
"Group date type","Тип даты группы",,
|
||||
"Group on type","Группа по типу",,
|
||||
"Groups","Группы",,
|
||||
"Help","Помощь",,
|
||||
"Hidden In Grid","Скрытые в сети",,
|
||||
"Hidden menu","Скрытое меню",,
|
||||
"Horizontal bar","Горизонтальная полоса",,
|
||||
"Icon","Икона",,
|
||||
"If","Если",,
|
||||
"If-module","Если-модуль",,
|
||||
"Image","Изображение",,
|
||||
"Import","Импорт",,
|
||||
"Import BPM","Импорт BPM",,
|
||||
"Import log","Импорт журнала",,
|
||||
"Incoming","Прибыль",,
|
||||
"Integer","Целостный",,
|
||||
"Is Json Relational Field",,,
|
||||
"Is json","Джсон",,
|
||||
"Is parameter","Есть параметр",,
|
||||
"Is wkf","Wkf",,
|
||||
"Javascript","Javascript",,
|
||||
"Json","Джсон",,
|
||||
"Json Field","Джсон Филд",,
|
||||
"Json Many To Many","Json Many To many To many",,
|
||||
"Json Many To One","Json Many To One",,
|
||||
"Json One To Many","Json One To many",,
|
||||
"Left menu","Левое меню",,
|
||||
"Line","Линия",,
|
||||
"Link","Связь",,
|
||||
"Logic operator","Логический оператор",,
|
||||
"Many To Many","Много-много-многом",,
|
||||
"Many To One","Многие к одному",,
|
||||
"Max Size","Максимальный размер",,
|
||||
"Menu action","Действие меню",,
|
||||
"Menu builder","Создатель меню",,
|
||||
"Menu builders","Создатели меню",,
|
||||
"MenuBuilder.Order","поря́док",,
|
||||
"Message","Сообщение",,
|
||||
"Message on alert or blocking","Сообщение о тревоге или блокировке",,
|
||||
"Message on success","Сообщение об успехе",,
|
||||
"Meta Model","Мета модель",,
|
||||
"Meta module","Мета-модуль",,
|
||||
"MetaMenu","Мета-меню",,
|
||||
"Min Size","Мин Размер",,
|
||||
"Mobile menu","Мобильное меню",,
|
||||
"Model","Модель",,
|
||||
"Module","Модуль",,
|
||||
"Month","Месяц",,
|
||||
"Name","Имя",,
|
||||
"Name Column",,,
|
||||
"Name Field","Поле имени",,
|
||||
"Name must not contains space","Имя не должно содержать пробелов.",,
|
||||
"Nav Select","Навигация Выбрать",,
|
||||
"Nb of passes","Nb пропусков",,
|
||||
"Nb of passes per status","Nb пропусков на статус",,
|
||||
"Node","Узел",,
|
||||
"Node type",,,
|
||||
"Nodes","Узлы",,
|
||||
"None",,,
|
||||
"OR","ИЛИ",,
|
||||
"Object","Объект",,
|
||||
"On Change","О Изменениях",,
|
||||
"On Click","Нажать кнопку",,
|
||||
"On New","На Новом",,
|
||||
"On Save","На Сохранить",,
|
||||
"One To Many","Один ко многим",,
|
||||
"Only use this menu-item if the given expression is true.","Используйте этот пункт меню только в том случае, если данное выражение соответствует истине.",,
|
||||
"Only use this menu-item if the given module is installed.","Данный пункт меню используется только в том случае, если данный модуль установлен.",,
|
||||
"Open record","Открытая запись",,
|
||||
"Open workflow","Открытый документооборот",,
|
||||
"Operator","Оператор",,
|
||||
"Outgoing","Отбывающий",,
|
||||
"Overview","Обзор",,
|
||||
"Pagination limit","Ограничение по количеству страниц",,
|
||||
"Panel","Панель",,
|
||||
"Parent","Родитель",,
|
||||
"Percentage(%)","Процент(%)",,
|
||||
"Permissions","Разрешения",,
|
||||
"Pie Chart","Круговая диаграмма",,
|
||||
"Please correct the workflow diagram.","Пожалуйста, исправьте схему рабочего процесса.",,
|
||||
"Please input value bind with single quotation.","Пожалуйста, свяжите вводимое значение с одной кавычкой.",,
|
||||
"Please provide unique code. The code '%s' is already used","Пожалуйста, предоставьте уникальный код. Код '%s' уже используется.",,
|
||||
"Process",,,
|
||||
"Process display type","Тип отображения процесса",,
|
||||
"Process studio","Студия процессов",,
|
||||
"Process tracking","Отслеживание процесса",,
|
||||
"Properties","Свойства",,
|
||||
"Radar","Радар",,
|
||||
"ReadOnly for",,,
|
||||
"Record Id","Ид записи",,
|
||||
"Record model","Модель записи",,
|
||||
"Record name","Имя записи",,
|
||||
"Regex","Регекс",,
|
||||
"Report","Доклад",,
|
||||
"Reporting",,,
|
||||
"Required","Требуется",,
|
||||
"Required If","Требуется Если",,
|
||||
"Roles","Роли",,
|
||||
"Scatter","Рассеивание",,
|
||||
"Script","Сценарий",,
|
||||
"Script type","Тип сценария",,
|
||||
"Second group by","Вторая группа по",,
|
||||
"Select Option","Выберите Параметр",,
|
||||
"Selection","Выбор",,
|
||||
"Selections",,,
|
||||
"Send directly","Отправить непосредственно",,
|
||||
"Send option","Отправить вариант",,
|
||||
"Separator","Сепаратор",,
|
||||
"Sequence","Последовательность",,
|
||||
"Show If","Показать Если",,
|
||||
"Show Title",,,
|
||||
"Show process tracking","Показать отслеживание процесса",,
|
||||
"Simple Select","Простой выбор",,
|
||||
"Source field","Исходное поле",,
|
||||
"Start node","Запустить узел",,
|
||||
"Status","Статус",,
|
||||
"Status per day","Статус в день",,
|
||||
"Status per month","Статус в месяц",,
|
||||
"Status time(days)","Время статуса (дни)",,
|
||||
"Status time(hours)","Время статуса (часы)",,
|
||||
"String","Стринг",,
|
||||
"Studio",,,
|
||||
"Sub lines","Подлинии",,
|
||||
"Tag count","Количество меток",,
|
||||
"Tag label","Метка",,
|
||||
"Tag method","Метод тегов",,
|
||||
"Tag style","Стиль тегов",,
|
||||
"Target","Цель",,
|
||||
"Target Json Model","Цель - Джсон Модель.",,
|
||||
"Target field","Целевое поле",,
|
||||
"Target json","Цель - Джсон.",,
|
||||
"Target object","Объект съемки",,
|
||||
"Target title",,,
|
||||
"Target type","Тип цели",,
|
||||
"Task node",,,
|
||||
"Template","Шаблон",,
|
||||
"Text","Текст",,
|
||||
"Time","Время",,
|
||||
"Time spent","Время, проведённое",,
|
||||
"Time spent (hours/days)","Время, затраченное (часы/дни)",,
|
||||
"Time spent per status (hours)","Время, потраченное на статус (в часах)",,
|
||||
"Time spent per status per user (hours)","Время, потраченное на статус одного пользователя (в часах)",,
|
||||
"Title","Название",,
|
||||
"To","К",,
|
||||
"Top menu","Верхнее меню",,
|
||||
"Total time per status","Общее время по статусу",,
|
||||
"Track flow","Гусеничный поток",,
|
||||
"Track workflow","Отслеживание рабочего процесса",,
|
||||
"Tracking line","Линия слежения",,
|
||||
"Tracking lines","Линии слежения",,
|
||||
"Transactional","Транзакционный",,
|
||||
"Transition","Переход",,
|
||||
"Transitions","Переходы",,
|
||||
"Type","Тип",,
|
||||
"UI options",,,
|
||||
"Update","Обновить",,
|
||||
"User","Пользователь",,
|
||||
"Validation type","Тип валидации",,
|
||||
"Value","Значение",,
|
||||
"Value expr","Значение Expr",,
|
||||
"View","Просмотр",,
|
||||
"View generated","Сгенерированный вид",,
|
||||
"View params","Просмотреть параметры",,
|
||||
"Views","Виды",,
|
||||
"Widget","Виджет",,
|
||||
"Wkf","Wkf",,
|
||||
"Wkf field","поле Wkf",,
|
||||
"Wkf sequence",,,
|
||||
"Wkf tracking","Отслеживание Wkf",,
|
||||
"Wkf trackings","Отслеживание Wkf",,
|
||||
"Wkf transition","переход Wkf",,
|
||||
"Workflow dashboard","Приборная панель управления рабочим процессом",,
|
||||
"Workflow is not saved","Процесс работы не сохраняется",,
|
||||
"Year","Год",,
|
||||
"contains","содержит",,
|
||||
"doesn't contains","не содержит",,
|
||||
"equal","равноценный",,
|
||||
"greater or equal","больше или равны",,
|
||||
"greater than","нечто большее",,
|
||||
"in","в пределах",,
|
||||
"include","включать",,
|
||||
"is false","это ложь",,
|
||||
"is not null","не является нулевым",,
|
||||
"is null","равняется нулю",,
|
||||
"is true","это правда",,
|
||||
"less or equal","менее или равный",,
|
||||
"less than","не особо",,
|
||||
"not equal","не равный",,
|
||||
"not in","не в",,
|
||||
"not include","не включает",,
|
||||
"value:BPM","ценность:BPM",,
|
||||
"value:Product App","ценность:Продукт App",,
|
||||
"xmlId","xmlId",,
|
||||
|
@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<csv-inputs xmlns="http://axelor.com/xml/ns/data-import"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://axelor.com/xml/ns/data-import http://axelor.com/xml/ns/data-import/data-import_5.2.xsd">
|
||||
|
||||
<input file="bpm_role.csv" separator=";" type="com.axelor.auth.db.Role" search="self.name = :name"/>
|
||||
|
||||
<input file="bpm_permission.csv" separator=";" type="com.axelor.auth.db.Permission" search="self.name = :name" call="com.axelor.csv.script.ImportPermission:importPermissionToRole">
|
||||
<bind to="canRead" eval="can_read == 'x' ? 'true' : 'false'"/>
|
||||
<bind to="canWrite" eval="can_write == 'x' ? 'true' : 'false'"/>
|
||||
<bind to="canCreate" eval="can_create == 'x' ? 'true' : 'false'"/>
|
||||
<bind to="canRemove" eval="can_remove == 'x' ? 'true' : 'false'"/>
|
||||
<bind to="canExport" eval="can_export == 'x' ? 'true' : 'false'"/>
|
||||
</input>
|
||||
|
||||
<input file="bpm_metaMenu.csv" separator=";" type="com.axelor.meta.db.MetaMenu" search="self.name = :name" update="true">
|
||||
<bind column="roles" to="roles" search="self.name in :roles" eval="roles.split('\\|') as List"/>
|
||||
</input>
|
||||
|
||||
</csv-inputs>
|
||||
|
||||
@ -0,0 +1,15 @@
|
||||
"name";"roles"
|
||||
"app-builder-root";"BPM Manager|BPM User|BPM Read"
|
||||
"app-builder-models-views";"BPM Manager|BPM User|BPM Read"
|
||||
"app-builder-models-views-model-studio";"BPM Manager|BPM User|BPM Read"
|
||||
"app-builder-models-views-custom-models";"BPM Manager|BPM User|BPM Read"
|
||||
"app-builder-models-views-custom-fields";"BPM Manager|BPM User|BPM Read"
|
||||
"app-builder-bpm";"BPM Manager|BPM User|BPM Read"
|
||||
"app-builder-bpm-process-studio";"BPM Manager|BPM User|BPM Read"
|
||||
"app-builder-bpm-process-tracking";"BPM Manager|BPM User|BPM Read"
|
||||
"app-builder-bpm-actions-reporting";"BPM Manager|BPM User|BPM Read"
|
||||
"app-builder-bpm-actions-reporting-chart-builders";"BPM Manager|BPM User|BPM Read"
|
||||
"app-builder-bpm-actions-reporting-dashboard-builders";"BPM Manager|BPM User|BPM Read"
|
||||
"app-builder-bpm-actions-reporting-action-builders";"BPM Manager|BPM User|BPM Read"
|
||||
"app-builder-bpm-actions-reporting-menu-builders";"BPM Manager|BPM User|BPM Read"
|
||||
"app-builder-bpm-apps-configurator";"BPM Manager|BPM User|BPM Read"
|
||||
|
@ -0,0 +1,49 @@
|
||||
"name";"object";"can_read";"can_write";"can_create";"can_remove";"can_export";"condition";"conditionParams";"roleName"
|
||||
"perm.studio.DashletBuilder.r";"com.axelor.studio.db.DashletBuilder";"x";;;;;;;"BPM Read"
|
||||
"perm.studio.AppBuilder.r";"com.axelor.studio.db.AppBuilder";"x";;;;;;;"BPM Read"
|
||||
"perm.studio.Wkf.r";"com.axelor.studio.db.Wkf";"x";;;;;;;"BPM Read"
|
||||
"perm.studio.WkfTrackingTime.r";"com.axelor.studio.db.WkfTrackingTime";"x";;;;;;;"BPM Read"
|
||||
"perm.studio.DashboardBuilder.r";"com.axelor.studio.db.DashboardBuilder";"x";;;;;;;"BPM Read"
|
||||
"perm.studio.ActionBuilderLine.r";"com.axelor.studio.db.ActionBuilderLine";"x";;;;;;;"BPM Read"
|
||||
"perm.studio.WkfTransition.r";"com.axelor.studio.db.WkfTransition";"x";;;;;;;"BPM Read"
|
||||
"perm.studio.WkfNode.r";"com.axelor.studio.db.WkfNode";"x";;;;;;;"BPM Read"
|
||||
"perm.studio.WkfTrackingTotal.r";"com.axelor.studio.db.WkfTrackingTotal";"x";;;;;;;"BPM Read"
|
||||
"perm.studio.ChartBuilder.r";"com.axelor.studio.db.ChartBuilder";"x";;;;;;;"BPM Read"
|
||||
"perm.studio.WkfTracking.r";"com.axelor.studio.db.WkfTracking";"x";;;;;;;"BPM Read"
|
||||
"perm.studio.WkfTrackingLine.r";"com.axelor.studio.db.WkfTrackingLine";"x";;;;;;;"BPM Read"
|
||||
"perm.studio.ActionBuilderView.r";"com.axelor.studio.db.ActionBuilderView";"x";;;;;;;"BPM Read"
|
||||
"perm.studio.ActionBuilder.r";"com.axelor.studio.db.ActionBuilder";"x";;;;;;;"BPM Read"
|
||||
"perm.studio.MenuBuilder.r";"com.axelor.studio.db.MenuBuilder";"x";;;;;;;"BPM Read"
|
||||
"perm.studio.Filter.r";"com.axelor.studio.db.Filter";"x";;;;;;;"BPM Read"
|
||||
"perm.studio.DashletBuilder.rwc";"com.axelor.studio.db.DashletBuilder";"x";"x";"x";;;;;"BPM User"
|
||||
"perm.studio.AppBuilder.rwc";"com.axelor.studio.db.AppBuilder";"x";"x";"x";;;;;"BPM User"
|
||||
"perm.studio.Wkf.rwc";"com.axelor.studio.db.Wkf";"x";"x";"x";;;;;"BPM User"
|
||||
"perm.studio.WkfTrackingTime.rwc";"com.axelor.studio.db.WkfTrackingTime";"x";"x";"x";;;;;"BPM User"
|
||||
"perm.studio.DashboardBuilder.rwc";"com.axelor.studio.db.DashboardBuilder";"x";"x";"x";;;;;"BPM User"
|
||||
"perm.studio.ActionBuilderLine.rwc";"com.axelor.studio.db.ActionBuilderLine";"x";"x";"x";;;;;"BPM User"
|
||||
"perm.studio.WkfTransition.rwc";"com.axelor.studio.db.WkfTransition";"x";"x";"x";;;;;"BPM User"
|
||||
"perm.studio.WkfNode.rwc";"com.axelor.studio.db.WkfNode";"x";"x";"x";;;;;"BPM User"
|
||||
"perm.studio.WkfTrackingTotal.rwc";"com.axelor.studio.db.WkfTrackingTotal";"x";"x";"x";;;;;"BPM User"
|
||||
"perm.studio.ChartBuilder.rwc";"com.axelor.studio.db.ChartBuilder";"x";"x";"x";;;;;"BPM User"
|
||||
"perm.studio.WkfTracking.rwc";"com.axelor.studio.db.WkfTracking";"x";"x";"x";;;;;"BPM User"
|
||||
"perm.studio.WkfTrackingLine.rwc";"com.axelor.studio.db.WkfTrackingLine";"x";"x";"x";;;;;"BPM User"
|
||||
"perm.studio.ActionBuilderView.rwc";"com.axelor.studio.db.ActionBuilderView";"x";"x";"x";;;;;"BPM User"
|
||||
"perm.studio.ActionBuilder.rwc";"com.axelor.studio.db.ActionBuilder";"x";"x";"x";;;;;"BPM User"
|
||||
"perm.studio.MenuBuilder.rwc";"com.axelor.studio.db.MenuBuilder";"x";"x";"x";;;;;"BPM User"
|
||||
"perm.studio.Filter.rwc";"com.axelor.studio.db.Filter";"x";"x";"x";;;;;"BPM User"
|
||||
"perm.studio.DashletBuilder.rwcde";"com.axelor.studio.db.DashletBuilder";"x";"x";"x";"x";"x";;;"BPM Manager"
|
||||
"perm.studio.AppBuilder.rwcde";"com.axelor.studio.db.AppBuilder";"x";"x";"x";"x";"x";;;"BPM Manager"
|
||||
"perm.studio.Wkf.rwcde";"com.axelor.studio.db.Wkf";"x";"x";"x";"x";"x";;;"BPM Manager"
|
||||
"perm.studio.WkfTrackingTime.rwcde";"com.axelor.studio.db.WkfTrackingTime";"x";"x";"x";"x";"x";;;"BPM Manager"
|
||||
"perm.studio.DashboardBuilder.rwcde";"com.axelor.studio.db.DashboardBuilder";"x";"x";"x";"x";"x";;;"BPM Manager"
|
||||
"perm.studio.ActionBuilderLine.rwcde";"com.axelor.studio.db.ActionBuilderLine";"x";"x";"x";"x";"x";;;"BPM Manager"
|
||||
"perm.studio.WkfTransition.rwcde";"com.axelor.studio.db.WkfTransition";"x";"x";"x";"x";"x";;;"BPM Manager"
|
||||
"perm.studio.WkfNode.rwcde";"com.axelor.studio.db.WkfNode";"x";"x";"x";"x";"x";;;"BPM Manager"
|
||||
"perm.studio.WkfTrackingTotal.rwcde";"com.axelor.studio.db.WkfTrackingTotal";"x";"x";"x";"x";"x";;;"BPM Manager"
|
||||
"perm.studio.ChartBuilder.rwcde";"com.axelor.studio.db.ChartBuilder";"x";"x";"x";"x";"x";;;"BPM Manager"
|
||||
"perm.studio.WkfTracking.rwcde";"com.axelor.studio.db.WkfTracking";"x";"x";"x";"x";"x";;;"BPM Manager"
|
||||
"perm.studio.WkfTrackingLine.rwcde";"com.axelor.studio.db.WkfTrackingLine";"x";"x";"x";"x";"x";;;"BPM Manager"
|
||||
"perm.studio.ActionBuilderView.rwcde";"com.axelor.studio.db.ActionBuilderView";"x";"x";"x";"x";"x";;;"BPM Manager"
|
||||
"perm.studio.ActionBuilder.rwcde";"com.axelor.studio.db.ActionBuilder";"x";"x";"x";"x";"x";;;"BPM Manager"
|
||||
"perm.studio.MenuBuilder.rwcde";"com.axelor.studio.db.MenuBuilder";"x";"x";"x";"x";"x";;;"BPM Manager"
|
||||
"perm.studio.Filter.rwcde";"com.axelor.studio.db.Filter";"x";"x";"x";"x";"x";;;"BPM Manager"
|
||||
|
@ -0,0 +1,4 @@
|
||||
"name";"description"
|
||||
"BPM Read";
|
||||
"BPM User";
|
||||
"BPM Manager";
|
||||
|
@ -0,0 +1,98 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<object-views xmlns="http://axelor.com/xml/ns/object-views"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://axelor.com/xml/ns/object-views http://axelor.com/xml/ns/object-views/object-views_5.2.xsd">
|
||||
|
||||
<grid name="action-builder-grid" title="Action builder" model="com.axelor.studio.db.ActionBuilder">
|
||||
<field name="name" />
|
||||
<field name="model" />
|
||||
<field name="typeSelect" />
|
||||
<field name="appBuilder" grid-view="app-builder-grid" form-view="app-builder-form"/>
|
||||
</grid>
|
||||
|
||||
<form name="action-builder-form" title="Action builder" model="com.axelor.studio.db.ActionBuilder" width="large">
|
||||
<panel name="mainPanel">
|
||||
<field name="isJson" onChange="action-action-builder-method-set-views,action-action-builder-type-select-change" colSpan="2"/>
|
||||
<field name="appBuilder" grid-view="app-builder-grid" form-view="app-builder-form"/>
|
||||
<field name="name" colSpan="9" required="true"/>
|
||||
<field name="typeSelect" onChange="action-action-builder-type-select-change" colSpan="3"/>
|
||||
<panel name="modelPanel" colSpan="6" itemSpan="12">
|
||||
<field name="model" widget="ref-text" x-target-name="name" x-target="com.axelor.meta.db.MetaJsonModel"
|
||||
requiredIf="(typeSelect < 2 || typeSelect == 4) && isJson"
|
||||
hideIf="typeSelect == 2 || !isJson"
|
||||
onChange="action-action-builder-method-set-views,action-action-builder-attrs-model-change" />
|
||||
<field name="model" hideIf="typeSelect == 2 || isJson"
|
||||
requiredIf="(typeSelect < 2 || typeSelect == 4) && !isJson"
|
||||
widget="ref-text" x-target-name="fullName" x-target="com.axelor.meta.db.MetaModel"
|
||||
onChange="action-action-builder-method-set-views,action-action-builder-attrs-model-change" />
|
||||
</panel>
|
||||
<panel name="emailSendOptionSelectPanel" colSpan="6" showIf="typeSelect == 4">
|
||||
<field name="emailSendOptionSelect" requiredIf="typeSelect == 4"/>
|
||||
</panel>
|
||||
<panel name="targetModelPanel" colSpan="6" itemSpan="12">
|
||||
<field name="targetModel" requiredIf="typeSelect == 0 && isJson" showIf="typeSelect == 0 && isJson" widget="ref-text"
|
||||
x-target-name="name" x-target="com.axelor.meta.db.MetaJsonModel"/>
|
||||
<field name="targetModel" requiredIf="typeSelect == 0 && !isJson" showIf="typeSelect == 0 && !isJson" widget="ref-text"
|
||||
x-target-name="fullName" x-target="com.axelor.meta.db.MetaModel"/>
|
||||
</panel>
|
||||
<field name="openRecord" showIf="typeSelect == 0" colSpan="4" />
|
||||
<field name="displayMsg" showIf="typeSelect == 0" colSpan="8"/>
|
||||
<field name="title" colSpan="12" showIf="typeSelect == 3" requiredIf="typeSelect == 3"/>
|
||||
<field name="actionBuilderViews" showIf="typeSelect == 3" colSpan="12">
|
||||
<editor>
|
||||
<field name="viewType" colSpan="3" />
|
||||
<field name="viewName" colSpan="5" widget="ref-text" x-target="com.axelor.meta.db.MetaView" x-target-name="name" onSelect="action-action-builder-view-name-domain"/>
|
||||
<field name="viewConditionToCheck" colSpan="4"/>
|
||||
</editor>
|
||||
</field>
|
||||
<field name="lines" title="Context" hideIf="typeSelect != 3" colSpan="12">
|
||||
<editor>
|
||||
<field name="name" title="Name" colSpan="4" />
|
||||
<field name="value" colSpan="8"/>
|
||||
</editor>
|
||||
</field>
|
||||
<field name="viewParams" title="View params" hideIf="typeSelect != 3" colSpan="12">
|
||||
<editor>
|
||||
<field name="name" title="Name" colSpan="4" />
|
||||
<field name="value" title="Value" colSpan="8"/>
|
||||
</editor>
|
||||
</field>
|
||||
<field name="domainCondition" showIf="typeSelect == 3" colSpan="12" />
|
||||
<panel-related name="linesPanel" field="lines" colSpan="12" hideIf="typeSelect > 1" grid-view="action-builder-line-grid" form-view="action-builder-line-form" />
|
||||
<panel name="scriptPanel" showIf="typeSelect == 2" colSpan="12" >
|
||||
<field name="scriptType" />
|
||||
<field name="transactional" />
|
||||
<field name="scriptText" widget="CodeEditor" x-code-syntax="javascript" colSpan="12" />
|
||||
</panel>
|
||||
<panel name="emailTemplatePanel" colSpan="12">
|
||||
<field name="scriptText" widget="html" title="Template" colSpan="12" showIf="typeSelect == 5"/>
|
||||
<field name="emailTemplate" onSelect="action-action-builder-attrs-template-domain" requiredIf="typeSelect == 4" grid-view="template-grid" form-view="template-form" showIf="typeSelect == 4"/>
|
||||
</panel>
|
||||
</panel>
|
||||
</form>
|
||||
|
||||
<action-record name="action-action-builder-type-select-change" model="com.axelor.studio.db.ActionBuilder">
|
||||
<field name="model" expr="eval:null"/>
|
||||
<field name="targetModel" expr="eval:null"/>
|
||||
</action-record>
|
||||
|
||||
<action-record name="action-action-builder-attrs-model-change" model="com.axelor.studio.db.ActionBuilder">
|
||||
<field name="emailTemplate" expr="eval:null"/>
|
||||
</action-record>
|
||||
|
||||
<action-attrs name="action-action-builder-view-name-domain">
|
||||
<attribute name="domain" for="viewName" expr="eval:"self.type = '${viewType}' "" if="viewType == 'dashboard'"/>
|
||||
<attribute name="domain" for="viewName" expr="eval:"self.type = '${viewType}' and self.model = 'com.axelor.meta.db.MetaJsonRecord' and self.name = 'custom-model-${_parent.model}-${viewType}' "" if="_parent.isJson && viewType != 'dashboard'"/>
|
||||
<attribute name="domain" for="viewName" expr="eval:"self.type = '${viewType}' and self.model = '${_parent.model}'"" if="!_parent.isJson && viewType != 'dashboard'"/>
|
||||
</action-attrs>
|
||||
|
||||
<action-attrs name="action-action-builder-attrs-template-domain">
|
||||
<attribute name="domain" for="emailTemplate" expr="eval:(model != null) ? " self.metaModel.fullName = '${model}' AND self.isJson = '${isJson}' " : " self.isJson = '${isJson}' "" if="!isJson"/>
|
||||
<attribute name="domain" for="emailTemplate" expr="eval:(model != null) ? " self.metaJsonModel.name = '${model}' AND self.isJson = '${isJson}' " : " self.isJson = '${isJson}' "" if="isJson"/>
|
||||
</action-attrs>
|
||||
|
||||
<action-method name="action-action-builder-method-set-views">
|
||||
<call class="com.axelor.studio.web.ActionBuilderController" method="setViews" if="typeSelect == 3"/>
|
||||
</action-method>
|
||||
|
||||
</object-views>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user