org.pau.assetmanager.viewmodel.AnnotationViewModel.java Source code

Java tutorial

Introduction

Here is the source code for org.pau.assetmanager.viewmodel.AnnotationViewModel.java

Source

/**
 * This file is part of Pau's Asset Manager Project.
 *
 * Pau's Asset Manager Project is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Pau's Asset Manager Project is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Pau's Asset Manager Project.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.pau.assetmanager.viewmodel;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.LinkedList;
import java.util.List;

import org.apache.commons.lang.time.DateUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.pau.assetmanager.business.AnnotationsBusiness;
import org.pau.assetmanager.business.ConceptsBusiness;
import org.pau.assetmanager.business.DaoFunction;
import org.pau.assetmanager.entities.Annotation;
import org.pau.assetmanager.entities.Annotation.AnnotationType;
import org.pau.assetmanager.entities.Book;
import org.pau.assetmanager.entities.Client;
import org.pau.assetmanager.entities.ExpensesAnnotation;
import org.pau.assetmanager.entities.GeneralExpensesAnnotation;
import org.pau.assetmanager.entities.GeneralIncomeAnnotation;
import org.pau.assetmanager.entities.IncomeAnnotation;
import org.pau.assetmanager.entities.MovementExpensesAnnotation;
import org.pau.assetmanager.entities.PropertyExpensesAnnotation;
import org.pau.assetmanager.entities.PropertyIncomeAnnotation;
import org.pau.assetmanager.entities.StockExpensesAnnotation;
import org.pau.assetmanager.entities.StockIncomeAnnotation;
import org.pau.assetmanager.viewmodel.stocks.ConceptValidation;
import org.pau.assetmanager.viewmodel.stocks.HistoricalStocksValuesDownloader;
import org.pau.assetmanager.viewmodel.stocks.StocksHistory;
import org.pau.assetmanager.viewmodel.stocks.StocksIncomeError;
import org.pau.assetmanager.viewmodel.stocks.StocksUtils;
import org.pau.assetmanager.viewmodel.type.BookSelectionType;
import org.pau.assetmanager.viewmodel.utils.AnnotationsFilter;
import org.pau.assetmanager.viewmodel.utils.BookSelection;
import org.pau.assetmanager.viewmodel.utils.SortingCriteria;
import org.zkoss.bind.BindUtils;
import org.zkoss.bind.annotation.BindingParam;
import org.zkoss.bind.annotation.Command;
import org.zkoss.bind.annotation.ContextParam;
import org.zkoss.bind.annotation.ContextType;
import org.zkoss.bind.annotation.DependsOn;
import org.zkoss.bind.annotation.GlobalCommand;
import org.zkoss.bind.annotation.Init;
import org.zkoss.bind.annotation.NotifyChange;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.InputEvent;
import org.zkoss.zk.ui.util.Clients;

import com.google.common.base.Optional;

/**
 * This class is the ViewModel class that deals with all the UI interactions
 * related to the editable grid of annotations. This grid has sorting and
 * filtering enabled for all the fields and also controls the enabling and the
 * visibility of the editable cells depending on its applicability.
 * 
 * The UI ZUL files involved directly or indirectly (using subclasses of the
 * this class) are the following: - general_expenses_annotations.zul -
 * general_income_annotations.zul - movement_annotations.zul -
 * property_expenses_annotations.zul - property_income_annotations.zul -
 * stocks_expenses_annotations.zul - stocks_income_annotations.zul
 * 
 * 
 * @author Pau Carr Cardona
 * 
 */

public class AnnotationViewModel {

    // book selection in the main view
    protected BookSelection bookSelection = null;
    // current year selected
    protected Integer currentYear = null;
    // filtering applied
    protected AnnotationsFilter annotationsFilter = new AnnotationsFilter();
    // reference to the annotation that is just created
    protected Annotation justCreatedAnnotation = null;
    // reference to the last created annotation
    // TODO: this is not clear at all and makes confusion with the field
    // 'justCreatedAnnotation' --> refactor!!
    protected Annotation lastestCreatedAnnotation = null;
    // the type of annotation selected (income or expenses)
    protected AnnotationType annotationType;

    protected static Logger logger = LogManager.getLogger(MonthlyReportViewModel.class);

    @Init
    public void init(@BindingParam("annotationType") String annotationType) {
        Calendar calendar = GregorianCalendar.getInstance();
        calendar.setTime(new Date());
        this.currentYear = calendar.get(Calendar.YEAR);
        this.annotationType = AnnotationType.valueOf(annotationType);
    }

    public BookSelectionType getBookSelectionType() {
        return bookSelection.getBookSelectionType();
    }

    public Client getSelectedClient() {
        return bookSelection.getSelectedClient();
    }

    public Integer getCurrentYear() {
        return currentYear;
    }

    // Annotations are notified by updateCurrentYear
    public void setCurrentYear(Integer currentYear) {
        this.currentYear = currentYear;
    }

    @Command
    @NotifyChange({ "annotations", "currentYear" })
    public void updateCurrentYear(@ContextParam(ContextType.TRIGGER_EVENT) Event event) {
        String value = (String) event.getData();
        Integer newValue = new Integer(value);
        if (!newValue.equals(currentYear)) {
            this.currentYear = newValue;
        }
    }

    @Command
    public void saveAnnotation(@BindingParam("annotation") Annotation annotation) {
        if (annotation.getId() != null) {
            if (annotation instanceof MovementExpensesAnnotation) {
                MovementExpensesAnnotation movementExpensesAnnotation = (MovementExpensesAnnotation) annotation;
                DaoFunction.mergeFunction().apply(movementExpensesAnnotation.getMovementIncomeAnnotation());
            }
            DaoFunction.mergeFunction().apply(annotation);
            HistoricalStocksValuesDownloader.updateStocksHistoricalValuesAsync();
            BindUtils.postGlobalCommand(null, null, "updateReportAnnotations", null);
        }
    }

    @NotifyChange({ "annotations", "getConceptsForFiltering", "getConcepts" })
    @Command
    public void saveAnnotationWithConcept(@BindingParam("annotation") Annotation annotation,
            @ContextParam(ContextType.TRIGGER_EVENT) InputEvent event) {
        if (annotation.getId() != null) {
            String concept = event.getValue();
            annotation.setConcept(concept);
            if (annotation instanceof MovementExpensesAnnotation) {
                MovementExpensesAnnotation movementExpensesAnnotation = (MovementExpensesAnnotation) annotation;
                DaoFunction.mergeFunction().apply(movementExpensesAnnotation.getMovementIncomeAnnotation());
            }
            DaoFunction.mergeFunction().apply(annotation);
            HistoricalStocksValuesDownloader.updateStocksHistoricalValuesAsync();
            BindUtils.postGlobalCommand(null, null, "updateReportAnnotations", null);
        }
    }

    @DependsOn({ "selectedBook", "bookSelectionType", "selectedClient", "currentYear", "annotationsFilter" })
    public List<Annotation> getAnnotations() {
        List<Annotation> annotations = new LinkedList<Annotation>();
        if (bookSelection.getSelectedBook() != null
                && bookSelection.getBookSelectionType().equals(BookSelectionType.SINGLE_BOOK)) {
            annotations = AnnotationsBusiness.getNonMovementAnnotations(Optional.<AnnotationType>of(annotationType),
                    bookSelection, Optional.<Integer>of(currentYear), SortingCriteria.DESCENDING,
                    annotationsFilter);
            if (justCreatedAnnotation != null && annotations.contains(justCreatedAnnotation)) {
                annotations.remove(justCreatedAnnotation);
                annotations.add(0, justCreatedAnnotation);
                justCreatedAnnotation = null;
            }
        }
        Clients.clearBusy();
        return annotations;
    }

    @NotifyChange({ "selectedBook", "bookSelectionType", "selectedClient" })
    @GlobalCommand
    public void updateBookSelection(@BindingParam("bookSelection") BookSelection bookSelection) {
        this.bookSelection = bookSelection;
    }

    @NotifyChange({ "annotations" })
    @Command
    public void addPropertyAnnotation() {
        Annotation annotation = null;
        if (annotationType.equals(AnnotationType.INCOME)) {
            PropertyIncomeAnnotation incomeAnnotation = new PropertyIncomeAnnotation();
            incomeAnnotation.setUpDefaults();
            annotation = incomeAnnotation;
            addDefaultValuesToAnnotation(annotation, bookSelection.getSelectedBook(), currentYear,
                    annotationsFilter);
        } else {
            PropertyExpensesAnnotation expensesAnnotation = new PropertyExpensesAnnotation();
            expensesAnnotation.setUpDefaults();
            annotation = expensesAnnotation;
            addDefaultValuesToAnnotation(annotation, bookSelection.getSelectedBook(), currentYear,
                    annotationsFilter);
        }
        addAnnotation(annotation);
        Clients.clearBusy();
    }

    @NotifyChange("wrongStockConcepts")
    @GlobalCommand
    public void updateReportAnnotations() {
    }

    public Annotation getJustCreatedAnnotation() {
        return justCreatedAnnotation;
    }

    public AnnotationsFilter getAnnotationsFilter() {
        return annotationsFilter;
    }

    public void setAnnotationsFilter(AnnotationsFilter annotationsFilter) {
        this.annotationsFilter = annotationsFilter;
    }

    public Annotation getLastestCreatedAnnotation() {
        return lastestCreatedAnnotation;
    }

    // TODO: check it!!
    public List<String> getConceptsForFiltering(@BindingParam("type") String type) {
        List<String> conceptsForFiltering = new LinkedList<String>();
        conceptsForFiltering.addAll(getConcepts(type));
        // sort concept in a case-unsensitive way
        Collections.sort(conceptsForFiltering, new Comparator<String>() {
            @Override
            public int compare(String stringA, String stringB) {
                return stringA.compareToIgnoreCase(stringB);
            }
        });
        conceptsForFiltering.add(0, AnnotationsFilter.ALL_CONCEPTS);
        return conceptsForFiltering;
    }

    public Book getSelectedBook() {
        return bookSelection.getSelectedBook();
    }

    @NotifyChange({ "annotations" })
    @Command
    public void addGeneralAnnotation() {
        Annotation annotation = null;
        if (annotationType.equals(AnnotationType.EXPENSES)) {
            ExpensesAnnotation stockExpensesAnnotation = new GeneralExpensesAnnotation();
            annotation = stockExpensesAnnotation;
            addDefaultValuesToAnnotation(annotation, bookSelection.getSelectedBook(), currentYear,
                    annotationsFilter);
        } else if (annotationType.equals(AnnotationType.INCOME)) {
            IncomeAnnotation stockIncomeAnnotation = new GeneralIncomeAnnotation();
            annotation = stockIncomeAnnotation;
            addDefaultValuesToAnnotation(annotation, bookSelection.getSelectedBook(), currentYear,
                    annotationsFilter);
        }
        addAnnotation(annotation);
        Clients.clearBusy();
    }

    @NotifyChange({ "annotations" })
    @Command
    public void addStocksAnnotation() {
        Annotation annotation = null;
        if (annotationType.equals(AnnotationType.EXPENSES)) {
            StockExpensesAnnotation stockExpensesAnnotation = new StockExpensesAnnotation();
            annotation = stockExpensesAnnotation;
        } else if (annotationType.equals(AnnotationType.INCOME)) {
            StockIncomeAnnotation stockIncomeAnnotation = new StockIncomeAnnotation();
            annotation = stockIncomeAnnotation;
        }
        addDefaultValuesToAnnotation(annotation, bookSelection.getSelectedBook(), currentYear, annotationsFilter);
        addAnnotation(annotation);
        Clients.clearBusy();
    }

    protected Annotation addAnnotation(Annotation annotation) {
        annotation = AnnotationsBusiness.createAnnotation(annotation);
        justCreatedAnnotation = annotation;
        lastestCreatedAnnotation = justCreatedAnnotation;
        annotationsFilter.clearDateAndCostFilter();
        BindUtils.postGlobalCommand(null, null, "updateReportAnnotations", null);
        return annotation;
    }

    protected void addDefaultValuesToAnnotation(Annotation annotation, Book selectedBook, Integer currentYear,
            AnnotationsFilter annotationsFilter) {
        annotation.setBook(selectedBook);
        annotation.setAmount(0.0);
        Calendar calendar = GregorianCalendar.getInstance();
        Integer systemDateYear = calendar.get(Calendar.YEAR);
        if (!systemDateYear.equals(currentYear)) {
            String dateAsString = "01/01/" + currentYear;
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd/MM/yyyy");
            try {
                Date dateForNewAnnotation = simpleDateFormat.parse(dateAsString);
                annotation.setDate(dateForNewAnnotation);
            } catch (ParseException e) {
                logger.error("Error parsing date", e);
            }
        } else {
            Calendar currentCalendar = GregorianCalendar.getInstance();
            currentCalendar = DateUtils.truncate(currentCalendar, Calendar.DATE);
            annotation.setDate(currentCalendar.getTime());
        }
        if (annotationsFilter.getConcept() != null
                && !annotationsFilter.getConcept().equals(AnnotationsFilter.ALL_CONCEPTS)) {
            annotation.setConcept(annotationsFilter.getConcept());
        } else {
            annotation.setConcept(getDefaultConcept(annotation));
        }
    }

    private String getDefaultConcept(Annotation annotation) {
        String concept = ConceptsBusiness.getDefaultConcept(annotation.getClass().getSimpleName());
        return concept;
    }

    @NotifyChange({ "annotations" })
    @Command
    public void deleteAnnotation(@ContextParam(ContextType.TRIGGER_EVENT) Event event) {
        Annotation annotation = (Annotation) event.getData();
        AnnotationsBusiness.deleteAnnotation(annotation);
        BindUtils.postGlobalCommand(null, null, "updateReportAnnotations", null);
        Clients.clearBusy();
    }

    @NotifyChange({ "annotations" })
    @Command
    public void duplicateAnnotation(@BindingParam("annotation") Annotation annotation,
            @ContextParam(ContextType.TRIGGER_EVENT) Event event) {
        annotation.setId(null);
        annotation.setDate(new Date());
        addAnnotation(annotation);
    }

    // TODO: check this for type
    public List<String> getConcepts(@BindingParam("type") String type) {
        List<String> concepts = new LinkedList<String>();
        concepts.add(ConceptsBusiness.getDefaultConcept(type));
        concepts.addAll(ConceptsBusiness.getConceptsUsedInBook(bookSelection));
        Collections.sort(concepts);
        return concepts;
    }

    /**
     * @return the list of wrong/inconsistent stock concepts. The method returns
     *         all the sold stock that were done at a time in which the number
     *         of bought stocks is below the amount of bought stocks (i.e. it is
     *         not possible to sell stocks one does not previously have)
     */
    @DependsOn("annotations")
    public List<ConceptValidation> getWrongStockConcepts() {
        List<ConceptValidation> conceptValidations = new LinkedList<ConceptValidation>();
        List<Annotation> annotations = StocksYearlyReportViewModel.getStocksAnnotationsUntilYear(bookSelection,
                currentYear);
        StocksHistory stocksHistory = StocksUtils.getStocksHistory(annotations);
        for (String currentConcept : stocksHistory.getStocksErrorsHistoryMap().keySet()) {
            StocksIncomeError currentError = stocksHistory.getStocksErrorsHistoryMap().get(currentConcept);
            ConceptValidation conceptValidation = new ConceptValidation(currentConcept, currentError.toString());
            conceptValidations.add(conceptValidation);
        }
        return conceptValidations;
    }

    @Command
    @NotifyChange({ "annotations" })
    public void refreshFilter(@ContextParam(ContextType.TRIGGER_EVENT) Event event) {

    }

    @Command
    @NotifyChange({ "annotations", "annotationsFilter" })
    public void disableDateFilter(@ContextParam(ContextType.TRIGGER_EVENT) Event event) {
        annotationsFilter.setDateFrom(null);
        annotationsFilter.setDateTo(null);
    }

    @Command
    @NotifyChange({ "annotations", "annotationsFilter" })
    public void disableForCompanyFilter(@ContextParam(ContextType.TRIGGER_EVENT) Event event) {
        annotationsFilter.setForCompany(null);
    }

    @Command
    @NotifyChange({ "annotations", "annotationsFilter" })
    public void disableUseQuarterly(@ContextParam(ContextType.TRIGGER_EVENT) Event event) {
        annotationsFilter.setUseQuarterly(null);
    }

    @Command
    @NotifyChange({ "annotations", "annotationsFilter" })
    public void disableCostFilter(@ContextParam(ContextType.TRIGGER_EVENT) Event event) {
        annotationsFilter.setCostFrom(null);
        annotationsFilter.setCostTo(null);
    }

    @Command
    @NotifyChange({ "annotations", "annotationsFilter" })
    public void disableRetentionFilter(@ContextParam(ContextType.TRIGGER_EVENT) Event event) {
        annotationsFilter.setRetentionFrom(null);
        annotationsFilter.setRetentionTo(null);
    }

    @Command
    @NotifyChange({ "annotations", "annotationsFilter" })
    public void disableVatFilter(@ContextParam(ContextType.TRIGGER_EVENT) Event event) {
        annotationsFilter.setVatFrom(null);
        annotationsFilter.setVatTo(null);
    }

    @Command
    @NotifyChange({ "annotations", "annotationsFilter" })
    public void disableUseYearlyFilter(@ContextParam(ContextType.TRIGGER_EVENT) Event event) {
        annotationsFilter.setUseYearly(null);
    }

    @Command
    @NotifyChange({ "annotations", "annotationsFilter" })
    public void disableDoneFilter(@ContextParam(ContextType.TRIGGER_EVENT) Event event) {
        annotationsFilter.setDone(null);
    }

    @Command
    @NotifyChange({ "annotations", "annotationsFilter" })
    public void disableDeductiblePercentageFilter(@ContextParam(ContextType.TRIGGER_EVENT) Event event) {
        annotationsFilter.setDeductiblePercentageFrom(null);
        annotationsFilter.setDeductiblePercentageTo(null);
    }

    @Command
    @NotifyChange({ "annotations", "annotationsFilter" })
    public void disableCommunityFilter(@ContextParam(ContextType.TRIGGER_EVENT) Event event) {
        annotationsFilter.setCommunity(null);
    }

}