XXX 20230817
--hosszútávon: cégnév v adószám alapján adatok letöltése publikus cégadatbázisból
---mindenhol lehessen törölni, legfejlebb a db szól
---project ID - párhuzamos generálás kezelése
---forintról visszaváltva pl. USD-re reset az áfá-n
--számla dátumok egyenlőek is lehetnek, a fizetési határidő a legnagyobb (tisztázni pontosan)
+
+ld. associates --mindenhol lehessen törölni, legfejlebb a db szól
++--project ID - párhuzamos generálás kezelése
++--forintról visszaváltva pl. USD-re reset az áfá-n
--munkalapnál csak az a projekt jelenjen meg amihez hozzá van rendelve, és a belépett felhasználó
+-számla dátumok egyenlőek is lehetnek, a fizetési határidő a legnagyobb (tisztázni pontosan)
-a ráfordítás nem veszi figyelembe a munka ráfordítást
-camunda beepitese: szamla erkeztetes, elszoszor szamlakep csatolas, majd approve
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
+import java.util.Optional;
public interface ProjectAssociateRepository extends JpaRepository<ProjectAssociate, Long> {
List<ProjectAssociate> findAllByProjectId(Long projectId);
+ List<ProjectAssociate> findAllByAssociateId(Long associateId);
+
+ Optional<ProjectAssociate> findByAssociateIdAndProjectId(Long associateId, Long projectId);
+
Long countByProjectId(Long projectId);
void deleteByProjectId(Long projectId);
import java.util.List;
public interface ProjectRepositorySearch {
- List<Project> search(String partialSearch, boolean filterShowActive, boolean filterShowInActive, Pageable pageable);
+ List<Project> search(String partialSearch, List<Long> projectIds, boolean filterShowActive, boolean filterShowInActive, Pageable pageable);
- long count(String partialSearch, boolean filterShowActive, boolean filterShowInActive);
+ long count(String partialSearch, List<Long> projectIds, boolean filterShowActive, boolean filterShowInActive);
}
package hu.user.lis.db.repository;
import hu.user.lis.db.Project;
+import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.query.QueryUtils;
@PersistenceContext
EntityManager entityManager;
- Predicate[] getPredicates(CriteriaBuilder cb, Root<Project> root, String partialSearch, boolean filterShowActive, boolean filterShowInActive) {
+ Predicate[] getPredicates(CriteriaBuilder cb, Root<Project> root, String partialSearch, List<Long> projectIds, boolean filterShowActive, boolean filterShowInActive) {
List<Predicate> predicates = new ArrayList<>();
if (StringUtils.isNotBlank(partialSearch)) {
List<Predicate> orPredicates = new ArrayList<>();
orPredicates.add(cb.like(cb.lower(root.join("partner").get("name")), "%" + partialSearch.toLowerCase() + "%"));
predicates.add(cb.or(orPredicates.toArray(new Predicate[]{})));
}
-
+ if (!ListUtils.emptyIfNull(projectIds).isEmpty()) {
+ predicates.add(root.get("id").in(projectIds));
+ }
if (filterShowActive && !filterShowInActive) {
predicates.add(cb.isTrue(root.get("active")));
}
}
@Override
- public List<Project> search(String partialSearch, boolean filterShowActive, boolean filterShowInActive, Pageable pageable) {
+ public List<Project> search(String partialSearch, List<Long> projectIds, boolean filterShowActive, boolean filterShowInActive, Pageable pageable) {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Project> cq = cb.createQuery(Project.class);
Root<Project> root = cq.from(Project.class);
- cq.where(getPredicates(cb, root, partialSearch, filterShowActive, filterShowInActive));
+ cq.where(getPredicates(cb, root, partialSearch, projectIds, filterShowActive, filterShowInActive));
cq.orderBy(QueryUtils.toOrders(pageable.getSort(), root, cb));
TypedQuery<Project> query = entityManager.createQuery(cq);
query.setMaxResults(pageable.getPageSize());
}
@Override
- public long count(String partialSearch, boolean filterShowActive, boolean filterShowInActive) {
+ public long count(String partialSearch, List<Long> projectIds, boolean filterShowActive, boolean filterShowInActive) {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Long> cq = cb.createQuery(Long.class);
Root<Project> root = cq.from(Project.class);
cq.select(cb.count(root));
- cq.where(getPredicates(cb, root, partialSearch, filterShowActive, filterShowInActive));
+ cq.where(getPredicates(cb, root, partialSearch, projectIds, filterShowActive, filterShowInActive));
return entityManager.createQuery(cq).getSingleResult();
}
}
public Associate save(Associate entity) {
return associateRepository.save(entity);
}
+
+ public void delete(Associate selectedEntity) {
+ associateRepository.delete(selectedEntity);
+ }
}
}
// ListModelList method felulirva
- // after 1. search ++++++++++
+ // after 1. searchByProject ++++++++++
@Override
public int getSize() {
if (this.resultSetSize < 0) {
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
+import java.util.*;
@Component
@Log4j2
@Autowired
ProjectAssociateRepository projectAssociateRepository;
- public List<ProjectAssociate> search(Long projectId) {
+ public List<ProjectAssociate> searchByProject(Long projectId) {
List<ProjectAssociate> result = null;
if (Objects.nonNull(projectId)) {
- log.info("Searching project associate using filter: projectId LIKE {}", projectId);
+ log.info("Searching project associate using filter: projectId = {}", projectId);
result = projectAssociateRepository.findAllByProjectId(projectId);
}
return result;
}
+ public List<ProjectAssociate> searchByAssociate(Long associateId) {
+ List<ProjectAssociate> result = null;
+ if (Objects.nonNull(associateId)) {
+ log.info("Searching project associate using filter: associateId = {}", associateId);
+ result = projectAssociateRepository.findAllByAssociateId(associateId);
+ }
+ return result;
+ }
+
+ public Optional<ProjectAssociate> searchByAssociateAndProject(Long associateId, Long projectId) {
+ log.info("Searching project associate using filter: associateId = {}, projectId = {} ", associateId, projectId);
+ return projectAssociateRepository.findByAssociateIdAndProjectId(associateId, projectId);
+ }
@Transactional
public void updateAssociates(Project project, Map<Long, Boolean> formAssociates) {
import hu.user.lis.db.Project;
import hu.user.lis.db.repository.ProjectRepository;
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.zul.FieldComparator;
+import javax.annotation.Nullable;
import java.util.List;
+import java.util.Objects;
@Component
@Log4j2
@Autowired
ProjectRepository projectRepository;
private String partialSearch;
+ private List<Long> projectIds;
@Override
public List<Project> getResultSet(int page, int pageSize, FieldComparator sortComparator) {
Pageable pageable = createPageable(0, SEARCH_LIMIT, null);
- List<Project> result = StringUtils.isBlank(partialSearch) ? projectRepository.findAll(pageable).toList() :
- projectRepository.search(partialSearch, true, false, pageable);
- return result;
+ return projectRepository.search(partialSearch, projectIds, true, false, pageable);
}
@Override
public int getResultSetCount() {
- int result = StringUtils.isBlank(partialSearch) ?
- (int) projectRepository.count() :
- (int) projectRepository.count(partialSearch, true, false);
- return result > SEARCH_LIMIT ? SEARCH_LIMIT : result;
+ int result = (int) projectRepository.count(partialSearch, projectIds, true, false);
+ return Math.min(result, SEARCH_LIMIT);
}
- public void search(String partialSearch) {
- log.info("Searching projects using filter {}", partialSearch);
+ public void search(String partialSearch, @Nullable List<Long> projectIds) {
+ if (Objects.isNull(projectIds)) {
+ log.info("Searching projects using filter {}", partialSearch);
+ } else {
+ log.info("Searching projects using filter {} in associated {} project", partialSearch, projectIds.size());
+ }
+ this.projectIds = projectIds;
this.partialSearch = partialSearch;
super.reset();
}
public List<Project> getResultSet(int page, int pageSize, FieldComparator sortComparator) {
Pageable pageable = createPageable(page, pageSize, sortComparator);
List<Project> result = listAll ? projectRepository.findAll() :
- projectRepository.search(partialName, filterShowActive, filterShowInActive, pageable);
+ projectRepository.search(partialName, null, filterShowActive, filterShowInActive, pageable);
return result;
}
@Override
public int getResultSetCount() {
long result = listAll ? projectRepository.count() :
- projectRepository.count(partialName, filterShowActive, filterShowInActive);
+ projectRepository.count(partialName, null, filterShowActive, filterShowInActive);
return (int) result;
}
public void search(String partialName) {
- log.info("Searching partner using filters: name LIKE {}");
+ log.info("Searching partner using filters: name LIKE {}", partialName);
listAll = false;
this.partialName = partialName;
super.reset();
private boolean canExecuteSearch() {
boolean result = StringUtils.isNotBlank(partialName) || StringUtils.isNotBlank(partialZipCode) || listAll;
- log.info("Can execute search: {}", result);
+ log.info("Can execute searchByProject: {}", result);
return result;
}
@Setter
public class InvoiceEditorModel extends EntityEditorModel<Invoice> {
+ private boolean vatCalculated;
+
@Init
public void init() {
super.init();
@AfterCompose
public void onAfterCompose(@ContextParam(ContextType.VIEW) Component view) {
- getEntitySelectorRouter().setFormDocument(Partner.class, getFormDocument(), "partner");
+ getEntitySelectorRouter().configureSelector(Partner.class, getFormDocument(), "partner");
}
@Command
public void onNetAmountChange() {
if (Currency.HUF.equals(getFormDocument().getCurrency())) {
+ vatCalculated = true;
getFormDocument().setGrossAmount(getFormDocument().getNetAmount() * 1.27);
getFormDocument().setVatAmount(getFormDocument().getGrossAmount() - getFormDocument().getNetAmount());
- BindUtils.postNotifyChange(getFormDocument(), "grossAmount", "vatAmount");
- validate();
+ } else {
+ if (vatCalculated) {
+ getFormDocument().setGrossAmount(0);
+ getFormDocument().setVatAmount(0);
+ vatCalculated = false;
+ }
}
+ BindUtils.postNotifyChange(getFormDocument(), "grossAmount", "vatAmount");
+ validate();
}
@Override
private void initDetails() {
initAssociates();
serviceRecordsDataModel.search(getFormDocument(), true);
- getEntitySelectorRouter().setFormDocument(Partner.class, getFormDocument(), "partner");
+ getEntitySelectorRouter().configureSelector(Partner.class, getFormDocument(), "partner");
incomeMarginsDataModel.recalculate(getFormDocument());
}
if (Objects.isNull(getFormDocument().getId())) {
return;
}
- List<ProjectAssociate> projectAssociates = projectAssociatesDataModel.search(getFormDocument().getId());
+ List<ProjectAssociate> projectAssociates = projectAssociatesDataModel.searchByProject(getFormDocument().getId());
for (int i = 0; i < associatesDataModel.getSize(); i++) {
Associate associate = associatesDataModel.getElementAt(i);
boolean exists = projectAssociates.stream()
import hu.user.lis.db.Associate;
import hu.user.lis.db.Project;
+import hu.user.lis.db.ProjectAssociate;
import hu.user.lis.db.ServiceRecord;
import hu.user.lis.ui.auth.CurrentProfile;
+import hu.user.lis.ui.data.ProjectAssociatesDataModel;
import hu.user.lis.ui.editor.common.EntityEditorModel;
+import hu.user.lis.ui.editor.selector.EntitySelectorModel;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.log4j.Log4j2;
import java.time.LocalDate;
import java.time.ZoneId;
-import java.util.Date;
-import java.util.Objects;
+import java.util.*;
+import java.util.stream.Collectors;
@Log4j2
@Getter
@WireVariable
CurrentProfile currentProfile;
+ @WireVariable
+ ProjectAssociatesDataModel projectAssociatesDataModel;
+
@Init
public void init() {
super.init();
@AfterCompose
public void onAfterCompose(@ContextParam(ContextType.VIEW) Component view) {
if (Objects.isNull(getFormDocument().getId())) {
- getFormDocument().setAssociate(currentProfile.getAssociate());
- getFormDocument().setWorkDay(Date.from(LocalDate.now().atStartOfDay(ZoneId.systemDefault()).toInstant()));
+ setDefaults();
}
- getEntitySelectorRouter().setFormDocument(Associate.class, getFormDocument(), "associate");
- getEntitySelectorRouter().setFormDocument(Project.class, getFormDocument(), "project");
+ initEntitySelectors();
+ }
+
+ private void initEntitySelectors() {
+ getEntitySelectorRouter().configureSelector(Associate.class, getFormDocument(), "associate");
+ EntitySelectorModel<?> projectEntitySelectorModel = getEntitySelectorRouter().configureSelector(Project.class, getFormDocument(), "project");
+ List<ProjectAssociate> projectAssociates = projectAssociatesDataModel.searchByAssociate(currentProfile.getAssociate().getId());
+ projectEntitySelectorModel.addStaticFilter("projects", getProjectIds(projectAssociates));
}
+ private void setDefaults() {
+ getFormDocument().setAssociate(currentProfile.getAssociate());
+ getFormDocument().setWorkDay(Date.from(LocalDate.now().atStartOfDay(ZoneId.systemDefault()).toInstant()));
+ }
+
+ @Override
+ protected boolean executePreSaveTask() {
+ boolean[] result = {true};
+ Optional<ProjectAssociate> opProjectAssociate = projectAssociatesDataModel.searchByAssociateAndProject(getFormDocument().getAssociate().getId(),
+ getFormDocument().getProject().getId());
+ if (!opProjectAssociate.isPresent()) {
+ Messagebox.show("A munkatárs a kiválasztott projekt résztvevője lesz.", "Megerősítés",
+ Messagebox.OK | Messagebox.CANCEL, Messagebox.QUESTION, e -> {
+ if (e.getName().equals("onCancel")) {
+ result[0] = false;
+ } else {
+
+ }
+ });
+ }
+ return result[0];
+ }
+
+ private List<Long> getProjectIds(List<ProjectAssociate> projectAssociates) {
+ if (Objects.nonNull(projectAssociates)) {
+ return projectAssociates.stream().map(ProjectAssociate::getProjectId).collect(Collectors.toList());
+ }
+ return Collections.emptyList();
+ }
+
+
@Override
protected boolean canSave(ServiceRecord entity) {
return Objects.nonNull(entity.getProject()) &&
@Command
public void onCloseWindow(@BindingParam("target") Window target, @BindingParam("save") boolean save) {
if (save) {
- if (saveEnabled) {
+ if (saveEnabled && executePreSaveTask()) {
Events.postEvent(new Event("onClose", target, formDocument));
}
} else {
}
}
+ protected boolean executePreSaveTask() {
+ return true;
+ }
+
private void setSaveEnabled(boolean saveEnabled) {
this.saveEnabled = saveEnabled;
log.info("Document save enabled {}", saveEnabled);
import hu.user.lis.services.data.EntityDataServiceBase;
import hu.user.lis.ui.data.CachedSpringDataModel;
+import lombok.Getter;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.zkoss.bind.BindContext;
import org.zkoss.zk.ui.event.OpenEvent;
import org.zkoss.zul.impl.XulElement;
+import java.util.HashMap;
+import java.util.Map;
+
@Log4j2
public abstract class EntitySelectorModel<T> {
+ private final Map<String, Object> staticFilters = new HashMap<>();
+
@Autowired
EntityDataServiceBase entityDataServiceBase;
+
+ @Getter
private T selectedEntity;
+
private Object formDocument;
+
private String member;
public abstract String selectorIdentifier();
protected abstract void reset();
- public T getSelectedEntity() {
- return selectedEntity;
- }
-
public void setSelectedEntity(T selectedEntity) {
this.selectedEntity = selectedEntity;
entityDataServiceBase.setFieldValue(formDocument, member, selectedEntity);
BindUtils.postNotifyChange(formDocument, member);
}
- public void setFormDocument(Object formDocument, String member) {
+ public void configureSelector(Object formDocument, String member) {
this.formDocument = formDocument;
this.member = member;
selectedEntity = (T) entityDataServiceBase.getFieldValue(formDocument, member);
BindUtils.postNotifyChange(this, "selectedEntity");
}
+
+ public void addStaticFilter(String kind, Object filter) {
+ staticFilters.put(kind, filter);
+ }
+
+ public Object getFilter(String kind) {
+ return staticFilters.get(kind);
+ }
}
return result;
}
- public void setFormDocument(Class<?> entityClass, Object formDocument, String member) {
- usedModels.stream()
- .filter(m -> m.selectorIdentifier().equals(entityClass.getSimpleName()))
- .forEach(m -> m.setFormDocument(formDocument, member));
+ public EntitySelectorModel<?> configureSelector(Class<?> entityClass, Object formDocument, String member) {
+ EntitySelectorModel<?> result = null;
+ for (EntitySelectorModel<?> model : usedModels) {
+ if (model.selectorIdentifier().equals(entityClass.getSimpleName())) {
+ model.configureSelector(formDocument, member);
+ result = model;
+ break;
+ }
+ }
+// usedModels.stream()
+// .filter(m -> m.selectorIdentifier().equals(entityClass.getSimpleName()))
+// .forEach(m -> m.configureSelector(formDocument, member));
+ return result;
}
}
import org.zkoss.bind.Converter;
import org.zkoss.zul.impl.XulElement;
+import java.util.List;
+
@Log4j2
@Getter
@Setter
@Override
protected void search(String filter) {
- projectSelectorDataModel.search(filter);
+ projectSelectorDataModel.search(filter, (List<Long>) getFilter("projects"));
}
@Override
protected void reset() {
- projectSelectorDataModel.search(null);
+ projectSelectorDataModel.search(null, (List<Long>) getFilter("projects"));
}
}
import org.zkoss.bind.annotation.Command;
import org.zkoss.bind.annotation.Init;
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;
});
}
+ @Command
+ public void onDelete() {
+ Messagebox.show("Biztosan törli a kijelölt elemet?", "Megerősítés",
+ Messagebox.OK | Messagebox.CANCEL, Messagebox.QUESTION, e -> {
+ if (!e.getName().equals("onCancel")) {
+ associatesDataModel.delete(getSelectedEntity());
+ refresh();
+ }
+ });
+ }
+
}
@AfterCompose
public void onAfterCompose(@ContextParam(ContextType.VIEW) Component view) {
- entitySelectorRouter.setFormDocument(Associate.class, this, "filterAssociate");
- entitySelectorRouter.setFormDocument(Project.class, this, "filterProject");
+ entitySelectorRouter.configureSelector(Associate.class, this, "filterAssociate");
+ entitySelectorRouter.configureSelector(Project.class, this, "filterProject");
}
private void refresh() {
public void onClearFilters() {
filterAssociate = null;
filterProject = null;
- entitySelectorRouter.setFormDocument(Associate.class, this, "filterAssociate");
- entitySelectorRouter.setFormDocument(Project.class, this, "filterProject");
+ entitySelectorRouter.configureSelector(Associate.class, this, "filterAssociate");
+ entitySelectorRouter.configureSelector(Project.class, this, "filterProject");
serviceRecordsDataModel.listAll();
}
Map<String, Object> data = (Map<String, Object>) evt.getData();
filterAssociate = (Associate) data.get("filterAssociate");
filterProject = (Project) data.get("filterProject");
- entitySelectorRouter.setFormDocument(Associate.class, this, "filterAssociate");
- entitySelectorRouter.setFormDocument(Project.class, this, "filterProject");
+ entitySelectorRouter.configureSelector(Associate.class, this, "filterAssociate");
+ entitySelectorRouter.configureSelector(Project.class, this, "filterProject");
serviceRecordsDataModel.search(filterProject, filterAssociate);
}
<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.selectedEntity)"/>
+ <toolbarbutton label="Törlés" iconSclass="z-icon-minus" onClick="@command('onDelete')"
+ disabled="@load(empty vm.selectedEntity)"/>
<separator orient="vertical"/>
<toolbarbutton mode="toggle" iconSclass="z-icon-check" label="Aktív"
checked="@bind(vm.filterShowActive)"/>
<?link rel="stylesheet" type="text/css" href="~./static/css/skeleton.css" ?>
<?link rel="stylesheet" type="text/css" href="~./static/css/webclient.css" ?>
<zk>
- <window id="associatePopup" width="60%" height="700px" closable="true"
+ <window id="associatePopup" width="60%" height="450px" closable="true"
viewModel="@id('vm') @init('hu.user.lis.ui.editor.AssociateEditorModel')">
<caption label="Munkatárs szerkesztés"/>
<borderlayout>
</listbox>
</bandpopup>
</bandbox>
- <!-- <button iconSclass="z-icon-search-plus" onClick="@command('onPopupPartners')"/>-->
+ <!-- <button iconSclass="z-icon-searchByProject-plus" onClick="@command('onPopupPartners')"/>-->
</hlayout>
</zk>
\ No newline at end of file
<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.selectedEntity)"/>
+ <toolbarbutton label="Törlés" iconSclass="z-icon-minus" onClick="@command('onDelete')"
+ disabled="@load(empty vm.selectedEntity)"/>
<separator orient="vertical"/>
<toolbarbutton mode="toggle" iconSclass="z-icon-check" label="Aktív"
checked="@bind(vm.filterShowActive)"/>
<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.selectedEntity)"/>
+ <toolbarbutton label="Törlés" iconSclass="z-icon-minus" onClick="@command('onDelete')"
+ disabled="@load(empty vm.selectedEntity)"/>
<separator orient="vertical"/>
<toolbarbutton mode="toggle" iconSclass="z-icon-check" label="Aktív"
checked="@bind(vm.filterShowActive)"/>
<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.selectedEntity)"/>
+ <toolbarbutton label="Törlés" iconSclass="z-icon-minus" onClick="@command('onDelete')"
+ disabled="@load(empty vm.selectedEntity)"/>
<separator orient="vertical"/>
<toolbarbutton label="Törlés" iconSclass="z-icon-minus" onClick="@command('onDelete')"
disabled="@load(empty vm.selectedEntity)"/>