Move content to subfolder to prepare for merge with -parent repository
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
package de.financer;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
|
||||
@SpringBootApplication
|
||||
public class FinancerApplication extends SpringBootServletInitializer {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(FinancerApplication.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
|
||||
return application.sources(FinancerApplication.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package de.financer;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
|
||||
public enum ResponseReason {
|
||||
OK(HttpStatus.OK),
|
||||
UNKNOWN_ERROR(HttpStatus.INTERNAL_SERVER_ERROR),
|
||||
INVALID_ACCOUNT_TYPE(HttpStatus.INTERNAL_SERVER_ERROR),
|
||||
FROM_ACCOUNT_NOT_FOUND(HttpStatus.INTERNAL_SERVER_ERROR),
|
||||
TO_ACCOUNT_NOT_FOUND(HttpStatus.INTERNAL_SERVER_ERROR),
|
||||
FROM_AND_TO_ACCOUNT_NOT_FOUND(HttpStatus.INTERNAL_SERVER_ERROR),
|
||||
INVALID_DATE_FORMAT(HttpStatus.INTERNAL_SERVER_ERROR),
|
||||
MISSING_DATE(HttpStatus.INTERNAL_SERVER_ERROR),
|
||||
AMOUNT_ZERO(HttpStatus.INTERNAL_SERVER_ERROR),
|
||||
MISSING_AMOUNT(HttpStatus.INTERNAL_SERVER_ERROR),
|
||||
INVALID_BOOKING_ACCOUNTS(HttpStatus.INTERNAL_SERVER_ERROR),
|
||||
MISSING_HOLIDAY_WEEKEND_TYPE(HttpStatus.INTERNAL_SERVER_ERROR),
|
||||
INVALID_HOLIDAY_WEEKEND_TYPE(HttpStatus.INTERNAL_SERVER_ERROR),
|
||||
MISSING_INTERVAL_TYPE(HttpStatus.INTERNAL_SERVER_ERROR),
|
||||
INVALID_INTERVAL_TYPE(HttpStatus.INTERNAL_SERVER_ERROR),
|
||||
MISSING_FIRST_OCCURRENCE(HttpStatus.INTERNAL_SERVER_ERROR),
|
||||
INVALID_FIRST_OCCURRENCE_FORMAT(HttpStatus.INTERNAL_SERVER_ERROR),
|
||||
INVALID_LAST_OCCURRENCE_FORMAT(HttpStatus.INTERNAL_SERVER_ERROR),
|
||||
MISSING_RECURRING_TRANSACTION_ID(HttpStatus.INTERNAL_SERVER_ERROR),
|
||||
INVALID_RECURRING_TRANSACTION_ID(HttpStatus.INTERNAL_SERVER_ERROR),
|
||||
RECURRING_TRANSACTION_NOT_FOUND(HttpStatus.INTERNAL_SERVER_ERROR),
|
||||
MISSING_TRANSACTION_ID(HttpStatus.INTERNAL_SERVER_ERROR),
|
||||
INVALID_TRANSACTION_ID(HttpStatus.INTERNAL_SERVER_ERROR),
|
||||
TRANSACTION_NOT_FOUND(HttpStatus.INTERNAL_SERVER_ERROR),
|
||||
ACCOUNT_NOT_FOUND(HttpStatus.INTERNAL_SERVER_ERROR),
|
||||
DUPLICATE_ACCOUNT_KEY(HttpStatus.INTERNAL_SERVER_ERROR),
|
||||
DUPLICATE_ACCOUNT_GROUP_NAME(HttpStatus.INTERNAL_SERVER_ERROR),
|
||||
ACCOUNT_GROUP_NOT_FOUND(HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
|
||||
private HttpStatus httpStatus;
|
||||
|
||||
ResponseReason(HttpStatus httpStatus) {
|
||||
this.httpStatus = httpStatus;
|
||||
}
|
||||
|
||||
public ResponseEntity toResponseEntity() {
|
||||
return new ResponseEntity<>(this.name(), this.httpStatus);
|
||||
}
|
||||
|
||||
public static ResponseReason fromResponseEntity(ResponseEntity<String> entity) {
|
||||
for (ResponseReason reason : values()) {
|
||||
if (reason.name().equals(entity.getBody())) {
|
||||
return reason;
|
||||
}
|
||||
}
|
||||
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package de.financer.config;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "financer")
|
||||
public class FinancerConfig {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(FinancerConfig.class);
|
||||
|
||||
private String serverUrl;
|
||||
private String dateFormat;
|
||||
private String version;
|
||||
|
||||
public String getServerUrl() {
|
||||
return serverUrl;
|
||||
}
|
||||
|
||||
public void setServerUrl(String serverUrl) {
|
||||
this.serverUrl = serverUrl;
|
||||
}
|
||||
|
||||
public String getDateFormat() {
|
||||
return dateFormat;
|
||||
}
|
||||
|
||||
public void setDateFormat(String dateFormat) {
|
||||
this.dateFormat = dateFormat;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(String version) {
|
||||
this.version = version;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
package de.financer.controller;
|
||||
|
||||
import de.financer.ResponseReason;
|
||||
import de.financer.config.FinancerConfig;
|
||||
import de.financer.controller.template.*;
|
||||
import de.financer.form.NewAccountForm;
|
||||
import de.financer.model.*;
|
||||
import de.financer.util.ControllerUtils;
|
||||
import de.financer.util.TransactionUtils;
|
||||
import de.financer.util.comparator.TransactionByDateByIdDescComparator;
|
||||
import org.apache.commons.collections4.IterableUtils;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Controller
|
||||
public class AccountController {
|
||||
@Autowired
|
||||
private FinancerConfig financerConfig;
|
||||
|
||||
@GetMapping({"/", "/accountOverview"})
|
||||
public String accountOverview(String showClosed, Model model) {
|
||||
final ResponseEntity<Iterable<Account>> response = new GetAllAccountsTemplate().exchange(this.financerConfig);
|
||||
final ResponseEntity<Iterable<RecurringTransaction>> rtDtRes = new GetAllRecurringTransactionsDueTodayTemplate()
|
||||
.exchange(this.financerConfig);
|
||||
final ResponseEntity<Iterable<RecurringTransaction>> rtAllActRes = new GetAllActiveRecurringTransactionsTemplate()
|
||||
.exchange(this.financerConfig);
|
||||
final boolean showClosedBoolean = BooleanUtils.toBoolean(showClosed);
|
||||
|
||||
model.addAttribute("accounts", ControllerUtils.filterAndSortAccounts(response.getBody(), showClosedBoolean));
|
||||
model.addAttribute("rtDueTodayCount", IterableUtils.size(rtDtRes.getBody()));
|
||||
model.addAttribute("rtAllActiveCount", IterableUtils.size(rtAllActRes.getBody()));
|
||||
model.addAttribute("showClosed", showClosedBoolean);
|
||||
ControllerUtils.addVersionAttribute(model, this.financerConfig);
|
||||
|
||||
return "account/accountOverview";
|
||||
}
|
||||
|
||||
@GetMapping("/newAccount")
|
||||
public String newAccount(Model model) {
|
||||
final ResponseEntity<Iterable<AccountGroup>> accountGroupResponse = new GetAllAccountGroupsTemplate()
|
||||
.exchange(this.financerConfig);
|
||||
|
||||
model.addAttribute("accountGroups", ControllerUtils.sortAccountGroups(accountGroupResponse.getBody()));
|
||||
model.addAttribute("accountTypes", AccountType.valueList());
|
||||
model.addAttribute("form", new NewAccountForm());
|
||||
ControllerUtils.addVersionAttribute(model, this.financerConfig);
|
||||
|
||||
return "account/newAccount";
|
||||
}
|
||||
|
||||
@PostMapping("/saveAccount")
|
||||
public String saveAccont(NewAccountForm form, Model model) {
|
||||
final UriComponentsBuilder builder = UriComponentsBuilder
|
||||
.fromHttpUrl(ControllerUtils.buildUrl(this.financerConfig, Function.ACC_CREATE_ACCOUNT))
|
||||
.queryParam("key", form.getKey())
|
||||
.queryParam("accountGroupName", form.getGroup())
|
||||
.queryParam("type", form.getType());
|
||||
|
||||
final ResponseEntity<String> response = new StringTemplate().exchange(builder);
|
||||
final ResponseReason responseReason = ResponseReason.fromResponseEntity(response);
|
||||
|
||||
if (!ResponseReason.OK.equals(responseReason)) {
|
||||
final ResponseEntity<Iterable<AccountGroup>> accountGroupResponse = new GetAllAccountGroupsTemplate()
|
||||
.exchange(this.financerConfig);
|
||||
|
||||
model.addAttribute("form", form);
|
||||
model.addAttribute("accountGroups", ControllerUtils.sortAccountGroups(accountGroupResponse.getBody()));
|
||||
model.addAttribute("accountTypes", AccountType.valueList());
|
||||
model.addAttribute("errorMessage", responseReason.name());
|
||||
ControllerUtils.addVersionAttribute(model, this.financerConfig);
|
||||
|
||||
return "account/newAccount";
|
||||
}
|
||||
|
||||
return "redirect:/accountOverview";
|
||||
}
|
||||
|
||||
@GetMapping("/accountDetails")
|
||||
public String accountDetails(String key, Model model) {
|
||||
final ResponseEntity<Account> response = new GetAccountByKeyTemplate().exchange(this.financerConfig, key);
|
||||
final Account account = response.getBody();
|
||||
final ResponseEntity<Iterable<Transaction>> transactionResponse = new GetAllTransactionsForAccountTemplate()
|
||||
.exchange(this.financerConfig, account.getKey());
|
||||
|
||||
List<Transaction> transactions = IterableUtils.toList(transactionResponse.getBody());
|
||||
|
||||
transactions.sort(new TransactionByDateByIdDescComparator());
|
||||
transactions.stream().forEach((t) -> TransactionUtils.adjustAmount(t, account));
|
||||
|
||||
model.addAttribute("account", account);
|
||||
model.addAttribute("transactions", transactions);
|
||||
model.addAttribute("isClosed", AccountStatus.CLOSED.equals(account.getStatus()));
|
||||
ControllerUtils.addVersionAttribute(model, this.financerConfig);
|
||||
|
||||
return "account/accountDetails";
|
||||
}
|
||||
|
||||
@GetMapping("/closeAccount")
|
||||
public String closeAccount(String key, Model model) {
|
||||
final UriComponentsBuilder closeBuilder = UriComponentsBuilder
|
||||
.fromHttpUrl(ControllerUtils.buildUrl(this.financerConfig, Function.ACC_CLOSE_ACCOUNT))
|
||||
.queryParam("key", key);
|
||||
|
||||
final ResponseEntity<String> closeResponse = new StringTemplate().exchange(closeBuilder);
|
||||
|
||||
final ResponseReason responseReason = ResponseReason.fromResponseEntity(closeResponse);
|
||||
|
||||
if (!ResponseReason.OK.equals(responseReason)) {
|
||||
final ResponseEntity<Account> response = new GetAccountByKeyTemplate().exchange(this.financerConfig, key);
|
||||
final Account account = response.getBody();
|
||||
final ResponseEntity<Iterable<Transaction>> transactionResponse = new GetAllTransactionsForAccountTemplate()
|
||||
.exchange(this.financerConfig, account.getKey());
|
||||
|
||||
List<Transaction> transactions = IterableUtils.toList(transactionResponse.getBody());
|
||||
|
||||
transactions.sort(new TransactionByDateByIdDescComparator());
|
||||
transactions.stream().forEach((t) -> TransactionUtils.adjustAmount(t, account));
|
||||
|
||||
model.addAttribute("account", account);
|
||||
model.addAttribute("transactions", transactions);
|
||||
model.addAttribute("isClosed", AccountStatus.CLOSED.equals(account.getStatus()));
|
||||
model.addAttribute("errorMessage", responseReason.name());
|
||||
ControllerUtils.addVersionAttribute(model, this.financerConfig);
|
||||
|
||||
return "account/accountDetails";
|
||||
}
|
||||
|
||||
return "redirect:/accountOverview";
|
||||
}
|
||||
|
||||
@GetMapping("/openAccount")
|
||||
public String openAccount(String key, Model model) {
|
||||
final UriComponentsBuilder openBuilder = UriComponentsBuilder
|
||||
.fromHttpUrl(ControllerUtils.buildUrl(this.financerConfig, Function.ACC_OPEN_ACCOUNT))
|
||||
.queryParam("key", key);
|
||||
|
||||
final ResponseEntity<String> closeResponse = new StringTemplate().exchange(openBuilder);
|
||||
|
||||
final ResponseReason responseReason = ResponseReason.fromResponseEntity(closeResponse);
|
||||
|
||||
if (!ResponseReason.OK.equals(responseReason)) {
|
||||
final ResponseEntity<Account> response = new GetAccountByKeyTemplate().exchange(this.financerConfig, key);
|
||||
final Account account = response.getBody();
|
||||
final ResponseEntity<Iterable<Transaction>> transactionResponse = new GetAllTransactionsForAccountTemplate()
|
||||
.exchange(this.financerConfig, account.getKey());
|
||||
|
||||
List<Transaction> transactions = IterableUtils.toList(transactionResponse.getBody());
|
||||
|
||||
transactions.sort(new TransactionByDateByIdDescComparator());
|
||||
transactions.stream().forEach((t) -> TransactionUtils.adjustAmount(t, account));
|
||||
|
||||
model.addAttribute("account", account);
|
||||
model.addAttribute("transactions", transactions);
|
||||
model.addAttribute("isClosed", AccountStatus.CLOSED.equals(account.getStatus()));
|
||||
model.addAttribute("errorMessage", responseReason.name());
|
||||
ControllerUtils.addVersionAttribute(model, this.financerConfig);
|
||||
|
||||
return "account/accountDetails";
|
||||
}
|
||||
|
||||
return "redirect:/accountOverview";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package de.financer.controller;
|
||||
|
||||
import de.financer.ResponseReason;
|
||||
import de.financer.config.FinancerConfig;
|
||||
import de.financer.controller.template.StringTemplate;
|
||||
import de.financer.form.NewAccountGroupForm;
|
||||
import de.financer.util.ControllerUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
@Controller
|
||||
public class AccountGroupController {
|
||||
@Autowired
|
||||
private FinancerConfig financerConfig;
|
||||
|
||||
@GetMapping("/newAccountGroup")
|
||||
public String newAccountGroup(Model model) {
|
||||
model.addAttribute("form", new NewAccountGroupForm());
|
||||
ControllerUtils.addVersionAttribute(model, this.financerConfig);
|
||||
|
||||
return "accountGroup/newAccountGroup";
|
||||
}
|
||||
|
||||
@PostMapping("/saveAccountGroup")
|
||||
public String saveAccontGroup(NewAccountGroupForm form, Model model) {
|
||||
final UriComponentsBuilder builder = UriComponentsBuilder
|
||||
.fromHttpUrl(ControllerUtils.buildUrl(this.financerConfig, Function.ACC_GP_CREATE_ACCOUNT_GROUP))
|
||||
.queryParam("name", form.getName());
|
||||
|
||||
final ResponseEntity<String> response = new StringTemplate().exchange(builder);
|
||||
final ResponseReason responseReason = ResponseReason.fromResponseEntity(response);
|
||||
|
||||
if (!ResponseReason.OK.equals(responseReason)) {
|
||||
model.addAttribute("form", form);
|
||||
model.addAttribute("errorMessage", responseReason.name());
|
||||
ControllerUtils.addVersionAttribute(model, this.financerConfig);
|
||||
|
||||
return "accountGroup/newAccountGroup";
|
||||
}
|
||||
|
||||
return "redirect:/accountOverview";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package de.financer.controller;
|
||||
|
||||
public enum Function {
|
||||
ACC_GET_BY_KEY("accounts/getByKey"),
|
||||
ACC_GET_ALL("accounts/getAll"),
|
||||
ACC_CREATE_ACCOUNT("accounts/createAccount"),
|
||||
ACC_CLOSE_ACCOUNT("accounts/closeAccount"),
|
||||
ACC_OPEN_ACCOUNT("accounts/openAccount"),
|
||||
|
||||
ACC_GP_CREATE_ACCOUNT_GROUP("accountGroups/createAccountGroup"),
|
||||
ACC_GP_GET_ALL("accountGroups/getAll"),
|
||||
|
||||
TR_GET_ALL("transactions/getAll"),
|
||||
TR_GET_ALL_FOR_ACCOUNT("transactions/getAllForAccount"),
|
||||
TR_CREATE_TRANSACTION("transactions/createTransaction"),
|
||||
TR_DELETE_TRANSACTION("transactions/deleteTransaction"),
|
||||
|
||||
RT_GET_ALL("recurringTransactions/getAll"),
|
||||
RT_GET_ALL_ACTIVE("recurringTransactions/getAllActive"),
|
||||
RT_GET_ALL_FOR_ACCOUNT("recurringTransactions/getAllForAccount"),
|
||||
RT_GET_ALL_DUE_TODAY("recurringTransactions/getAllDueToday"),
|
||||
RT_CREATE_RECURRING_TRANSACTION("recurringTransactions/createRecurringTransaction"),
|
||||
RT_DELETE_RECURRING_TRANSACTION("recurringTransactions/deleteRecurringTransaction"),
|
||||
RT_CREATE_TRANSACTION("recurringTransactions/createTransaction");
|
||||
|
||||
private String path;
|
||||
|
||||
Function(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return this.path;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,237 @@
|
||||
package de.financer.controller;
|
||||
|
||||
import de.financer.ResponseReason;
|
||||
import de.financer.config.FinancerConfig;
|
||||
import de.financer.controller.template.*;
|
||||
import de.financer.form.NewRecurringTransactionForm;
|
||||
import de.financer.form.RecurringToTransactionWithAmountForm;
|
||||
import de.financer.model.Account;
|
||||
import de.financer.model.HolidayWeekendType;
|
||||
import de.financer.model.IntervalType;
|
||||
import de.financer.model.RecurringTransaction;
|
||||
import de.financer.util.ControllerUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@Controller
|
||||
public class RecurringTransactionController {
|
||||
|
||||
@Autowired
|
||||
private FinancerConfig financerConfig;
|
||||
|
||||
@GetMapping("/newRecurringTransaction")
|
||||
public String newRecurringTransaction(Model model) {
|
||||
final ResponseEntity<Iterable<Account>> response = new GetAllAccountsTemplate().exchange(this.financerConfig);
|
||||
final NewRecurringTransactionForm form = new NewRecurringTransactionForm();
|
||||
|
||||
form.setRemind(Boolean.TRUE);
|
||||
|
||||
model.addAttribute("accounts", ControllerUtils.filterAndSortAccounts(response.getBody()));
|
||||
model.addAttribute("intervalTypes", IntervalType.valueList());
|
||||
model.addAttribute("holidayWeekendTypes", HolidayWeekendType.valueList());
|
||||
model.addAttribute("form", form);
|
||||
ControllerUtils.addVersionAttribute(model, this.financerConfig);
|
||||
|
||||
return "recurringTransaction/newRecurringTransaction";
|
||||
}
|
||||
|
||||
@PostMapping("/saveRecurringTransaction")
|
||||
public String saveRecurringTransaction(NewRecurringTransactionForm form, Model model) {
|
||||
final UriComponentsBuilder builder = UriComponentsBuilder
|
||||
.fromHttpUrl(ControllerUtils.buildUrl(this.financerConfig, Function.RT_CREATE_RECURRING_TRANSACTION))
|
||||
.queryParam("fromAccountKey", form.getFromAccountKey())
|
||||
.queryParam("toAccountKey", form.getToAccountKey())
|
||||
.queryParam("amount", form.getAmount())
|
||||
.queryParam("firstOccurrence", ControllerUtils.formatDate(this.financerConfig, form.getFirstOccurrence()))
|
||||
.queryParam("lastOccurrence", ControllerUtils.formatDate(this.financerConfig, form.getLastOccurrence()))
|
||||
.queryParam("holidayWeekendType", form.getHolidayWeekendType())
|
||||
.queryParam("intervalType", form.getIntervalType())
|
||||
.queryParam("description", form.getDescription())
|
||||
.queryParam("remind", form.getRemind());
|
||||
|
||||
final ResponseEntity<String> response = new StringTemplate().exchange(builder);
|
||||
|
||||
final ResponseReason responseReason = ResponseReason.fromResponseEntity(response);
|
||||
|
||||
if (!ResponseReason.OK.equals(responseReason)) {
|
||||
final ResponseEntity<Iterable<Account>> getAllResponse = new GetAllAccountsTemplate()
|
||||
.exchange(this.financerConfig);
|
||||
|
||||
model.addAttribute("accounts", ControllerUtils.filterAndSortAccounts(getAllResponse.getBody()));
|
||||
model.addAttribute("intervalTypes", IntervalType.valueList());
|
||||
model.addAttribute("holidayWeekendTypes", HolidayWeekendType.valueList());
|
||||
model.addAttribute("form", form);
|
||||
model.addAttribute("errorMessage", responseReason.name());
|
||||
ControllerUtils.addVersionAttribute(model, this.financerConfig);
|
||||
|
||||
return "recurringTransaction/newRecurringTransaction";
|
||||
}
|
||||
|
||||
return "redirect:/accountOverview";
|
||||
}
|
||||
|
||||
@GetMapping("/recurringTransactionDueToday")
|
||||
public String recurringTransactionDueToday(Model model) {
|
||||
final ResponseEntity<Iterable<RecurringTransaction>> response = new GetAllRecurringTransactionsDueTodayTemplate()
|
||||
.exchange(this.financerConfig);
|
||||
|
||||
model.addAttribute("recurringTransactions", response.getBody());
|
||||
model.addAttribute("subTitle", "dueToday");
|
||||
ControllerUtils.addVersionAttribute(model, this.financerConfig);
|
||||
|
||||
return "recurringTransaction/recurringTransactionList";
|
||||
}
|
||||
|
||||
@GetMapping("/recurringTransactionActive")
|
||||
public String recurringTransactionActive(Model model) {
|
||||
final ResponseEntity<Iterable<RecurringTransaction>> response = new GetAllActiveRecurringTransactionsTemplate()
|
||||
.exchange(this.financerConfig);
|
||||
|
||||
model.addAttribute("recurringTransactions", response.getBody());
|
||||
model.addAttribute("subTitle", "active");
|
||||
ControllerUtils.addVersionAttribute(model, this.financerConfig);
|
||||
|
||||
return "recurringTransaction/recurringTransactionList";
|
||||
}
|
||||
|
||||
@GetMapping("/recurringTransactionAll")
|
||||
public String recurringTransactionAll(Model model) {
|
||||
final ResponseEntity<Iterable<RecurringTransaction>> response = new GetAllRecurringTransactionsTemplate()
|
||||
.exchange(this.financerConfig);
|
||||
|
||||
model.addAttribute("recurringTransactions", response.getBody());
|
||||
model.addAttribute("subTitle", "all");
|
||||
ControllerUtils.addVersionAttribute(model, this.financerConfig);
|
||||
|
||||
return "recurringTransaction/recurringTransactionList";
|
||||
}
|
||||
|
||||
@GetMapping("/deleteRecurringTransaction")
|
||||
public String deleteRecurringTransaction(String recurringTransactionId, Model model) {
|
||||
final UriComponentsBuilder builder = UriComponentsBuilder
|
||||
.fromHttpUrl(ControllerUtils.buildUrl(this.financerConfig, Function.RT_DELETE_RECURRING_TRANSACTION))
|
||||
.queryParam("recurringTransactionId", recurringTransactionId);
|
||||
|
||||
final ResponseEntity<String> response = new StringTemplate().exchange(builder);
|
||||
final ResponseReason responseReason = ResponseReason.fromResponseEntity(response);
|
||||
final ResponseEntity<Iterable<RecurringTransaction>> allResponse = new GetAllRecurringTransactionsTemplate()
|
||||
.exchange(this.financerConfig);
|
||||
|
||||
model.addAttribute("recurringTransactions", allResponse.getBody());
|
||||
model.addAttribute("subTitle", "all");
|
||||
ControllerUtils.addVersionAttribute(model, this.financerConfig);
|
||||
|
||||
if (!ResponseReason.OK.equals(responseReason)) {
|
||||
model.addAttribute("errorMessage", responseReason.name());
|
||||
|
||||
return "recurringTransaction/recurringTransactionList";
|
||||
}
|
||||
|
||||
return "recurringTransaction/recurringTransactionList";
|
||||
}
|
||||
|
||||
@GetMapping("/recurringToTransaction")
|
||||
public String recurringToTransaction(String recurringTransactionId, String sub, Model model) {
|
||||
final UriComponentsBuilder builder = UriComponentsBuilder
|
||||
.fromHttpUrl(ControllerUtils.buildUrl(this.financerConfig, Function.RT_CREATE_TRANSACTION))
|
||||
.queryParam("recurringTransactionId", recurringTransactionId);
|
||||
|
||||
final ResponseEntity<String> response = new StringTemplate().exchange(builder);
|
||||
final ResponseReason responseReason = ResponseReason.fromResponseEntity(response);
|
||||
|
||||
if (!ResponseReason.OK.equals(responseReason)) {
|
||||
model.addAttribute("errorMessage", responseReason.name());
|
||||
model.addAttribute("subTitle", sub);
|
||||
ControllerUtils.addVersionAttribute(model, this.financerConfig);
|
||||
|
||||
Iterable<RecurringTransaction> recurringTransactions;
|
||||
|
||||
switch (sub) {
|
||||
case "all":
|
||||
recurringTransactions = new GetAllRecurringTransactionsTemplate()
|
||||
.exchange(this.financerConfig).getBody();
|
||||
break;
|
||||
case "active":
|
||||
recurringTransactions = new GetAllRecurringTransactionsTemplate()
|
||||
.exchange(this.financerConfig).getBody();
|
||||
break;
|
||||
case "dueToday":
|
||||
recurringTransactions = new GetAllRecurringTransactionsDueTodayTemplate()
|
||||
.exchange(this.financerConfig).getBody();
|
||||
break;
|
||||
default:
|
||||
recurringTransactions = new ArrayList<>();
|
||||
}
|
||||
|
||||
model.addAttribute("recurringTransactions", recurringTransactions);
|
||||
|
||||
return "recurringTransaction/recurringTransactionList";
|
||||
}
|
||||
|
||||
return "redirect:/accountOverview";
|
||||
}
|
||||
|
||||
@GetMapping("/recurringToTransactionWithAmount")
|
||||
public String recurringToTransactionWithAmount(String recurringTransactionId, String sub, Model model) {
|
||||
ControllerUtils.addVersionAttribute(model, this.financerConfig);
|
||||
|
||||
RecurringToTransactionWithAmountForm form = new RecurringToTransactionWithAmountForm();
|
||||
|
||||
form.setRecurringTransactionId(recurringTransactionId);
|
||||
form.setSubTitle(sub);
|
||||
|
||||
model.addAttribute("form", form);
|
||||
|
||||
return "recurringTransaction/recurringToTransactionWithAmount";
|
||||
}
|
||||
|
||||
@PostMapping("/createTransactionWithAmount")
|
||||
public String createTransactionWithAmount(RecurringToTransactionWithAmountForm form, Model model) {
|
||||
final UriComponentsBuilder builder = UriComponentsBuilder
|
||||
.fromHttpUrl(ControllerUtils.buildUrl(this.financerConfig, Function.RT_CREATE_TRANSACTION))
|
||||
.queryParam("recurringTransactionId", form.getRecurringTransactionId())
|
||||
.queryParam("amount", form.getAmount());
|
||||
|
||||
final ResponseEntity<String> response = new StringTemplate().exchange(builder);
|
||||
final ResponseReason responseReason = ResponseReason.fromResponseEntity(response);
|
||||
|
||||
if (!ResponseReason.OK.equals(responseReason)) {
|
||||
model.addAttribute("errorMessage", responseReason.name());
|
||||
model.addAttribute("subTitle", form.getSubTitle());
|
||||
ControllerUtils.addVersionAttribute(model, this.financerConfig);
|
||||
|
||||
Iterable<RecurringTransaction> recurringTransactions;
|
||||
|
||||
switch (form.getSubTitle()) {
|
||||
case "all":
|
||||
recurringTransactions = new GetAllRecurringTransactionsTemplate()
|
||||
.exchange(this.financerConfig).getBody();
|
||||
break;
|
||||
case "active":
|
||||
recurringTransactions = new GetAllRecurringTransactionsTemplate()
|
||||
.exchange(this.financerConfig).getBody();
|
||||
break;
|
||||
case "dueToday":
|
||||
recurringTransactions = new GetAllRecurringTransactionsDueTodayTemplate()
|
||||
.exchange(this.financerConfig).getBody();
|
||||
break;
|
||||
default:
|
||||
recurringTransactions = new ArrayList<>();
|
||||
}
|
||||
|
||||
model.addAttribute("recurringTransactions", recurringTransactions);
|
||||
|
||||
return "recurringTransaction/recurringTransactionList";
|
||||
}
|
||||
|
||||
return "redirect:/accountOverview";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
package de.financer.controller;
|
||||
|
||||
import de.financer.ResponseReason;
|
||||
import de.financer.config.FinancerConfig;
|
||||
import de.financer.controller.template.GetAccountByKeyTemplate;
|
||||
import de.financer.controller.template.GetAllAccountsTemplate;
|
||||
import de.financer.controller.template.GetAllTransactionsForAccountTemplate;
|
||||
import de.financer.controller.template.StringTemplate;
|
||||
import de.financer.form.NewTransactionForm;
|
||||
import de.financer.model.Account;
|
||||
import de.financer.model.AccountStatus;
|
||||
import de.financer.model.Transaction;
|
||||
import de.financer.util.ControllerUtils;
|
||||
import de.financer.util.TransactionUtils;
|
||||
import de.financer.util.comparator.TransactionByDateByIdDescComparator;
|
||||
import org.apache.commons.collections4.IterableUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Controller
|
||||
public class TransactionController {
|
||||
|
||||
@Autowired
|
||||
private FinancerConfig financerConfig;
|
||||
|
||||
@GetMapping("/newTransaction")
|
||||
public String newTransaction(Model model) {
|
||||
final ResponseEntity<Iterable<Account>> response = new GetAllAccountsTemplate().exchange(this.financerConfig);
|
||||
|
||||
model.addAttribute("accounts", ControllerUtils.filterAndSortAccounts(response.getBody()));
|
||||
model.addAttribute("form", new NewTransactionForm());
|
||||
ControllerUtils.addVersionAttribute(model, this.financerConfig);
|
||||
|
||||
return "transaction/newTransaction";
|
||||
}
|
||||
|
||||
@PostMapping("/saveTransaction")
|
||||
public String saveTransaction(NewTransactionForm form, Model model) {
|
||||
final UriComponentsBuilder builder = UriComponentsBuilder
|
||||
.fromHttpUrl(ControllerUtils.buildUrl(this.financerConfig, Function.TR_CREATE_TRANSACTION))
|
||||
.queryParam("fromAccountKey", form.getFromAccountKey())
|
||||
.queryParam("toAccountKey", form.getToAccountKey())
|
||||
.queryParam("amount", form.getAmount())
|
||||
.queryParam("date", ControllerUtils.formatDate(this.financerConfig, form.getDate()))
|
||||
.queryParam("description", form.getDescription());
|
||||
|
||||
final ResponseEntity<String> response = new StringTemplate().exchange(builder);
|
||||
final ResponseReason responseReason = ResponseReason.fromResponseEntity(response);
|
||||
|
||||
if (!ResponseReason.OK.equals(responseReason)) {
|
||||
final ResponseEntity<Iterable<Account>> accRes = new GetAllAccountsTemplate().exchange(this.financerConfig);
|
||||
|
||||
model.addAttribute("accounts", ControllerUtils.filterAndSortAccounts(accRes.getBody()));
|
||||
model.addAttribute("form", form);
|
||||
model.addAttribute("errorMessage", responseReason.name());
|
||||
ControllerUtils.addVersionAttribute(model, this.financerConfig);
|
||||
|
||||
return "transaction/newTransaction";
|
||||
}
|
||||
|
||||
return "redirect:/accountOverview";
|
||||
}
|
||||
|
||||
@GetMapping("/deleteTransaction")
|
||||
public String deleteTransaction(String transactionId, String accountKey, Model model) {
|
||||
final UriComponentsBuilder builder = UriComponentsBuilder
|
||||
.fromHttpUrl(ControllerUtils.buildUrl(this.financerConfig, Function.TR_DELETE_TRANSACTION))
|
||||
.queryParam("transactionId", transactionId);
|
||||
|
||||
final ResponseEntity<String> response = new StringTemplate().exchange(builder);
|
||||
final ResponseReason responseReason = ResponseReason.fromResponseEntity(response);
|
||||
|
||||
final ResponseEntity<Account> accountResponse = new GetAccountByKeyTemplate().exchange(this.financerConfig, accountKey);
|
||||
final Account account = accountResponse.getBody();
|
||||
final ResponseEntity<Iterable<Transaction>> transactionResponse = new GetAllTransactionsForAccountTemplate()
|
||||
.exchange(this.financerConfig, account.getKey());
|
||||
|
||||
List<Transaction> transactions = IterableUtils.toList(transactionResponse.getBody());
|
||||
|
||||
transactions.sort(new TransactionByDateByIdDescComparator());
|
||||
transactions.stream().forEach((t) -> TransactionUtils.adjustAmount(t, account));
|
||||
|
||||
model.addAttribute("account", account);
|
||||
model.addAttribute("transactions", transactions);
|
||||
model.addAttribute("isClosed", AccountStatus.CLOSED.equals(account.getStatus()));
|
||||
ControllerUtils.addVersionAttribute(model, this.financerConfig);
|
||||
|
||||
if (!ResponseReason.OK.equals(responseReason)) {
|
||||
model.addAttribute("errorMessage", responseReason.name());
|
||||
|
||||
return "account/accountDetails";
|
||||
}
|
||||
|
||||
return "account/accountDetails";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package de.financer.controller.handler;
|
||||
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
import org.springframework.web.client.ResponseErrorHandler;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class NoExceptionResponseErrorHandler implements ResponseErrorHandler {
|
||||
@Override
|
||||
public boolean hasError(ClientHttpResponse response) throws IOException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleError(ClientHttpResponse response) throws IOException {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package de.financer.controller.template;
|
||||
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import de.financer.controller.handler.NoExceptionResponseErrorHandler;
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
public class FinancerRestTemplate<T> {
|
||||
public ResponseEntity<T> exchange(String url, ParameterizedTypeReference<T> type) {
|
||||
final RestTemplate restTemplate = new RestTemplate();
|
||||
|
||||
restTemplate.setErrorHandler(new NoExceptionResponseErrorHandler());
|
||||
|
||||
return restTemplate.exchange(url, HttpMethod.GET, null, type);
|
||||
}
|
||||
|
||||
public ResponseEntity<T> exchange(String url, Class<T> type) {
|
||||
final RestTemplate restTemplate = new RestTemplate();
|
||||
|
||||
restTemplate.setErrorHandler(new NoExceptionResponseErrorHandler());
|
||||
|
||||
return restTemplate.exchange(url, HttpMethod.GET, null, type);
|
||||
}
|
||||
|
||||
// The spring.jackson. properties are not picked up by the RestTemplate and its converter,
|
||||
// so we need to overwrite it here
|
||||
private MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
|
||||
MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
|
||||
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
|
||||
jsonConverter.setObjectMapper(objectMapper);
|
||||
|
||||
return jsonConverter;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package de.financer.controller.template;
|
||||
|
||||
import de.financer.config.FinancerConfig;
|
||||
import de.financer.controller.Function;
|
||||
import de.financer.model.Account;
|
||||
import de.financer.util.ControllerUtils;
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
public class GetAccountByKeyTemplate {
|
||||
public ResponseEntity<Account> exchange(FinancerConfig financerConfig, String key) {
|
||||
final UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(ControllerUtils
|
||||
.buildUrl(financerConfig, Function.ACC_GET_BY_KEY))
|
||||
.queryParam("key", key);
|
||||
|
||||
return new FinancerRestTemplate<Account>()
|
||||
.exchange(builder.toUriString(), new ParameterizedTypeReference<Account>() {
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package de.financer.controller.template;
|
||||
|
||||
import de.financer.config.FinancerConfig;
|
||||
import de.financer.controller.Function;
|
||||
import de.financer.model.AccountGroup;
|
||||
import de.financer.util.ControllerUtils;
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
|
||||
public class GetAllAccountGroupsTemplate {
|
||||
public ResponseEntity<Iterable<AccountGroup>> exchange(FinancerConfig financerConfig) {
|
||||
return new FinancerRestTemplate<Iterable<AccountGroup>>().exchange(ControllerUtils
|
||||
.buildUrl(financerConfig, Function.ACC_GP_GET_ALL), new ParameterizedTypeReference<Iterable<AccountGroup>>() {
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package de.financer.controller.template;
|
||||
|
||||
import de.financer.config.FinancerConfig;
|
||||
import de.financer.controller.Function;
|
||||
import de.financer.model.Account;
|
||||
import de.financer.util.ControllerUtils;
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
|
||||
public class GetAllAccountsTemplate {
|
||||
public ResponseEntity<Iterable<Account>> exchange(FinancerConfig financerConfig) {
|
||||
return new FinancerRestTemplate<Iterable<Account>>().exchange(ControllerUtils
|
||||
.buildUrl(financerConfig, Function.ACC_GET_ALL), new ParameterizedTypeReference<Iterable<Account>>() {
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package de.financer.controller.template;
|
||||
|
||||
import de.financer.config.FinancerConfig;
|
||||
import de.financer.controller.Function;
|
||||
import de.financer.model.RecurringTransaction;
|
||||
import de.financer.util.ControllerUtils;
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
|
||||
public class GetAllActiveRecurringTransactionsTemplate {
|
||||
public ResponseEntity<Iterable<RecurringTransaction>> exchange(FinancerConfig financerConfig) {
|
||||
return new FinancerRestTemplate<Iterable<RecurringTransaction>>().exchange(ControllerUtils
|
||||
.buildUrl(financerConfig, Function.RT_GET_ALL_ACTIVE), new ParameterizedTypeReference<Iterable<RecurringTransaction>>() {
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package de.financer.controller.template;
|
||||
|
||||
import de.financer.config.FinancerConfig;
|
||||
import de.financer.controller.Function;
|
||||
import de.financer.model.RecurringTransaction;
|
||||
import de.financer.util.ControllerUtils;
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
|
||||
public class GetAllRecurringTransactionsDueTodayTemplate {
|
||||
public ResponseEntity<Iterable<RecurringTransaction>> exchange(FinancerConfig financerConfig) {
|
||||
return new FinancerRestTemplate<Iterable<RecurringTransaction>>().exchange(ControllerUtils
|
||||
.buildUrl(financerConfig, Function.RT_GET_ALL_DUE_TODAY), new ParameterizedTypeReference<Iterable<RecurringTransaction>>() {
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package de.financer.controller.template;
|
||||
|
||||
import de.financer.config.FinancerConfig;
|
||||
import de.financer.controller.Function;
|
||||
import de.financer.model.RecurringTransaction;
|
||||
import de.financer.util.ControllerUtils;
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
|
||||
public class GetAllRecurringTransactionsTemplate {
|
||||
public ResponseEntity<Iterable<RecurringTransaction>> exchange(FinancerConfig financerConfig) {
|
||||
return new FinancerRestTemplate<Iterable<RecurringTransaction>>().exchange(ControllerUtils
|
||||
.buildUrl(financerConfig, Function.RT_GET_ALL), new ParameterizedTypeReference<Iterable<RecurringTransaction>>() {
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package de.financer.controller.template;
|
||||
|
||||
import de.financer.config.FinancerConfig;
|
||||
import de.financer.controller.Function;
|
||||
import de.financer.model.Transaction;
|
||||
import de.financer.util.ControllerUtils;
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
public class GetAllTransactionsForAccountTemplate {
|
||||
public ResponseEntity<Iterable<Transaction>> exchange(FinancerConfig financerConfig, String accountKey) {
|
||||
final UriComponentsBuilder transactionBuilder = UriComponentsBuilder
|
||||
.fromHttpUrl(ControllerUtils.buildUrl(financerConfig, Function.TR_GET_ALL_FOR_ACCOUNT))
|
||||
.queryParam("accountKey", accountKey);
|
||||
|
||||
return new FinancerRestTemplate<Iterable<Transaction>>()
|
||||
.exchange(transactionBuilder.toUriString(), new ParameterizedTypeReference<Iterable<Transaction>>() {
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package de.financer.controller.template;
|
||||
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
public class StringTemplate {
|
||||
public ResponseEntity<String> exchange(UriComponentsBuilder builder) {
|
||||
return new FinancerRestTemplate<String>()
|
||||
.exchange(builder.toUriString(), new ParameterizedTypeReference<String>() {
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package de.financer.form;
|
||||
|
||||
public class NewAccountForm {
|
||||
private String key;
|
||||
private String type;
|
||||
private String group;
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getGroup() {
|
||||
return group;
|
||||
}
|
||||
|
||||
public void setGroup(String group) {
|
||||
this.group = group;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package de.financer.form;
|
||||
|
||||
public class NewAccountGroupForm {
|
||||
private String name;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package de.financer.form;
|
||||
|
||||
public class NewRecurringTransactionForm {
|
||||
private String fromAccountKey;
|
||||
private String toAccountKey;
|
||||
private String amount;
|
||||
private String description;
|
||||
private String firstOccurrence;
|
||||
private String lastOccurrence;
|
||||
private String intervalType;
|
||||
private String holidayWeekendType;
|
||||
private Boolean remind;
|
||||
|
||||
public String getFromAccountKey() {
|
||||
return fromAccountKey;
|
||||
}
|
||||
|
||||
public void setFromAccountKey(String fromAccountKey) {
|
||||
this.fromAccountKey = fromAccountKey;
|
||||
}
|
||||
|
||||
public String getToAccountKey() {
|
||||
return toAccountKey;
|
||||
}
|
||||
|
||||
public void setToAccountKey(String toAccountKey) {
|
||||
this.toAccountKey = toAccountKey;
|
||||
}
|
||||
|
||||
public String getAmount() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
public void setAmount(String amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getFirstOccurrence() {
|
||||
return firstOccurrence;
|
||||
}
|
||||
|
||||
public void setFirstOccurrence(String firstOccurrence) {
|
||||
this.firstOccurrence = firstOccurrence;
|
||||
}
|
||||
|
||||
public String getLastOccurrence() {
|
||||
return lastOccurrence;
|
||||
}
|
||||
|
||||
public void setLastOccurrence(String lastOccurrence) {
|
||||
this.lastOccurrence = lastOccurrence;
|
||||
}
|
||||
|
||||
public String getIntervalType() {
|
||||
return intervalType;
|
||||
}
|
||||
|
||||
public void setIntervalType(String intervalType) {
|
||||
this.intervalType = intervalType;
|
||||
}
|
||||
|
||||
public String getHolidayWeekendType() {
|
||||
return holidayWeekendType;
|
||||
}
|
||||
|
||||
public void setHolidayWeekendType(String holidayWeekendType) {
|
||||
this.holidayWeekendType = holidayWeekendType;
|
||||
}
|
||||
|
||||
public Boolean getRemind() {
|
||||
return remind;
|
||||
}
|
||||
|
||||
public void setRemind(Boolean remind) {
|
||||
this.remind = remind;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package de.financer.form;
|
||||
|
||||
public class NewTransactionForm {
|
||||
private String fromAccountKey;
|
||||
private String toAccountKey;
|
||||
private String amount;
|
||||
private String date;
|
||||
private String description;
|
||||
|
||||
public String getFromAccountKey() {
|
||||
return fromAccountKey;
|
||||
}
|
||||
|
||||
public void setFromAccountKey(String fromAccountKey) {
|
||||
this.fromAccountKey = fromAccountKey;
|
||||
}
|
||||
|
||||
public String getToAccountKey() {
|
||||
return toAccountKey;
|
||||
}
|
||||
|
||||
public void setToAccountKey(String toAccountKey) {
|
||||
this.toAccountKey = toAccountKey;
|
||||
}
|
||||
|
||||
public String getAmount() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
public void setAmount(String amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public String getDate() {
|
||||
return date;
|
||||
}
|
||||
|
||||
public void setDate(String date) {
|
||||
this.date = date;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package de.financer.form;
|
||||
|
||||
public class RecurringToTransactionWithAmountForm {
|
||||
private String recurringTransactionId;
|
||||
private String amount;
|
||||
private String subTitle;
|
||||
|
||||
public String getRecurringTransactionId() {
|
||||
return recurringTransactionId;
|
||||
}
|
||||
|
||||
public void setRecurringTransactionId(String recurringTransactionId) {
|
||||
this.recurringTransactionId = recurringTransactionId;
|
||||
}
|
||||
|
||||
public String getAmount() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
public void setAmount(String amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public String getSubTitle() {
|
||||
return subTitle;
|
||||
}
|
||||
|
||||
public void setSubTitle(String subTitle) {
|
||||
this.subTitle = subTitle;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package de.financer.model;
|
||||
|
||||
public class Account {
|
||||
private Long id;
|
||||
private String key;
|
||||
private AccountType type;
|
||||
private AccountStatus status;
|
||||
private Long currentBalance;
|
||||
private AccountGroup accountGroup;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public AccountType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(AccountType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public AccountStatus getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(AccountStatus status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public Long getCurrentBalance() {
|
||||
return currentBalance;
|
||||
}
|
||||
|
||||
public void setCurrentBalance(Long currentBalance) {
|
||||
this.currentBalance = currentBalance;
|
||||
}
|
||||
|
||||
public AccountGroup getAccountGroup() {
|
||||
return accountGroup;
|
||||
}
|
||||
|
||||
public void setAccountGroup(AccountGroup accountGroup) {
|
||||
this.accountGroup = accountGroup;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package de.financer.model;
|
||||
|
||||
public class AccountGroup {
|
||||
private Long id;
|
||||
private String name;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package de.financer.model;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public enum AccountStatus {
|
||||
/** Indicates that the account is open for bookings */
|
||||
OPEN,
|
||||
/** Indicates that the account is closed and bookings to it are forbidden */
|
||||
CLOSED;
|
||||
|
||||
/**
|
||||
* This method validates whether the given string represents a valid account status.
|
||||
*
|
||||
* @param status to check
|
||||
* @return whether the given status represents a valid account status
|
||||
*/
|
||||
public static boolean isValidType(String status) {
|
||||
return Arrays.stream(AccountStatus.values()).anyMatch((accountStatus) -> accountStatus.name().equals(status));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package de.financer.model;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public enum AccountType {
|
||||
/** Used to mark an account that acts as a source of money, e.g. monthly wage */
|
||||
INCOME,
|
||||
|
||||
/** Indicates a real account at a bank, e.g. a check payment account */
|
||||
BANK,
|
||||
|
||||
/** Marks an account as physical cash, e.g. the money currently in the purse */
|
||||
CASH,
|
||||
|
||||
/** Used to mark an account that acts as a destination of money, e.g. through buying goods */
|
||||
EXPENSE,
|
||||
|
||||
/** Marks an account as a liability from a third party, e.g. credit card or loan */
|
||||
LIABILITY,
|
||||
|
||||
/** Marks the start account that is to be used to book all the opening balances for the different accounts */
|
||||
START;
|
||||
|
||||
/**
|
||||
* This method validates whether the given string represents a valid account type.
|
||||
*
|
||||
* @param type to check
|
||||
* @return whether the given type represents a valid account type
|
||||
*/
|
||||
public static boolean isValidType(String type) {
|
||||
return Arrays.stream(AccountType.values()).anyMatch((accountType) -> accountType.name().equals(type));
|
||||
}
|
||||
|
||||
public static List<String> valueList() {
|
||||
return Arrays.stream(AccountType.values()).map(AccountType::name).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package de.financer.model;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* This enum specifies constants that control how actions should be handled that would fall on a holiday
|
||||
* or weekday (where usually are no bookings done by e.g. banks)
|
||||
*/
|
||||
public enum HolidayWeekendType {
|
||||
/** Indicates that the action should be done on the specified day regardless whether it's a holiday or a weekend */
|
||||
SAME_DAY,
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Indicates that the action should be deferred to the next workday.
|
||||
* </p>
|
||||
* <pre>
|
||||
* Example 1:
|
||||
* MO TU WE TH FR SA SO
|
||||
* H WE WE -> Holiday/WeekEnd
|
||||
* X -> Due date of action
|
||||
* X' -> Deferred, effective due date of action
|
||||
* </pre>
|
||||
* <pre>
|
||||
* Example 2:
|
||||
* TU WE TH FR SA SO MO
|
||||
* H WE WE -> Holiday/WeekEnd
|
||||
* X -> Due date of action
|
||||
* X' -> Deferred, effective due date of action
|
||||
* </pre>
|
||||
*
|
||||
*/
|
||||
NEXT_WORKDAY,
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Indicates that the action should preponed to the previous day
|
||||
* </p>
|
||||
* <pre>
|
||||
* Example 1:
|
||||
* MO TU WE TH FR SA SO
|
||||
* H WE WE -> Holiday/WeekEnd
|
||||
* X -> Due date of action
|
||||
* X' -> Earlier, effective due date of action
|
||||
* </pre>
|
||||
* <pre>
|
||||
* Example 2:
|
||||
* MO TU WE TH FR SA SO
|
||||
* H WE WE -> Holiday/WeekEnd
|
||||
* X -> Due date of action
|
||||
* X' -> Earlier, effective due date of action
|
||||
* </pre>
|
||||
*/
|
||||
PREVIOUS_WORKDAY;
|
||||
|
||||
/**
|
||||
* This method validates whether the given string represents a valid holiday weekend type.
|
||||
*
|
||||
* @param type to check
|
||||
* @return whether the given type represents a valid holiday weekend type
|
||||
*/
|
||||
public static boolean isValidType(String type) {
|
||||
return Arrays.stream(HolidayWeekendType.values()).anyMatch((holidayWeekendType) -> holidayWeekendType.name().equals(type));
|
||||
}
|
||||
|
||||
public static List<String> valueList() {
|
||||
return Arrays.stream(HolidayWeekendType.values()).map(HolidayWeekendType::name).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package de.financer.model;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public enum IntervalType {
|
||||
/** Indicates that an action should be executed every day */
|
||||
DAILY,
|
||||
|
||||
/** Indicates that an action should be executed once a week */
|
||||
WEEKLY,
|
||||
|
||||
/** Indicates that an action should be executed once a month */
|
||||
MONTHLY,
|
||||
|
||||
/** Indicates that an action should be executed once a quarter */
|
||||
QUARTERLY,
|
||||
|
||||
/** Indicates that an action should be executed once a year */
|
||||
YEARLY;
|
||||
|
||||
/**
|
||||
* This method validates whether the given string represents a valid interval type.
|
||||
*
|
||||
* @param type to check
|
||||
* @return whether the given type represents a valid interval type
|
||||
*/
|
||||
public static boolean isValidType(String type) {
|
||||
return Arrays.stream(IntervalType.values()).anyMatch((intervalType) -> intervalType.name().equals(type));
|
||||
}
|
||||
|
||||
public static List<String> valueList() {
|
||||
return Arrays.stream(IntervalType.values()).map(IntervalType::name).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package de.financer.model;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
public class RecurringTransaction {
|
||||
private Long id;
|
||||
private Account fromAccount;
|
||||
private Account toAccount;
|
||||
private String description;
|
||||
private Long amount;
|
||||
private IntervalType intervalType;
|
||||
private LocalDate firstOccurrence;
|
||||
private LocalDate lastOccurrence;
|
||||
private HolidayWeekendType holidayWeekendType;
|
||||
private boolean remind;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public Account getFromAccount() {
|
||||
return fromAccount;
|
||||
}
|
||||
|
||||
public void setFromAccount(Account fromAccount) {
|
||||
this.fromAccount = fromAccount;
|
||||
}
|
||||
|
||||
public Account getToAccount() {
|
||||
return toAccount;
|
||||
}
|
||||
|
||||
public void setToAccount(Account toAccount) {
|
||||
this.toAccount = toAccount;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public Long getAmount() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
public void setAmount(Long amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public HolidayWeekendType getHolidayWeekendType() {
|
||||
return holidayWeekendType;
|
||||
}
|
||||
|
||||
public void setHolidayWeekendType(HolidayWeekendType holidayWeekendType) {
|
||||
this.holidayWeekendType = holidayWeekendType;
|
||||
}
|
||||
|
||||
public LocalDate getLastOccurrence() {
|
||||
return lastOccurrence;
|
||||
}
|
||||
|
||||
public void setLastOccurrence(LocalDate lastOccurrence) {
|
||||
this.lastOccurrence = lastOccurrence;
|
||||
}
|
||||
|
||||
public LocalDate getFirstOccurrence() {
|
||||
return firstOccurrence;
|
||||
}
|
||||
|
||||
public void setFirstOccurrence(LocalDate firstOccurrence) {
|
||||
this.firstOccurrence = firstOccurrence;
|
||||
}
|
||||
|
||||
public IntervalType getIntervalType() {
|
||||
return intervalType;
|
||||
}
|
||||
|
||||
public void setIntervalType(IntervalType intervalType) {
|
||||
this.intervalType = intervalType;
|
||||
}
|
||||
|
||||
public boolean isRemind() {
|
||||
return remind;
|
||||
}
|
||||
|
||||
public void setRemind(boolean remind) {
|
||||
this.remind = remind;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package de.financer.model;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
public class Transaction {
|
||||
private Long id;
|
||||
private Account fromAccount;
|
||||
private Account toAccount;
|
||||
private LocalDate date;
|
||||
private String description;
|
||||
private Long amount;
|
||||
private RecurringTransaction recurringTransaction;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public Account getFromAccount() {
|
||||
return fromAccount;
|
||||
}
|
||||
|
||||
public void setFromAccount(Account fromAccount) {
|
||||
this.fromAccount = fromAccount;
|
||||
}
|
||||
|
||||
public Account getToAccount() {
|
||||
return toAccount;
|
||||
}
|
||||
|
||||
public void setToAccount(Account toAccount) {
|
||||
this.toAccount = toAccount;
|
||||
}
|
||||
|
||||
public LocalDate getDate() {
|
||||
return date;
|
||||
}
|
||||
|
||||
public void setDate(LocalDate date) {
|
||||
this.date = date;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public Long getAmount() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
public void setAmount(Long amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public RecurringTransaction getRecurringTransaction() {
|
||||
return recurringTransaction;
|
||||
}
|
||||
|
||||
public void setRecurringTransaction(RecurringTransaction recurringTransaction) {
|
||||
this.recurringTransaction = recurringTransaction;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package de.financer.util;
|
||||
|
||||
import de.financer.config.FinancerConfig;
|
||||
import de.financer.controller.Function;
|
||||
import de.financer.model.Account;
|
||||
import de.financer.model.AccountGroup;
|
||||
import de.financer.model.AccountStatus;
|
||||
import de.financer.model.RecurringTransaction;
|
||||
import de.financer.util.comparator.AccountByTypeByIdComparator;
|
||||
import org.apache.commons.collections4.IterableUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.ui.Model;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ControllerUtils {
|
||||
public static String buildUrl(FinancerConfig financerConfig, Function function) {
|
||||
return String.format("%s%s", financerConfig.getServerUrl(), function.getPath());
|
||||
}
|
||||
|
||||
public static List<Account> filterAndSortAccounts(Iterable<Account> accounts) {
|
||||
return filterAndSortAccounts(accounts, false);
|
||||
}
|
||||
|
||||
public static List<Account> filterAndSortAccounts(Iterable<Account> accounts, boolean showClosed) {
|
||||
return IterableUtils.toList(accounts).stream()
|
||||
.filter((acc) -> AccountStatus.OPEN
|
||||
.equals(acc.getStatus()) || showClosed)
|
||||
.sorted(new AccountByTypeByIdComparator())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static List<AccountGroup> sortAccountGroups(Iterable<AccountGroup> accountGroups) {
|
||||
return IterableUtils.toList(accountGroups).stream()
|
||||
.sorted(Comparator.comparing(AccountGroup::getName))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static String formatDate(FinancerConfig financerConfig, String dateFromForm) {
|
||||
if (StringUtils.isEmpty(dateFromForm)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// The format is always "yyyy-MM-dd", see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/date
|
||||
final LocalDate formatted = LocalDate.parse(dateFromForm, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
|
||||
|
||||
return formatted.format(DateTimeFormatter.ofPattern(financerConfig.getDateFormat()));
|
||||
}
|
||||
|
||||
public static List<RecurringTransaction> filterEmptyEntries(Iterable<RecurringTransaction> recurringTransactions) {
|
||||
return IterableUtils.toList(recurringTransactions).stream()
|
||||
.filter((rt) -> rt.getFromAccount() != null && rt.getToAccount() != null)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static void addVersionAttribute(Model model, FinancerConfig financerConfig) {
|
||||
model.addAttribute("financerVersion", financerConfig.getVersion());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package de.financer.util;
|
||||
|
||||
import de.financer.model.Account;
|
||||
import de.financer.model.AccountType;
|
||||
import de.financer.model.Transaction;
|
||||
|
||||
import static de.financer.model.AccountType.*;
|
||||
|
||||
public class TransactionUtils {
|
||||
public static final void adjustAmount(Transaction t, Account account) {
|
||||
boolean isFrom = t.getFromAccount().getKey().equals(account.getKey());
|
||||
|
||||
if (AccountType.START.equals(t.getFromAccount().getType()) && AccountType.LIABILITY.equals(t.getToAccount().getType())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isFrom) {
|
||||
t.setAmount(t.getAmount() * TransactionUtils.getMultiplierFromAccount(account));
|
||||
}
|
||||
else {
|
||||
t.setAmount(t.getAmount() * TransactionUtils.getMultiplierToAccount(account));
|
||||
}
|
||||
}
|
||||
|
||||
public static long getMultiplierFromAccount(Account fromAccount) {
|
||||
// There is no multiplier if the from account is an EXPENSE account because
|
||||
// it's not a valid from account type
|
||||
|
||||
final AccountType accountType = fromAccount.getType();
|
||||
|
||||
if (INCOME.equals(accountType)) {
|
||||
return 1L;
|
||||
} else if (BANK.equals(accountType)) {
|
||||
return -1L;
|
||||
} else if (CASH.equals(accountType)) {
|
||||
return -1L;
|
||||
} else if (LIABILITY.equals(accountType)) {
|
||||
return 1L;
|
||||
} else if (START.equals(accountType)) {
|
||||
return 1L;
|
||||
}
|
||||
|
||||
return 1L;
|
||||
}
|
||||
|
||||
public static long getMultiplierToAccount(Account toAccount) {
|
||||
// There are no multipliers for INCOME and START accounts
|
||||
// because they are not valid to account types
|
||||
|
||||
final AccountType accountType = toAccount.getType();
|
||||
|
||||
if (BANK.equals(accountType)) {
|
||||
return 1L;
|
||||
} else if (CASH.equals(accountType)) {
|
||||
return 1L;
|
||||
} else if (LIABILITY.equals(accountType)) {
|
||||
return -1L;
|
||||
} else if (EXPENSE.equals(accountType)) {
|
||||
return 1L;
|
||||
}
|
||||
|
||||
return -1L;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package de.financer.util.comparator;
|
||||
|
||||
import de.financer.model.Account;
|
||||
import de.financer.model.AccountType;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.Map;
|
||||
|
||||
public class AccountByTypeByIdComparator implements Comparator<Account> {
|
||||
//@formatter:off
|
||||
private static final Map<AccountType, Integer> SORT_ORDER = Map.of(AccountType.BANK, 1,
|
||||
AccountType.CASH, 2,
|
||||
AccountType.INCOME, 3,
|
||||
AccountType.LIABILITY, 4,
|
||||
AccountType.EXPENSE, 5,
|
||||
AccountType.START, 6);
|
||||
//@formatter:on
|
||||
|
||||
@Override
|
||||
public int compare(Account o1, Account o2) {
|
||||
int typeOrder = SORT_ORDER.get(o1.getType()).compareTo(SORT_ORDER.get(o2.getType()));
|
||||
|
||||
return typeOrder != 0 ? typeOrder : o1.getId().compareTo(o2.getId());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package de.financer.util.comparator;
|
||||
|
||||
import de.financer.model.Transaction;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
public class TransactionByDateByIdDescComparator implements Comparator<Transaction> {
|
||||
@Override
|
||||
public int compare(Transaction o1, Transaction o2) {
|
||||
int dateOrder = o1.getDate().compareTo(o2.getDate()) * -1;
|
||||
|
||||
return dateOrder != 0 ? dateOrder : o1.getId().compareTo(o2.getId()) * -1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
# Hibernate
|
||||
spring.jpa.show-sql=true
|
||||
|
||||
financer.serverUrl=http://localhost:8089/financer-server/
|
||||
@@ -0,0 +1,30 @@
|
||||
###
|
||||
### This is the main configuration file of the application.
|
||||
### Filtering of the @...@ values happens via the maven-resource-plugin. The execution of the plugin is configured in
|
||||
### the Spring Boot parent POM.
|
||||
|
||||
spring.profiles.active=@activeProfiles@
|
||||
|
||||
# This properties are just for the embedded Tomcat used while developing
|
||||
# In a standalone servlet container instance the context path is usually defined by the name
|
||||
# of the .war file. See property 'finalName' in the POM for more info.
|
||||
server.servlet.context-path=/financer-web-client
|
||||
server.port=8090
|
||||
|
||||
info.app.name=Financer Web Client
|
||||
info.app.description=A web interface for the financer server application
|
||||
info.build.group=@project.groupId@
|
||||
info.build.artifact=@project.artifactId@
|
||||
info.build.version=@project.version@
|
||||
|
||||
logging.level.de.financer=DEBUG
|
||||
logging.file=financer-web-client.log
|
||||
logging.file.max-history=7
|
||||
logging.file.max-size=50MB
|
||||
|
||||
# The date format of the client-supplied date string, used to parse the string into a proper object
|
||||
financer.dateFormat=dd.MM.yyyy
|
||||
financer.version=@project.version@
|
||||
financer.serverUrl=http://localhost:8080/financer-server/
|
||||
|
||||
spring.messages.basename=i18n/message
|
||||
159
financer-web-client/src/main/resources/i18n/message.properties
Normal file
159
financer-web-client/src/main/resources/i18n/message.properties
Normal file
@@ -0,0 +1,159 @@
|
||||
financer.account-overview.title=financer\: overview
|
||||
financer.account-overview.available-actions=Available actions\:
|
||||
financer.account-overview.available-actions.show-closed=Show closed accounts
|
||||
financer.account-overview.available-actions.hide-closed=Hide closed accounts
|
||||
financer.account-overview.available-actions.create-account=Create new account
|
||||
financer.account-overview.available-actions.create-transaction=Create new transaction
|
||||
financer.account-overview.available-actions.create-recurring-transaction=Create new recurring transaction
|
||||
financer.account-overview.available-actions.recurring-transaction-all=Show all recurring transactions
|
||||
financer.account-overview.available-actions.create-account-group=Create new account group
|
||||
financer.account-overview.status=Status\:
|
||||
financer.account-overview.status.recurring-transaction-due-today=Recurring transactions due today\:
|
||||
financer.account-overview.status.recurring-transaction-active=Active recurring transactions\:
|
||||
financer.account-overview.table-header.id=ID
|
||||
financer.account-overview.table-header.key=Account
|
||||
financer.account-overview.table-header.group=Group
|
||||
financer.account-overview.table-header.balance=Current Balance
|
||||
financer.account-overview.table-header.type=Type
|
||||
financer.account-overview.table-header.status=Status
|
||||
|
||||
financer.account-new.title=financer\: create new account
|
||||
financer.account-new.label.key=Key\:
|
||||
financer.account-new.label.type=Type\:
|
||||
financer.account-new.label.group=Group\:
|
||||
financer.account-new.submit=Create account
|
||||
|
||||
financer.account-group-new.title=financer\: create new account group
|
||||
financer.account-group-new.label.name=Name\:
|
||||
financer.account-group-new.submit=Create account group
|
||||
|
||||
financer.transaction-new.title=financer\: create new transaction
|
||||
financer.transaction-new.label.from-account=From account\:
|
||||
financer.transaction-new.label.to-account=To account\:
|
||||
financer.transaction-new.label.amount=Amount\:
|
||||
financer.transaction-new.label.date=Date\:
|
||||
financer.transaction-new.label.description=Description\:
|
||||
financer.transaction-new.submit=Create transaction
|
||||
financer.transaction-new.account-type.BANK={0}|Bank|{1}
|
||||
financer.transaction-new.account-type.CASH={0}|Cash|{1}
|
||||
financer.transaction-new.account-type.INCOME={0}|Income|{1}
|
||||
financer.transaction-new.account-type.LIABILITY={0}|Liability|{1}
|
||||
financer.transaction-new.account-type.EXPENSE={0}|Expense|{1}
|
||||
financer.transaction-new.account-type.START={0}|Start|{1}
|
||||
|
||||
financer.recurring-transaction-new.title=financer\: create new recurring transaction
|
||||
financer.recurring-transaction-new.label.from-account=From account\:
|
||||
financer.recurring-transaction-new.label.to-account=To account\:
|
||||
financer.recurring-transaction-new.label.amount=Amount\:
|
||||
financer.recurring-transaction-new.label.first-occurrence=First occurrence\:
|
||||
financer.recurring-transaction-new.label.last-occurrence=Last occurrence\:
|
||||
financer.recurring-transaction-new.label.interval-type=Interval\:
|
||||
financer.recurring-transaction-new.label.holiday-weekend-type=Holiday/weekend rule\:
|
||||
financer.recurring-transaction-new.label.description=Description\:
|
||||
financer.recurring-transaction-new.label.remind=Remind if due\:
|
||||
financer.recurring-transaction-new.submit=Create recurring transaction
|
||||
financer.recurring-transaction-new.account-type.BANK={0}|Bank|{1}
|
||||
financer.recurring-transaction-new.account-type.CASH={0}|Cash|{1}
|
||||
financer.recurring-transaction-new.account-type.INCOME={0}|Income|{1}
|
||||
financer.recurring-transaction-new.account-type.LIABILITY={0}|Liability|{1}
|
||||
financer.recurring-transaction-new.account-type.EXPENSE={0}|Expense|{1}
|
||||
financer.recurring-transaction-new.account-type.START={0}|Start|{1}
|
||||
|
||||
financer.recurring-transaction-list.title.dueToday=financer\: recurring transactions due today
|
||||
financer.recurring-transaction-list.title.active=financer\: active recurring transactions
|
||||
financer.recurring-transaction-list.title.all=financer\: all recurring transaction
|
||||
financer.recurring-transaction-list.table-header.id=ID
|
||||
financer.recurring-transaction-list.table-header.fromAccount=From account
|
||||
financer.recurring-transaction-list.table-header.toAccount=To account
|
||||
financer.recurring-transaction-list.table-header.firstOccurrence=First occurrence
|
||||
financer.recurring-transaction-list.table-header.lastOccurrence=Last occurrence
|
||||
financer.recurring-transaction-list.table-header.amount=Amount
|
||||
financer.recurring-transaction-list.table-header.description=Description
|
||||
financer.recurring-transaction-list.table-header.intervalType=Interval
|
||||
financer.recurring-transaction-list.table-header.holidayWeekendType=Holiday/weekend rule
|
||||
financer.recurring-transaction-list.table-header.actions=Actions
|
||||
financer.recurring-transaction-list.table.actions.createTransaction=Create transaction
|
||||
financer.recurring-transaction-list.table.actions.createTransactionWithAmount=Create transaction with amount
|
||||
financer.recurring-transaction-list.table.actions.editRecurringTransaction=Edit
|
||||
financer.recurring-transaction-list.table.actions.deleteRecurringTransaction=Delete
|
||||
|
||||
financer.account-details.title=financer\: account details
|
||||
financer.account-details.available-actions=Available actions\:
|
||||
financer.account-details.available-actions.close-account=Close account
|
||||
financer.account-details.available-actions.open-account=Open account
|
||||
financer.account-details.available-actions.back-to-overview=Back to overview
|
||||
financer.account-details.table-header.id=ID
|
||||
financer.account-details.table-header.fromAccount=From account
|
||||
financer.account-details.table-header.toAccount=To account
|
||||
financer.account-details.table-header.date=Date
|
||||
financer.account-details.table-header.amount=Amount
|
||||
financer.account-details.table-header.description=Description
|
||||
financer.account-details.table-header.byRecurring=Recurring?
|
||||
financer.account-details.details.type=Type\:
|
||||
financer.account-details.details.balance=Current balance\:
|
||||
financer.account-details.details.group=Group\:
|
||||
financer.account-details.table-header.actions=Actions
|
||||
financer.account-details.table.actions.deleteTransaction=Delete
|
||||
|
||||
financer.recurring-to-transaction-with-amount.title=financer\: create transaction from recurring with amount
|
||||
financer.recurring-to-transaction-with-amount.label.amount=Amount\:
|
||||
financer.recurring-to-transaction-with-amount.submit=Create
|
||||
|
||||
financer.interval-type.DAILY=Daily
|
||||
financer.interval-type.WEEKLY=Weekly
|
||||
financer.interval-type.MONTHLY=Monthly
|
||||
financer.interval-type.QUARTERLY=Quarterly
|
||||
financer.interval-type.YEARLY=Yearly
|
||||
|
||||
financer.holiday-weekend-type.SAME_DAY=Same day
|
||||
financer.holiday-weekend-type.NEXT_WORKDAY=Next workday
|
||||
financer.holiday-weekend-type.PREVIOUS_WORKDAY=Previous workday
|
||||
|
||||
financer.account-type.BANK=Bank
|
||||
financer.account-type.CASH=Cash
|
||||
financer.account-type.INCOME=Income
|
||||
financer.account-type.LIABILITY=Liability
|
||||
financer.account-type.EXPENSE=Expense
|
||||
financer.account-type.START=Start
|
||||
|
||||
financer.account-status.OPEN=Open
|
||||
financer.account-status.CLOSED=Closed
|
||||
|
||||
financer.heading.transaction-new=financer\: create new transaction
|
||||
financer.heading.recurring-transaction-new=financer\: create new recurring transaction
|
||||
financer.heading.account-new=financer\: create new account
|
||||
financer.heading.account-group-new=financer\: create new account group
|
||||
financer.heading.account-overview=financer\: overview
|
||||
financer.heading.account-details=financer\: account details for {0}
|
||||
financer.heading.recurring-transaction-list.dueToday=financer\: recurring transactions due today
|
||||
financer.heading.recurring-transaction-list.active=financer\: active recurring transactions
|
||||
financer.heading.recurring-transaction-list.all=financer\: all recurring transaction
|
||||
financer.heading.recurring-to-transaction-with-amount=financer\: create transaction from recurring with amount
|
||||
|
||||
financer.error-message.UNKNOWN_ERROR=An unknown error occurred!
|
||||
financer.error-message.INVALID_ACCOUNT_TYPE=The selected account type is not valid!
|
||||
financer.error-message.FROM_ACCOUNT_NOT_FOUND=The specified from account has not been found!
|
||||
financer.error-message.TO_ACCOUNT_NOT_FOUND=The specified to account has not been found!
|
||||
financer.error-message.FROM_AND_TO_ACCOUNT_NOT_FOUND=Neither from nor to have not been found!
|
||||
financer.error-message.INVALID_DATE_FORMAT=The date entered has the wrong format!
|
||||
financer.error-message.MISSING_DATE=No date entered!
|
||||
financer.error-message.AMOUNT_ZERO=Zero is not a valid booking amount!
|
||||
financer.error-message.MISSING_AMOUNT=No amount entered!
|
||||
financer.error-message.INVALID_BOOKING_ACCOUNTS=The booking is not valid! No booking allowed from the from account type to the to account type!
|
||||
financer.error-message.MISSING_HOLIDAY_WEEKEND_TYPE=No holiday weekend type entered!
|
||||
financer.error-message.INVALID_HOLIDAY_WEEKEND_TYPE=The holiday weekend type is not valid!
|
||||
financer.error-message.MISSING_INTERVAL_TYPE=No interval type entered!
|
||||
financer.error-message.INVALID_INTERVAL_TYPE=The interval type is not valid!
|
||||
financer.error-message.MISSING_FIRST_OCCURRENCE=No first occurrence entered!
|
||||
financer.error-message.INVALID_FIRST_OCCURRENCE_FORMAT=The date format of the first occurrence is invalid!
|
||||
financer.error-message.INVALID_LAST_OCCURRENCE_FORMAT=The date format of the last occurrence is invalid!
|
||||
financer.error-message.MISSING_RECURRING_TRANSACTION_ID=No recurring transaction entered!
|
||||
financer.error-message.INVALID_RECURRING_TRANSACTION_ID=The recurring transaction is not valid!
|
||||
financer.error-message.RECURRING_TRANSACTION_NOT_FOUND=The recurring transaction could not be found!
|
||||
financer.error-message.MISSING_TRANSACTION_ID=No transaction entered!
|
||||
financer.error-message.INVALID_TRANSACTION_ID=The transaction is not valid!
|
||||
financer.error-message.TRANSACTION_NOT_FOUND=The transaction could not be found!
|
||||
financer.error-message.ACCOUNT_NOT_FOUND=The account could not be found!
|
||||
financer.error-message.DUPLICATE_ACCOUNT_KEY=An account with the given key already exists!
|
||||
financer.error-message.DUPLICATE_ACCOUNT_GROUP_NAME=An account group with the given key already exists!
|
||||
financer.error-message.ACCOUNT_GROUP_NOT_FOUND=The account group could not be found!
|
||||
@@ -0,0 +1,131 @@
|
||||
financer.account-overview.title=financer\: \u00DCbersicht
|
||||
financer.account-overview.available-actions=Verf\u00FCgbare Aktionen\:
|
||||
financer.account-overview.available-actions.show-closed=Zeige auch geschlossene Konten
|
||||
financer.account-overview.available-actions.hide-closed=Verstecke geschlossene Konten
|
||||
financer.account-overview.available-actions.create-account=Neues Konto erstellen
|
||||
financer.account-overview.available-actions.create-transaction=Neue Buchung erstellen
|
||||
financer.account-overview.available-actions.create-recurring-transaction=Neue wiederkehrende Buchung erstellen
|
||||
financer.account-overview.available-actions.recurring-transaction-all=Zeige alle wiederkehrende Buchungen
|
||||
financer.account-overview.available-actions.create-account-group=Neue Konto-Gruppe erstellen
|
||||
financer.account-overview.status=Status\:
|
||||
financer.account-overview.status.recurring-transaction-due-today=Wiederkehrende Buchungen heute f\u00E4llig\:
|
||||
financer.account-overview.status.recurring-transaction-active=Aktive wiederkehrende Buchungen\:
|
||||
financer.account-overview.table-header.id=ID
|
||||
financer.account-overview.table-header.key=Konto
|
||||
financer.account-overview.table-header.group=Gruppe
|
||||
financer.account-overview.table-header.balance=Kontostand
|
||||
financer.account-overview.table-header.type=Typ
|
||||
financer.account-overview.table-header.status=Status
|
||||
|
||||
financer.account-new.title=financer\: Neues Konto erstellen
|
||||
financer.account-new.label.key=Schl\u00FCssel\:
|
||||
financer.account-new.label.type=Typ\:
|
||||
financer.account-new.label.group=Gruppe\:
|
||||
financer.account-new.submit=Konto erstellen
|
||||
|
||||
financer.account-group-new.title=financer\: Neue Konto-Gruppe erstellen
|
||||
financer.account-group-new.label.name=Name\:
|
||||
financer.account-group-new.submit=Konto-Gruppe erstellen
|
||||
|
||||
financer.transaction-new.title=financer\: Neue Buchung erstellen
|
||||
financer.transaction-new.label.from-account=Von Konto\:
|
||||
financer.transaction-new.label.to-account=An Konto\:
|
||||
financer.transaction-new.label.amount=Betrag\:
|
||||
financer.transaction-new.label.date=Datum\:
|
||||
financer.transaction-new.label.description=Beschreibung\:
|
||||
financer.transaction-new.submit=Buchung erstellen
|
||||
financer.transaction-new.account-type.BANK={0}|Bank|{1}
|
||||
financer.transaction-new.account-type.CASH={0}|Bar|{1}
|
||||
financer.transaction-new.account-type.INCOME={0}|Einkommen|{1}
|
||||
financer.transaction-new.account-type.LIABILITY={0}|Verbindlichkeit|{1}
|
||||
financer.transaction-new.account-type.EXPENSE={0}|Aufwand|{1}
|
||||
financer.transaction-new.account-type.START={0}|Anfangsbestand|{1}
|
||||
|
||||
financer.recurring-transaction-new.title=financer\: Neue wiederkehrende Buchung erstellen
|
||||
financer.recurring-transaction-new.label.from-account=Von Konto\:
|
||||
financer.recurring-transaction-new.label.to-account=An Konto\:
|
||||
financer.recurring-transaction-new.label.amount=Betrag\:
|
||||
financer.recurring-transaction-new.label.first-occurrence=Erstes Auftreten\:
|
||||
financer.recurring-transaction-new.label.last-occurrence=Letztes Auftreten\:
|
||||
financer.recurring-transaction-new.label.interval-type=Intervall\:
|
||||
financer.recurring-transaction-new.label.holiday-weekend-type=Feiertag-/Wochenendregel\:
|
||||
financer.recurring-transaction-new.label.description=Beschreibung\:
|
||||
financer.recurring-transaction-new.label.remind=Erinnern wenn f\u00E4llig\:
|
||||
financer.recurring-transaction-new.submit=Wiederkehrende Buchung erstellen
|
||||
financer.recurring-transaction-new.account-type.BANK={0}|Bank|{1}
|
||||
financer.recurring-transaction-new.account-type.CASH={0}|Bar|{1}
|
||||
financer.recurring-transaction-new.account-type.INCOME={0}|Einkommen|{1}
|
||||
financer.recurring-transaction-new.account-type.LIABILITY={0}|Verbindlichkeit|{1}
|
||||
financer.recurring-transaction-new.account-type.EXPENSE={0}|Aufwand|{1}
|
||||
financer.recurring-transaction-new.account-type.START={0}|Anfangsbestand|{1}
|
||||
|
||||
financer.recurring-transaction-list.title.dueToday=financer\: wiederkehrende Buchungen heute f\u00E4llig
|
||||
financer.recurring-transaction-list.title.active=financer\: aktive wiederkehrende Buchungen
|
||||
financer.recurring-transaction-list.title.all=financer\: alle wiederkehrende Buchungen
|
||||
financer.recurring-transaction-list.table-header.id=ID
|
||||
financer.recurring-transaction-list.table-header.fromAccount=Von Konto
|
||||
financer.recurring-transaction-list.table-header.toAccount=An Konto
|
||||
financer.recurring-transaction-list.table-header.firstOccurrence=Erstes Auftreten
|
||||
financer.recurring-transaction-list.table-header.lastOccurrence=Letztes Auftreten
|
||||
financer.recurring-transaction-list.table-header.amount=Betrag
|
||||
financer.recurring-transaction-list.table-header.description=Beschreibung
|
||||
financer.recurring-transaction-list.table-header.intervalType=Intervall
|
||||
financer.recurring-transaction-list.table-header.holidayWeekendType=Feiertag-/Wochenendregel
|
||||
financer.recurring-transaction-list.table-header.actions=Aktionen
|
||||
financer.recurring-transaction-list.table.actions.createTransaction=Erstelle Buchung
|
||||
financer.recurring-transaction-list.table.actions.createTransactionWithAmount=Erstelle Buchung mit Betrag
|
||||
financer.recurring-transaction-list.table.actions.editRecurringTransaction=Bearbeiten
|
||||
financer.recurring-transaction-list.table.actions.deleteRecurringTransaction=L\u00F6schen
|
||||
|
||||
financer.account-details.title=financer\: Kontodetails
|
||||
financer.account-details.available-actions=Verf\u00FCgbare Aktionen\:
|
||||
financer.account-details.available-actions.close-account=Konto schlie\u00DFen
|
||||
financer.account-details.available-actions.open-account=Konto \u00F6ffnen
|
||||
financer.account-details.available-actions.back-to-overview=Zur\u00FCck zur \u00DCbersicht
|
||||
financer.account-details.table-header.id=ID
|
||||
financer.account-details.table-header.fromAccount=Von Konto
|
||||
financer.account-details.table-header.toAccount=An Konto
|
||||
financer.account-details.table-header.date=Datum
|
||||
financer.account-details.table-header.amount=Betrag
|
||||
financer.account-details.table-header.description=Beschreibung
|
||||
financer.account-details.table-header.byRecurring=Wiederkehrend?
|
||||
financer.account-details.details.type=Typ\:
|
||||
financer.account-details.details.balance=Kontostand\:
|
||||
financer.account-details.details.group=Gruppe\:
|
||||
financer.account-details.table-header.actions=Aktionen
|
||||
financer.account-details.table.actions.deleteTransaction=L\u00F6schen
|
||||
|
||||
financer.recurring-to-transaction-with-amount.title=financer\: Buchung mit Betrag aus wiederkehrender Buchung erstellen
|
||||
financer.recurring-to-transaction-with-amount.label.amount=Betrag\:
|
||||
financer.recurring-to-transaction-with-amount.submit=Erstellen
|
||||
|
||||
financer.interval-type.DAILY=T\u00E4glich
|
||||
financer.interval-type.WEEKLY=W\u00F6chentlich
|
||||
financer.interval-type.MONTHLY=Monatlich
|
||||
financer.interval-type.QUARTERLY=Viertelj\u00E4hrlich
|
||||
financer.interval-type.YEARLY=J\u00E4hrlich
|
||||
|
||||
financer.holiday-weekend-type.SAME_DAY=Gleicher Tag
|
||||
financer.holiday-weekend-type.NEXT_WORKDAY=N\u00E4chster Werktag
|
||||
financer.holiday-weekend-type.PREVIOUS_WORKDAY=Vorheriger Werktag
|
||||
|
||||
financer.account-type.BANK=Bank
|
||||
financer.account-type.CASH=Bar
|
||||
financer.account-type.INCOME=Einkommen
|
||||
financer.account-type.LIABILITY=Verbindlichkeit
|
||||
financer.account-type.EXPENSE=Aufwand
|
||||
financer.account-type.START=Anfangsbestand
|
||||
|
||||
financer.account-status.OPEN=Offen
|
||||
financer.account-status.CLOSED=Geschlossen
|
||||
|
||||
financer.heading.transaction-new=financer\: Neue Buchung erstellen
|
||||
financer.heading.recurring-transaction-new=financer\: Neue wiederkehrende Buchung erstellen
|
||||
financer.heading.account-new=financer\: Neues Konto erstellen
|
||||
financer.heading.account-group-new=financer\: Neue Konto-Gruppe erstellen
|
||||
financer.heading.account-overview=financer\: \u00DCbersicht
|
||||
financer.heading.account-details=financer\: Kontodetails f\u00FCr {0}
|
||||
financer.heading.recurring-transaction-list.dueToday=financer\: wiederkehrende Buchungen heute f\u00E4llig
|
||||
financer.heading.recurring-transaction-list.active=financer\: aktive wiederkehrende Buchungen
|
||||
financer.heading.recurring-transaction-list.all=financer\: alle wiederkehrende Buchungen
|
||||
financer.heading.recurring-to-transaction-with-amount=financer\: Buchung mit Betrag aus wiederkehrender Buchung erstellen
|
||||
93
financer-web-client/src/main/resources/static/css/main.css
Normal file
93
financer-web-client/src/main/resources/static/css/main.css
Normal file
@@ -0,0 +1,93 @@
|
||||
#account-overview-table,
|
||||
#account-transaction-table,
|
||||
#recurring-transaction-list-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
text-align: left;
|
||||
margin-top: 1.5em;
|
||||
margin-bottom: 1.5em;
|
||||
}
|
||||
|
||||
#account-overview-table th,
|
||||
#account-overview-table td,
|
||||
#account-transaction-table th,
|
||||
#account-transaction-table td,
|
||||
#recurring-transaction-list-table th,
|
||||
#recurring-transaction-list-table td {
|
||||
border-bottom: 1px solid #ddd;
|
||||
padding: 0.3em;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
tr:hover {
|
||||
background-color: lightgrey;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 450px) {
|
||||
.hideable-column {
|
||||
display: none;
|
||||
}
|
||||
#new-account-form *,
|
||||
#new-transaction-form *,
|
||||
#new-recurring-transaction-form * {
|
||||
width: 100% !important;
|
||||
}
|
||||
#action-container * {
|
||||
display: block !important;
|
||||
margin-bottom: 0.1em;
|
||||
}
|
||||
}
|
||||
|
||||
#action-container * {
|
||||
display: inline-grid;
|
||||
padding-inline-end: 1em;
|
||||
margin-bottom: 0.2em;
|
||||
}
|
||||
|
||||
#account-details-action-container *,
|
||||
#recurring-transaction-list-table-actions-container *,
|
||||
#account-transaction-table-actions-container * {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#details-container,
|
||||
#status-container {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
#status-container > span, div {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#details-container > div {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#new-account-form *,
|
||||
#new-transaction-form *,
|
||||
#new-recurring-transaction-form *,
|
||||
#recurring-to-transaction-with-amount-form *,
|
||||
#new-account-group-form * {
|
||||
display: block;
|
||||
margin-top: 1em;
|
||||
width: 20em;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
#footer-container * {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#footer-container > hr {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#footer-container > span {
|
||||
text-align: center;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.errorMessage {
|
||||
color: #ff6666;
|
||||
display: block;
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<title th:text="#{financer.account-details.title}"/>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" th:href="@{/css/main.css}">
|
||||
</head>
|
||||
<body>
|
||||
<h1 th:text="#{financer.heading.account-details(${account.key})}" />
|
||||
<span class="errorMessage" th:if="${errorMessage != null}" th:text="#{'financer.error-message.' + ${errorMessage}}"/>
|
||||
<div id="details-container">
|
||||
<div id="type-container">
|
||||
<span th:text="#{financer.account-details.details.type}"/>
|
||||
<span th:text="#{'financer.account-type.' + ${account.type}}"/>
|
||||
</div>
|
||||
<div id="balance-container">
|
||||
<span th:text="#{financer.account-details.details.balance}"/>
|
||||
<span th:text="${#numbers.formatDecimal(account.currentBalance/100D, 1, 'DEFAULT', 2, 'DEFAULT')}"/>
|
||||
</div>
|
||||
<div id="group-container">
|
||||
<span th:text="#{financer.account-details.details.group}"/>
|
||||
<span th:text="${account.accountGroup?.name}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div id="account-details-action-container">
|
||||
<span th:text="#{financer.account-details.available-actions}"/>
|
||||
<a th:if="${!isClosed}" th:href="@{/closeAccount(key=${account.key})}"
|
||||
th:text="#{financer.account-details.available-actions.close-account}"/>
|
||||
<a th:if="${isClosed}" th:href="@{/openAccount(key=${account.key})}"
|
||||
th:text="#{financer.account-details.available-actions.open-account}"/>
|
||||
<a th:href="@{/accountOverview}"
|
||||
th:text="#{financer.account-details.available-actions.back-to-overview}"/>
|
||||
</div>
|
||||
<table id="account-transaction-table">
|
||||
<tr>
|
||||
<th class="hideable-column" th:text="#{financer.account-details.table-header.id}"/>
|
||||
<th th:text="#{financer.account-details.table-header.fromAccount}"/>
|
||||
<th th:text="#{financer.account-details.table-header.toAccount}"/>
|
||||
<th th:text="#{financer.account-details.table-header.date}"/>
|
||||
<th th:text="#{financer.account-details.table-header.amount}"/>
|
||||
<th th:text="#{financer.account-details.table-header.description}"/>
|
||||
<th th:text="#{financer.account-details.table-header.byRecurring}"/>
|
||||
<th th:text="#{financer.account-details.table-header.actions}"/>
|
||||
</tr>
|
||||
<tr th:each="transaction : ${transactions}">
|
||||
<td class="hideable-column" th:text="${transaction.id}"/>
|
||||
<td th:text="${transaction.fromAccount.key}" />
|
||||
<td th:text="${transaction.toAccount.key}" />
|
||||
<td th:text="${transaction.date}" />
|
||||
<td th:text="${#numbers.formatDecimal(transaction.amount/100D, 1, 'DEFAULT', 2, 'DEFAULT')}"/>
|
||||
<td th:text="${transaction.description}" />
|
||||
<td th:text="${transaction.recurringTransaction != null}" />
|
||||
<td>
|
||||
<div id="account-transaction-table-actions-container">
|
||||
<a th:href="@{/deleteTransaction(transactionId=${transaction.id}, accountKey=${account.key})}"
|
||||
th:text="#{financer.account-details.table.actions.deleteTransaction}"/>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div th:replace="includes/footer :: footer"/>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,64 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<title th:text="#{financer.account-overview.title}"/>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" th:href="@{/css/main.css}">
|
||||
</head>
|
||||
<body>
|
||||
<h1 th:text="#{financer.heading.account-overview}" />
|
||||
<div id="status-container">
|
||||
<span th:text="#{financer.account-overview.status}"/>
|
||||
<div>
|
||||
<span th:text="#{financer.account-overview.status.recurring-transaction-due-today}"/>
|
||||
<a th:href="@{/recurringTransactionDueToday}" th:text="${rtDueTodayCount}"/>
|
||||
</div>
|
||||
<div>
|
||||
<span th:text="#{financer.account-overview.status.recurring-transaction-active}"/>
|
||||
<a th:href="@{/recurringTransactionActive}" th:text="${rtAllActiveCount}"/>
|
||||
</div>
|
||||
</div>
|
||||
<span th:text="#{financer.account-overview.available-actions}"/>
|
||||
<div id="action-container">
|
||||
<div id="action-container-sub-accounts">
|
||||
<a th:if="${!showClosed}" th:href="@{'/accountOverview?showClosed=true'}"
|
||||
th:text="#{financer.account-overview.available-actions.show-closed}"/>
|
||||
<a th:if="${showClosed}" th:href="@{'/accountOverview'}"
|
||||
th:text="#{financer.account-overview.available-actions.hide-closed}"/>
|
||||
<a th:href="@{/newAccount}" th:text="#{financer.account-overview.available-actions.create-account}"/>
|
||||
<a th:href="@{/newAccountGroup}" th:text="#{financer.account-overview.available-actions.create-account-group}"/>
|
||||
</div>
|
||||
<div id="action-container-sub-transactions">
|
||||
<a th:href="@{/newTransaction}" th:text="#{financer.account-overview.available-actions.create-transaction}"/>
|
||||
</div>
|
||||
<div id="action-container-sub-recurring-transactions">
|
||||
<a th:href="@{/newRecurringTransaction}"
|
||||
th:text="#{financer.account-overview.available-actions.create-recurring-transaction}"/>
|
||||
<a th:href="@{/recurringTransactionAll}"
|
||||
th:text="#{financer.account-overview.available-actions.recurring-transaction-all}"/>
|
||||
</div>
|
||||
</div>
|
||||
<table id="account-overview-table">
|
||||
<tr>
|
||||
<th class="hideable-column" th:text="#{financer.account-overview.table-header.id}"/>
|
||||
<th th:text="#{financer.account-overview.table-header.key}"/>
|
||||
<th th:text="#{financer.account-overview.table-header.balance}"/>
|
||||
<th class="hideable-column" th:text="#{financer.account-overview.table-header.group}"/>
|
||||
<th class="hideable-column" th:text="#{financer.account-overview.table-header.type}"/>
|
||||
<th class="hideable-column" th:text="#{financer.account-overview.table-header.status}"/>
|
||||
</tr>
|
||||
<tr th:each="acc : ${accounts}">
|
||||
<td class="hideable-column" th:text="${acc.id}"/>
|
||||
<td>
|
||||
<a th:href="@{/accountDetails(key=${acc.key})}" th:text="${acc.key}"/>
|
||||
</td>
|
||||
<td th:text="${#numbers.formatDecimal(acc.currentBalance/100D, 1, 'DEFAULT', 2, 'DEFAULT')}"/>
|
||||
<td class="hideable-column" th:text="${acc.accountGroup?.name}"/>
|
||||
<td class="hideable-column" th:text="#{'financer.account-type.' + ${acc.type}}"/>
|
||||
<td class="hideable-column" th:text="#{'financer.account-status.' + ${acc.status}}"/>
|
||||
</tr>
|
||||
</table>
|
||||
<div th:replace="includes/footer :: footer"/>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,27 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<title th:text="#{financer.account-new.title}"/>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" th:href="@{/css/main.css}">
|
||||
</head>
|
||||
<body>
|
||||
<h1 th:text="#{financer.heading.account-new}" />
|
||||
<span class="errorMessage" th:if="${errorMessage != null}" th:text="#{'financer.error-message.' + ${errorMessage}}"/>
|
||||
<form id="new-account-form" action="#" th:action="@{/saveAccount}" th:object="${form}" method="post">
|
||||
<label for="inputKey" th:text="#{financer.account-new.label.key}"/>
|
||||
<input type="text" id="inputKey" th:field="*{key}" />
|
||||
<label for="selectType" th:text="#{financer.account-new.label.type}"/>
|
||||
<select id="selectType" th:field="*{type}">
|
||||
<option th:each="type : ${accountTypes}" th:value="${type}" th:text="#{'financer.account-type.' + ${type}}"/>
|
||||
</select>
|
||||
<label for="selectGroup" th:text="#{financer.account-new.label.group}"/>
|
||||
<select id="selectGroup" th:field="*{group}">
|
||||
<option th:each="group : ${accountGroups}" th:value="${group.name}" th:text="${group.name}"/>
|
||||
</select>
|
||||
<input type="submit" th:value="#{financer.account-new.submit}" />
|
||||
</form>
|
||||
<div th:replace="includes/footer :: footer"/>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,19 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<title th:text="#{financer.account-group-new.title}"/>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" th:href="@{/css/main.css}">
|
||||
</head>
|
||||
<body>
|
||||
<h1 th:text="#{financer.heading.account-group-new}" />
|
||||
<span class="errorMessage" th:if="${errorMessage != null}" th:text="#{'financer.error-message.' + ${errorMessage}}"/>
|
||||
<form id="new-account-group-form" action="#" th:action="@{/saveAccountGroup}" th:object="${form}" method="post">
|
||||
<label for="inputName" th:text="#{financer.account-group-new.label.name}"/>
|
||||
<input type="text" id="inputName" th:field="*{name}" />
|
||||
<input type="submit" th:value="#{financer.account-group-new.submit}" />
|
||||
</form>
|
||||
<div th:replace="includes/footer :: footer"/>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,4 @@
|
||||
<div id="footer-container" th:fragment="footer">
|
||||
<hr>
|
||||
<span th:text="'financer v' + ${financerVersion}"/>
|
||||
</div>
|
||||
@@ -0,0 +1,48 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<title th:text="#{financer.recurring-transaction-new.title}"/>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" th:href="@{/css/main.css}">
|
||||
</head>
|
||||
<body>
|
||||
<h1 th:text="#{financer.heading.recurring-transaction-new}" />
|
||||
<span class="errorMessage" th:if="${errorMessage != null}" th:text="#{'financer.error-message.' + ${errorMessage}}"/>
|
||||
<form id="new-recurring-transaction-form" action="#" th:action="@{/saveRecurringTransaction}" th:object="${form}"
|
||||
method="post">
|
||||
<label for="selectFromAccount" th:text="#{financer.recurring-transaction-new.label.from-account}"/>
|
||||
<select id="selectFromAccount" th:field="*{fromAccountKey}">
|
||||
<option th:each="acc : ${accounts}" th:value="${acc.key}"
|
||||
th:text="#{'financer.recurring-transaction-new.account-type.' + ${acc.type}(${acc.key},${#numbers.formatDecimal(acc.currentBalance/100D, 1, 'DEFAULT', 2, 'DEFAULT')})}"/>
|
||||
</select>
|
||||
<label for="selectToAccount" th:text="#{financer.recurring-transaction-new.label.to-account}"/>
|
||||
<select id="selectToAccount" th:field="*{toAccountKey}">
|
||||
<option th:each="acc : ${accounts}" th:value="${acc.key}"
|
||||
th:text="#{'financer.recurring-transaction-new.account-type.' + ${acc.type}(${acc.key},${#numbers.formatDecimal(acc.currentBalance/100D, 1, 'DEFAULT', 2, 'DEFAULT')})}"/>
|
||||
</select>
|
||||
<label for="inputAmount" th:text="#{financer.recurring-transaction-new.label.amount}"/>
|
||||
<input type="text" id="inputAmount" th:field="*{amount}"/>
|
||||
<label for="inputFirstOccurrence" th:text="#{financer.recurring-transaction-new.label.first-occurrence}"/>
|
||||
<input type="date" id="inputFirstOccurrence" th:field="*{firstOccurrence}"/>
|
||||
<label for="inputLastOccurrence" th:text="#{financer.recurring-transaction-new.label.last-occurrence}"/>
|
||||
<input type="date" id="inputLastOccurrence" th:field="*{lastOccurrence}"/>
|
||||
<label for="selectInterval" th:text="#{financer.recurring-transaction-new.label.interval-type}"/>
|
||||
<select id="selectInterval" th:field="*{intervalType}">
|
||||
<option th:each="inter : ${intervalTypes}" th:value="${inter}"
|
||||
th:text="#{'financer.interval-type.' + ${inter}}"/>
|
||||
</select>
|
||||
<label for="selectHolidayWeekend" th:text="#{financer.recurring-transaction-new.label.holiday-weekend-type}"/>
|
||||
<select id="selectHolidayWeekend" th:field="*{holidayWeekendType}">
|
||||
<option th:each="hdwt : ${holidayWeekendTypes}" th:value="${hdwt}"
|
||||
th:text="#{'financer.holiday-weekend-type.' + ${hdwt}}"/>
|
||||
</select>
|
||||
<label for="inputDescription" th:text="#{financer.recurring-transaction-new.label.description}"/>
|
||||
<input type="text" id="inputDescription" th:field="*{description}"/>
|
||||
<label for="inputRemind" th:text="#{financer.recurring-transaction-new.label.remind}" />
|
||||
<input type="checkbox" id="inputRemind" th:field="*{remind}" />
|
||||
<input type="submit" th:value="#{financer.recurring-transaction-new.submit}"/>
|
||||
</form>
|
||||
<div th:replace="includes/footer :: footer"/>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,22 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<title th:text="#{financer.recurring-to-transaction-with-amount.title}"/>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" th:href="@{/css/main.css}">
|
||||
</head>
|
||||
<body>
|
||||
<h1 th:text="#{financer.heading.recurring-to-transaction-with-amount}" />
|
||||
<span class="errorMessage" th:if="${errorMessage != null}" th:text="#{'financer.error-message.' + ${errorMessage}}"/>
|
||||
<form id="recurring-to-transaction-with-amount-form" action="#" th:action="@{/createTransactionWithAmount}" th:object="${form}"
|
||||
method="post">
|
||||
<label for="inputAmount" th:text="#{financer.recurring-to-transaction-with-amount.label.amount}"/>
|
||||
<input type="text" id="inputAmount" th:field="*{amount}"/>
|
||||
<input type="hidden" id="inputId" th:field="*{recurringTransactionId}"/>
|
||||
<input type="hidden" id="inputSub" th:field="*{subTitle}"/>
|
||||
<input type="submit" th:value="#{financer.recurring-to-transaction-with-amount.submit}"/>
|
||||
</form>
|
||||
<div th:replace="includes/footer :: footer"/>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,53 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<title th:text="#{'financer.recurring-transaction-list.title.' + ${subTitle}}"/>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" th:href="@{/css/main.css}">
|
||||
</head>
|
||||
<body>
|
||||
<h1 th:text="#{'financer.heading.recurring-transaction-list.' + ${subTitle}}"/>
|
||||
<span class="errorMessage" th:if="${errorMessage != null}" th:text="#{'financer.error-message.' + ${errorMessage}}"/>
|
||||
<table id="recurring-transaction-list-table">
|
||||
<tr>
|
||||
<th class="hideable-column" th:text="#{financer.recurring-transaction-list.table-header.id}"/>
|
||||
<th th:text="#{financer.recurring-transaction-list.table-header.fromAccount}"/>
|
||||
<th th:text="#{financer.recurring-transaction-list.table-header.toAccount}"/>
|
||||
<th th:text="#{financer.recurring-transaction-list.table-header.firstOccurrence}"/>
|
||||
<th th:text="#{financer.recurring-transaction-list.table-header.lastOccurrence}"/>
|
||||
<th th:text="#{financer.recurring-transaction-list.table-header.amount}"/>
|
||||
<th th:text="#{financer.recurring-transaction-list.table-header.description}"/>
|
||||
<th th:text="#{financer.recurring-transaction-list.table-header.intervalType}"/>
|
||||
<th th:text="#{financer.recurring-transaction-list.table-header.holidayWeekendType}"/>
|
||||
<th th:text="#{financer.recurring-transaction-list.table-header.actions}"/>
|
||||
</tr>
|
||||
<tr th:each="rt : ${recurringTransactions}">
|
||||
<td class="hideable-column" th:text="${rt.id}"/>
|
||||
<td>
|
||||
<a th:href="@{/accountDetails(key=${rt.fromAccount.key})}" th:text="${rt.fromAccount.key}"/>
|
||||
</td>
|
||||
<td>
|
||||
<a th:href="@{/accountDetails(key=${rt.toAccount.key})}" th:text="${rt.toAccount.key}"/>
|
||||
</td>
|
||||
<td th:text="${rt.firstOccurrence}"/>
|
||||
<td th:text="${rt.lastOccurrence}"/>
|
||||
<td th:text="${#numbers.formatDecimal(rt.amount/100D, 1, 'DEFAULT', 2, 'DEFAULT')}"/>
|
||||
<td th:text="${rt.description}"/>
|
||||
<td th:text="#{'financer.interval-type.' + ${rt.intervalType}}"/>
|
||||
<td th:text="#{'financer.holiday-weekend-type.' + ${rt.holidayWeekendType}}"/>
|
||||
<td>
|
||||
<div id="recurring-transaction-list-table-actions-container">
|
||||
<a th:href="@{/recurringToTransaction(recurringTransactionId=${rt.id}, sub=${subTitle})}"
|
||||
th:text="#{financer.recurring-transaction-list.table.actions.createTransaction}"/>
|
||||
<a th:href="@{/recurringToTransactionWithAmount(recurringTransactionId=${rt.id}, sub=${subTitle})}"
|
||||
th:text="#{financer.recurring-transaction-list.table.actions.createTransactionWithAmount}"/>
|
||||
<a th:if="${subTitle == 'all'}" th:href="@{/deleteRecurringTransaction(recurringTransactionId=${rt.id})}"
|
||||
th:text="#{financer.recurring-transaction-list.table.actions.deleteRecurringTransaction}"/>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div th:replace="includes/footer :: footer"/>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,33 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<title th:text="#{financer.transaction-new.title}"/>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" th:href="@{/css/main.css}">
|
||||
</head>
|
||||
<body>
|
||||
<h1 th:text="#{financer.heading.transaction-new}" />
|
||||
<span class="errorMessage" th:if="${errorMessage != null}" th:text="#{'financer.error-message.' + ${errorMessage}}"/>
|
||||
<form id="new-transaction-form" action="#" th:action="@{/saveTransaction}" th:object="${form}"
|
||||
method="post">
|
||||
<label for="selectFromAccount" th:text="#{financer.transaction-new.label.from-account}"/>
|
||||
<select id="selectFromAccount" th:field="*{fromAccountKey}">
|
||||
<option th:each="acc : ${accounts}" th:value="${acc.key}"
|
||||
th:text="#{'financer.transaction-new.account-type.' + ${acc.type}(${acc.key},${#numbers.formatDecimal(acc.currentBalance/100D, 1, 'DEFAULT', 2, 'DEFAULT')})}"/>
|
||||
</select>
|
||||
<label for="selectToAccount" th:text="#{financer.transaction-new.label.to-account}"/>
|
||||
<select id="selectToAccount" th:field="*{toAccountKey}">
|
||||
<option th:each="acc : ${accounts}" th:value="${acc.key}"
|
||||
th:text="#{'financer.transaction-new.account-type.' + ${acc.type}(${acc.key},${#numbers.formatDecimal(acc.currentBalance/100D, 1, 'DEFAULT', 2, 'DEFAULT')})}"/>
|
||||
</select>
|
||||
<label for="inputAmount" th:text="#{financer.transaction-new.label.amount}"/>
|
||||
<input type="text" id="inputAmount" th:field="*{amount}"/>
|
||||
<label for="inputDate" th:text="#{financer.transaction-new.label.date}"/>
|
||||
<input type="date" id="inputDate" th:field="*{date}"/>
|
||||
<label for="inputDescription" th:text="#{financer.transaction-new.label.description}"/>
|
||||
<input type="text" id="inputDescription" th:field="*{description}"/>
|
||||
<input type="submit" th:value="#{financer.transaction-new.submit}"/>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,31 @@
|
||||
package de.financer;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = FinancerApplication.class)
|
||||
@AutoConfigureMockMvc
|
||||
@TestPropertySource(
|
||||
locations = "classpath:application-integrationtest.properties")
|
||||
public class FinancerApplicationBootTest {
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Test
|
||||
public void test_appBoots() {
|
||||
// Nothing to do in this test as we just want to startup the app
|
||||
// to make sure that spring, flyway and hibernate all work
|
||||
// as expected even after changes
|
||||
// While this slightly increases build time it's an easy and safe
|
||||
// way to ensure that the app can start
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
spring.profiles.active=dev
|
||||
|
||||
spring.datasource.url=jdbc:hsqldb:mem:.
|
||||
spring.datasource.username=sa
|
||||
spring.flyway.locations=classpath:/database/hsqldb,classpath:/database/hsqldb/integration,classpath:/database/common
|
||||
Reference in New Issue
Block a user