--- /dev/null
+-- // add price exchange fields to treasury
+-- Migration SQL that makes the change goes here.
+
+INSERT INTO profile (type, setting) VALUES ('General', '{"autoProjectMarginUpdate": true}');
+
+-- //@UNDO
+-- SQL to undo the change goes here.
+
+DELETE FROM profile WHERE type="General";
import hu.user.lis.db.Associate;
import hu.user.lis.db.Profile;
import hu.user.lis.db.repository.ProfileRepository;
+import hu.user.lis.service.data.EntityDataService;
+import hu.user.lis.ui.data.common.ObjectDictionary;
import hu.user.lis.ui.session.SessionSettings;
+import lombok.Getter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
public static final String ASSOCIATE = "ASSOCIATE";
public static final String SETTINGS = "SETTINGS";
+
@Autowired
private ProfileRepository profileRepository;
@Autowired
private SessionSettings sessionSettings;
+ @Getter
+ private ObjectDictionary generalSettings;
+
+ @Autowired
+ private EntityDataService<ObjectDictionary> entityDataService;
public Associate getAssociate() {
return (Associate) sessionSettings.getAttribute(ASSOCIATE);
}
-// @Getter
-// Map<String, Profile> settings = new HashMap<>();
public void setAssociate(Associate associate) {
sessionSettings.setAttribute(ASSOCIATE, associate);
+ profileRepository.findByLoginAndType(null, "General").ifPresent(profile -> {
+ generalSettings = entityDataService.fromJSON(profile.getSetting(), ObjectDictionary.class);
+ });
loadSettings();
}
+ public void saveGeneralSettings() {
+ profileRepository.findByLoginAndType(null, "General").ifPresent(profile -> {
+ String setting = entityDataService.toJSON(generalSettings);
+ profile.setSetting(setting);
+ profileRepository.save(profile);
+ });
+ }
+
private void loadSettings() {
if (Objects.isNull(getAssociate())) {
return;
import hu.user.lis.db.Project;
import hu.user.lis.db.ServiceRecord;
import hu.user.lis.db.Treasury;
+import hu.user.lis.ui.editor.ExchangedRateValueUpdater;
+import hu.user.lis.ui.properties.GeneralSettings;
import lombok.extern.log4j.Log4j2;
+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 java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.Objects;
@Component
@Log4j2
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class IncomeMarginsDataModel extends ArrayList<MoneyAmount> {
+ @Autowired
+ private GeneralSettings generalSettings;
+
+ @Autowired
+ private ExchangedRateValueUpdater exchangedRateValueUpdater;
+
public void recalculate(Project project, ServiceRecordsDataModel serviceRecordsDataModel) throws Exception {
+ boolean autoUpdateProjectMargin = generalSettings.getAutoProjectMarginUpdate();
+
+ MoneyBalance projectHUFBalance = MoneyBalance.builder().build();
clear();
+
Map<Currency, MoneyAmount> balances = new HashMap<>();
List<OutgoingInvoice> outgoingInvoices = project.getOutgoingInvoices();
- if (Objects.nonNull(outgoingInvoices)) {
- for (Invoice invoice : outgoingInvoices) {
- addBalance(balances, MoneyAmount.fromInvoice(invoice));
+ for (Invoice invoice : outgoingInvoices) {
+ addBalance(balances, MoneyAmount.fromInvoice(invoice));
+ if (autoUpdateProjectMargin) {
+ double income = exchangedRateValueUpdater.updateInvoiceExchangedValues(invoice);
+ projectHUFBalance.addIncome(income);
}
}
List<IncomingInvoice> incomingInvoices = project.getIncomingInvoices();
- if (Objects.nonNull(incomingInvoices)) {
- for (Invoice invoice : incomingInvoices) {
- subtractBalance(balances, MoneyAmount.fromInvoice(invoice));
+ for (Invoice invoice : incomingInvoices) {
+ subtractBalance(balances, MoneyAmount.fromInvoice(invoice));
+ if (autoUpdateProjectMargin) {
+ double expense = exchangedRateValueUpdater.updateInvoiceExchangedValues(invoice);
+ projectHUFBalance.addExpense(expense);
}
}
List<Treasury> treasuries = project.getTreasuries();
- if (Objects.nonNull(treasuries)) {
- for (Treasury treasury : treasuries) {
- subtractBalance(balances, MoneyAmount.fromTreasuryBuy(treasury));
- addBalance(balances, MoneyAmount.fromTreasurySell(treasury));
+ for (Treasury treasury : treasuries) {
+ subtractBalance(balances, MoneyAmount.fromTreasuryBuy(treasury));
+ addBalance(balances, MoneyAmount.fromTreasurySell(treasury));
+ if (autoUpdateProjectMargin) {
+ double margin = exchangedRateValueUpdater.updateTreasuryExchangedValues(treasury);
+ if (margin < 0) {
+ projectHUFBalance.addExpense(-1 * margin);
+ } else {
+ projectHUFBalance.addIncome(margin);
+ }
}
}
for (int i = 0; i < serviceRecordsDataModel.getSize(); i++) {
ServiceRecord serviceRecord = serviceRecordsDataModel.getElementAt(i);
- subtractBalance(balances, MoneyAmount.fromServiceRecord(serviceRecord));
+ MoneyAmount moneyAmount = MoneyAmount.fromServiceRecord(serviceRecord);
+ subtractBalance(balances, moneyAmount);
+ if (autoUpdateProjectMargin) {
+ projectHUFBalance.addExpense(moneyAmount.getGrossAmountHUF());
+ }
}
balances.keySet().stream().sorted().forEach(currency -> this.add(balances.get(currency)));
BindUtils.postNotifyChange(this, "*");
+
+ if (autoUpdateProjectMargin) {
+ project.setSellingPrice(projectHUFBalance.getIncome());
+ project.setSupplyPrice(projectHUFBalance.getExpense());
+ project.setMargin(projectHUFBalance.getIncome() - projectHUFBalance.getExpense());
+ BindUtils.postNotifyChange(project, "sellingPrice", "supplyPrice", "margin");
+ }
+
}
@Setter
@Builder
public class MoneyBalance {
+
@Builder.Default
- Double income = (double) 0;
+ private Double income = (double) 0;
+
@Builder.Default
- Double expense = (double) 0;
+ private Double expense = (double) 0;
+
+
+ public void addIncome(double income) {
+ this.income += income;
+ }
+
+ public void addExpense(double expanse) {
+ this.expense += expanse;
+ }
}
--- /dev/null
+package hu.user.lis.ui.data.common;
+
+import java.util.HashMap;
+
+public class ObjectDictionary extends HashMap<String, Object> {
+}
package hu.user.lis.ui.editor;
-import hu.user.lis.db.*;
+import hu.user.lis.db.Currency;
+import hu.user.lis.db.IncomingInvoice;
+import hu.user.lis.db.Invoice;
+import hu.user.lis.db.OutgoingInvoice;
+import hu.user.lis.db.Project;
+import hu.user.lis.db.Treasury;
import hu.user.lis.service.mnb.ExchangeRateService;
import hu.user.lis.ui.data.MoneyBalance;
import lombok.extern.log4j.Log4j2;
+import org.apache.http.annotation.Obsolete;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Autowired
private ExchangeRateService exchangeRateService;
+ @Obsolete
public MoneyBalance update(Project project) {
MoneyBalance result = MoneyBalance.builder().build();
for (IncomingInvoice incomingInvoice : project.getIncomingInvoices()) {
return result;
}
- private void updateTreasuryExchangedValues(Treasury treasury) {
+ public double updateTreasuryExchangedValues(Treasury treasury) {
+ double result = 0;
+
Date initialDate = treasury.getTransactionDate();
Currency currency = treasury.getBuyCurrency();
if (!Currency.HUF.equals(currency) && Objects.isNull(treasury.getBuyExchangeRate())) {
treasury.setSellAmountHUF(treasury.getBuyAmount() * exchangeRate);
}
}
+
+ return treasury.getSellAmountHUF() - treasury.getBuyAmountHUF();
}
- private double updateInvoiceExchangedValues(Invoice invoice) {
+ public double updateInvoiceExchangedValues(Invoice invoice) {
if (!Currency.HUF.equals(invoice.getCurrency()) && Objects.isNull(invoice.getExchangeRate())) {
Date initialDate = invoice.getPaymentDeadline();
LocalDate exchangeDate = Objects.isNull(initialDate) ? LocalDate.now() :
import lombok.Setter;
import lombok.extern.log4j.Log4j2;
import org.zkoss.bind.BindUtils;
-import org.zkoss.bind.annotation.*;
+import org.zkoss.bind.annotation.AfterCompose;
+import org.zkoss.bind.annotation.Command;
+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 org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.select.annotation.WireVariable;
@Override
public void onEvent(Event evt) {
- if (isEventForCurrentDocument(evt)) {
+ if (isPropertyChangedEventForCurrentDocument(evt)) {
// PropertyChangeEvent propertyEvent = (PropertyChangeEvent) evt;
// String[] dates = {"completionDate", "createDate", "paymentDeadline"};
// if (Arrays.asList(dates).contains(propertyEvent.getProperty())) {
import hu.user.lis.ui.data.AssociatesDataModel;
import hu.user.lis.ui.data.IncomeMarginsDataModel;
import hu.user.lis.ui.data.InvoiceDataModel;
-import hu.user.lis.ui.data.MoneyBalance;
import hu.user.lis.ui.data.ProjectAssociatesDataModel;
import hu.user.lis.ui.data.ProjectStatusDataModel;
import hu.user.lis.ui.data.ProjectsDataModel;
import org.zkoss.zul.Panel;
import org.zkoss.zul.Window;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
projectStatusDataModel.listActive();
}
+ @Override
+ protected boolean canPropertyCauseValidation(String property) {
+ List<String> prohibitedNames = Arrays.asList("sellingPrice", "supplyPrice", "margin");
+ return !prohibitedNames.contains(property);
+ }
+
@Override
public void onEvent(Event evt) {
super.onEvent(evt);
Object data = evt.getData();
initDocuments(data);
initDetails();
- //validate();
}
}
initAssociates();
serviceRecordsDataModel.search(getFormDocument(), true);
getEntitySelectorRouter().configureSelector(Partner.class, getFormDocument(), "partner");
- safeRecalcMargin();
+ safeRecalculateMargin();
}
@Override
protected boolean areDifferent(Project entity) {
- return super.areDifferent(entity) || isAssociatesChanged() || !invoiceDocumentActions.isEmpty() || !treasuryDocumentActions.isEmpty();
+ return super.areDifferent(entity) ||
+ isAssociatesChanged() ||
+ !invoiceDocumentActions.isEmpty() ||
+ !treasuryDocumentActions.isEmpty();
}
@Command
@Override
public void validate() {
super.validate();
- //updateExchangeRateBasedValues();
- safeRecalcMargin();
- }
-
- private void updateExchangeRateBasedValues() {
- try {
- MoneyBalance balance = exchangedRateValueUpdater.update(getFormDocument());
- getFormDocument().setSellingPrice(balance.getIncome());
- getFormDocument().setSupplyPrice(balance.getExpense());
- getFormDocument().setMargin(balance.getIncome() - balance.getExpense());
- BindUtils.postNotifyChange(getFormDocument(), "sellingPrice", "supplyPrice", "margin");
- } catch (Exception e) {
- log.error(e.getMessage());
- }
+ safeRecalculateMargin();
}
- private void safeRecalcMargin() {
+ private void safeRecalculateMargin() {
try {
incomeMarginsDataModel.recalculate(getFormDocument(), serviceRecordsDataModel);
} catch (Exception e) {
import lombok.Setter;
import lombok.extern.log4j.Log4j2;
import org.zkoss.bind.PropertyChangeEvent;
-import org.zkoss.bind.annotation.*;
+import org.zkoss.bind.annotation.AfterCompose;
+import org.zkoss.bind.annotation.BindingParam;
+import org.zkoss.bind.annotation.Command;
+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 org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.Events;
import java.time.LocalDate;
import java.time.ZoneId;
-import java.util.*;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
import java.util.stream.Collectors;
@Log4j2
@Override
public void onEvent(Event evt) {
- if (isEventForCurrentDocument(evt)) {
+ if (isPropertyChangedEventForCurrentDocument(evt)) {
PropertyChangeEvent propertyEvent = (PropertyChangeEvent) evt;
log.info("Property changed: {}", propertyEvent.getProperty());
@Override
public void onEvent(Event evt) {
- if (isEventForCurrentDocument(evt)) {
+ if (isPropertyChangedEventForCurrentDocument(evt)) {
validate();
}
}
- protected boolean isEventForCurrentDocument(Event evt) {
+ protected boolean canPropertyCauseValidation(String property) {
+ return true;
+ }
+
+ protected boolean isPropertyChangedEventForCurrentDocument(Event evt) {
if (evt instanceof PropertyChangeEvent) {
PropertyChangeEvent propertyEvent = (PropertyChangeEvent) evt;
- return (Objects.nonNull(propertyEvent.getBase()) && Objects.nonNull(formDocument) && propertyEvent.getBase().equals(formDocument));
+ return canPropertyCauseValidation(propertyEvent.getProperty()) &&
+ (Objects.nonNull(propertyEvent.getBase()) && Objects.nonNull(formDocument) && propertyEvent.getBase().equals(formDocument));
}
return false;
}
--- /dev/null
+package hu.user.lis.ui.properties;
+
+import hu.user.lis.ui.auth.CurrentProfile;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class GeneralSettings {
+ @Autowired
+ private CurrentProfile currentProfile;
+
+ public boolean getAutoProjectMarginUpdate() {
+ return (boolean) currentProfile.getGeneralSettings().get("autoProjectMarginUpdate");
+ }
+
+}
package hu.user.lis.ui.view;
import hu.user.lis.db.ProjectStatus;
+import hu.user.lis.ui.auth.CurrentProfile;
import hu.user.lis.ui.data.ProjectStatusDataModel;
import hu.user.lis.ui.view.common.AsyncBaseModel;
import lombok.Getter;
@Log4j2
@VariableResolver(DelegatingVariableResolver.class)
public class SettingsViewModel extends AsyncBaseModel {
- @WireVariable
+
@Getter
+ @WireVariable
ProjectStatusDataModel projectStatusDataModel;
@Getter
private ProjectStatus selectedProjectStatus;
+ @Getter
+ @WireVariable
+ private CurrentProfile currentProfile;
+
@Init
public void init() {
Clients.evalJavaScript("pushNav('/settings')");
projectStatusDataModel.save(entity);
projectStatusDataModel.listAll();
} catch (Exception e) {
- Messagebox.show("A mentés sikertelen! A elvárt az egyedi státusz elnevezés.", "Hiba", Messagebox.OK , Messagebox.ERROR);
+ Messagebox.show("A mentés sikertelen! A elvárt az egyedi státusz elnevezés.", "Hiba", Messagebox.OK, Messagebox.ERROR);
}
}
- public void setSelectedProjectStatus(ProjectStatus selectedProjectStatus) {
- this.selectedProjectStatus = selectedProjectStatus;
+ @Command
+ public void onGeneralSettingsChanged() {
+ try {
+ currentProfile.saveGeneralSettings();
+ } catch (Exception e) {
+ Messagebox.show("A mentés sikertelen!", "Hiba", Messagebox.OK, Messagebox.ERROR);
+ }
}
}
<vlayout vflex="true" style="overflow: auto">
<hbox pack="stretch">
<div class="input-group">
- <span class="input-group-addon">Bevétel:</span>
+ <span class="input-group-addon">Kiadás:</span>
<label value="@load(vm.formDocument.supplyPrice) @converter('hu.user.lis.ui.converter.DoubleToStringConverter')"/>
<span class="input-group-addon">HUF</span>
</div>
<div class="input-group">
- <span class="input-group-addon">Kiadás:</span>
+ <span class="input-group-addon">Bevétel:</span>
<label value="@load(vm.formDocument.sellingPrice) @converter('hu.user.lis.ui.converter.DoubleToStringConverter')"/>
<span class="input-group-addon">HUF</span>
</div>
</hbox>
</caption>
- <panel collapsible="true" open="false" border="rounded"
+ <panel collapsible="true" open="true" border="rounded"
+ onOpen="@command('onOpenFormPanel', parentPanel=centerPanel)">
+ <caption label="Általános működés" style="cursor: pointer"
+ onClick="@command('onClickFormPanel', parentPanel=centerPanel, panel=self.parent)"/>
+ <panelchildren>
+ <vlayout>
+ <checkbox label="Projekt árrés automatikus frissítése" mold="switch"
+ checked="@bind(vm.currentProfile.generalSettings['autoProjectMarginUpdate'])"
+ onCheck="@command('onGeneralSettingsChanged')"/>
+ </vlayout>
+ </panelchildren>
+ </panel>
+ <separator orient="vertical"/>
+ <panel collapsible="true" open="true" border="rounded"
onOpen="@command('onOpenFormPanel', parentPanel=centerPanel)">
<caption label="Projekt státusz" style="cursor: pointer"
onClick="@command('onClickFormPanel', parentPanel=centerPanel, panel=self.parent)"/>