net.sourceforge.fenixedu.domain.accounting.Receipt.java Source code

Java tutorial

Introduction

Here is the source code for net.sourceforge.fenixedu.domain.accounting.Receipt.java

Source

/**
 * Copyright  2002 Instituto Superior Tcnico
 *
 * This file is part of FenixEdu Core.
 *
 * FenixEdu Core is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * FenixEdu Core 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with FenixEdu Core.  If not, see <http://www.gnu.org/licenses/>.
 */
package net.sourceforge.fenixedu.domain.accounting;

import static net.sourceforge.fenixedu.injectionCode.AccessControl.check;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import net.sourceforge.fenixedu.dataTransferObject.accounting.CreditNoteEntryDTO;
import net.sourceforge.fenixedu.domain.Person;
import net.sourceforge.fenixedu.domain.administrativeOffice.AdministrativeOffice;
import net.sourceforge.fenixedu.domain.exceptions.DomainException;
import net.sourceforge.fenixedu.domain.organizationalStructure.Party;
import net.sourceforge.fenixedu.domain.organizationalStructure.Unit;
import net.sourceforge.fenixedu.predicates.AcademicPredicates;
import net.sourceforge.fenixedu.predicates.RolePredicates;
import net.sourceforge.fenixedu.util.FenixConfigurationManager;
import net.sourceforge.fenixedu.util.Money;

import org.apache.commons.lang.StringUtils;
import org.fenixedu.bennu.core.domain.Bennu;
import org.joda.time.DateTime;
import org.joda.time.YearMonthDay;

public class Receipt extends Receipt_Base {

    public static final String GENERIC_CONTRIBUTOR_PARTY_NUMBER = " ";

    private static final Integer MIN_YEAR_TO_CREATE_RECEIPTS = FenixConfigurationManager.getConfiguration()
            .getReceiptMinYearToCreate();

    private static final Map<Integer, String> NUMBER_SERIES_BY_YEAR = new HashMap<Integer, String>();

    static {

        final String[] parts = FenixConfigurationManager.getConfiguration().getReceiptNumberSeriesForYears()
                .split(",");

        for (final String part : parts) {
            if (!StringUtils.isEmpty(part)) {
                final String[] yearAndSeries = part.split(":");
                NUMBER_SERIES_BY_YEAR.put(Integer.valueOf(yearAndSeries[0]), yearAndSeries[1]);
            }
        }

    }

    public static Comparator<Receipt> COMPARATOR_BY_NUMBER = new Comparator<Receipt>() {
        @Override
        public int compare(Receipt leftReceipt, Receipt rightReceipt) {
            int comparationResult = leftReceipt.getReceiptNumber().compareTo(rightReceipt.getReceiptNumber());
            return (comparationResult == 0) ? leftReceipt.getExternalId().compareTo(rightReceipt.getExternalId())
                    : comparationResult;
        }
    };

    protected Receipt() {
        super();
    }

    static public Receipt createWithContributorParty(Person responsible, Person person, Party contributor,
            Integer year, List<Entry> entries) {
        final Receipt result = new Receipt();
        result.init(responsible, person, contributor, null, year, entries, NUMBER_SERIES_BY_YEAR.get(year));

        return result;
    }

    static public Receipt createWithContributorName(Person responsible, Person person, String contributorName,
            Integer year, List<Entry> entries) {
        final Receipt result = new Receipt();
        result.init(responsible, person, null, contributorName, year, entries, NUMBER_SERIES_BY_YEAR.get(year));

        return result;
    }

    static public Receipt createWithContributorPartyOrContributorName(Person responsible, Person person,
            Party contributorParty, String contributorName, Integer year, List<Entry> entries) {
        final Receipt result = new Receipt();
        result.init(responsible, person, contributorParty, contributorName, year, entries,
                NUMBER_SERIES_BY_YEAR.get(year));

        return result;

    }

    private void init(Person responsible, Person person, Party contributorParty, String contributorName,
            Integer year, List<Entry> entries, String numberSeries) {

        checkParameters(person, contributorParty, contributorName, year, entries);

        checkRulesToCreate(person, year, entries);

        super.setNumber(generateReceiptNumber(year));
        super.setRootDomainObject(Bennu.getInstance());
        super.setYear(year);
        super.setNumberSeries(numberSeries);
        super.setPerson(person);
        super.setContributorParty(contributorParty);
        super.setContributorName(contributorName);
        super.setWhenCreated(new DateTime());
        changeState(responsible, ReceiptState.ACTIVE);
        super.setReceiptDate(
                new YearMonthDay().getYear() != year.intValue() ? getLastDayOfYear(year) : new YearMonthDay());

        for (final Entry entry : entries) {
            entry.setActiveReceipt(this);
        }
    }

    private YearMonthDay getLastDayOfYear(Integer year) {
        return new YearMonthDay(year, 12, 31);
    }

    private void checkRulesToCreate(final Person person, final Integer year, final List<Entry> entries) {

        final YearMonthDay today = new YearMonthDay();

        if (year < MIN_YEAR_TO_CREATE_RECEIPTS.intValue()) {
            throw new DomainException("error.accounting.Receipt.invalid.receipt.year",
                    MIN_YEAR_TO_CREATE_RECEIPTS.toString());
        }

        for (final Entry entry : entries) {
            if (entry.getWhenRegistered().getYear() != year) {
                throw new DomainException("error.accounting.Receipt.entries.must.belong.to.receipt.civil.year");
            }

            if (!entry.getAccountingTransaction().isSourceAccountFromParty(person)) {
                throw new DomainException("error.accounting.Receipt.entries.must.belong.to.person");
            }
        }
    }

    private void checkParameters(Person person, Party contributor, String contributorName, Integer year,
            List<Entry> entries) {

        if (person == null) {
            throw new DomainException("error.accouting.Receipt.person.cannot.be.null");
        }

        checkContributorParameters(contributor, contributorName);

        if (year == null) {
            throw new DomainException("error.accounting.Receipt.year.cannot.be.null");
        }

        if (entries == null) {
            throw new DomainException("error.accounting.Receipt.entries.cannot.be.null");
        }

        if (entries.isEmpty()) {
            throw new DomainException("error.accounting.Receipt.entries.cannot.be.empty");
        }

    }

    private void checkContributorParameters(Party contributor, String contributorName) {
        if (contributor == null && StringUtils.isEmpty(contributorName)) {
            throw new DomainException("error.accounting.Receipt.contributor.or.contributorName.must.be.not.null");
        }

        if (contributor != null && !StringUtils.isEmpty(contributorName)) {
            throw new DomainException("error.accounting.Receipt.contributor.and.contributorName.are.exclusive");
        }
    }

    private void changeState(final Person responsible, final ReceiptState state) {
        markChange(responsible);
        super.setState(state);
    }

    private void markChange(final Person responsible) {
        super.setWhenUpdated(new DateTime());
        super.setResponsible(responsible);
    }

    @Override
    public void addEntries(Entry entries) {
        throw new DomainException("error.accounting.Receipt.cannot.add.new.entries");
    }

    @Override
    public Set<Entry> getEntriesSet() {
        return Collections.unmodifiableSet(super.getEntriesSet());
    }

    @Override
    public void removeEntries(Entry entries) {
        throw new DomainException("error.accounting.Receipt.cannot.remove.entries");
    }

    @Override
    public void setNumber(Integer number) {
        throw new DomainException("error.accounting.Receipt.cannot.modify.number");
    }

    @Override
    public void removeReceiptsVersions(ReceiptPrintVersion receiptsVersions) {
        throw new DomainException("error.accounting.Receipt.cannot.remove.receiptVersions");
    }

    @Override
    public void setPerson(Person person) {
        throw new DomainException("error.accounting.Receipt.cannot.modify.person");
    }

    @Override
    public void setYear(Integer year) {
        throw new DomainException("error.accounting.Receipt.cannot.modify.year");
    }

    @Override
    public void setWhenCreated(DateTime whenCreated) {
        throw new DomainException("error.accounting.Receipt.cannot.modify.creation.date");
    }

    @Override
    public void addCreditNotes(CreditNote creditNote) {
        throw new DomainException("error.accounting.Receipt.cannot.add.creditNote");
    }

    @Override
    public void setResponsible(Person responsible) {
        throw new DomainException("error.accounting.Receipt.cannot.modify.responsible");
    }

    @Override
    public void setContributorParty(Party contributorParty) {
        throw new DomainException("error.accounting.Receipt.cannot.modify.contributorParty");
    }

    @Override
    public Set<CreditNote> getCreditNotesSet() {
        return Collections.unmodifiableSet(super.getCreditNotesSet());
    }

    @Override
    public void removeCreditNotes(CreditNote creditNote) {
        throw new DomainException("error.accounting.Receipt.cannot.remove.creditNote");
    }

    @Override
    public void setState(ReceiptState state) {
        throw new DomainException("error.accounting.Receipt.cannot.modify.state");
    }

    @Override
    public void setOwnerUnit(Unit ownerUnit) {
        throw new UnsupportedOperationException();
    }

    private Integer generateReceiptNumber(int year) {
        final List<Receipt> receipts = getReceiptsFor(year);
        return receipts.isEmpty() ? 1
                : Collections.max(receipts, Receipt.COMPARATOR_BY_NUMBER).getReceiptNumber() + 1;
    }

    public static List<Receipt> getReceiptsFor(int year) {
        final List<Receipt> result = new ArrayList<Receipt>();
        for (final Receipt receipt : Bennu.getInstance().getReceiptsSet()) {
            if (receipt.getYear().intValue() == year) {
                result.add(receipt);
            }
        }

        return result;
    }

    public void registerReceiptPrint(Person person) {
        if (getState().isToRegisterPrint()) {
            new ReceiptPrintVersion(this, person);
        }
    }

    public ReceiptPrintVersion getMostRecentReceiptPrintVersion() {

        ReceiptPrintVersion result = null;
        for (final ReceiptPrintVersion receiptVersion : getReceiptsVersionsSet()) {
            if (result == null || receiptVersion.getWhenCreated().isAfter(result.getWhenCreated())) {
                result = receiptVersion;
            }
        }
        return result;
    }

    public Money getTotalAmount() {
        Money result = Money.ZERO;
        for (final Entry entry : getEntriesSet()) {
            result = result.add(entry.getOriginalAmount());
        }
        return result;
    }

    public boolean isFromAdministrativeOffice(AdministrativeOffice administrativeOffice) {
        for (final Entry entry : getEntriesSet()) {
            if (!entry.getAccountingTransaction().getEvent()
                    .isPayableOnAdministrativeOffice(administrativeOffice)) {
                return false;
            }
        }
        return true;
    }

    public CreditNote createCreditNote(final Person responsible, final PaymentMode paymentMode,
            final List<CreditNoteEntryDTO> creditNoteEntryDTOs) {

        return CreditNote.create(this, responsible, creditNoteEntryDTOs);
    }

    public void annul(final Person responsible) {
        checkRulesToAnnul();
        changeState(responsible, ReceiptState.ANNULLED);
    }

    private void checkRulesToAnnul() {
        if (hasAnyActiveCreditNotes()) {
            throw new DomainException("error.accounting.Receipt.cannot.annul.receipts.with.credit.notes");
        }

    }

    private boolean hasAnyActiveCreditNotes() {
        Collection<CreditNote> creditNotes = getCreditNotesSet();

        for (CreditNote creditNote : creditNotes) {
            if (!creditNote.isAnnulled()) {
                return true;
            }
        }

        return false;
    }

    public boolean isActive() {
        return getState() == ReceiptState.ACTIVE;
    }

    public boolean isAnnulled() {
        return getState() == ReceiptState.ANNULLED;
    }

    public Set<Entry> getReimbursableEntries() {
        final Set<Entry> result = new HashSet<Entry>();

        for (final Entry entry : getEntriesSet()) {
            if (entry.isReimbursementAppliable()) {
                result.add(entry);
            }
        }

        return result;
    }

    public void deleteReceiptPrintVersions() {
        check(this, RolePredicates.MANAGER_PREDICATE);
        for (; !getReceiptsVersionsSet().isEmpty(); getReceiptsVersionsSet().iterator().next().delete()) {
            ;
        }
    }

    public void delete() {
        check(this, RolePredicates.MANAGER_PREDICATE);

        if (!canBeDeleted()) {
            throw new DomainException("error.accounting.Receipt.cannot.be.deleted");
        }

        deleteReceiptPrintVersions();

        super.setContributorParty(null);
        super.setResponsible(null);
        super.getEntriesSet().clear();
        super.setPerson(null);

        setRootDomainObject(null);

        super.deleteDomainObject();
    }

    private boolean canBeDeleted() {
        return getCreditNotesSet().isEmpty();
    }

    public boolean isNumberSeriesDefined() {
        return !StringUtils.isEmpty(getNumberSeries());
    }

    public String getNumberWithSeries() {
        return !isNumberSeriesDefined() ? String.valueOf(super.getNumber()) : super.getNumber() + getNumberSeries();
    }

    @Override
    @Deprecated
    public Integer getNumber() {
        throw new DomainException(
                "error.net.sourceforge.fenixedu.domain.accounting.Receipt.use.getNumberWithSeries.instead");
    }

    private Integer getReceiptNumber() {
        return super.getNumber();
    }

    public void changeContributor(final Party contributor) {
        check(this, RolePredicates.MANAGER_PREDICATE);
        super.setContributorParty(contributor);
    }

    public List<CreditNote> getEmittedCreditNotes() {
        final List<CreditNote> result = new ArrayList<CreditNote>();
        for (final CreditNote creditNote : super.getCreditNotesSet()) {
            if (creditNote.isEmitted()) {
                result.add(creditNote);
            }
        }

        return result;

    }

    public void edit(final Person responsible, final Party contributorParty, final String contributorName) {
        check(this, AcademicPredicates.MANAGE_STUDENT_PAYMENTS);
        markChange(responsible);
        checkContributorParameters(contributorParty, contributorName);
        super.setContributorParty(contributorParty);
        super.setContributorName(contributorName);
    }

    public void changeStateAndEntries(final ReceiptState state, final Set<Entry> newEntries) {
        check(this, RolePredicates.MANAGER_PREDICATE);

        super.setState(state);

        super.getEntriesSet().clear();

        for (final Entry entry : newEntries) {
            entry.setActiveReceipt(this);
        }

    }

    public boolean isSecondPrintVersion() {
        return getReceiptsVersionsSet().size() >= 1;
    }

    static public Receipt readByYearAndNumber(final Integer year, final Integer number, final String series) {
        for (final Receipt receipt : Receipt.getReceiptsFor(year)) {
            if (receipt.getReceiptNumber().equals(number)) {
                if (series == null && receipt.getNumberSeries() == null) {
                    return receipt;
                } else if (series != null && receipt.getNumberSeries() != null
                        && series.equals(receipt.getNumberSeries())) {
                    return receipt;
                }
            }
        }

        return null;
    }

}