package org.internna.ossmoney.mvc;
import java.util.Set;
import java.util.Date;
import java.util.List;
import java.util.TreeSet;
import java.util.ArrayList;
import java.util.SortedSet;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import org.internna.ossmoney.model.Payee;
import org.internna.ossmoney.model.Account;
import org.internna.ossmoney.cache.CacheStore;
import org.internna.ossmoney.model.AccountType;
import org.internna.ossmoney.model.Subcategory;
import org.internna.ossmoney.services.AccountService;
import org.internna.ossmoney.model.AccountTransaction;
import org.internna.ossmoney.model.security.UserDetails;
import org.internna.ossmoney.model.FinancialInstitution;
import org.springframework.ui.ModelMap;
import org.springframework.util.CollectionUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import static org.springframework.util.StringUtils.hasText;
@Controller
@RequestMapping("/financial/accounts")
public final class AccountController {
@Autowired private CacheStore cache;
@Autowired private AccountService accountService;
@InitBinder
public void initBinder(WebDataBinder binder) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
}
@RequestMapping
public String index(ModelMap modelMap) {
modelMap.addAttribute("all", Boolean.TRUE);
SortedSet<Account> accounts = new TreeSet<Account>();
UserDetails user = UserDetails.findCurrentUser();
Set<Account> userAccounts = user.getAccounts();
if (CollectionUtils.isEmpty(userAccounts)) {
return CollectionUtils.isEmpty(user.getInstitutions()) ? "administration/createInstitution" : createForm(modelMap);
}
accounts.addAll(userAccounts);
modelMap.addAttribute("accounts", accounts);
return "accounts/index";
}
@RequestMapping("/favorites")
public String favorites(ModelMap modelMap) {
modelMap.addAttribute("all", Boolean.FALSE);
modelMap.addAttribute("accounts", UserDetails.findCurrentUser().getFavoriteAccounts());
return "accounts/favorites";
}
@RequestMapping("/{id}")
public String details(@PathVariable Long id, ModelMap modelMap) {
return details(Account.findAccount(id), modelMap);
}
protected String details(Account account, ModelMap modelMap) {
if (account != null) {
UserDetails user = UserDetails.findCurrentUser();
if (account.belongsTo(user)) {
modelMap.addAttribute("account", account);
modelMap.addAttribute("transactions", new TreeSet<AccountTransaction>(account.getTransactions()));
}
}
return account.isCreditCard() ? "accounts/detailscc" : account.isBankAccount() ? "accounts/details" : "accounts/investment";
}
@RequestMapping("/create")
public String createForm(ModelMap modelMap) {
UserDetails user = UserDetails.findCurrentUser();
Set<FinancialInstitution> institutions = new TreeSet<FinancialInstitution>(user.getInstitutions());
if (CollectionUtils.isEmpty(institutions)) {
return "administration/createInstitution";
}
modelMap.addAttribute("institutions", institutions);
modelMap.addAttribute("types", AccountType.findAllAccountTypes());
return "accounts/create";
}
@RequestMapping(value = "/create", method = RequestMethod.POST)
public String create(Account account, ModelMap modelMap) {
accountService.createAccount(account);
cache.invalidate(account.getOwner());
return index(modelMap);
}
@RequestMapping("/add")
public String addTransaction(ModelMap modelMap) {
fillTransactionModel(modelMap);
return "accounts/add";
}
@RequestMapping("/add/{account}")
public String addTransaction(@PathVariable Long account, ModelMap modelMap) {
UserDetails user = fillTransactionModel(modelMap);
fillProvidedAccount(account, user, modelMap);
return "accounts/add";
}
protected UserDetails fillTransactionModel(ModelMap modelMap) {
UserDetails user = fillTransferTransactionModel(modelMap);
modelMap.addAttribute("payees", new TreeSet<Payee>(user.getPayees()));
modelMap.addAttribute("categories", new TreeSet<Subcategory>(Subcategory.findSelectableCategories(user)));
return user;
}
protected UserDetails fillTransferTransactionModel(ModelMap modelMap) {
UserDetails user = UserDetails.findCurrentUser();
List<Account> accounts = Account.findOpenAccounts(user);
modelMap.addAttribute("accounts", accounts);
String currency = "EUR";
if (!CollectionUtils.isEmpty(accounts)) {
currency = accounts.get(0).getCurrency();
}
modelMap.addAttribute("currency", currency);
return user;
}
@SuppressWarnings("unchecked")
protected void fillProvidedAccount(Long account, UserDetails user, ModelMap modelMap) {
Account loaded = Account.findAccount(account);
if ((loaded != null) && (loaded.belongsTo(user))) {
modelMap.addAttribute("account", loaded);
modelMap.addAttribute("currency", loaded.getCurrency());
List<Account> accounts = new ArrayList<Account>((List<Account>) modelMap.get("accounts"));
accounts.remove(loaded);
modelMap.addAttribute("accounts", accounts);
}
}
@RequestMapping(value = "/add", method = RequestMethod.POST)
public String addTransaction(AccountTransaction transaction, ModelMap modelMap) {
long accountId = accountService.addTransaction(transaction);
cache.invalidate(transaction.getAccount().getOwner());
return details(accountId, modelMap);
}
@RequestMapping("/transfer")
public String transfer(ModelMap modelMap) {
fillTransferTransactionModel(modelMap);
return "accounts/transfer";
}
@RequestMapping("/transfer/{account}")
public String transfer(@PathVariable Long account, ModelMap modelMap) {
UserDetails user = fillTransferTransactionModel(modelMap);
fillProvidedAccount(account, user, modelMap);
return "accounts/transfer";
}
@RequestMapping(value = "/transfer", method = RequestMethod.POST)
public String transfer(Long origin, Long target, Date operationDate, BigDecimal amount, BigDecimal chargeAmount, double rate, String memo, ModelMap modelMap) {
cache.invalidate(UserDetails.findCurrentUser());
accountService.transferMoney(origin, target, operationDate, amount, chargeAmount, rate, memo);
return details(origin, modelMap);
}
@RequestMapping("/balance/{accountId}")
public String balance(@PathVariable Long accountId, ModelMap modelMap) {
Account account = Account.findAccount(accountId);
if (account != null) {
UserDetails user = UserDetails.findCurrentUser();
if (account.belongsTo(user) && account.isCreditCard()) {
modelMap.addAttribute("account", account);
modelMap.addAttribute("origin", user.getBankAccounts());
modelMap.addAttribute("transactions", AccountTransaction.findUnreconciledTransactions(account));
}
}
return "accounts/balance";
}
@RequestMapping(value = "/pay-balance", method = RequestMethod.POST)
public String balance(Long accountId, Long originId, String transactions, Date operationDate, ModelMap modelMap) {
if (hasText(transactions)) {
Account origin = Account.findAccount(originId);
Account account = Account.findAccount(accountId);
if ((account != null) && (origin != null)) {
UserDetails user = UserDetails.findCurrentUser();
if (account.belongsTo(user) && origin.belongsTo(user)) {
cache.invalidate(user);
accountService.balance(user, account, origin, operationDate, transactions.split("-"));
}
}
}
return index(modelMap);
}
@RequestMapping("/view/{id}")
public String view(@PathVariable Long id, ModelMap modelMap) {
Account account = Account.findAccount(id);
UserDetails user = UserDetails.findCurrentUser();
modelMap.addAttribute("institutions", new TreeSet<FinancialInstitution>(user.getInstitutions()));
if (account.belongsTo(user)) {
modelMap.addAttribute("account", account);
}
return "accounts/view";
}
@RequestMapping(value = "/edit", method = RequestMethod.POST)
public String edit(Account account, ModelMap modelMap) {
UserDetails user = UserDetails.findCurrentUser();
Account loaded = Account.findAccount(account.getId());
if (loaded.belongsTo(user)) {
cache.invalidate(user);
loaded.setIsbn(account.getIsbn());
loaded.setName(account.getName());
loaded.setLocale(account.getLocale());
loaded.setOpened(account.getOpened());
loaded.setFavorite(account.getFavorite());
loaded.setDescription(account.getDescription());
loaded.setAccountNumber(account.getAccountNumber());
loaded.setInitialBalance(account.getInitialBalance());
loaded.setHeldAt(FinancialInstitution.findFinancialInstitution(account.getHeldAt().getId()));
loaded.merge();
}
return index(modelMap);
}
@RequestMapping("/view-transaction/{id}")
public String viewTransaction(@PathVariable Long id, ModelMap modelMap) {
String jsp = "accounts/view-transaction";
UserDetails user = fillTransactionModel(modelMap);
AccountTransaction accountTransaction = AccountTransaction.findAccountTransaction(id);
if ((accountTransaction != null) && (accountTransaction.isInvestmentTransaction())) {
jsp = "redirect:/financial/investments/view/" + accountTransaction.getInvestment().getId();
} else if ((accountTransaction != null) && (accountTransaction.getAccount().belongsTo(user))) {
modelMap.addAttribute("transaction", accountTransaction);
}
return jsp;
}
@RequestMapping(value = "/edit-transaction", method = RequestMethod.POST)
public String editTransaction(AccountTransaction transaction, ModelMap modelMap) {
UserDetails user = UserDetails.findCurrentUser();
AccountTransaction loaded = AccountTransaction.findAccountTransaction(transaction.getId());
if (loaded.getAccount().belongsTo(user)) {
cache.invalidate(user);
loaded.setMemo(transaction.getMemo());
loaded.setAmount(transaction.getAmount());
loaded.setOperationDate(transaction.getOperationDate());
loaded.setReferenceNumber(transaction.getReferenceNumber());
loaded.setPayee(Payee.findPayee(transaction.getPayee().getId()));
loaded.setSubcategory(Subcategory.findSubcategory(transaction.getSubcategory().getId()));
loaded.merge();
}
return details(loaded.getAccount().getId(), modelMap);
}
@RequestMapping("/remove/{id}")
public String remove(@PathVariable Long id, ModelMap modelMap) {
Account account = null;
AccountTransaction transaction = AccountTransaction.findAccountTransaction(id);
if (transaction != null) {
account = transaction.getAccount();
if (account.belongsTo(UserDetails.findCurrentUser())) {
transaction.remove();
}
}
return details(account, modelMap);
}
}