xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>lis-app</artifactId>
- <version>0.1.4-SNAPSHOT</version>
+ <version>0.1.5-SNAPSHOT</version>
<parent>
<groupId>hu.user</groupId>
<artifactId>lis</artifactId>
+++ /dev/null
-/*
- * Copyright (c) $today.year-$today.month-24.
- * By elGekko
- */
-
-package hu.user.lis;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.InjectionPoint;
-import org.springframework.beans.factory.config.ConfigurableBeanFactory;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.Scope;
-
-@Configuration
-public class LoggerConfiguration {
-
- @Bean
- @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
- public Logger logger(InjectionPoint ip) {
- final Class lClass;
- if (ip.getMethodParameter() == null)
- lClass = ip.getField().getDeclaringClass();
- else
- lClass = ip.getMethodParameter().getContainingClass();
- return LoggerFactory.getLogger(lClass);
- }
-
-}
\ No newline at end of file
package hu.user.lis;
-import org.slf4j.Logger;
-import org.springframework.beans.factory.annotation.Autowired;
+import lombok.extern.log4j.Log4j2;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+@Log4j2
@Configuration
@EnableWebMvc
public class WebAppConfigurer implements WebMvcConfigurer {
- @Autowired
- private Logger logger;
-
//Fajlok kiszolgalasa kulso mappabol es a war-bol
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry
.addResourceHandler("/files/**")
.addResourceLocations("file:/opt/");
- logger.info("Resource handlers added");
+ log.info("Resource handlers added");
// registry
// .addResourceHandler("/resources/**")
// .addResourceLocations("/resources/");
jpa:
# hibernate:
# use-new-id-generator-mappings: false
- show-sql: true
+ show-sql: false
properties:
hibernate:
format_sql: true
import lombok.extern.log4j.Log4j2;
import org.camunda.bpm.engine.RuntimeService;
+import org.camunda.bpm.engine.TaskService;
import org.camunda.bpm.engine.runtime.ProcessInstance;
+import org.camunda.bpm.engine.task.Task;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringRunner;
+import java.util.List;
+
@Log4j2
@SpringBootTest
@ComponentScan("hu.user.lis")
@TestPropertySource("classpath:application-dev.yaml")
public class ImportIncomingInvoicesIT {
+ // @Rule
+// public ProcessEngineRule processEngineRule = new ProcessEngineRule();
@Autowired
private RuntimeService runtimeService;
+ @Autowired
+ private TaskService taskService;
+
+// @Test
+// @Deployment(resources = {"import-incoming-invoices.bpmn"})
+// public void testImportIncomingInvoiceAspect() throws InterruptedException {
+// RuntimeService runtimeService = processEngineRule.getRuntimeService();
+// runtimeService.startProcessInstanceByKey("importIncomingInvoices");
+//
+// TaskService taskService = processEngineRule.getTaskService();
+// List<Task> taskList = taskService.createTaskQuery().list();
+// taskList.forEach(t -> {
+// assertThat(t.getTaskDefinitionKey()).isEqualTo("assignProjectAndAttachFile");
+// taskService.complete(t.getId());
+// });
+// }
+
@Test
public void testImportIncomingInvoice() throws InterruptedException {
+ List<ProcessInstance> processInstances = runtimeService.createProcessInstanceQuery().list();
+ processInstances.forEach(p -> {
+ //log.info("{} {}", p.getProcessInstanceId(), p.getProcessDefinitionId());
+ try {
+ runtimeService.deleteProcessInstance(p.getProcessInstanceId(), "Canceled");
+ } catch (Exception e) {
+ }
+ //taskService.complete(t.getId());
+ });
+
+ processInstances = runtimeService.createProcessInstanceQuery().list();
+ processInstances.forEach(p -> {
+ log.info("{} {}", p.getProcessInstanceId(), p.getProcessDefinitionId());
+ //taskService.complete(t.getId());
+ });
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("importIncomingInvoices");
+ processInstances = runtimeService.createProcessInstanceQuery().list();
+ processInstances.forEach(p -> {
+ log.info("{} {}", p.getProcessInstanceId(), p.getProcessDefinitionId());
+ //taskService.complete(t.getId());
+ });
+
+
+ List<Task> taskList = taskService.createTaskQuery().processInstanceId(processInstance.getId()).list();
+ taskList.forEach(t -> {
+ log.info(t.getTaskDefinitionKey());
+ //taskService.complete(t.getId());
+ });
- //verify(processInstance).hasFinished("WorkFinished");
while (true) {
ProcessInstance active = runtimeService.createProcessInstanceQuery().processInstanceId(processInstance.getProcessInstanceId()).active().singleResult();
if (active == null) {
<artifactId>lis-services</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>hu.user</groupId>
+ <artifactId>lis-workflow</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ </dependency>
</dependencies>
</project>
\ No newline at end of file
public class Constants {
public static final String BINDING_QUEUE = "$ZKBIND_DEFQUE$";
public static final String PROJECT_EDITOR_QUEUE = "PROJECT_EDITOR_QUEUE";
+ public static final String PROCESS_EVENT_QUEUE = "PROJECT_EDITOR_QUEUE";
public static final String SHOW_PROJECT_EDITOR = "SHOW_PROJECT_EDITOR";
public static final String SHOW_PROJECTS_LIST = "SHOW_PROJECTS_LIST";
public static final String SHOW_SERVICE_RECORDS_LIST = "SHOW_SERVICE_RECORDS_LIST";
public static final String SET_SERVICE_RECORDS_LIST_DATA = "SET_SERVICE_RECORDS_LIST_DATA";
public static final String SET_PROJECT_EDITOR_DATA = "SET_PROJECT_EDITOR_DATA";
public static final String SET_PROJECTS_LIST_DATA = "SET_PROJECTS_LIST_DATA";
-
+ public static final String REFRESH_INVOICE_IMPORT_TASKS = "REFRESH_INVOICE_IMPORT_TASKS";
public static final String NAV_PARTNERS = "/partners";
public static final String NAV_PROJECTS = "/projects";
public static final String NAV_PROJECT = "/project";
+ public static final String NAV_PROJECT_WILD_CARD = "/project/**";
public static final String NAV_ASSOCIATES = "/associates";
public static final String NAV_PROJECT_ASSOCIATES = "/project-associates";
public static final String NAV_SERVICE_RECORDS = "/service-records";
public static final String NAV_SETTINGS = "/settings";
+ public static final String NAV_IMPORT_INVOICES_ASSIGN = "/import-invoices-assign";
+ public static final String NAV_IMPORT_INVOICES_APPROVE = "/import-invoices-approve";
+ public static final String NAV_LOGIN = "/login";
+ public static final String NAV_LOGOUT = "/logout";
+ public static final String NAV_ROOT = "/";
- public static final String WIDGET_ENTITY_SELECTOR = "~./widget/entity-selector.zul";
-
+ public static final String NAV_API = "/api";
+ public static final String WIDGET_ENTITY_SELECTOR = "~./widget/entity-selector.zul";
}
package hu.user.lis.ui.auth;
+import hu.user.lis.ui.Constants;
import lombok.extern.log4j.Log4j2;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.core.Authentication;
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null || authentication instanceof AnonymousAuthenticationToken) {
- Executions.sendRedirect("/login");
+ Executions.sendRedirect(Constants.NAV_LOGIN);
}
}
package hu.user.lis.ui.config;
+import hu.user.lis.ui.Constants;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
return "login";
}
- @GetMapping({"/partners", "/projects", "/associates", "/project-associates", "/service-records", "/settings", "/project/**"})
+ @GetMapping({
+ Constants.NAV_PARTNERS,
+ Constants.NAV_PROJECTS,
+ Constants.NAV_ASSOCIATES,
+ Constants.NAV_PROJECT_ASSOCIATES,
+ Constants.NAV_SERVICE_RECORDS,
+ Constants.NAV_IMPORT_INVOICES_ASSIGN,
+ Constants.NAV_IMPORT_INVOICES_APPROVE,
+ Constants.NAV_SETTINGS,
+ Constants.NAV_PROJECT_WILD_CARD
+ })
public String index() {
return "index";
}
package hu.user.lis.ui.config;
+import hu.user.lis.ui.Constants;
import hu.user.lis.ui.auth.LdapUserDetailsContextMapper;
import hu.user.lis.ui.auth.LocalAuthProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.web.authentication.Http403ForbiddenEntryPoint;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
-import static hu.user.lis.ui.view.IndexViewModel.NAVIGATION;
-
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
- String[] navigation = NAVIGATION.keySet().toArray(new String[]{});
+ //String[] navigation = NAVIGATION.keySet().toArray(new String[]{});
http.headers().frameOptions().sameOrigin();
http.authorizeRequests()
.antMatchers(ZUL_FILES).denyAll() // block direct access to zul files
.antMatchers(HttpMethod.POST, "/zkau/upload/**").permitAll() // allow zk resources
.regexMatchers(HttpMethod.GET, REMOVE_DESKTOP_REGEX).permitAll() // allow desktop cleanup
.requestMatchers(req -> "rmDesktop".equals(req.getParameter("cmd_0"))).permitAll() // allow desktop cleanup from ZATS
- .mvcMatchers("/", "/login", "/logout", "/api/**").permitAll()
+ .mvcMatchers(Constants.NAV_ROOT, Constants.NAV_LOGIN, Constants.NAV_LOGOUT, Constants.NAV_API + "/**").permitAll()
//mvcMatchers(navigation).hasRole("USER")
.anyRequest().authenticated()
.and()
.formLogin()
- .loginPage("/login").defaultSuccessUrl("/partners")
+ .loginPage(Constants.NAV_LOGIN).defaultSuccessUrl(Constants.NAV_PARTNERS)
.and()
- .logout().logoutUrl("/logout").logoutSuccessUrl("/")
+ .logout().logoutUrl(Constants.NAV_LOGOUT).logoutSuccessUrl(Constants.NAV_LOGIN)
.and()
.exceptionHandling()
.defaultAuthenticationEntryPointFor(
--- /dev/null
+package hu.user.lis.ui.data;
+
+import hu.user.lis.ui.data.common.CachedSpringDataModel;
+import hu.user.lis.workflow.event.ImportInvoicesEvent;
+import hu.user.lis.workflow.invoice.service.WorkflowManagerService;
+import lombok.extern.log4j.Log4j2;
+import org.camunda.bpm.engine.task.Task;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.config.ConfigurableBeanFactory;
+import org.springframework.context.ApplicationListener;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+import org.zkoss.json.JSONObject;
+import org.zkoss.zul.FieldComparator;
+import org.zkoss.zul.event.ListDataEvent;
+
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@Component
+@Log4j2
+@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
+public class ApproveInvoicesDataModel extends CachedSpringDataModel<JSONObject> implements ApplicationListener<ImportInvoicesEvent> {
+ @Autowired
+ WorkflowManagerService workflowManagerService;
+
+ public void refresh() {
+ super.reset();
+ }
+
+ @Override
+ public void onApplicationEvent(ImportInvoicesEvent event) {
+ fireEvent(ListDataEvent.STRUCTURE_CHANGED, -1, -1);
+ }
+
+ public void completeTask(JSONObject selectedEntity, Map<String, Object> vars) {
+ String taskId = (String) selectedEntity.get("taskId");
+ workflowManagerService.completeTask(taskId, vars);
+ }
+
+ @Override
+ public List<JSONObject> getResultSet(int page, int pageSize, FieldComparator sortComparator) {
+ List<Task> tasks = workflowManagerService.listApproveInvoiceTasks();
+ return tasks.stream().map(t -> {
+ JSONObject o = new JSONObject();
+ o.put("taskId", t.getId());
+ o.putAll(workflowManagerService.getVariables(t.getId()));
+ log.info("Task {}", o);
+ return o;
+ }).collect(Collectors.toList());
+ }
+
+ @Override
+ public int getResultSetCount() {
+ return workflowManagerService.listApproveInvoiceTasks().size();
+ }
+}
import hu.user.lis.db.Associate;
import hu.user.lis.db.repository.AssociateRepository;
+import hu.user.lis.ui.data.common.CachedSpringDataModel;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import hu.user.lis.db.repository.AssociateRepository;
import hu.user.lis.services.data.AssociateService;
import hu.user.lis.services.data.EntityDataService;
+import hu.user.lis.ui.data.common.CachedSpringDataModel;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
--- /dev/null
+package hu.user.lis.ui.data;
+
+import hu.user.lis.ui.data.common.CachedSpringDataModel;
+import hu.user.lis.workflow.invoice.service.WorkflowManagerService;
+import lombok.extern.log4j.Log4j2;
+import org.camunda.bpm.engine.task.Task;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.config.ConfigurableBeanFactory;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+import org.zkoss.json.JSONObject;
+import org.zkoss.zul.FieldComparator;
+
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@Component
+@Log4j2
+@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
+public class ImportInvoicesDataModel extends CachedSpringDataModel<JSONObject> {
+ @Autowired
+ WorkflowManagerService workflowManagerService;
+
+ public void refresh() {
+ super.reset();
+ }
+
+ public void completeTask(JSONObject selectedEntity, Map<String, Object> vars) {
+ String taskId = (String) selectedEntity.get("taskId");
+ workflowManagerService.completeTask(taskId, vars);
+ }
+
+ @Override
+ public List<JSONObject> getResultSet(int page, int pageSize, FieldComparator sortComparator) {
+ List<Task> tasks = workflowManagerService.listAssignInvoiceTasks();
+ return tasks.stream().map(t -> {
+ JSONObject o = new JSONObject();
+ o.put("taskId", t.getId());
+ o.putAll(workflowManagerService.getVariables(t.getId()));
+ log.info("Task {}", o);
+ return o;
+ }).collect(Collectors.toList());
+ }
+
+ @Override
+ public int getResultSetCount() {
+ return workflowManagerService.listAssignInvoiceTasks().size();
+ }
+}
import hu.user.lis.db.Partner;
import hu.user.lis.db.repository.PartnerRepository;
+import hu.user.lis.ui.data.common.CachedSpringDataModel;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import hu.user.lis.db.repository.PartnerRepository;
import hu.user.lis.services.data.EntityDataService;
import hu.user.lis.services.data.PartnerService;
+import hu.user.lis.ui.data.common.CachedSpringDataModel;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import hu.user.lis.db.Project;
import hu.user.lis.db.repository.ProjectRepository;
+import hu.user.lis.ui.data.common.CachedSpringDataModel;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import hu.user.lis.db.ProjectStatus;
import hu.user.lis.db.repository.ProjectStatusRepository;
import hu.user.lis.services.data.ProjectStatusService;
+import hu.user.lis.ui.data.common.CachedSpringDataModel;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import hu.user.lis.db.ProjectStatus;
import hu.user.lis.db.repository.ProjectRepository;
import hu.user.lis.services.data.EntityDataService;
+import hu.user.lis.ui.data.common.CachedSpringDataModel;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import hu.user.lis.db.repository.ServiceRecordRepository;
import hu.user.lis.services.data.EntityDataService;
import hu.user.lis.services.data.ServiceRecordService;
+import hu.user.lis.ui.data.common.CachedSpringDataModel;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import hu.user.lis.db.Supplier;
import hu.user.lis.services.data.SupplierService;
+import hu.user.lis.ui.data.common.CachedDataModel;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import hu.user.lis.db.Supplier;
import hu.user.lis.services.data.SupplierService;
+import hu.user.lis.ui.data.common.CachedDataModel;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
-package hu.user.lis.ui.data;
+package hu.user.lis.ui.data.common;
import lombok.Setter;
import lombok.extern.log4j.Log4j2;
-package hu.user.lis.ui.data;
+package hu.user.lis.ui.data.common;
import hu.user.lis.db.Profile;
import hu.user.lis.services.data.EntityDataService;
-package hu.user.lis.ui.data;
+package hu.user.lis.ui.data.common;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Builder;
@Builder
@Log4j2
public class FormDocument extends JSONObject {
-
+
private Object data;
public FormDocument setData(Object data) {
--- /dev/null
+package hu.user.lis.ui.editor;
+
+import com.google.common.collect.ImmutableMap;
+import hu.user.lis.db.Invoice;
+import hu.user.lis.db.Partner;
+import hu.user.lis.db.Project;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.extern.log4j.Log4j2;
+import org.zkoss.bind.annotation.*;
+import org.zkoss.zk.ui.Component;
+import org.zkoss.zk.ui.event.Event;
+import org.zkoss.zk.ui.event.Events;
+import org.zkoss.zul.Window;
+
+import java.util.Objects;
+
+@Log4j2
+@Getter
+@Setter
+public class ImportInvoiceApproveEditorModel extends InvoiceEditorModel {
+ @Init
+ public void init() {
+ super.init();
+ }
+
+ @Override
+ protected boolean canSave(Invoice entity) {
+ return super.canSave(entity)
+ && Objects.nonNull(entity.getProject())
+ && Objects.nonNull(entity.getFile());
+ }
+
+ @AfterCompose
+ public void onAfterCompose(@ContextParam(ContextType.VIEW) Component view) {
+ getEntitySelectorRouter().configureSelector(Project.class, getFormDocument(), "project");
+ getEntitySelectorRouter().configureSelector(Partner.class, getFormDocument(), "partner");
+ validate();
+ }
+
+ @Command
+ public void onCloseApproveWindow(@BindingParam("target") Window target, @BindingParam("save") int save) {
+ if (save == 0) {
+ Events.postEvent(new Event("onClose", target, null));
+ return;
+ }
+ ImmutableMap<String, Object> args = ImmutableMap.of("approved", save == 2, "modifiedEntity", getFormDocument());
+ if (save == 1) {
+ Events.postEvent(new Event("onClose", target,
+ ImmutableMap.of("approved", false)));
+ return;
+ }
+
+ if (isSaveEnabled()) {
+ Events.postEvent(new Event("onClose", target,
+ ImmutableMap.of("approved", true, "modifiedEntity", getFormDocument())));
+ }
+ }
+}
--- /dev/null
+package hu.user.lis.ui.editor;
+
+import hu.user.lis.db.Invoice;
+import hu.user.lis.db.Partner;
+import hu.user.lis.db.Project;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.extern.log4j.Log4j2;
+import org.zkoss.bind.annotation.AfterCompose;
+import org.zkoss.bind.annotation.ContextParam;
+import org.zkoss.bind.annotation.ContextType;
+import org.zkoss.bind.annotation.Init;
+import org.zkoss.zk.ui.Component;
+
+import java.util.Objects;
+
+@Log4j2
+@Getter
+@Setter
+public class ImportInvoiceAssignEditorModel extends InvoiceEditorModel {
+ @Init
+ public void init() {
+ super.init();
+ }
+
+ @Override
+ protected boolean canSave(Invoice entity) {
+ return super.canSave(entity)
+ && Objects.nonNull(entity.getProject())
+ && Objects.nonNull(entity.getFile());
+ }
+
+ @AfterCompose
+ public void onAfterCompose(@ContextParam(ContextType.VIEW) Component view) {
+ getEntitySelectorRouter().configureSelector(Project.class, getFormDocument(), "project");
+ getEntitySelectorRouter().configureSelector(Partner.class, getFormDocument(), "partner");
+ validate();
+ }
+}
@Init
public void init() {
+
super.init();
}
public static final String TREASURY = "~./editor/treasury-editor.zul";
public static final String ASSOCIATE = "~./editor/associate-editor.zul";
public static final String PARTNER = "~./editor/partner-editor.zul";
-
+ public static final String IMPORT_INVOICE_ASSIGN = "~./editor/import-invoice-assign-editor.zul";
+ public static final String IMPORT_INVOICE_APPROVE = "~./editor/import-invoice-approve-editor.zul";
public static final String PROJECT = "~./editor/project-editor.zul";
public static <E> void doEdit(String page, E entity, EditCompleted<E> editCompleted) {
import hu.user.lis.db.Associate;
import hu.user.lis.ui.converter.AssociateToNameConverter;
import hu.user.lis.ui.data.AssociateSelectorDataModel;
-import hu.user.lis.ui.data.CachedSpringDataModel;
+import hu.user.lis.ui.data.common.CachedSpringDataModel;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.log4j.Log4j2;
package hu.user.lis.ui.editor.selector;
import hu.user.lis.services.data.EntityDataServiceBase;
-import hu.user.lis.ui.data.CachedSpringDataModel;
+import hu.user.lis.ui.data.common.CachedSpringDataModel;
import lombok.Getter;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import hu.user.lis.db.Partner;
import hu.user.lis.ui.converter.PartnerToNameConverter;
-import hu.user.lis.ui.data.CachedSpringDataModel;
import hu.user.lis.ui.data.PartnerSelectorDataModel;
+import hu.user.lis.ui.data.common.CachedSpringDataModel;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.log4j.Log4j2;
import hu.user.lis.db.Project;
import hu.user.lis.ui.converter.ProjectToInfoConverter;
-import hu.user.lis.ui.data.CachedSpringDataModel;
import hu.user.lis.ui.data.ProjectSelectorDataModel;
+import hu.user.lis.ui.data.common.CachedSpringDataModel;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.log4j.Log4j2;
@Service
@Log4j2
public class EventBus {
+ private EventQueue<Event> getProcessEventQueue() {
+ return EventQueues.lookup(Constants.PROCESS_EVENT_QUEUE, EventQueues.APPLICATION, true);
+ }
private EventQueue<Event> getQueue() {
return EventQueues.lookup(Constants.PROJECT_EDITOR_QUEUE, EventQueues.SESSION, true);
getBindingQueue().subscribe(listener);
}
+ public void registerForProcessEvent(EventListener listener) {
+ getProcessEventQueue().subscribe(listener);
+ }
+
public void unregister(EventListener listener) {
try {
getQueue().unsubscribe(listener);
getBindingQueue().unsubscribe(listener);
+ getProcessEventQueue().unsubscribe(listener);
} catch (Exception e) {
// log.warn("Not necessary to unregister");
}
public void setProjectsListData(Object data) {
getQueue().publish(new Event(Constants.SET_PROJECTS_LIST_DATA, null, data));
}
+
+ public void refreshImportInvoiceTasks(String eventType) {
+ getProcessEventQueue().publish(new Event(Constants.REFRESH_INVOICE_IMPORT_TASKS, null, eventType));
+ }
}
--- /dev/null
+package hu.user.lis.ui.event;
+
+import hu.user.lis.workflow.event.ImportInvoicesEvent;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationListener;
+import org.springframework.stereotype.Component;
+
+@Component
+public class ProcessEventRouter implements ApplicationListener<ImportInvoicesEvent> {
+ @Autowired
+ EventBus eventBus;
+
+ @Override
+ public void onApplicationEvent(ImportInvoicesEvent event) {
+ eventBus.refreshImportInvoiceTasks(event.getEventType());
+ }
+}
--- /dev/null
+package hu.user.lis.ui.view;
+
+import com.google.common.collect.ImmutableMap;
+import hu.user.lis.db.Invoice;
+import hu.user.lis.db.repository.InvoiceRepository;
+import hu.user.lis.ui.Constants;
+import hu.user.lis.ui.data.ApproveInvoicesDataModel;
+import hu.user.lis.ui.data.common.CachedSpringDataModel;
+import hu.user.lis.ui.editor.common.Editors;
+import hu.user.lis.ui.event.EventBus;
+import hu.user.lis.ui.event.ProcessEventRouter;
+import hu.user.lis.ui.view.common.EntityViewModel;
+import lombok.Getter;
+import lombok.extern.log4j.Log4j2;
+import org.zkoss.bind.BindUtils;
+import org.zkoss.bind.annotation.Command;
+import org.zkoss.bind.annotation.Init;
+import org.zkoss.bind.annotation.NotifyChange;
+import org.zkoss.json.JSONObject;
+import org.zkoss.zk.ui.Executions;
+import org.zkoss.zk.ui.event.Event;
+import org.zkoss.zk.ui.event.EventListener;
+import org.zkoss.zk.ui.select.annotation.VariableResolver;
+import org.zkoss.zk.ui.select.annotation.WireVariable;
+import org.zkoss.zkplus.spring.DelegatingVariableResolver;
+import org.zkoss.zul.Window;
+
+import java.util.Map;
+import java.util.Objects;
+
+@Getter
+@Log4j2
+@VariableResolver(DelegatingVariableResolver.class)
+public class ApproveInvoicesViewModel extends EntityViewModel<JSONObject> implements EventListener<Event> {
+ @WireVariable
+ ApproveInvoicesDataModel approveInvoicesDataModel;
+
+ @WireVariable
+ ProcessEventRouter processEventRouter;
+
+ @WireVariable
+ InvoiceRepository invoiceRepository;
+
+ @WireVariable
+ EventBus eventBus;
+
+ @Override
+ protected CachedSpringDataModel<JSONObject> getDataModel() {
+ return approveInvoicesDataModel;
+ }
+
+ @Override
+ protected String getNavigation() {
+ return Constants.NAV_IMPORT_INVOICES_APPROVE;
+ }
+
+ @Init
+ public void init() {
+ super.init();
+ }
+
+ @Command
+ @NotifyChange("approveInvoicesDataModel")
+ public void onRefresh() {
+ setSelectedEntity(null);
+ approveInvoicesDataModel.refresh();
+ BindUtils.postNotifyChange(this, "selectedEntity");
+ BindUtils.postNotifyChange(this, "approveInvoicesDataModel");
+ }
+
+ @Command
+ public void onHandleTask() {
+ Invoice entity = (Invoice) getSelectedEntity().get("invoiceEntity");
+ ImmutableMap<String, Object> args = ImmutableMap.of("formDocument", entity);
+ Window editorWindow = (Window) Executions.createComponents(Editors.IMPORT_INVOICE_APPROVE, null, args);
+ editorWindow.addEventListener("onClose", e -> {
+ if (Objects.nonNull(e.getData())) {
+ Map<String, Object> results = (Map<String, Object>) e.getData();
+ boolean approved = (boolean) results.get("approved");
+ Invoice modifiedEntity = (Invoice) results.get("modifiedEntity");
+ //TODO move entity persistance to BPMN
+ if (approved) {
+ invoiceRepository.save(modifiedEntity);
+ }
+ approveInvoicesDataModel.completeTask(getSelectedEntity(), results);
+ onRefresh();
+ }
+ });
+ editorWindow.doModal();
+ editorWindow.setFocus(true);
+ }
+
+ @Override
+ public void onEvent(Event event) throws Exception {
+ if (Constants.REFRESH_INVOICE_IMPORT_TASKS.equals(event.getName())) {
+ onRefresh();
+ log.info("Refreshed by {}", event.getData());
+ }
+ }
+}
--- /dev/null
+package hu.user.lis.ui.view;
+
+import com.google.common.collect.ImmutableMap;
+import hu.user.lis.db.Invoice;
+import hu.user.lis.ui.Constants;
+import hu.user.lis.ui.data.ImportInvoicesDataModel;
+import hu.user.lis.ui.data.common.CachedSpringDataModel;
+import hu.user.lis.ui.editor.common.Editors;
+import hu.user.lis.ui.event.EventBus;
+import hu.user.lis.ui.event.ProcessEventRouter;
+import hu.user.lis.ui.view.common.EntityViewModel;
+import hu.user.lis.workflow.invoice.service.WorkflowManagerService;
+import lombok.Getter;
+import lombok.extern.log4j.Log4j2;
+import org.zkoss.bind.BindUtils;
+import org.zkoss.bind.annotation.Command;
+import org.zkoss.bind.annotation.Destroy;
+import org.zkoss.bind.annotation.Init;
+import org.zkoss.json.JSONObject;
+import org.zkoss.zk.ui.event.Event;
+import org.zkoss.zk.ui.event.EventListener;
+import org.zkoss.zk.ui.select.annotation.VariableResolver;
+import org.zkoss.zk.ui.select.annotation.WireVariable;
+import org.zkoss.zkplus.spring.DelegatingVariableResolver;
+
+@Getter
+@Log4j2
+@VariableResolver(DelegatingVariableResolver.class)
+public class AssignInvoicesViewModel extends EntityViewModel<JSONObject> implements EventListener<Event> {
+ @WireVariable
+ ImportInvoicesDataModel importInvoicesDataModel;
+
+ @WireVariable
+ ProcessEventRouter processEventRouter;
+
+ @WireVariable
+ EventBus eventBus;
+
+ @WireVariable
+ WorkflowManagerService workflowManagerService;
+
+ @Override
+ protected CachedSpringDataModel<JSONObject> getDataModel() {
+ return importInvoicesDataModel;
+ }
+
+ @Override
+ protected String getNavigation() {
+ return Constants.NAV_IMPORT_INVOICES_ASSIGN;
+ }
+
+ @Init
+ public void init() {
+ super.init();
+ eventBus.registerForProcessEvent(this);
+ }
+
+ @Command
+ public void onRefresh() {
+ setSelectedEntity(null);
+ importInvoicesDataModel.refresh();
+ BindUtils.postNotifyChange(this, "selectedEntity");
+ BindUtils.postNotifyChange(this, "importInvoicesDataModel");
+ }
+
+ @Command
+ public void onHandleTask() {
+ Invoice entity = (Invoice) getSelectedEntity().get("invoiceEntity");
+ Editors.doEdit(Editors.IMPORT_INVOICE_ASSIGN, entity, modifiedEntity -> {
+ importInvoicesDataModel.completeTask(getSelectedEntity(), ImmutableMap.of("invoiceEntity", modifiedEntity));
+ onRefresh();
+ });
+ }
+
+ @Override
+ public void onEvent(Event event) throws Exception {
+ if (Constants.REFRESH_INVOICE_IMPORT_TASKS.equals(event.getName())) {
+ onRefresh();
+ log.info("Refreshed by {}", event.getData());
+ }
+ }
+
+ @Destroy
+ public void onDestroy() {
+ eventBus.unregister(this);
+ }
+}
import hu.user.lis.db.Associate;
import hu.user.lis.ui.Constants;
import hu.user.lis.ui.data.AssociatesDataModel;
-import hu.user.lis.ui.data.CachedSpringDataModel;
+import hu.user.lis.ui.data.common.CachedSpringDataModel;
import hu.user.lis.ui.editor.common.Editors;
import hu.user.lis.ui.view.common.FilterActiveViewModel;
import lombok.Getter;
import org.zkoss.zk.ui.select.annotation.WireVariable;
import org.zkoss.zul.Messagebox;
-import static hu.user.lis.ui.data.CachedDataModel.ASCENDING;
-import static hu.user.lis.ui.data.CachedDataModel.NATURAL;
+import static hu.user.lis.ui.data.common.CachedDataModel.ASCENDING;
+import static hu.user.lis.ui.data.common.CachedDataModel.NATURAL;
@Log4j2
public class AssociatesViewModel extends FilterActiveViewModel<Associate> {
package hu.user.lis.ui.view;
-import com.google.common.collect.ImmutableMap;
import hu.user.lis.ui.Constants;
import hu.user.lis.ui.auth.CurrentProfile;
import hu.user.lis.ui.editor.common.Editors;
import hu.user.lis.ui.event.EventBus;
import hu.user.lis.ui.session.SessionSettings;
+import hu.user.lis.workflow.invoice.service.WorkflowManagerService;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.log4j.Log4j2;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.select.annotation.VariableResolver;
import org.zkoss.zk.ui.select.annotation.WireVariable;
-
-import java.util.Map;
+import org.zkoss.zk.ui.util.Notification;
@Log4j2
@VariableResolver(org.zkoss.zkplus.spring.DelegatingVariableResolver.class)
@Getter
@Setter
-public class IndexViewModel implements EventListener {
- private static final String PARTNERS_LIST = "~./partners.zul";
+public class IndexViewModel implements EventListener<Event> {
+ // private static final String PARTNERS_LIST = "~./partners.zul";
private static final String PROJECTS_LIST = "~./projects.zul";
- private static final String ASSOCIATES_LIST = "~./associates.zul";
- private static final String PROJECT_ASSOCIATES_LIST = "~./project-associates.zul";
+ // private static final String ASSOCIATES_LIST = "~./associates.zul";
+// private static final String PROJECT_ASSOCIATES_LIST = "~./project-associates.zul";
private static final String SERVICE_RECORDS_LIST = "~./service-records.zul";
- private static final String SETTINGS_LIST = "~./settings.zul";
- public static Map<String, String> NAVIGATION = ImmutableMap.of(
- Constants.NAV_PARTNERS, PARTNERS_LIST,
- Constants.NAV_PROJECTS, PROJECTS_LIST,
- Constants.NAV_PROJECT, Editors.PROJECT,
- Constants.NAV_ASSOCIATES, ASSOCIATES_LIST,
- Constants.NAV_PROJECT_ASSOCIATES, PROJECT_ASSOCIATES_LIST,
- Constants.NAV_SERVICE_RECORDS, SERVICE_RECORDS_LIST,
- Constants.NAV_SETTINGS, SETTINGS_LIST
- );
+// private static final String SETTINGS_LIST = "~./settings.zul";
+// private static final String IMPORT_INVOICES_LIST = "~./import-invoices-assign.zul";
+// private static final String APPROVE_INVOICES_LIST = "~./import-invoices-approve.zul";
+//
+// public static Map<String, String> NAVIGATION = ImmutableMap.of(
+// Constants.NAV_PARTNERS, PARTNERS_LIST,
+// Constants.NAV_PROJECTS, PROJECTS_LIST,
+// Constants.NAV_PROJECT, Editors.PROJECT,
+// Constants.NAV_ASSOCIATES, ASSOCIATES_LIST,
+// Constants.NAV_PROJECT_ASSOCIATES, PROJECT_ASSOCIATES_LIST,
+// Constants.NAV_SERVICE_RECORDS, SERVICE_RECORDS_LIST,
+// Constants.NAV_SETTINGS, SETTINGS_LIST,
+// Constants.NAV_IMPORT_INVOICES, IMPORT_INVOICES_LIST,
+// Constants.NAV_APPROVE_INVOICES, IMPORT_INVOICES_LIST
+// );
+
+ @WireVariable
+ EventBus eventBus;
@WireVariable
BuildProperties buildProperties;
SessionSettings sessionSettings;
@WireVariable
- EventBus eventBus;
+ CurrentProfile currentProfile;
@WireVariable
- CurrentProfile currentProfile;
+ WorkflowManagerService workflowManagerService;
String searchPhrase;
}
private void route(String path) {
- if (path.startsWith("/project/") && path.split("/").length > 2) {
+ if (path.startsWith(Constants.NAV_PROJECTS + "/") && path.split("/").length > 2) {
String id = path.split("/")[2];
selectPage(Editors.PROJECT);
eventBus.setProjectEditorData(Long.parseLong(id));
} else {
- if (NAVIGATION.containsKey(path)) {
- setPage(NAVIGATION.get(path));
- } else {
- setPage(PARTNERS_LIST);
- }
+ if (Constants.NAV_ROOT.equals(path))
+ path = Constants.NAV_PARTNERS;
+ setPage("~." + path + ".zul");
}
}
@Destroy
public void onDestroy() {
- log.info("Destroy {}");
eventBus.unregister(this);
}
+
+ @Command
+ public void onStartImportInvoiceProcess() {
+ try {
+ workflowManagerService.startImportIncomingInvoicesProcess();
+ } catch (Exception e) {
+ Notification.show(e.getMessage(), true);
+ }
+ }
+
+ @Command
+ public void onCancelImportInvoiceProcess() {
+ workflowManagerService.cancelInvoiceImportProcess();
+ }
}
import com.google.common.collect.ImmutableMap;
import hu.user.lis.db.Partner;
import hu.user.lis.ui.Constants;
-import hu.user.lis.ui.data.CachedSpringDataModel;
import hu.user.lis.ui.data.PartnersDataModel;
+import hu.user.lis.ui.data.common.CachedSpringDataModel;
import hu.user.lis.ui.editor.common.Editors;
import hu.user.lis.ui.view.common.FilterActiveViewModel;
import lombok.Getter;
import org.zkoss.zk.ui.select.annotation.WireVariable;
import org.zkoss.zul.Messagebox;
-import static hu.user.lis.ui.data.CachedDataModel.ASCENDING;
-import static hu.user.lis.ui.data.CachedDataModel.NATURAL;
+import static hu.user.lis.ui.data.common.CachedDataModel.ASCENDING;
+import static hu.user.lis.ui.data.common.CachedDataModel.NATURAL;
@Log4j2
public class PartnersViewModel extends FilterActiveViewModel<Partner> {
import com.google.common.collect.ImmutableMap;
import hu.user.lis.db.Project;
import hu.user.lis.ui.Constants;
-import hu.user.lis.ui.data.CachedSpringDataModel;
import hu.user.lis.ui.data.ProjectsDataModel;
+import hu.user.lis.ui.data.common.CachedSpringDataModel;
import hu.user.lis.ui.event.EventBus;
import hu.user.lis.ui.view.common.FilterActiveViewModel;
import lombok.Getter;
import java.util.Map;
import java.util.Objects;
-import static hu.user.lis.ui.data.CachedDataModel.ASCENDING;
-import static hu.user.lis.ui.data.CachedDataModel.NATURAL;
+import static hu.user.lis.ui.data.common.CachedDataModel.ASCENDING;
+import static hu.user.lis.ui.data.common.CachedDataModel.NATURAL;
@Log4j2
import hu.user.lis.db.Project;
import hu.user.lis.db.ServiceRecord;
import hu.user.lis.ui.Constants;
-import hu.user.lis.ui.data.CachedSpringDataModel;
import hu.user.lis.ui.data.ServiceRecordsDataModel;
+import hu.user.lis.ui.data.common.CachedSpringDataModel;
import hu.user.lis.ui.editor.common.Editors;
import hu.user.lis.ui.editor.selector.EntitySelectorRouter;
import hu.user.lis.ui.event.EventBus;
import java.util.Map;
import java.util.Objects;
-import static hu.user.lis.ui.data.CachedDataModel.ASCENDING;
-import static hu.user.lis.ui.data.CachedDataModel.NATURAL;
+import static hu.user.lis.ui.data.common.CachedDataModel.ASCENDING;
+import static hu.user.lis.ui.data.common.CachedDataModel.NATURAL;
@Log4j2
package hu.user.lis.ui.view.common;
import hu.user.lis.services.data.EntityDataService;
-import hu.user.lis.ui.data.CachedSpringDataModel;
+import hu.user.lis.ui.data.common.CachedSpringDataModel;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.log4j.Log4j2;
--- /dev/null
+<?link rel="stylesheet" type="text/css" href="~./static/css/skeleton.css" ?>
+<?link rel="stylesheet" type="text/css" href="~./static/css/webclient.css" ?>
+<?component name="entity-selector" inline="true" class="hu.user.lis.ui.editor.widget.EntitySelector"?>
+<zk>
+ <zscript>
+ import hu.user.lis.db.Currency;
+ ListModelList currencies = new ListModelList(Currency.values());
+ </zscript>
+ <window id="invoiceApprovePopup" width="50%" height="400px" closable="true"
+ maximizable="true" sizable="true"
+ viewModel="@id('vm') @init('hu.user.lis.ui.editor.ImportInvoiceApproveEditorModel')">
+ <caption label="Számla import - Jóváhagyás"/>
+ <borderlayout>
+ <center border="none" vflex="true" hflex="true">
+ <tabbox vflex="true" hflex="true">
+ <tabs>
+ <tab label="Adatok" selected="true"/>
+ <tab label="Számlakép"/>
+ </tabs>
+ <tabpanels>
+ <tabpanel>
+ <vlayout hflex="true">
+ <label value="Projekt"/>
+ <entity-selector entity="Project" hflex="true"/>
+
+ <label value="Leírás"/>
+ <textbox hflex="true" instant="true"
+ value="@bind(vm.formDocument.title) @validator(vm)"
+ forward="onOK=submit.onClick, onCancel=cancel.onClick"/>
+ <label value="Partner"/>
+ <entity-selector entity="Partner"/>
+ <hlayout>
+ <vlayout>
+ <label value="Sorszám"/>
+ <textbox instant="true" value="@bind(vm.formDocument.humanId) @validator(vm)"
+ forward="onOK=submit.onClick, onCancel=cancel.onClick"/>
+ </vlayout>
+ <vlayout>
+ <label value="Pénznem"/>
+ <combobox instant="true" model="${currencies}"
+ selectedItem="@bind(vm.formDocument.currency) @validator(vm)"
+ onChange="@command('onNetAmountChange')"
+ forward="onOK=submit.onClick, onCancel=cancel.onClick"/>
+
+ </vlayout>
+ <vlayout>
+ <label value="Nettó összeg"/>
+ <doublebox value="@bind(vm.formDocument.netAmount) @validator(vm)"
+ format="#,###.##" locale="hu" instant="true"
+ onChange="@command('onNetAmountChange')"
+ forward="onOK=submit.onClick, onCancel=cancel.onClick"/>
+ </vlayout>
+ <vlayout>
+ <label value="Bruttó összeg"/>
+ <doublebox value="@bind(vm.formDocument.grossAmount) @validator(vm)"
+ format="#,###.##" locale="hu" instant="true"
+ forward="onOK=submit.onClick, onCancel=cancel.onClick"/>
+ </vlayout>
+ <vlayout>
+ <label value="ÁFA"/>
+ <doublebox value="@bind(vm.formDocument.vatAmount) @validator(vm)"
+ format="#,###.##" locale="hu" instant="true"
+ forward="onOK=submit.onClick, onCancel=cancel.onClick"/>
+ </vlayout>
+ </hlayout>
+ <hlayout>
+ <vlayout>
+ <label value="Kiállítás dátuma"/>
+ <datebox instant="true" format="yyyy. MM. dd."
+ value="@bind(vm.formDocument.createDate) @validator(vm)"
+ forward="onOK=submit.onClick, onCancel=cancel.onClick"/>
+ </vlayout>
+ <vlayout>
+ <label value="Teljesítés dátuma"/>
+ <datebox instant="true" format="yyyy. MM. dd."
+ value="@bind(vm.formDocument.completionDate) @validator(vm)"
+ forward="onOK=submit.onClick, onCancel=cancel.onClick"/>
+ </vlayout>
+ <vlayout>
+ <label value="Fizetési határidő"/>
+ <datebox instant="true" format="yyyy. MM. dd."
+ value="@bind(vm.formDocument.paymentDeadline) @validator(vm)"
+ forward="onOK=submit.onClick, onCancel=cancel.onClick"/>
+ </vlayout>
+ </hlayout>
+ </vlayout>
+ </tabpanel>
+ <tabpanel>
+ <borderlayout>
+ <north flex="true">
+ <toolbar>
+ <toolbarbutton label="Feltöltés" iconSclass="z-icon-plus" upload="true"
+ onUpload="@command('onUploadFile')"/>
+ <toolbarbutton label="Törlés" iconSclass="z-icon-remove"
+ onClick="@command('onRemoveFile')"
+ disabled="@load(empty vm.formDocument.file)"/>
+ </toolbar>
+ </north>
+ <center border="none" flex="true">
+ <iframe hflex="true" vflex="true"
+ content="@load(vm.formDocument.file) @converter('hu.user.lis.ui.converter.ByteArrayToAMediaConverter')"/>
+ </center>
+ </borderlayout>
+ </tabpanel>
+ </tabpanels>
+ </tabbox>
+
+ </center>
+ <south border="none" flex="true" style="text-align: right; padding: 10px;">
+ <hlayout>
+ <button id="cancel" label="Bezár"
+ onClick="@command('onCloseApproveWindow', target=invoiceApprovePopup, save=0)"/>
+ <button id="reject" label="Elutasít" style="border-color: red"
+ onClick="@command('onCloseApproveWindow', target=invoiceApprovePopup, save=1)"/>
+ <button id="submit" label="Jóváhagy" style="border-color: green"
+ onClick="@command('onCloseApproveWindow', target=invoiceApprovePopup, save=2)"
+ disabled="@bind(not vm.saveEnabled)"/>
+ </hlayout>
+ </south>
+ </borderlayout>
+ </window>
+</zk>
--- /dev/null
+<?link rel="stylesheet" type="text/css" href="~./static/css/skeleton.css" ?>
+<?link rel="stylesheet" type="text/css" href="~./static/css/webclient.css" ?>
+<?component name="entity-selector" inline="true" class="hu.user.lis.ui.editor.widget.EntitySelector"?>
+<zk>
+ <zscript>
+ import hu.user.lis.db.Currency;
+ ListModelList currencies = new ListModelList(Currency.values());
+ </zscript>
+ <window id="invoiceAssignPopup" width="50%" height="400px" closable="true"
+ maximizable="true" sizable="true"
+ viewModel="@id('vm') @init('hu.user.lis.ui.editor.ImportInvoiceAssignEditorModel')">
+ <caption label="Számla import - Csatolás"/>
+ <borderlayout>
+ <center border="none" vflex="true" hflex="true">
+ <tabbox vflex="true" hflex="true">
+ <tabs>
+ <tab label="Adatok" selected="true"/>
+ <tab label="Számlakép"/>
+ </tabs>
+ <tabpanels>
+ <tabpanel>
+ <vlayout hflex="true">
+ <label value="Projekt"/>
+ <entity-selector entity="Project" hflex="true"/>
+
+ <label value="Leírás"/>
+ <textbox hflex="true" instant="true"
+ value="@bind(vm.formDocument.title) @validator(vm)"
+ forward="onOK=submit.onClick, onCancel=cancel.onClick"/>
+ <label value="Partner"/>
+ <entity-selector entity="Partner"/>
+ <hlayout>
+ <vlayout>
+ <label value="Sorszám"/>
+ <textbox instant="true" value="@bind(vm.formDocument.humanId) @validator(vm)"
+ forward="onOK=submit.onClick, onCancel=cancel.onClick"/>
+ </vlayout>
+ <vlayout>
+ <label value="Pénznem"/>
+ <combobox instant="true" model="${currencies}"
+ selectedItem="@bind(vm.formDocument.currency) @validator(vm)"
+ onChange="@command('onNetAmountChange')"
+ forward="onOK=submit.onClick, onCancel=cancel.onClick"/>
+
+ </vlayout>
+ <vlayout>
+ <label value="Nettó összeg"/>
+ <doublebox value="@bind(vm.formDocument.netAmount) @validator(vm)"
+ format="#,###.##" locale="hu" instant="true"
+ onChange="@command('onNetAmountChange')"
+ forward="onOK=submit.onClick, onCancel=cancel.onClick"/>
+ </vlayout>
+ <vlayout>
+ <label value="Bruttó összeg"/>
+ <doublebox value="@bind(vm.formDocument.grossAmount) @validator(vm)"
+ format="#,###.##" locale="hu" instant="true"
+ forward="onOK=submit.onClick, onCancel=cancel.onClick"/>
+ </vlayout>
+ <vlayout>
+ <label value="ÁFA"/>
+ <doublebox value="@bind(vm.formDocument.vatAmount) @validator(vm)"
+ format="#,###.##" locale="hu" instant="true"
+ forward="onOK=submit.onClick, onCancel=cancel.onClick"/>
+ </vlayout>
+ </hlayout>
+ <hlayout>
+ <vlayout>
+ <label value="Kiállítás dátuma"/>
+ <datebox instant="true" format="yyyy. MM. dd."
+ value="@bind(vm.formDocument.createDate) @validator(vm)"
+ forward="onOK=submit.onClick, onCancel=cancel.onClick"/>
+ </vlayout>
+ <vlayout>
+ <label value="Teljesítés dátuma"/>
+ <datebox instant="true" format="yyyy. MM. dd."
+ value="@bind(vm.formDocument.completionDate) @validator(vm)"
+ forward="onOK=submit.onClick, onCancel=cancel.onClick"/>
+ </vlayout>
+ <vlayout>
+ <label value="Fizetési határidő"/>
+ <datebox instant="true" format="yyyy. MM. dd."
+ value="@bind(vm.formDocument.paymentDeadline) @validator(vm)"
+ forward="onOK=submit.onClick, onCancel=cancel.onClick"/>
+ </vlayout>
+ </hlayout>
+ </vlayout>
+ </tabpanel>
+ <tabpanel>
+ <borderlayout>
+ <north flex="true">
+ <toolbar>
+ <toolbarbutton label="Feltöltés" iconSclass="z-icon-plus" upload="true"
+ onUpload="@command('onUploadFile')"/>
+ <toolbarbutton label="Törlés" iconSclass="z-icon-remove"
+ onClick="@command('onRemoveFile')"
+ disabled="@load(empty vm.formDocument.file)"/>
+ </toolbar>
+ </north>
+ <center border="none" flex="true">
+ <iframe hflex="true" vflex="true"
+ content="@load(vm.formDocument.file) @converter('hu.user.lis.ui.converter.ByteArrayToAMediaConverter')"/>
+ </center>
+ </borderlayout>
+ </tabpanel>
+ </tabpanels>
+ </tabbox>
+
+ </center>
+ <south border="none" flex="true" style="text-align: right; padding: 10px;">
+ <hlayout>
+ <button id="cancel" label="Bezár"
+ onClick="@command('onCloseWindow', target=invoiceAssignPopup, save=false)"/>
+ <button id="submit" label="Mentés"
+ onClick="@command('onCloseWindow', target=invoiceAssignPopup, save=true)"
+ disabled="@bind(not vm.saveEnabled)"/>
+ </hlayout>
+ </south>
+ </borderlayout>
+ </window>
+</zk>
--- /dev/null
+<zk>
+ <window vflex="true" viewModel="@id('vm') @init('hu.user.lis.ui.view.ApproveInvoicesViewModel')">
+ <!-- <timer id="timer" delay="1000" repeats="true" onTimer="@command('uiTick')"/>-->
+ <caption label="Számla import - Jóváhagyás"/>
+
+ <borderlayout>
+ <north flex="true">
+ <toolbar>
+ <toolbarbutton label="Frissít" iconSclass="z-icon-refresh"
+ onClick="@command('onRefresh')"/>
+ <!-- <toolbarbutton label="Léptet" iconSclass="z-icon-tasks"-->
+ <!-- onClick="@command('onCompleteTask')" disabled="@load(empty vm.selectedEntity)"/>-->
+ </toolbar>
+ </north>
+ <center border="none" flex="true">
+ <listbox id="importInvoicesList" vflex="true" model="@load(vm.approveInvoicesDataModel)"
+ autopaging="true" mold="paging" pagingPosition="top" multiple="false"
+ onSelect="@command('onListSelection')" onDoubleClick="@command('onHandleTask')">
+ <listhead sizable="true">
+ <listheader label="Azonosító" sort="auto(humanId)" align="left"/>
+ <listheader label="Partner" sort="auto(partner.name)" align="left"/>
+ </listhead>
+ <template name="model">
+ <listitem>
+ <listcell label="@load(each['invoiceEntity'].humanId)"/>
+ <listcell label="@load(each['invoiceEntity'].partner.name)"/>
+ </listitem>
+ </template>
+ </listbox>
+ </center>
+ </borderlayout>
+ </window>
+</zk>
\ No newline at end of file
--- /dev/null
+<zk>
+ <window vflex="true" viewModel="@id('vm') @init('hu.user.lis.ui.view.AssignInvoicesViewModel')">
+ <!-- <timer id="timer" delay="1000" repeats="true" onTimer="@command('uiTick')"/>-->
+ <caption label="Számla import - Csatolás"/>
+
+ <borderlayout>
+ <north flex="true">
+ <toolbar>
+ <toolbarbutton label="Frissít" iconSclass="z-icon-refresh"
+ onClick="@command('onRefresh')"/>
+ <!-- <toolbarbutton label="Léptet" iconSclass="z-icon-tasks"-->
+ <!-- onClick="@command('onHandleTask')" disabled="@load(empty vm.selectedEntity)"/>-->
+ </toolbar>
+ </north>
+ <center border="none" flex="true">
+ <listbox id="importInvoicesList" vflex="true" model="@load(vm.importInvoicesDataModel)"
+ autopaging="true" mold="paging" pagingPosition="top" multiple="false"
+ onSelect="@command('onListSelection')" onDoubleClick="@command('onHandleTask')">
+ <listhead sizable="true">
+ <listheader label="Azonosító" sort="auto(humanId)" align="left"/>
+ <listheader label="Partner" sort="auto(partner.name)" align="left"/>
+ </listhead>
+ <template name="model">
+ <listitem>
+ <listcell label="@load(each['invoiceEntity'].humanId)"/>
+ <listcell label="@load(each['invoiceEntity'].partner.name)"/>
+ </listitem>
+ </template>
+ </listbox>
+ </center>
+ </borderlayout>
+ </window>
+</zk>
\ No newline at end of file
<menuseparator/>
<menuitem iconSclass="z-icon-user" label="Munkatársak"
onClick="@command(vm.selectPage('~./associates.zul'))"/>
+ <menu iconSclass="z-icon-tasks" label="Számla import">
+ <menupopup>
+ <menuitem iconSclass="z-icon-paperclip" label="Csatolás"
+ onClick="@command(vm.selectPage('~./import-invoices-assign.zul'))"/>
+ <menuitem iconSclass="z-icon-check-square-o" label="Jóváhagyás"
+ onClick="@command(vm.selectPage('~./import-invoices-approve.zul'))"/>
+ <menuseparator/>
+ <menuitem iconSclass="z-icon-code-fork" label="Import elindítása"
+ onClick="@command('onStartImportInvoiceProcess')"/>
+ <menuitem iconSclass="z-icon-times-circle-o" label="Import leállítása"
+ onClick="@command('onCancelImportInvoiceProcess')"/>
+ </menupopup>
+ </menu>
<menuseparator/>
<menuitem iconSclass="z-icon-cogs" label="Beállítások"
onClick="@command(vm.selectPage('~./settings.zul'))"/>
+ <!-- <menuitem iconSclass="z-icon-cogs" label="Camunda"-->
+ <!-- onClick="@command(vm.selectPage('/camunda'))"/>-->
</menubar>
<hbox hflex="min" pack="right">
<textbox value="@bind(vm.searchPhrase)" onOK="@command('search')" disabled="true"></textbox>
<artifactId>camunda-bpm-spring-boot-starter-rest</artifactId>
<version>${camunda.spring-boot.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-context</artifactId>
+ </dependency>
</dependencies>
</project>
--- /dev/null
+package hu.user.lis.workflow.event;
+
+public class ImportInvoicesEvent extends ProcessEvent {
+ public ImportInvoicesEvent(Object source) {
+ super(source);
+ }
+}
--- /dev/null
+package hu.user.lis.workflow.event;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.context.ApplicationEvent;
+
+@Getter
+@Setter
+public class ProcessEvent extends ApplicationEvent {
+
+ private String name;
+ private String key;
+ private String id;
+ private String eventType;
+
+ public ProcessEvent(Object source) {
+ super(source);
+ }
+}
package hu.user.lis.workflow.invoice;
-import hu.user.lis.db.Invoice;
-import hu.user.lis.db.Partner;
+import hu.user.lis.db.IncomingInvoice;
import hu.user.lis.db.repository.InvoiceRepository;
-import hu.user.lis.db.repository.PartnerRepository;
+import hu.user.lis.workflow.invoice.service.IncomingInvoiceFetcherService;
import lombok.extern.log4j.Log4j2;
-import org.apache.commons.lang3.RandomUtils;
import org.camunda.bpm.engine.delegate.DelegateExecution;
import org.camunda.bpm.engine.delegate.JavaDelegate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
-import java.util.List;
-
@Log4j2
@Component
public class DownloadInvoiceData implements JavaDelegate {
@Autowired
InvoiceRepository invoiceRepository;
+
@Autowired
- PartnerRepository partnerRepository;
+ IncomingInvoiceFetcherService incomingInvoiceFetcherService;
+
@Override
public void execute(DelegateExecution delegateExecution) throws Exception {
- String invoiceHumanId = (String) delegateExecution.getVariableLocal("invoice");
- log.info("Processing incoice {}", invoiceHumanId);
- Invoice invoice = Invoice.builder()
- .humanId(invoiceHumanId)
- .partner(getRandomPartner())
- .build();
+ String humanId = (String) delegateExecution.getVariable("invoice");
+ log.info("Processing invoice {}", humanId);
+ IncomingInvoice invoice = incomingInvoiceFetcherService.getInvoice(humanId);
invoiceRepository.save(invoice);
- log.info("Invoice {} processed", invoiceHumanId);
+ delegateExecution.setVariableLocal("invoiceEntity", invoice);
+ log.info("Invoice {} processed", humanId);
}
- private Partner getRandomPartner() {
- List<Partner> partners = partnerRepository.findAll();
- return partners.get(RandomUtils.nextInt(0, partners.size()));
- }
}
package hu.user.lis.workflow.invoice;
+import hu.user.lis.workflow.invoice.service.IncomingInvoiceFetcherService;
import lombok.extern.log4j.Log4j2;
import org.camunda.bpm.engine.delegate.DelegateExecution;
import org.camunda.bpm.engine.delegate.JavaDelegate;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
-import java.util.Arrays;
import java.util.List;
@Log4j2
@Component
public class ListNewInvoices implements JavaDelegate {
+ @Autowired
+ IncomingInvoiceFetcherService incomingInvoiceFetcherService;
+
@Override
public void execute(DelegateExecution delegateExecution) throws Exception {
log.info("Executing");
- List<String> invoices = Arrays.asList("Invoice-test-1", "Invoice-test-2", "Invoice-test-3");
+ List<String> invoices = incomingInvoiceFetcherService.getNewInvoices();
delegateExecution.setVariableLocal("invoices", invoices);
}
}
--- /dev/null
+package hu.user.lis.workflow.invoice.service;
+
+import hu.user.lis.db.Currency;
+import hu.user.lis.db.IncomingInvoice;
+import hu.user.lis.db.Partner;
+import hu.user.lis.db.repository.PartnerRepository;
+import hu.user.lis.services.data.DataGeneratorService;
+import org.apache.commons.lang3.RandomUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+@Service
+public class IncomingInvoiceFetcherService {
+ private static final SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
+ @Autowired
+ private PartnerRepository partnerRepository;
+ @Autowired
+ private DataGeneratorService dataGeneratorService;
+
+ public List<String> getNewInvoices() {
+ return Arrays.asList("Invoice-test-1", "Invoice-test-2", "Invoice-test-3");
+ }
+
+ public IncomingInvoice getInvoice(String humanId) throws Exception {
+ int currencyIndex = RandomUtils.nextInt(0, 3);
+ String title = dataGeneratorService.faker().commerce().productName();
+ Currency currency = Arrays.stream(Currency.values()).filter(p -> p.getVal() == currencyIndex).findFirst().orElse(Currency.HUF);
+ Date completionDate = dataGeneratorService.faker().date().between(formatter.parse("2010-01-01"), new Date());
+ Date createDate = dataGeneratorService.faker().date().past(RandomUtils.nextInt(6, 20), TimeUnit.DAYS, completionDate);
+ Date paymentDeadline = dataGeneratorService.faker().date().future(1, TimeUnit.DAYS, completionDate);
+ double netAmount = RandomUtils.nextFloat(5000, 1000000);
+ double grossAmount = netAmount * 1.27;
+ double vatAmount = grossAmount - netAmount;
+ return IncomingInvoice.builder()
+ .humanId(humanId)
+ .title(title)
+ .currency(currency)
+ .partner(getRandomPartner())
+ .completionDate(completionDate)
+ .createDate(createDate)
+ .paymentDeadline(paymentDeadline)
+ .completionDate(completionDate)
+ .createDate(createDate)
+ .paymentDeadline(paymentDeadline)
+ .netAmount(netAmount)
+ .grossAmount(grossAmount)
+ .vatAmount(vatAmount)
+ .income(true)
+ .build();
+ }
+
+ private Partner getRandomPartner() {
+ List<Partner> partners = partnerRepository.findAll();
+ return partners.get(RandomUtils.nextInt(0, partners.size()));
+ }
+}
--- /dev/null
+package hu.user.lis.workflow.invoice.service;
+
+import hu.user.lis.workflow.event.ImportInvoicesEvent;
+import lombok.extern.log4j.Log4j2;
+import org.camunda.bpm.engine.RuntimeService;
+import org.camunda.bpm.engine.TaskService;
+import org.camunda.bpm.engine.impl.history.event.HistoryEvent;
+import org.camunda.bpm.engine.runtime.ProcessInstance;
+import org.camunda.bpm.engine.task.Task;
+import org.camunda.bpm.spring.boot.starter.event.ExecutionEvent;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.context.event.EventListener;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Map;
+
+@Log4j2
+@Service
+public class WorkflowManagerService {
+ @Autowired
+ private ApplicationEventPublisher applicationEventPublisher;
+
+ @Autowired
+ private RuntimeService runtimeService;
+
+ @Autowired
+ private TaskService taskService;
+
+ public void startImportIncomingInvoicesProcess() throws Exception {
+ long instanceCount = runtimeService.createProcessInstanceQuery().processDefinitionKey("importIncomingInvoices").active().count();
+ if (instanceCount > 0) {
+ throw new Exception("A számla import folyamat 1 példányban futhat!");
+ }
+ runtimeService.startProcessInstanceByKey("importIncomingInvoices");
+ }
+
+ public Map<String, Object> getVariables(String id) {
+ return taskService.getVariables(id);
+ }
+
+ public List<Task> listAssignInvoiceTasks() {
+ List<Task> taskList = taskService.createTaskQuery().taskDefinitionKey("assignProjectAndAttachFile").list();
+ return taskList;
+ }
+
+ public List<Task> listApproveInvoiceTasks() {
+ List<Task> taskList = taskService.createTaskQuery().taskDefinitionKey("approveAssignment").list();
+ return taskList;
+ }
+
+ public void cancelInvoiceImportProcess() {
+ List<ProcessInstance> processInstances = runtimeService.createProcessInstanceQuery().processDefinitionKey("importIncomingInvoices").list();
+ processInstances.forEach(p -> {
+ log.info("Killing {} {}", p.getProcessInstanceId(), p.getProcessDefinitionId());
+ try {
+ runtimeService.deleteProcessInstance(p.getProcessInstanceId(), "Canceled");
+ } catch (Exception e) {
+ }
+ });
+ }
+
+ @EventListener
+ public void onExecutionEvent(ExecutionEvent executionEvent) {
+// log.info("ExecutionEvent {}", executionEvent.getEventName());
+//
+// if ("assignProjectAndAttachFile".equals(executionEvent.getCurrentActivityId())) {
+// ImportInvoicesEvent event = new ImportInvoicesEvent(this);
+// event.setId(executionEvent.getProcessInstanceId());
+// event.setEventType(executionEvent.getEventName());
+// applicationEventPublisher.publishEvent(event);
+// }
+// if ("end".equals(executionEvent.getEventName())) {
+// }
+ }
+
+ @EventListener
+ public void onHistoryEvent(HistoryEvent historyEvent) {
+ log.info("HistoryEvent {}", historyEvent.getEventType());
+ if ("importIncomingInvoices".equals(historyEvent.getProcessDefinitionKey())) {
+ ImportInvoicesEvent event = new ImportInvoicesEvent(this);
+ event.setId(historyEvent.getProcessInstanceId());
+ event.setKey(historyEvent.getProcessDefinitionKey());
+ event.setName(historyEvent.getProcessDefinitionName());
+ event.setEventType(historyEvent.getEventType());
+
+ applicationEventPublisher.publishEvent(event);
+ }
+
+ }
+
+ public void completeTask(String taskId) {
+ taskService.complete(taskId);
+ }
+
+ public void completeTask(String taskId, Map<String, Object> vars) {
+ taskService.complete(taskId, vars);
+ }
+}
<?xml version="1.0" encoding="UTF-8"?>
-<bpmn:definitions xmlns:bpmn="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:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:modeler="http://camunda.org/schema/modeler/1.0" id="Definitions_07nj4df" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.14.0" modeler:executionPlatform="Camunda Platform" modeler:executionPlatformVersion="7.15.0">
+<bpmn:definitions xmlns:bpmn="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:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:modeler="http://camunda.org/schema/modeler/1.0" id="Definitions_07nj4df" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.14.0" modeler:executionPlatform="Camunda Platform" modeler:executionPlatformVersion="7.15.0">
<bpmn:process id="importIncomingInvoices" name="Import Incoming Invoices" isExecutable="true" camunda:versionTag="0.1">
<bpmn:startEvent id="StartEvent_1" camunda:asyncBefore="true">
<bpmn:outgoing>Flow_1gzempz</bpmn:outgoing>
<bpmn:serviceTask id="Activity_0q29ngn" name="List new invoices" camunda:asyncBefore="true" camunda:delegateExpression="${listNewInvoices}">
<bpmn:extensionElements />
<bpmn:incoming>Flow_1gzempz</bpmn:incoming>
- <bpmn:outgoing>Flow_15jorzs</bpmn:outgoing>
+ <bpmn:outgoing>Flow_0y5cjps</bpmn:outgoing>
</bpmn:serviceTask>
- <bpmn:sequenceFlow id="Flow_15jorzs" sourceRef="Activity_0q29ngn" targetRef="Activity_02fjt6a" />
- <bpmn:serviceTask id="Activity_02fjt6a" name="Download invoice datas" camunda:asyncBefore="true" camunda:delegateExpression="${downloadInvoiceData}">
- <bpmn:extensionElements />
- <bpmn:incoming>Flow_15jorzs</bpmn:incoming>
- <bpmn:outgoing>Flow_1v1bne3</bpmn:outgoing>
- <bpmn:multiInstanceLoopCharacteristics camunda:asyncBefore="true" camunda:collection="invoices" camunda:elementVariable="invoice" />
- </bpmn:serviceTask>
- <bpmn:endEvent id="Event_0ots211">
- <bpmn:incoming>Flow_1v1bne3</bpmn:incoming>
+ <bpmn:subProcess id="assignAndApproveInvoices" name="Assign and approve">
+ <bpmn:incoming>Flow_0y5cjps</bpmn:incoming>
+ <bpmn:outgoing>Flow_0vgb0nw</bpmn:outgoing>
+ <bpmn:multiInstanceLoopCharacteristics camunda:collection="invoices" camunda:elementVariable="invoice" />
+ <bpmn:startEvent id="Event_1v3e1za">
+ <bpmn:outgoing>Flow_1ubjpz9</bpmn:outgoing>
+ </bpmn:startEvent>
+ <bpmn:endEvent id="Event_1cc91rc">
+ <bpmn:incoming>Flow_0uvj71q</bpmn:incoming>
+ </bpmn:endEvent>
+ <bpmn:sequenceFlow id="Flow_00r2v71" sourceRef="approveAssignment" targetRef="Gateway_1folrc8" />
+ <bpmn:userTask id="assignProjectAndAttachFile" name="Assign invoice">
+ <bpmn:extensionElements />
+ <bpmn:incoming>Flow_14m4iht</bpmn:incoming>
+ <bpmn:incoming>Flow_0efz1ox</bpmn:incoming>
+ <bpmn:outgoing>Flow_0c887e2</bpmn:outgoing>
+ </bpmn:userTask>
+ <bpmn:sequenceFlow id="Flow_0c887e2" sourceRef="assignProjectAndAttachFile" targetRef="approveAssignment" />
+ <bpmn:userTask id="approveAssignment" name="Approve invoice assignment">
+ <bpmn:incoming>Flow_0c887e2</bpmn:incoming>
+ <bpmn:outgoing>Flow_00r2v71</bpmn:outgoing>
+ </bpmn:userTask>
+ <bpmn:serviceTask id="Activity_02fjt6a" name="Download invoice datas" camunda:asyncBefore="true" camunda:delegateExpression="${downloadInvoiceData}">
+ <bpmn:extensionElements />
+ <bpmn:incoming>Flow_1ubjpz9</bpmn:incoming>
+ <bpmn:outgoing>Flow_14m4iht</bpmn:outgoing>
+ </bpmn:serviceTask>
+ <bpmn:sequenceFlow id="Flow_1ubjpz9" sourceRef="Event_1v3e1za" targetRef="Activity_02fjt6a" />
+ <bpmn:sequenceFlow id="Flow_14m4iht" sourceRef="Activity_02fjt6a" targetRef="assignProjectAndAttachFile" />
+ <bpmn:exclusiveGateway id="Gateway_1folrc8" default="Flow_0uvj71q">
+ <bpmn:incoming>Flow_00r2v71</bpmn:incoming>
+ <bpmn:outgoing>Flow_0uvj71q</bpmn:outgoing>
+ <bpmn:outgoing>Flow_0efz1ox</bpmn:outgoing>
+ </bpmn:exclusiveGateway>
+ <bpmn:sequenceFlow id="Flow_0uvj71q" sourceRef="Gateway_1folrc8" targetRef="Event_1cc91rc" />
+ <bpmn:sequenceFlow id="Flow_0efz1ox" sourceRef="Gateway_1folrc8" targetRef="assignProjectAndAttachFile">
+ <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">${not approved}</bpmn:conditionExpression>
+ </bpmn:sequenceFlow>
+ </bpmn:subProcess>
+ <bpmn:endEvent id="Event_07aly41">
+ <bpmn:incoming>Flow_0vgb0nw</bpmn:incoming>
</bpmn:endEvent>
- <bpmn:sequenceFlow id="Flow_1v1bne3" sourceRef="Activity_02fjt6a" targetRef="Event_0ots211" />
+ <bpmn:sequenceFlow id="Flow_0vgb0nw" sourceRef="assignAndApproveInvoices" targetRef="Event_07aly41" />
+ <bpmn:sequenceFlow id="Flow_0y5cjps" sourceRef="Activity_0q29ngn" targetRef="assignAndApproveInvoices" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="importIncomingInvoices">
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
- <dc:Bounds x="179" y="99" width="36" height="36" />
+ <dc:Bounds x="179" y="159" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0hxl7uq_di" bpmnElement="Activity_0q29ngn">
- <dc:Bounds x="270" y="77" width="100" height="80" />
+ <dc:Bounds x="270" y="137" width="100" height="80" />
+ </bpmndi:BPMNShape>
+ <bpmndi:BPMNShape id="Event_07aly41_di" bpmnElement="Event_07aly41">
+ <dc:Bounds x="1272" y="159" width="36" height="36" />
+ </bpmndi:BPMNShape>
+ <bpmndi:BPMNShape id="Activity_0u274ph_di" bpmnElement="assignAndApproveInvoices" isExpanded="true">
+ <dc:Bounds x="420" y="77" width="800" height="203" />
+ <bpmndi:BPMNLabel />
+ </bpmndi:BPMNShape>
+ <bpmndi:BPMNShape id="Event_1v3e1za_di" bpmnElement="Event_1v3e1za">
+ <dc:Bounds x="460.33333333333337" y="159" width="36" height="36" />
+ </bpmndi:BPMNShape>
+ <bpmndi:BPMNShape id="Activity_08g5whq_di" bpmnElement="assignProjectAndAttachFile">
+ <dc:Bounds x="710" y="137" width="100" height="80" />
+ <bpmndi:BPMNLabel />
+ </bpmndi:BPMNShape>
+ <bpmndi:BPMNShape id="Activity_003yviv_di" bpmnElement="approveAssignment">
+ <dc:Bounds x="870" y="137" width="100" height="80" />
+ <bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_035tjqs_di" bpmnElement="Activity_02fjt6a">
- <dc:Bounds x="430" y="77" width="100" height="80" />
+ <dc:Bounds x="550" y="137" width="100" height="80" />
</bpmndi:BPMNShape>
- <bpmndi:BPMNShape id="Event_0ots211_di" bpmnElement="Event_0ots211">
- <dc:Bounds x="592" y="99" width="36" height="36" />
+ <bpmndi:BPMNShape id="Gateway_1folrc8_di" bpmnElement="Gateway_1folrc8" isMarkerVisible="true">
+ <dc:Bounds x="1025" y="152" width="50" height="50" />
</bpmndi:BPMNShape>
+ <bpmndi:BPMNShape id="Event_1cc91rc_di" bpmnElement="Event_1cc91rc">
+ <dc:Bounds x="1122" y="159" width="36" height="36" />
+ </bpmndi:BPMNShape>
+ <bpmndi:BPMNEdge id="Flow_00r2v71_di" bpmnElement="Flow_00r2v71">
+ <di:waypoint x="970" y="177" />
+ <di:waypoint x="1025" y="177" />
+ </bpmndi:BPMNEdge>
+ <bpmndi:BPMNEdge id="Flow_0c887e2_di" bpmnElement="Flow_0c887e2">
+ <di:waypoint x="810" y="177" />
+ <di:waypoint x="870" y="177" />
+ </bpmndi:BPMNEdge>
+ <bpmndi:BPMNEdge id="Flow_1ubjpz9_di" bpmnElement="Flow_1ubjpz9">
+ <di:waypoint x="496" y="177" />
+ <di:waypoint x="550" y="177" />
+ </bpmndi:BPMNEdge>
+ <bpmndi:BPMNEdge id="Flow_14m4iht_di" bpmnElement="Flow_14m4iht">
+ <di:waypoint x="650" y="177" />
+ <di:waypoint x="710" y="177" />
+ </bpmndi:BPMNEdge>
+ <bpmndi:BPMNEdge id="Flow_0uvj71q_di" bpmnElement="Flow_0uvj71q">
+ <di:waypoint x="1075" y="177" />
+ <di:waypoint x="1122" y="177" />
+ </bpmndi:BPMNEdge>
+ <bpmndi:BPMNEdge id="Flow_0efz1ox_di" bpmnElement="Flow_0efz1ox">
+ <di:waypoint x="1050" y="202" />
+ <di:waypoint x="1050" y="240" />
+ <di:waypoint x="760" y="240" />
+ <di:waypoint x="760" y="217" />
+ </bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1gzempz_di" bpmnElement="Flow_1gzempz">
- <di:waypoint x="215" y="117" />
- <di:waypoint x="270" y="117" />
+ <di:waypoint x="215" y="177" />
+ <di:waypoint x="270" y="177" />
</bpmndi:BPMNEdge>
- <bpmndi:BPMNEdge id="Flow_15jorzs_di" bpmnElement="Flow_15jorzs">
- <di:waypoint x="370" y="117" />
- <di:waypoint x="430" y="117" />
+ <bpmndi:BPMNEdge id="Flow_0vgb0nw_di" bpmnElement="Flow_0vgb0nw">
+ <di:waypoint x="1220" y="177" />
+ <di:waypoint x="1272" y="177" />
</bpmndi:BPMNEdge>
- <bpmndi:BPMNEdge id="Flow_1v1bne3_di" bpmnElement="Flow_1v1bne3">
- <di:waypoint x="530" y="117" />
- <di:waypoint x="592" y="117" />
+ <bpmndi:BPMNEdge id="Flow_0y5cjps_di" bpmnElement="Flow_0y5cjps">
+ <di:waypoint x="370" y="177" />
+ <di:waypoint x="420" y="177" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>