de.inren.service.banking.BankDataServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for de.inren.service.banking.BankDataServiceImpl.java

Source

/**
 * Copyright 2014 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package de.inren.service.banking;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Nullable;
import javax.annotation.Resource;

import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVRecord;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import de.inren.data.domain.banking.Account;
import de.inren.data.domain.banking.Category;
import de.inren.data.domain.banking.CategoryFilter;
import de.inren.data.domain.banking.Transaction;
import de.inren.data.domain.banking.TransactionCategoryFilterSpecification;
import de.inren.data.domain.banking.TransactionDateSpecification;
import de.inren.data.domain.tagging.Tag;
import de.inren.data.repositories.banking.AccountRepository;
import de.inren.data.repositories.banking.CategoryFilterRepository;
import de.inren.data.repositories.banking.CategoryRepository;
import de.inren.data.repositories.banking.TransactionRepository;
import de.inren.data.repositories.tagging.TagRepository;
import de.inren.service.banking.TransactionSummary.TransactionSummaryType;

@Service(value = "bankDataService")
@Transactional(readOnly = true)
public class BankDataServiceImpl implements BankDataService {
    private static final Sort SORT_VALUTA_ASC = new Sort(Direction.ASC, "valutaDate");

    private final static Logger log = LoggerFactory.getLogger(BankDataServiceImpl.class);

    @Resource
    private AccountRepository accountRepository;

    @Resource
    private TransactionRepository transactionRepository;

    @Resource
    private CategoryRepository categoryRepository;

    @Resource
    private TagRepository tagRepository;

    @Resource
    private CategoryFilterRepository categoryFilterRepository;

    private boolean initDone = false;

    @Override
    public void init() {
        if (!initDone) {
            log.info("BankDataService init start.");
            initDone = true;
            log.info("BankDataService init done.");
        }
    }

    @Override
    public void importTransactionCsv(byte[] bytes) throws IOException {
        Iterable<CSVRecord> records = getIngDibaCsvFormat().parse(createReader(bytes));
        Account account = new Account();
        for (CSVRecord record : records) {
            switch ((int) record.getRecordNumber()) {
            case 1: // Umsatzanzeige
                break;
            case 2: // Kunde
                account.setOwner(record.get(1).trim());
                break;
            case 3: // Konto
                String[] vals = record.get(1).split(":");
                account.setName(vals[0].trim());
                account.setNumber(vals[1].trim());
                account = validateAccount(account);
                break;
            case 4: //
                break;
            case 5: // Zeitraum
                break;
            case 6: // Saldo
                break;
            case 7: // Leer
                break;
            case 8: // berschrift
                break;
            default: // Eintrag
                Transaction transaction = new Transaction();
                transaction.setAccountNumber(account.getNumber().trim());
                transaction.setAccountingDate(getDate(record.get(0)));
                transaction.setValutaDate(getDate(record.get(1)));
                transaction.setPrincipal(record.get(2).trim());
                transaction.setAccountingText(record.get(3).trim());
                transaction.setPurpose(record.get(4).trim());
                transaction.setAmount(getBigDecimal(record.get(5)));
                transaction.setTransactionCurrency(record.get(6).trim());
                transaction.setBalance(getBigDecimal(record.get(7)));
                transaction.setBalanceCurrency(record.get(8).trim());
                transaction.setHashCode(transaction.createHashCode());
                Transaction oldTransaction = transactionRepository.findByHashCode(transaction.getHashCode());
                // only save new transactions
                if (oldTransaction == null) {
                    transactionRepository.save(transaction);
                }
            }
        }
        // Add the categories to the new (all) transactions. Should be
        // optimized.
        Iterable<Category> categories = categoryRepository.findAll();
        for (Category category : categories) {
            applyCategoryToTransactions(category);
        }
    }

    private BigDecimal getBigDecimal(String value) {
        value = value.replace(".", "");
        value = value.replace(',', '.');
        return BigDecimal.valueOf(Double.parseDouble(value));
    }

    private Date getDate(String dateStr) {
        SimpleDateFormat formatter = new SimpleDateFormat("dd.MM.yyyy");
        try {
            return formatter.parse(dateStr.trim());
        } catch (ParseException e) {
            throw new IllegalStateException(e);
        }

    }

    private Account validateAccount(Account account) {
        Account entity = accountRepository.findByNumber(account.getNumber());
        if (entity == null) {
            entity = accountRepository.save(account);
        } else {
            if (!account.getName().equals(entity.getName())) {
                entity.setName(account.getName());
                entity = accountRepository.save(entity);
            }
        }
        return entity;
    }

    @Override
    public void importFinanceCsv(byte[] bytes) throws IOException {
        Iterable<CSVRecord> records = getIngDibaCsvFormat().parse(createReader(bytes));
        for (CSVRecord record : records) {
            log.info(record.toString());
        }
    }

    private Reader createReader(byte[] bytes) throws UnsupportedEncodingException {
        String csv = new String(bytes, "ISO-8859-15");
        Reader reader = new BufferedReader(new StringReader(csv));
        return reader;
    }

    private CSVFormat getIngDibaCsvFormat() {
        return CSVFormat.DEFAULT.withDelimiter(';');
    }

    @Override
    public Transaction save(Transaction transaction) {
        return transactionRepository.save(transaction);
    }

    @Override
    public CategoryFilter save(CategoryFilter categoryFilter) {
        categoryFilter = categoryFilterRepository.save(categoryFilter);
        applyCategoryToTransactions(categoryFilter);
        return categoryFilter;
    }

    @Override
    public List<String> getCategoryNames() {
        List<String> result = new ArrayList<String>();
        Iterable<Category> categories = categoryRepository.findAll();
        for (Category category : categories) {
            result.add(category.getName());
        }
        return result;
    }

    @Override
    public void removeCategoryFromTransactions(CategoryFilter categoryFilter) {

        List<Transaction> entities = transactionRepository
                .findAll(new TransactionCategoryFilterSpecification(categoryFilter), SORT_VALUTA_ASC);
        Iterator<Transaction> iterator = entities.iterator();
        while (iterator.hasNext()) {
            Transaction transaction = (Transaction) iterator.next();
            if (transaction.isCategoryFixed()) {
                iterator.remove();
            } else {
                transaction.setCategory(null);
            }

        }
        transactionRepository.save(entities);
    }

    @Override
    public void applyCategoryToTransactions(CategoryFilter categoryFilter) {
        List<Transaction> entities = transactionRepository
                .findAll(new TransactionCategoryFilterSpecification(categoryFilter), SORT_VALUTA_ASC);
        Iterator<Transaction> iterator = entities.iterator();
        while (iterator.hasNext()) {
            Transaction transaction = (Transaction) iterator.next();
            if (transaction.isCategoryFixed()) {
                iterator.remove();
            } else {
                transaction.setCategory(categoryFilter.getCategory().getName());
            }
        }
        transactionRepository.save(entities);
    }

    @Override
    public List<Category> findAllCategories() {
        List<Category> categories = new ArrayList<Category>();
        Iterable<Category> entities = categoryRepository.findAll();
        for (Category category : entities) {
            categories.add(category);
        }
        return categories;
    }

    @Override
    public void applyCategoryToTransactions(Category category) {
        for (CategoryFilter categoryFilter : category.getFilter()) {
            List<Transaction> entities = transactionRepository
                    .findAll(new TransactionCategoryFilterSpecification(categoryFilter));
            for (Transaction transaction : entities) {
                transaction.setCategory(category.getName());
            }
            transactionRepository.save(entities);
        }

    }

    @Override
    public void removeCategoryFromTransactions(Category category) {
        List<Transaction> entities = transactionRepository.findAllByCategory(category.getName());
        for (Transaction transaction : entities) {
            transaction.setCategory(null);
        }
        transactionRepository.save(entities);
    }

    @Override
    public void deleteCategory(Category category) {
        categoryFilterRepository.delete(category.getFilter());
        removeCategoryFromTransactions(category);
        categoryRepository.delete(category);
    }

    @Override
    public Category save(Category entity) {
        return categoryRepository.save(entity);
    }

    @Override
    public Collection<TransactionSummary> calculateTransactionSummary(TransactionSummaryType transactionSummaryType,
            Date from, @Nullable Date until) {
        if (transactionSummaryType.name().equals(TransactionSummaryType.ALL.name())) {
            Map<String, TransactionSummary> summery = new HashMap<String, TransactionSummary>();
            List<Transaction> entities = transactionRepository
                    .findAll(new TransactionDateSpecification(from, until));
            for (Transaction transaction : entities) {
                if (StringUtils.isEmpty(transaction.getCategory())) {
                    transaction.setCategory("no category");
                }
                if (summery.containsKey(transaction.getCategory())) {
                    TransactionSummary sum = summery.get(transaction.getCategory());
                    sum.addTransaction(transaction);
                    log.info(String.valueOf(transaction.getAmount()) + "=>" + sum.toString());
                } else {
                    summery.put(transaction.getCategory(), new TransactionSummary(transaction.getCategory(),
                            transaction.getAmount(), transaction.getBalanceCurrency(), transaction));
                }
            }
            return summery.values();
        } else {
            return calculateTransactionSummary(
                    transactionSummaryType.name().equals(TransactionSummaryType.INCOME.name()), from, until);
        }
    }

    private Collection<TransactionSummary> calculateTransactionSummary(boolean income, Date from,
            @Nullable Date until) {
        Map<String, TransactionSummary> summery = new HashMap<String, TransactionSummary>();
        List<Category> categories = categoryRepository.findByIncome(income);
        Set<String> categoryNames = new HashSet<String>();
        if (!income) {
            categoryNames.add("no category");
        }
        for (Category category : categories) {
            categoryNames.add(category.getName());
        }

        List<Transaction> entities = transactionRepository.findAll(new TransactionDateSpecification(from, until),
                SORT_VALUTA_ASC);
        for (Transaction transaction : entities) {
            if (!income && StringUtils.isEmpty(transaction.getCategory())) {
                transaction.setCategory("no category");
            }
            if (categoryNames.contains(transaction.getCategory())) {
                if (summery.containsKey(transaction.getCategory())) {
                    TransactionSummary sum = summery.get(transaction.getCategory());
                    sum.addTransaction(transaction);
                    log.info(String.valueOf(transaction.getAmount()) + "=>" + sum.toString());
                } else {
                    summery.put(transaction.getCategory(), new TransactionSummary(transaction.getCategory(),
                            transaction.getAmount(), transaction.getBalanceCurrency(), transaction));
                }
            }
        }
        return summery.values();
    }

    @Override
    public List<PrincipalInfo> getPrincipalInfo() {
        Map<String, PrincipalInfo> infoMap = new HashMap<String, PrincipalInfo>();
        Iterable<Transaction> all = transactionRepository.findAll();
        for (Transaction transaction : all) {
            PrincipalInfo info;
            if (infoMap.containsKey(transaction.getPrincipal())) {
                info = infoMap.get(transaction.getPrincipal());
                info.setCount(info.getCount() + 1);
                info.setFiltered(info.isFiltered() || !StringUtils.isEmpty(transaction.getCategory()));
            } else {
                infoMap.put(transaction.getPrincipal(), new PrincipalInfo(transaction.getPrincipal(), 1,
                        !StringUtils.isEmpty(transaction.getCategory())));
            }
        }
        return new ArrayList<PrincipalInfo>(infoMap.values());
    }

    @Override
    public BalanceSummary loadBalanceSummary(Date from, Date until) {
        BalanceSummary balanceSummary = new BalanceSummary();
        balanceSummary.setFrom(from);
        balanceSummary.setUntil(until);
        Iterable<Account> accounts = accountRepository.findAll();
        for (Account account : accounts) {
            balanceSummary.getAccounts().add(account);
            List<Transaction> transactions = transactionRepository
                    .findAll(new TransactionDateSpecification(from, until, account.getNumber()), SORT_VALUTA_ASC);
            if (!transactions.isEmpty()) {
                balanceSummary.getFromBalance().put(account.getNumber(), transactions.get(0).getBalance());
                balanceSummary.getUntilBalance().put(account.getNumber(),
                        transactions.get(transactions.size() - 1).getBalance());
            } else {
                balanceSummary.getFromBalance().put(account.getNumber(), BigDecimal.ZERO);
                balanceSummary.getUntilBalance().put(account.getNumber(), BigDecimal.ZERO);
            }
        }
        return balanceSummary;
    }

    @Override
    public List<Category> findAllCategoriesForMonthReport() {
        return categoryRepository.findByMarksMonth(true);
    }

    @Override
    public List<Transaction> findTransactionsByCategory(Category category) {
        return transactionRepository.findAllByCategory(category.getName(), SortByValutaDateAsc());
    }

    private Sort SortByValutaDateAsc() {
        return new Sort(Sort.Direction.ASC, "valutaDate");
    }

    @Override
    public Tag save(Tag tag) {
        return tagRepository.save(tag);
    }

    @Override
    public void deleteTag(Tag tag) {
        tagRepository.delete(tag);

    }

    @Override
    public void applyTagToTransactions(Tag tag) {
        System.out.println("applyTagToTransactions(Tag " + tag + ")");
    }

    @Override
    public void removeTagFromTransactions(Tag tag) {
        System.out.println("removeTagFromTransactions(Tag " + tag + ")");
    }

    @Override
    public List<String> loadAllTagNames() {
        List<String> names = new ArrayList<>();
        Iterable<Tag> all = tagRepository.findAll();
        for (Tag tag : all) {
            names.add(tag.getName());
        }
        return names;
    }
}