<modelVersion>4.0.0</modelVersion>
<groupId>hu.user</groupId>
<artifactId>lis-app</artifactId>
- <version>0.0.3-SNAPSHOT</version>
+ <version>0.0.4-SNAPSHOT</version>
<parent>
<groupId>hu.user</groupId>
<artifactId>lis</artifactId>
package hu.user.lis.db;
+
+import lombok.Getter;
+
+@Getter
public enum Currency {
- HUF, USD, EURO
+ HUF(0), USD(1), EURO(2);
+ final int val;
+
+ Currency(int val) {
+ this.val = val;
+ }
+
+
}
import lombok.*;
-import java.time.LocalDate;
+import java.util.Date;
@Getter
@Setter
double netAmount;
double grossAmount;
double vatAmount;
- LocalDate completionDate;
- LocalDate createDate;
- LocalDate paymentDeadline;
+ Date completionDate;
+ Date createDate;
+ Date paymentDeadline;
}
import lombok.*;
+import java.util.List;
+
@Getter
@Setter
@Builder
String contactName;
Partner partner;
boolean active;
+ List<Invoice> incomingInvoices;
+ List<Invoice> outgoingInvoices;
+
}
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
- <dependency>
- <groupId>com.fasterxml.jackson.core</groupId>
- <artifactId>jackson-databind</artifactId>
- </dependency>
</dependencies>
</project>
Invoice copy(Invoice sourceEntity) throws JsonProcessingException;
+ String toString(Invoice sourceEntity) throws JsonProcessingException;
+
+ Invoice copy(Invoice sourceEntity, String property, Object value) throws JsonProcessingException, NoSuchFieldException, IllegalAccessException;
+
void replace(Invoice targetEntity, Invoice replacementEntity);
+
+ List<Invoice> getRandom(boolean income);
}
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
+import hu.user.lis.db.Currency;
import hu.user.lis.db.Invoice;
+import hu.user.lis.db.Partner;
import org.apache.commons.lang3.RandomStringUtils;
+import org.apache.commons.lang3.RandomUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
+import java.lang.reflect.Field;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
import java.util.List;
+import java.util.concurrent.TimeUnit;
@Service
public class InvoiceServiceImpl implements InvoiceService {
- private List<Invoice> entities;
+ int GENERATE_COUNT = 1000;
+ private List<Invoice> incomingEntities;
+ private List<Invoice> outgoingEntities;
@Autowired
DataGeneratorService dataGeneratorService;
-
+ @Autowired
+ PartnerService partnerService;
@Autowired
ObjectMapper mapper;
@Override
public List<Invoice> getAll() {
- if (entities == null) {
- entities = generate();
+ if (incomingEntities == null) {
+ try {
+ incomingEntities = generate(true);
+ } catch (ParseException e) {
+ throw new RuntimeException(e);
+ }
}
- return entities;
+ if (outgoingEntities == null) {
+ try {
+ outgoingEntities = generate(false);
+ } catch (ParseException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ ArrayList<Invoice> result = new ArrayList<>(incomingEntities);
+ result.addAll(outgoingEntities);
+ return result;
}
@Override
@Override
public void add(Invoice entity) {
- entities.add(entity);
- }
-
- @Override
- public Invoice copy(Invoice sourceEntity) throws JsonProcessingException {
- ObjectMapper mapper = new ObjectMapper();
- String json = mapper.writeValueAsString(sourceEntity);
- return mapper.readValue(json, Invoice.class);
}
@Override
public void replace(Invoice targetEntity, Invoice replacementEntity) {
- Invoice listEntity = entities.stream().filter(p -> p.getId().equals(targetEntity.getId())).findFirst().get();
- entities.remove(listEntity);
- entities.add(replacementEntity);
}
- private List<Invoice> generate() {
+ private List<Invoice> generate(boolean income) throws ParseException {
List<Invoice> result = new ArrayList<>();
- for (int i = 0; i < 100; i++) {
+
+ SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
+ for (int i = 0; i < GENERATE_COUNT; i++) {
String id = RandomStringUtils.random(8, "0123456789abcdef");
String title = dataGeneratorService.faker().commerce().productName();
- Invoice entity = Invoice.builder().id(id).title(title).build();
+ Partner partner = partnerService.getRandom();
+ 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);
+ int currencyIndex = RandomUtils.nextInt(0, 3);
+ Currency currency = Arrays.stream(Currency.values())
+ .filter(p -> p.getVal() == currencyIndex)
+ .findFirst().get();
+ double netAmount = RandomUtils.nextFloat(5000, 1000000);
+ double grossAmount = netAmount * 1.27;
+ double vatAmount = grossAmount - netAmount;
+ Invoice entity = Invoice.builder()
+ .id(id)
+ .title(title)
+ .currency(currency)
+ .partner(partner)
+ .completionDate(completionDate)
+ .createDate(createDate)
+ .paymentDeadline(paymentDeadline)
+ .netAmount(netAmount)
+ .grossAmount(grossAmount)
+ .vatAmount(vatAmount)
+ .income(income)
+ .build();
result.add(entity);
}
return result;
}
+
+ @Override
+ public List<Invoice> getRandom(boolean income) {
+ getAll();
+ int count = RandomUtils.nextInt(10, 20);
+ List<Invoice> result = new ArrayList<>();
+ for (int i = 0; i < count; i++) {
+ int index = RandomUtils.nextInt(0, 500);
+ if (income) {
+ result.add(incomingEntities.get(index));
+ } else {
+ result.add(outgoingEntities.get(index));
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public Invoice copy(Invoice sourceEntity) throws JsonProcessingException {
+ String json = toString(sourceEntity);
+ return mapper.readValue(json, Invoice.class);
+ }
+
+ @Override
+ public String toString(Invoice sourceEntity) throws JsonProcessingException {
+ return mapper.writeValueAsString(sourceEntity);
+ }
+
+ @Override
+ public Invoice copy(Invoice sourceEntity, String property, Object value) throws JsonProcessingException, NoSuchFieldException, IllegalAccessException {
+ Invoice result = copy(sourceEntity);
+ Field field = result.getClass().getDeclaredField(property);
+ field.setAccessible(true);
+ field.set(result, value);
+ return result;
+ }
}
void replace(Partner targetEntity, Partner replacementEntity);
Partner getRandom();
+
+ String toString(Partner sourceEntity) throws JsonProcessingException;
+
+ Partner copy(Partner sourceEntity, String property, Object value) throws JsonProcessingException, NoSuchFieldException, IllegalAccessException;
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
+import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
entities.add(entity);
}
- @Override
- public Partner copy(Partner sourceEntity) throws JsonProcessingException {
- ObjectMapper mapper = new ObjectMapper();
- String json = mapper.writeValueAsString(sourceEntity);
- return mapper.readValue(json, Partner.class);
- }
-
@Override
public void replace(Partner targetEntity, Partner replacementEntity) {
Partner listEntity = entities.stream().filter(p -> p.getId().equals(targetEntity.getId())).findFirst().get();
}
return result;
}
+
+ @Override
+ public Partner copy(Partner sourceEntity) throws JsonProcessingException {
+ String json = toString(sourceEntity);
+ return mapper.readValue(json, Partner.class);
+ }
+
+ @Override
+ public String toString(Partner sourceEntity) throws JsonProcessingException {
+ return mapper.writeValueAsString(sourceEntity);
+ }
+
+ @Override
+ public Partner copy(Partner sourceEntity, String property, Object value) throws JsonProcessingException, NoSuchFieldException, IllegalAccessException {
+ Partner result = copy(sourceEntity);
+ Field field = result.getClass().getDeclaredField(property);
+ field.setAccessible(true);
+ field.set(result, value);
+ return result;
+ }
}
boolean isInvalid(Project entity);
- String toString(Project entity);
+ String toString(Project sourceEntity) throws JsonProcessingException;
+
+ Project copy(Project sourceEntity, String property, Object value) throws JsonProcessingException, NoSuchFieldException, IllegalAccessException;
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
+import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@Autowired
PartnerService partnerService;
+ @Autowired
+ InvoiceService invoiceService;
+
@Override
public List<Project> getAll() {
if (entities == null) {
public Project createNew() {
String id = RandomStringUtils.random(8, "0123456789abcdef");
String humanId = dataGeneratorService.faker().code().isbn13(true);
- return Project.builder().id(id).humanId(humanId).active(true).build();
+ return Project.builder()
+ .id(id)
+ .humanId(humanId)
+ .incomingInvoices(new ArrayList<>())
+ .outgoingInvoices(new ArrayList<>())
+ .active(true)
+ .build();
}
@Override
entities.add(entity);
}
- @Override
- public Project copy(Project sourceEntity) throws JsonProcessingException {
- ObjectMapper mapper = new ObjectMapper();
- String json = mapper.writeValueAsString(sourceEntity);
- return mapper.readValue(json, Project.class);
- }
-
@Override
public void replace(Project targetEntity, Project replacementEntity) {
Project partnerInList = entities.stream().filter(p -> p.getId().equals(targetEntity.getId())).findFirst().get();
.name(name)
.contactName(contactName)
.partner(partner)
+ .incomingInvoices(invoiceService.getRandom(true))
+ .outgoingInvoices(invoiceService.getRandom(false))
.build();
result.add(entity);
}
}
@Override
- public String toString(Project entity) {
- ObjectMapper mapper = new ObjectMapper();
- try {
- return mapper.writeValueAsString(entity);
- } catch (JsonProcessingException e) {
- log.catching(e);
- }
- return null;
+ public Project copy(Project sourceEntity) throws JsonProcessingException {
+ String json = toString(sourceEntity);
+ return mapper.readValue(json, Project.class);
+ }
+
+ @Override
+ public String toString(Project sourceEntity) throws JsonProcessingException {
+ return mapper.writeValueAsString(sourceEntity);
+ }
+
+ @Override
+ public Project copy(Project sourceEntity, String property, Object value) throws JsonProcessingException, NoSuchFieldException, IllegalAccessException {
+ Project result = copy(sourceEntity);
+ Field field = result.getClass().getDeclaredField(property);
+ field.setAccessible(true);
+ field.set(result, value);
+ return result;
}
}
-package hu.user.lis.ui;
+package hu.user.lis.ui.config;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
public String admin() {
return "admin/index";
}
+
+ @GetMapping("/projects")
+ public String projects() {
+ return "index";
+ }
}
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
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.bind.BindUtils;
import org.zkoss.zul.FieldComparator;
@Component
@Log4j2
+@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class PartnerSelectorDataModel extends CachedDataModel<Partner> {
static private final int SEARCH_LIMIT = 10;
private String partialName;
import lombok.extern.log4j.Log4j2;
import org.springframework.boot.info.BuildProperties;
import org.zkoss.bind.annotation.Init;
+import org.zkoss.zk.ui.Executions;
+import org.zkoss.zk.ui.event.Event;
+import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.select.annotation.VariableResolver;
import org.zkoss.zk.ui.select.annotation.WireVariable;
+import javax.servlet.http.HttpServletRequest;
+
@Log4j2
@VariableResolver(org.zkoss.zkplus.spring.DelegatingVariableResolver.class)
+@Getter
+@Setter
public class IndexViewModel {
- @Getter
@WireVariable
BuildProperties buildProperties;
-
- @Getter
- @Setter
String searchPhrase;
+ int selectedPage;
+
@Init
public void init() {
- log.info("Init");
+ HttpServletRequest nativeRequest = (HttpServletRequest) Executions.getCurrent().getNativeRequest();
+ String path = (String) Executions.getCurrent().getAttribute("javax.servlet.forward.servlet_path");
+ if ("/projects".equals(path)) {
+ Events.postEvent(new Event("onFulFillProjectsTab"));
+ }
+ log.info("Init {}", path);
}
+
}
--- /dev/null
+package hu.user.lis.ui.view;
+
+import hu.user.lis.db.Currency;
+import hu.user.lis.db.Invoice;
+import hu.user.lis.services.data.InvoiceService;
+import hu.user.lis.ui.data.PartnerSelectorDataModel;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.extern.log4j.Log4j2;
+import org.apache.commons.lang3.StringUtils;
+import org.zkoss.bind.BindContext;
+import org.zkoss.bind.BindUtils;
+import org.zkoss.bind.ValidationContext;
+import org.zkoss.bind.annotation.*;
+import org.zkoss.bind.validator.AbstractValidator;
+import org.zkoss.zk.ui.Component;
+import org.zkoss.zk.ui.Executions;
+import org.zkoss.zk.ui.event.Event;
+import org.zkoss.zk.ui.event.Events;
+import org.zkoss.zk.ui.event.InputEvent;
+import org.zkoss.zk.ui.event.OpenEvent;
+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.Objects;
+
+@Log4j2
+@Getter
+@Setter
+@VariableResolver(DelegatingVariableResolver.class)
+public class InvoiceEditorModel extends AbstractValidator {
+ private Invoice origDocument;
+ private Invoice formDocument;
+ @WireVariable
+ private PartnerSelectorDataModel partnerSelectorDataModel;
+ @WireVariable
+ private InvoiceService invoiceServiceImpl;
+ private boolean formInvalid = true;
+
+ @Init
+ public void init() {
+ log.info("Initialized");
+ origDocument = (Invoice) Executions.getCurrent().getArg().get("origDocument");
+ formDocument = (Invoice) Executions.getCurrent().getArg().get("formDocument");
+ partnerSelectorDataModel.clearSelection();
+ }
+
+ @Command
+ public void onNetAmountChange() {
+ if (Currency.HUF.equals(formDocument.getCurrency())) {
+ formDocument.setGrossAmount(formDocument.getNetAmount() * 1.27);
+ formDocument.setVatAmount(formDocument.getGrossAmount() - formDocument.getNetAmount());
+ BindUtils.postNotifyChange(this.formDocument, "grossAmount", "vatAmount");
+ }
+ }
+
+ @Command
+ public void onCloseWindow(@BindingParam("target") Window target, @BindingParam("select") boolean select) {
+ if (select && formInvalid) {
+ return;
+ }
+ Event closeEvent = new Event("onClose", target, select ? formDocument : null);
+ Events.postEvent(closeEvent);
+ }
+
+ @Command
+ public void onPartnerBandChanging(@ContextParam(ContextType.BIND_CONTEXT) BindContext ctx) {
+ InputEvent event = (InputEvent) ctx.getTriggerEvent();
+ log.info("onPartnerBandChanging: {}", event.getValue());
+ partnerSelectorDataModel.search(event.getValue());
+ }
+
+ @Command
+ public void onPartnerBandOpen(@ContextParam(ContextType.BIND_CONTEXT) BindContext ctx) {
+ OpenEvent event = (OpenEvent) ctx.getTriggerEvent();
+ log.info("onPartnerBandOpen: {}", event.isOpen());
+ partnerSelectorDataModel.search(null);
+ }
+
+ @Override
+ @NotifyChange("formInvalid")
+ public void validate(ValidationContext ctx) {
+ Component target = ctx.getBindContext().getComponent();
+ String property = ctx.getProperty().getProperty();
+ Object value = ctx.getProperty().getValue();
+ log.info("Validating caused by {} {} {}", target.getId(), property, value);
+ updateFormInvalid(false);
+ try {
+ Invoice newData = invoiceServiceImpl.copy(formDocument, property, value);
+ if (!Objects.isNull(origDocument) && invoiceServiceImpl.toString(origDocument).equals(invoiceServiceImpl.toString(newData))) {
+ log.info("Document not changed");
+ updateFormInvalid(true);
+ return;
+ }
+
+ if (newData.getNetAmount() <= 0 ||
+ newData.getGrossAmount() <= 0 ||
+ newData.getVatAmount() <= 0 ||
+ StringUtils.isBlank(newData.getTitle()) ||
+ Objects.isNull(newData.getPartner()) ||
+ Objects.isNull(newData.getCompletionDate()) ||
+ Objects.isNull(newData.getCreateDate()) ||
+ Objects.isNull(newData.getPaymentDeadline()) ||
+ newData.getCreateDate().after(newData.getCompletionDate()) ||
+ newData.getCompletionDate().after(newData.getPaymentDeadline())
+ ) {
+ log.info("Document is not valid");
+ updateFormInvalid(true);
+ }
+ } catch (Exception e) {
+ log.catching(e);
+ }
+
+ }
+
+ private void updateFormInvalid(boolean invalid) {
+ setFormInvalid(invalid);
+ BindUtils.postNotifyChange(this, "formInvalid");
+ }
+}
package hu.user.lis.ui.view;
import hu.user.lis.db.Partner;
+import hu.user.lis.services.data.PartnerService;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.log4j.Log4j2;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.Events;
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;
@VariableResolver(DelegatingVariableResolver.class)
public class PartnerEditorModel extends AbstractValidator {
private Partner formDocument;
- private boolean formInvalid;
+ private Partner origDocument;
+ private boolean formInvalid = true;
+ @WireVariable
+ PartnerService partnerServiceImpl;
@Init
public void init() {
log.info("Initialized");
+ origDocument = (Partner) Executions.getCurrent().getArg().get("origDocument");
formDocument = (Partner) Executions.getCurrent().getArg().get("formDocument");
}
String property = ctx.getProperty().getProperty();
Object value = ctx.getProperty().getValue();
log.info("Validating caused by {} {} {}", target.getId(), property, value);
- boolean invalid = Objects.isNull(value) || StringUtils.isBlank(Objects.toString(value));
+ updateFormInvalid(false);
+ try {
+ Partner newData = partnerServiceImpl.copy(formDocument, property, value);
+ if (!Objects.isNull(origDocument) && partnerServiceImpl.toString(origDocument).equals(partnerServiceImpl.toString(newData))) {
+ log.info("Document not changed");
+ updateFormInvalid(true);
+ return;
+ }
+ if (StringUtils.isBlank(newData.getName()) ||
+ StringUtils.isBlank(newData.getAddress()) ||
+ StringUtils.isBlank(newData.getVatNr())
+ ) {
+ log.info("Document is not valid");
+ updateFormInvalid(true);
+ }
+
+
+ } catch (Exception e) {
+ log.catching(e);
+ }
+ }
+
+ private void updateFormInvalid(boolean invalid) {
setFormInvalid(invalid);
BindUtils.postNotifyChange(this, "formInvalid");
}
import org.zkoss.zul.Window;
import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
import java.util.Set;
@Log4j2
}
@Command
- public void onAddNew() {
+ public void onAdd() {
String page = "~./partner.zul";
- Partner editPartner = partnersDataModel.getPartnerService().createNew();
- Window partnerWindow = (Window) Executions.createComponents(page, null,
- Collections.singletonMap("formDocument", editPartner));
- partnerWindow.addEventListener("onClose", e -> {
+ Partner newEntity = partnersDataModel.getPartnerService().createNew();
+ Window editorWindow = (Window) Executions.createComponents(page, null,
+ Collections.singletonMap("formDocument", newEntity));
+ editorWindow.addEventListener("onClose", e -> {
if (e.getData() != null) {
log.info("Partner popup result {}", e.getData());
- partnersDataModel.getPartnerService().add(editPartner);
+ partnersDataModel.getPartnerService().add(newEntity);
partnersDataModel.clearSelection();
refresh();
- partnersDataModel.addToSelection(editPartner);
+ partnersDataModel.addToSelection(newEntity);
+ selectedPartner = newEntity;
+
// Optional<Listitem> listItem = partnersList.getItems().stream()
-// .filter(li -> ((Partner) li.getValue()).getId().equals(editPartner.getId()))
+// .filter(li -> ((Partner) li.getValue()).getId().equals(newEntity.getId()))
// .findFirst();
// if (listItem.isPresent()) {
// Clients.scrollIntoView(listItem.get());
// });
}
});
- partnerWindow.doModal();
+ editorWindow.doModal();
}
@Command
public void onEdit() throws JsonProcessingException {
String page = "~./partner.zul";
- Partner editPartner = partnersDataModel.getPartnerService().copy(selectedPartner);
- Window partnerWindow = (Window) Executions.createComponents(page, null,
- Collections.singletonMap("formDocument", editPartner));
- partnerWindow.addEventListener("onClose", e -> {
+ Partner editEntity = partnersDataModel.getPartnerService().copy(selectedPartner);
+ Map<String, Object> arg = new HashMap<>();
+ arg.put("origDocument", selectedPartner);
+ arg.put("formDocument", editEntity);
+ Window editorWindow = (Window) Executions.createComponents(page, null, arg);
+ editorWindow.addEventListener("onClose", e -> {
if (e.getData() != null) {
log.info("Partner popup result {}", e.getData());
Partner modifiedEntity = (Partner) e.getData();
selectedPartner = modifiedEntity;
}
});
- partnerWindow.doModal();
+ editorWindow.doModal();
}
package hu.user.lis.ui.view;
-import hu.user.lis.db.Partner;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import hu.user.lis.db.Invoice;
import hu.user.lis.db.Project;
+import hu.user.lis.services.data.InvoiceService;
+import hu.user.lis.services.data.ProjectService;
import hu.user.lis.ui.data.PartnerSelectorDataModel;
-import hu.user.lis.ui.data.ProjectsDataModel;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.log4j.Log4j2;
import org.zkoss.zkplus.spring.DelegatingVariableResolver;
import org.zkoss.zul.Window;
-import java.util.Objects;
+import java.util.*;
@Log4j2
@Getter
@VariableResolver(DelegatingVariableResolver.class)
public class ProjectEditorModel extends AbstractValidator {
private Project formDocument;
- private Partner selectedPartner;
+ private Project origDocument;
@WireVariable
private PartnerSelectorDataModel partnerSelectorDataModel;
@WireVariable
- private ProjectsDataModel projectsDataModel;
- private boolean formInvalid;
+ private InvoiceService invoiceServiceImpl;
+ @WireVariable
+ private ProjectService projectServiceImpl;
+ private boolean formInvalid = true;
+ private Invoice selectedIncomingInvoice;
+ private Invoice selectedOutgoingInvoice;
@Init
public void init() {
log.info("Initialized");
+ origDocument = (Project) Executions.getCurrent().getArg().get("origDocument");
formDocument = (Project) Executions.getCurrent().getArg().get("formDocument");
- selectedPartner = formDocument.getPartner();
partnerSelectorDataModel.clearSelection();
}
if (e.getData() != null) {
partnerSelectorDataModel.clearSelection();
//setSelectedSupplierId(((Supplier) e.getData()).getId());
- BindUtils.postNotifyChange(null, null, this, "selectedSupplierId");
+ BindUtils.postNotifyChange(this, "selectedSupplierId");
}
});
suppliersWindow.doModal();
}
- @NotifyChange({"selectedPartner"})
- public void setSelectedPartner(Partner selectedPartner) {
- this.selectedPartner = selectedPartner;
- formDocument.setPartner(selectedPartner);
- }
-
@Override
public void validate(ValidationContext ctx) {
Component target = ctx.getBindContext().getComponent();
String property = ctx.getProperty().getProperty();
Object value = ctx.getProperty().getValue();
log.info("Validating caused by {} {} {}", target.getId(), property, value);
- boolean invalid = Objects.isNull(value) || StringUtils.isBlank(Objects.toString(value));
+ try {
+ Project newData = projectServiceImpl.copy(formDocument, property, value);
+ validate(newData);
+ } catch (Exception e) {
+ log.catching(e);
+ }
+ }
+
+ private void validate(Project newData) throws JsonProcessingException {
+ updateFormInvalid(false);
+ if (!Objects.isNull(origDocument) && projectServiceImpl.toString(origDocument).equals(projectServiceImpl.toString(newData))) {
+ log.info("Document not changed");
+ updateFormInvalid(true);
+ return;
+ }
+
+ if (StringUtils.isBlank(newData.getName()) ||
+ StringUtils.isBlank(newData.getContactName()) ||
+ Objects.isNull(newData.getPartner())
+ ) {
+ log.info("Document is not valid");
+ updateFormInvalid(true);
+ }
+ }
+
+ @Command
+ public void onAddIncoming() {
+ String page = "~./invoice.zul";
+ Invoice editEntity = invoiceServiceImpl.createNew();
+ editEntity.setIncome(true);
+ Window editorWindow = (Window) Executions.createComponents(page, null,
+ Collections.singletonMap("formDocument", editEntity));
+ editorWindow.addEventListener("onClose", e -> {
+ if (e.getData() != null) {
+ formDocument.getIncomingInvoices().add(editEntity);
+ selectedIncomingInvoice = editEntity;
+ BindUtils.postNotifyChange(this, "selectedIncomingInvoice");
+ BindUtils.postNotifyChange(this.formDocument, "incomingInvoices");
+ Project newData = projectServiceImpl.copy(formDocument);
+ validate(newData);
+ }
+ });
+ editorWindow.doModal();
+ }
+
+ @Command
+ public void onEditIncoming() throws JsonProcessingException {
+ String page = "~./invoice.zul";
+ Invoice editEntity = invoiceServiceImpl.copy(selectedIncomingInvoice);
+ Map<String, Object> arg = new HashMap<>();
+ arg.put("origDocument", selectedIncomingInvoice);
+ arg.put("formDocument", editEntity);
+ Window editorWindow = (Window) Executions.createComponents(page, null, arg);
+ editorWindow.addEventListener("onClose", e -> {
+ if (e.getData() != null) {
+ Invoice modifiedEntity = (Invoice) e.getData();
+ List<Invoice> incomingInvoices = formDocument.getIncomingInvoices();
+ int index = incomingInvoices.indexOf(selectedIncomingInvoice);
+ incomingInvoices.remove(selectedIncomingInvoice);
+ incomingInvoices.add(index, modifiedEntity);
+ selectedIncomingInvoice = modifiedEntity;
+ BindUtils.postNotifyChange(this, "selectedIncomingInvoice");
+ BindUtils.postNotifyChange(this.formDocument, "incomingInvoices");
+ Project newData = projectServiceImpl.copy(formDocument);
+ validate(newData);
+ }
+ });
+ editorWindow.doModal();
+ }
+
+ @Command
+ public void onRemoveIncoming() {
+ if (selectedIncomingInvoice == null) {
+ return;
+ }
+ formDocument.getIncomingInvoices().remove(selectedIncomingInvoice);
+ selectedIncomingInvoice = null;
+ BindUtils.postNotifyChange(this, "selectedIncomingInvoice");
+ BindUtils.postNotifyChange(this.formDocument, "incomingInvoices");
+ }
+
+ @Command
+ public void onAddOutgoing() {
+ String page = "~./invoice.zul";
+ Invoice editEntity = invoiceServiceImpl.createNew();
+ Window editorWindow = (Window) Executions.createComponents(page, null,
+ Collections.singletonMap("formDocument", editEntity));
+ editorWindow.addEventListener("onClose", e -> {
+ if (e.getData() != null) {
+ formDocument.getOutgoingInvoices().add(editEntity);
+ selectedOutgoingInvoice = editEntity;
+ BindUtils.postNotifyChange(this, "selectedOutgoingInvoice");
+ BindUtils.postNotifyChange(this.formDocument, "outgoingInvoices");
+ Project newData = projectServiceImpl.copy(formDocument);
+ validate(newData);
+ }
+ });
+ editorWindow.doModal();
+ }
+
+ @Command
+ public void onEditOutgoing() throws JsonProcessingException {
+ String page = "~./invoice.zul";
+ Invoice editEntity = invoiceServiceImpl.copy(selectedOutgoingInvoice);
+ Map<String, Object> arg = new HashMap<>();
+ arg.put("origDocument", selectedOutgoingInvoice);
+ arg.put("formDocument", editEntity);
+ Window editorWindow = (Window) Executions.createComponents(page, null, arg);
+ editorWindow.addEventListener("onClose", e -> {
+ if (e.getData() != null) {
+ Invoice modifiedEntity = (Invoice) e.getData();
+ List<Invoice> outgoingInvoices = formDocument.getOutgoingInvoices();
+ int index = outgoingInvoices.indexOf(selectedOutgoingInvoice);
+ outgoingInvoices.remove(selectedOutgoingInvoice);
+ outgoingInvoices.add(index, modifiedEntity);
+ selectedOutgoingInvoice = modifiedEntity;
+ BindUtils.postNotifyChange(this, "selectedOutgoingInvoice");
+ BindUtils.postNotifyChange(this.formDocument, "outgoingInvoices");
+ Project newData = projectServiceImpl.copy(formDocument);
+ validate(newData);
+ }
+ });
+ editorWindow.doModal();
+ }
+
+ @Command
+ public void onRemoveOutgoing() {
+ if (selectedOutgoingInvoice == null) {
+ return;
+ }
+ formDocument.getOutgoingInvoices().remove(selectedOutgoingInvoice);
+ selectedOutgoingInvoice = null;
+ BindUtils.postNotifyChange(this, "selectedOutgoingInvoice");
+ BindUtils.postNotifyChange(this.formDocument, "outgoingInvoices");
+ }
+
+ private void updateFormInvalid(boolean invalid) {
setFormInvalid(invalid);
BindUtils.postNotifyChange(this, "formInvalid");
}
import org.zkoss.zul.Window;
import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
import java.util.Set;
@Log4j2
}
@Command
- public void onAddNew() {
+ public void onAdd() {
String page = "~./project.zul";
- Project editEntity = projectsDataModel.getProjectService().createNew();
+ Project newEntity = projectsDataModel.getProjectService().createNew();
Window partnerWindow = (Window) Executions.createComponents(page, null,
- Collections.singletonMap("formDocument", editEntity));
+ Collections.singletonMap("formDocument", newEntity));
partnerWindow.addEventListener("onClose", e -> {
if (e.getData() != null) {
log.info("Partner popup result {}", e.getData());
- projectsDataModel.getProjectService().add(editEntity);
+ projectsDataModel.getProjectService().add(newEntity);
projectsDataModel.clearSelection();
refresh();
- projectsDataModel.addToSelection(editEntity);
+ projectsDataModel.addToSelection(newEntity);
+ selectedProject = newEntity;
// Optional<Listitem> listItem = partnersList.getItems().stream()
// .filter(li -> ((Partner) li.getValue()).getId().equals(editPartner.getId()))
// .findFirst();
public void onEdit() throws JsonProcessingException {
String page = "~./project.zul";
Project editEntity = projectsDataModel.getProjectService().copy(selectedProject);
- Window partnerWindow = (Window) Executions.createComponents(page, null,
- Collections.singletonMap("formDocument", editEntity));
+ Map<String, Object> arg = new HashMap<>();
+ arg.put("origDocument", selectedProject);
+ arg.put("formDocument", editEntity);
+
+ Window partnerWindow = (Window) Executions.createComponents(page, null, arg);
partnerWindow.addEventListener("onClose", e -> {
if (e.getData() != null) {
log.info("Project popup result {}", e.getData());
</hlayout>
</north>
<center border="none" hflex="true">
- <tabbox id="mainContent" vflex="true" hflex="true" orient="top">
+ <tabbox id="mainContent" vflex="true" hflex="true" orient="top" selectedIndex="@bind(vm.selectedPage)">
<tabs visible="false">
<tab id="tab0" label="Partnerek" selected="true"/>
<tab id="tab1" label="Projektek"/>
<tabpanel id="partnersTab">
<partners/>
</tabpanel>
- <tabpanel id="projectsTab" fulfill="self.linkedTab.onSelect, projectsMenuItem.onClick">
+ <tabpanel id="projectsTab"
+ fulfill="self.linkedTab.onSelect, projectsMenuItem.onClick, onFulFillProjectsTab">
<projects/>
</tabpanel>
</tabpanels>
--- /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="partner-selector" inline="true" macroURI="~./partner-selector.zul"?>
+<zk>
+ <zscript>
+ import hu.user.lis.db.Currency;
+ ListModelList currencies = new ListModelList(Currency.values());
+ </zscript>
+ <window id="invoicePopup" title="Számla szerkesztés" width="50%" height="50%" closable="true"
+ viewModel="@id('vm') @init('hu.user.lis.ui.view.InvoiceEditorModel')">
+ <borderlayout>
+ <center border="none" vflex="true" hflex="true">
+ <tabbox vflex="true" hflex="true">
+ <tabs>
+ <tab label="Adatok" selected="true"/>
+ </tabs>
+ <tabpanels>
+ <tabpanel>
+ <vlayout 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"/>
+ <partner-selector/>
+ <hlayout>
+ <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="#.##" 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="#.##" instant="true"
+ forward="onOK=submit.onClick, onCancel=cancel.onClick"/>
+ </vlayout>
+ <vlayout>
+ <label value="ÁFA"/>
+ <doublebox value="@bind(vm.formDocument.vatAmount) @validator(vm)"
+ format="#.##" instant="true"
+ forward="onOK=submit.onClick, onCancel=cancel.onClick"/>
+ </vlayout>
+ </hlayout>
+ <hlayout>
+ <vlayout>
+ <label value="Kiállítás dátuma"/>
+ <datebox instant="true" locale="hu"
+ 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" locale="hu"
+ 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" locale="hu"
+ value="@bind(vm.formDocument.paymentDeadline) @validator(vm)"
+ forward="onOK=submit.onClick, onCancel=cancel.onClick"/>
+ </vlayout>
+ </hlayout>
+ <label value="Bevétel számla"/>
+ <checkbox mold="switch" checked="@bind(vm.formDocument.income)" disabled="true"/>
+ </vlayout>
+ </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=invoicePopup, select=false)"/>
+ <button id="submit" label="Mentés"
+ onClick="@command('onCloseWindow', target=invoicePopup, select=true)"
+ disabled="@bind(vm.formInvalid)"/>
+ </hlayout>
+ </south>
+ </borderlayout>
+ </window>
+</zk>
\ No newline at end of file
<zk xmlns:c="client">
<hlayout>
<bandbox id="bd" autodrop="true" iconSclass="z-icon-sort-down"
- value="@load(vm.selectedPartner) @converter('hu.user.lis.ui.converter.PartnerToNameConverter')"
+ value="@load(vm.formDocument.partner) @converter('hu.user.lis.ui.converter.PartnerToNameConverter')"
onChanging="@command('onPartnerBandChanging')" onOpen="@command('onPartnerBandOpen')"
forward="onOK=submit.onClick, onCancel=cancel.onClick">
<attribute c:name="_doKeyDown">
<bandpopup>
<listbox id="bd-list" height="250px" width="450px"
model="@bind(vm.partnerSelectorDataModel)"
- selectedItem="@bind(vm.selectedPartner) @validator(vm)"
+ selectedItem="@bind(vm.formDocument.partner) @validator(vm)"
onClick="bd.close()"
onDoubleClick="bd.close()">
<listhead visible="false">
viewModel="@id('vm') @init('hu.user.lis.ui.view.PartnerEditorModel')">
<borderlayout>
<center border="none" vflex="true" hflex="true">
- <vlayout hflex="true">
- <label value="Név"/>
- <textbox hflex="true" instant="true" value="@bind(vm.formDocument.name) @validator(vm)"
- forward="onOK=submit.onClick, onCancel=cancel.onClick"/>
- <label value="Adószám"/>
- <textbox hflex="true" instant="true" value="@bind(vm.formDocument.vatNr) @validator(vm)"
- forward="onOK=submit.onClick, onCancel=cancel.onClick"/>
- <label value="Cím"/>
- <textbox hflex="true" instant="true" value="@bind(vm.formDocument.address) @validator(vm)"
- forward="onOK=submit.onClick, onCancel=cancel.onClick"/>
- <label value="Aktív"/>
- <checkbox mold="switch" checked="@bind(vm.formDocument.active)"/>
- </vlayout>
+ <tabbox vflex="true" hflex="true">
+ <tabs>
+ <tab label="Adatok" selected="true"/>
+ </tabs>
+ <tabpanels>
+ <tabpanel>
+ <vlayout hflex="true">
+ <label value="Név"/>
+ <textbox hflex="true" instant="true" value="@bind(vm.formDocument.name) @validator(vm)"
+ forward="onOK=submit.onClick, onCancel=cancel.onClick"/>
+ <label value="Adószám"/>
+ <textbox hflex="true" instant="true" value="@bind(vm.formDocument.vatNr) @validator(vm)"
+ forward="onOK=submit.onClick, onCancel=cancel.onClick"/>
+ <label value="Cím"/>
+ <textbox hflex="true" instant="true"
+ value="@bind(vm.formDocument.address) @validator(vm)"
+ forward="onOK=submit.onClick, onCancel=cancel.onClick"/>
+ <label value="Aktív"/>
+ <checkbox mold="switch" checked="@bind(vm.formDocument.active)"/>
+ </vlayout>
+ </tabpanel>
+ </tabpanels>
+ </tabbox>
</center>
- <south flex="true" style="text-align: right; padding: 10px">
+ <south border="none" flex="true" style="text-align: right; padding: 10px">
<hlayout>
<button id="cancel" label="Bezár"
onClick="@command('onCloseWindow', target=partnerPopup, select=false)"/>
<borderlayout>
<north flex="true">
<toolbar>
- <toolbarbutton label="Új partner" iconSclass="z-icon-plus" onClick="@command('onAddNew')"/>
+ <toolbarbutton label="Hozzáadás" iconSclass="z-icon-plus" onClick="@command('onAdd')"/>
<toolbarbutton label="Szerkesztés" iconSclass="z-icon-edit" onClick="@command('onEdit')"
disabled="@load(empty vm.selectedPartner)"/>
<separator orient="vertical"/>
<?link rel="stylesheet" type="text/css" href="~./static/css/webclient.css" ?>
<?component name="partner-selector" inline="true" macroURI="~./partner-selector.zul"?>
<zk>
- <window id="currentPopup" title="Projekt szerkesztés" width="60%" height="40%" closable="true"
+ <window id="projectPopup" title="Projekt szerkesztés" width="60%" height="80%" closable="true"
viewModel="@id('vm') @init('hu.user.lis.ui.view.ProjectEditorModel')">
<borderlayout>
<center border="none" vflex="true" hflex="true">
- <vlayout hflex="true">
- <label value="Azonosító"/>
- <textbox hflex="true" instant="true"
- value="@bind(vm.formDocument.humanId) @validator(vm)"
- readonly="true"
- forward="onOK=submit.onClick, onCancel=cancel.onClick"/>
- <label value="Név"/>
- <textbox hflex="true" instant="true"
- value="@bind(vm.formDocument.name) @validator(vm)"
- forward="onOK=submit.onClick, onCancel=cancel.onClick"/>
- <label value="Kapcsolattartó"/>
- <textbox hflex="true" instant="true"
- value="@bind(vm.formDocument.contactName) @validator(vm)"
- forward="onOK=submit.onClick, onCancel=cancel.onClick"/>
- <label value="Partner"/>
- <partner-selector/>
- <label value="Aktív"/>
- <checkbox mold="switch" checked="@bind(vm.formDocument.active)"/>
- </vlayout>
+ <tabbox vflex="true" hflex="true">
+ <tabs>
+ <tab label="Adatok" selected="true"/>
+ <tab label="Számlák"/>
+ </tabs>
+ <tabpanels>
+ <tabpanel>
+ <vlayout hflex="true">
+ <label value="Azonosító"/>
+ <textbox hflex="true" instant="true"
+ value="@bind(vm.formDocument.humanId) @validator(vm)"
+ readonly="true"
+ forward="onOK=submit.onClick, onCancel=cancel.onClick"/>
+ <label value="Név"/>
+ <textbox hflex="true" instant="true"
+ value="@bind(vm.formDocument.name) @validator(vm)"
+ forward="onOK=submit.onClick, onCancel=cancel.onClick"/>
+ <label value="Kapcsolattartó"/>
+ <textbox hflex="true" instant="true"
+ value="@bind(vm.formDocument.contactName) @validator(vm)"
+ forward="onOK=submit.onClick, onCancel=cancel.onClick"/>
+ <label value="Partner"/>
+ <partner-selector/>
+ <label value="Aktív"/>
+ <checkbox mold="switch" checked="@bind(vm.formDocument.active)"/>
+ </vlayout>
+ </tabpanel>
+ <tabpanel>
+ <hbox spacing="0" width="100%" height="100%">
+ <window title="Bevétel" border="none" hflex="true" vflex="true">
+ <borderlayout>
+ <north border="none" flex="true">
+ <toolbar>
+ <toolbarbutton label="Hozzáadás" iconSclass="z-icon-plus"
+ onClick="@command('onAddIncoming')"/>
+ <toolbarbutton label="Szerkesztés" iconSclass="z-icon-edit"
+ onClick="@command('onEditIncoming')"
+ disabled="@load(empty vm.selectedIncomingInvoice)"/>
+ <toolbarbutton label="Törlés" iconSclass="z-icon-remove"
+ onClick="@command('onRemoveIncoming')"
+ disabled="@load(empty vm.selectedIncomingInvoice)"/>
+ </toolbar>
+ </north>
+ <center border="none" flex="true">
+ <listbox vflex="true" model="@load(vm.formDocument.incomingInvoices)"
+ selectedItem="@bind(vm.selectedIncomingInvoice)"
+ onDoubleClick="@command('onEditIncoming')"
+ forward="onOK=submit.onClick, onCancel=cancel.onClick">
+ <listhead>
+ <listheader label="Leírás" align="left"/>
+ <listheader label="Partner" align="left"/>
+ <listheader label="Nettó összeg" align="left"/>
+ <listheader label="Fizetési határidő" align="left"/>
+ </listhead>
+ <template name="model">
+ <listitem>
+ <listcell label="@load(each.title)"/>
+ <listcell label="@load(each.partner.name)"/>
+ <listcell label="@load(each.netAmount)"/>
+ <listcell label="@load(each.paymentDeadline)"/>
+ </listitem>
+ </template>
+ </listbox>
+ </center>
+ </borderlayout>
+ </window>
+
+ <splitter/>
+
+ <window title="Kiadás" border="none" hflex="true" vflex="true">
+ <borderlayout>
+ <north border="none" flex="true">
+ <toolbar>
+ <toolbarbutton label="Hozzáadás" iconSclass="z-icon-plus"
+ onClick="@command('onAddOutgoing')"/>
+ <toolbarbutton label="Szerkesztés" iconSclass="z-icon-edit"
+ onClick="@command('onEditOutgoing')"
+ disabled="@load(empty vm.selectedOutgoingInvoice)"/>
+ <toolbarbutton label="Törlés" iconSclass="z-icon-remove"
+ onClick="@command('onRemoveOutgoing')"
+ disabled="@load(empty vm.selectedOutgoingInvoice)"/>
+ </toolbar>
+ </north>
+ <center border="none" flex="true">
+ <listbox vflex="true" model="@load(vm.formDocument.outgoingInvoices)"
+ selectedItem="@bind(vm.selectedOutgoingInvoice)"
+ onDoubleClick="@command('onEditOutgoing')"
+ forward="onOK=submit.onClick, onCancel=cancel.onClick">
+ <listhead>
+ <listheader label="Leírás" align="left"/>
+ <listheader label="Partner" align="left"/>
+ <listheader label="Nettó összeg" align="left"/>
+ <listheader label="Fizetési határidő" align="left"/>
+ </listhead>
+ <template name="model">
+ <listitem>
+ <listcell label="@load(each.title)"/>
+ <listcell label="@load(each.partner.name)"/>
+ <listcell label="@load(each.netAmount)"/>
+ <listcell label="@load(each.paymentDeadline)"/>
+ </listitem>
+ </template>
+ </listbox>
+ </center>
+ </borderlayout>
+ </window>
+ </hbox>
+ </tabpanel>
+ </tabpanels>
+ </tabbox>
+
</center>
- <south flex="true" style="text-align: right; padding: 10px">
+ <south border="none" flex="true" style="text-align: right; padding: 10px;">
<hlayout>
<button id="cancel" label="Bezár"
- onClick="@command('onCloseWindow', target=currentPopup, select=false)"/>
+ onClick="@command('onCloseWindow', target=projectPopup, select=false)"/>
<button id="submit" label="Mentés"
- onClick="@command('onCloseWindow', target=currentPopup, select=true)"
+ onClick="@command('onCloseWindow', target=projectPopup, select=true)"
disabled="@bind(vm.formInvalid)"/>
</hlayout>
</south>
font-weight: bold;
}
</style>
+ <script>
+ //history.pushState({}, "", "/projects");
+ </script>
<window title="Projektek" vflex="true" viewModel="@id('vm') @init('hu.user.lis.ui.view.ProjectsViewModel')">
<borderlayout>
<north flex="true">
<toolbar>
- <toolbarbutton label="Új projekt" iconSclass="z-icon-plus" onClick="@command('onAddNew')"/>
+ <toolbarbutton label="Hozzáadás" iconSclass="z-icon-plus" onClick="@command('onAdd')"/>
<toolbarbutton label="Szerkesztés" iconSclass="z-icon-edit" onClick="@command('onEdit')"
disabled="@load(empty vm.selectedProject)"/>
<separator orient="vertical"/>
</north>
<center border="none" flex="true">
<listbox id="partnersList" vflex="true" model="@load(vm.projectsDataModel)"
- autopaging="true" pagingPosition="top"
- onSelect="@command('onListSelection')" onDoubleClick="@command('onEdit')">
+ autopaging="true" pagingPosition="top" onSelect="@command('onListSelection')"
+ onDoubleClick="@command('onEdit')">
<custom-attributes org.zkoss.zul.listbox.selectOnHighlight.disabled="true"/>
<listhead>