All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.nakedobjects.example.expenses.claims.items.AbstractExpenseItem Maven / Gradle / Ivy

There is a newer version: 3.0.3
Show newest version
package org.nakedobjects.example.expenses.claims.items;

import java.util.List;

import org.nakedobjects.applib.AbstractDomainObject;
import org.nakedobjects.applib.annotation.Disabled;
import org.nakedobjects.applib.annotation.Hidden;
import org.nakedobjects.applib.annotation.MemberOrder;
import org.nakedobjects.applib.annotation.Named;
import org.nakedobjects.applib.value.Date;
import org.nakedobjects.applib.value.Money;
import org.nakedobjects.example.expenses.claims.AbstractClaim;
import org.nakedobjects.example.expenses.claims.Claim;
import org.nakedobjects.example.expenses.claims.ClaimRepository;
import org.nakedobjects.example.expenses.claims.ExpenseItem;
import org.nakedobjects.example.expenses.claims.ExpenseItemStatus;
import org.nakedobjects.example.expenses.claims.ExpenseType;
import org.nakedobjects.example.expenses.claims.ProjectCode;
import org.nakedobjects.example.expenses.employee.Employee;
import org.nakedobjects.example.expenses.services.UserFinder;


public abstract class AbstractExpenseItem extends AbstractDomainObject implements ExpenseItem {

    // {{ Title & Icon
    public String title() {
        StringBuilder t = new StringBuilder();
        t.append(getExpenseType());
        return t.toString();
    }

    public String iconName() {
        return getExpenseType().iconName();
    }

    // }}

    // {{ Injected Services
    /*
     * This region contains references to the services (Repositories, Factories or other Services) used by
     * this domain object. The references are injected by the application container.
     */

    // {{ Injected: ClaimRepository
    private ClaimRepository claimRepository;

    /**
     * Injected by the application container.
     */
    public void setClaimRepository(ClaimRepository claimRepository) {
        this.claimRepository = claimRepository;
    }

    // }}

    // {{ Injected: UserFinder
    private UserFinder userFinder;

    /**
     * This field is not persisted, nor displayed to the user.
     */
    protected UserFinder getUserFinder() {
        return this.userFinder;
    }

    /**
     * Injected by the application container.
     */
    public void setUserFinder(UserFinder userFinder) {
        this.userFinder = userFinder;
    }

    // }}

    // }}

    // {{ Life Cycle methods
    public void created() {
        changeStatusToNewIncomplete();
    }

    public void saved() {
        claim.addToExpenseItems(this);
    }

    // }}

    // {{ ExpenseType
    private ExpenseType expenseType;

    @Hidden
    public ExpenseType getExpenseType() {
        resolve(expenseType);
        return this.expenseType;
    }

    public void setExpenseType(ExpenseType expenseType) {
        this.expenseType = expenseType;
        objectChanged();
    }

    // }}

    // {{ getClaimant
    /**
     * Helper method
     */
    private Employee getClaimant() {
        return getClaim().getClaimant();
    }

    // }}

    // {{ Project Code
    private ProjectCode projectCode;

    @Hidden
    public void newProjectCode(final ProjectCode newCode) {
        modifyProjectCode(newCode);
    }

    @MemberOrder(sequence = "4")
    public ProjectCode getProjectCode() {
        resolve(projectCode);
        return projectCode;
    }

    public void setProjectCode(final ProjectCode projectCode) {
        this.projectCode = projectCode;
        objectChanged();
    }

    public void modifyProjectCode(final ProjectCode newCode) {
        setProjectCode(newCode);
        checkIfComplete();
    }

    public void clearProjectCode() {
        setProjectCode(null);
        checkIfComplete();
    }

    public String disableProjectCode() {
        return disabledIfLocked();
    }
    // }}

    // {{ Claim
    private AbstractClaim claim;

    @Hidden
    public AbstractClaim getClaim() {
        resolve(claim);
        return this.claim;
    }

    public void setClaim(AbstractClaim claim) {
        this.claim = claim;
        objectChanged();
    }

    // }}

    // {{ Amount
    private Money amount;

    @MemberOrder(sequence = "3")
    public Money getAmount() {
        resolve(amount);
        return this.amount;
    }

    public void setAmount(Money amount) {
        this.amount = amount;
        objectChanged();
    }

    public void modifyAmount(final Money newAmount) {
        if (newAmount != null) {
            // coerce currency to current currency
            setAmount(new Money(newAmount.doubleValue(), getClaim().currencyCode()));
            checkIfComplete();
            recalculateClaimTotalIfPersistent();
        }
    }

    public String validateAmount(final Money newAmount) {
        return validateAnyAmountField(newAmount);
    }

    public String disableAmount() {
        return disabledIfLocked();
    }

    public final static String CURRENCY_NOT_VALID_FOR_THIS_CLAIM = "Currency not valid for this claim";

    protected String checkCurrency(final Money newAmount) {
        if (newAmount == null || newAmount.getCurrency().equalsIgnoreCase(getClaim().currencyCode())) {
            return null;
        }
        return CURRENCY_NOT_VALID_FOR_THIS_CLAIM + ": " + newAmount.getCurrency();
    }

    public final static String AMOUNT_CANNOT_BE_NEGATIVE = "Amount cannot be negative";

    protected String validateAnyAmountField(final Money newAmount) {
        return newAmount != null && newAmount.isLessThanZero() ? AMOUNT_CANNOT_BE_NEGATIVE : checkCurrency(newAmount);
    }

    @Hidden
    public void initialiseAmount() {
        setAmount(new Money(0.0, getClaim().currencyCode()));
    }

    // }}

    // {{ Date Incurred
    private Date dateIncurred;

    @MemberOrder(sequence = "1")
    public Date getDateIncurred() {
        resolve(dateIncurred);
        return dateIncurred;
    }

    public void setDateIncurred(final Date dateIncurred) {
        this.dateIncurred = dateIncurred;
        objectChanged();
    }

    public void modifyDateIncurred(final Date newDate) {
        setDateIncurred(newDate);
        checkIfComplete();
    }

    public void clearDateIncurred() {
        setDateIncurred(null);
        checkIfComplete();
    }

    public String disableDateIncurred() {
        return disabledIfLocked();
    }

    // }}

    // {{ Description
    private String description;

    @MemberOrder(sequence = "2")
    public String getDescription() {
        resolve(description);
        return description;
    }

    public void setDescription(final String Title) {
        this.description = Title;
        objectChanged();
    }

    public void modifyDescription(final String newTitle) {
        setDescription(newTitle);
        checkIfComplete();
    }

    public void clearDescription() {
        setDescription(null);
        checkIfComplete();
    }

    private final static String DESCRIPTION_WARN = "Description cannot be empty";

    public String validateDescription(final String newTitle) {
        return newTitle != null && newTitle.length() > 0 ? null : DESCRIPTION_WARN;
    }

    public String disableDescription() {
        return disabledIfLocked();
    }

    // }}

    // {{ Status
    private void changeStatusTo(String title) {
        setStatus(claimRepository.findExpenseItemStatus(title));
    }

    @Hidden
    public boolean isNewIncomplete() {
        return getStatus().isNewIncomplete();
    }

    @Hidden
    public void changeStatusToNewIncomplete() {
        changeStatusTo(ExpenseItemStatus.NEW_INCOMPLETE);
    }

    @Hidden
    public boolean isNewComplete() {
        return getStatus().isNewComplete();
    }

    @Hidden
    public void changeStatusToNewComplete() {
        changeStatusTo(ExpenseItemStatus.NEW_COMPLETE);
    }

    @Hidden
    public boolean isApproved() {
        return getStatus().isApproved();
    }

    @Hidden
    public void changeStatusToApproved() {
        changeStatusTo(ExpenseItemStatus.APPROVED);
    }

    @Hidden
    public boolean isRejected() {
        return getStatus().isRejected();
    }

    @Hidden
    public void changeStatusToRejected() {
        changeStatusTo(ExpenseItemStatus.REJECTED);
    }

    @Hidden
    public boolean isQueried() {
        return getStatus().isQueried();
    }

    @Hidden
    public void changeStatusToQueried() {
        changeStatusTo(ExpenseItemStatus.QUERIED);
    }

    private ExpenseItemStatus status;

    @MemberOrder(sequence = "5")
    @Disabled
    public ExpenseItemStatus getStatus() {
        resolve(status);
        return status;
    }

    public void setStatus(final ExpenseItemStatus status) {
        this.status = status;
        objectChanged();
    }

    // }}

    // {{ Comment (visible only when status is Rejected or Queried)
    private String comment;

    @Disabled
    public String getComment() {
        resolve(comment);
        return this.comment;
    }

    public void setComment(String reason) {
        this.comment = reason;
        objectChanged();
    }

    public boolean hideComment() {
        return !(isRejected() || isQueried());
    }

    // }}

    // {{ Controls
    protected boolean mandatoryFieldsComplete() {
        return (amount != null && !amount.isZero() && dateIncurred != null && description != null && !description.equals("")
                && projectCode != null && mandatorySubClassFieldsComplete());
    }

    protected abstract boolean mandatorySubClassFieldsComplete();

    protected void checkIfComplete() {
        if (isNewComplete() && !mandatoryFieldsComplete()) {
            changeStatusToNewIncomplete();
        }
        if (isNewIncomplete() && mandatoryFieldsComplete()) {
            changeStatusToNewComplete();
        }
    }

    // {{ Locked
    private boolean locked;

    @Hidden
    public boolean isLocked() {
        resolve();
        return locked;
    }

    public void setLocked(boolean locked) {
        this.locked = locked;
        objectChanged();
    }

    private final static String SUBMITTED_WARN = "Read-only : submitted";

    protected String disabledIfLocked() {
        return isLocked() ? SUBMITTED_WARN : null;
    }

    // }}
    // }}

    // {{ Copy From
    @MemberOrder(sequence="5")
	public void copyFrom(final ExpenseItem otherItem) {
        if (belongsToSameClaim(otherItem)) {
            if (dateIncurred == null) {
                modifyDateIncurred(otherItem.getDateIncurred());
            }
        } else if (getClass().isInstance(otherItem)) {
            copyAllSameClassFields(otherItem);
        }
    }

    public String disableCopyFrom() {
        return disabledIfLocked();
    }

    public String validateCopyFrom(final ExpenseItem otherItem) {
        if (belongsToSameClaim(otherItem) || (getClass().equals(otherItem.getClass()))) {
            return null;
        }
        return COPY_WARN;
    }
    

    private final static String COPY_WARN = "Cannot copy";


    protected void copyAllSameClassFields(final ExpenseItem otherItem) {
        copyAllFieldsFromAbstractExpenseItem(otherItem);
        copyAnyEmptyFieldsSpecificToSubclassOfAbstractExpenseItem(otherItem);
    }

    protected void copyAllFieldsFromAbstractExpenseItem(final ExpenseItem otherItem) {
        if (amount == null || amount.isZero()) {
            // Guard against different currency
            if (otherItem.getAmount().getCurrency().equals(getAmount().getCurrency())) { // TODO: Use
                // hasSameCurrencyAs
                // on Money when
                // implemented
                modifyAmount(otherItem.getAmount());
            }
        }
        if (description == null || description.equals("")) {
            modifyDescription(otherItem.getDescription());
        }
        if (projectCode == null) {
            modifyProjectCode(otherItem.getProjectCode());
        }
    }

    protected abstract void copyAnyEmptyFieldsSpecificToSubclassOfAbstractExpenseItem(final ExpenseItem otherItem);

    protected boolean belongsToSameClaim(final ExpenseItem otherItem) {
        return claim.equals(otherItem.getClaim());
    }

    // }}

    // {{ Recalculate
    protected void checkIfCompleteAndRecalculateClaimTotalIfPersistent() {
        recalculateClaimTotalIfPersistent();
        if (!isLocked()) {
            checkIfComplete();
        }
    }

    protected void recalculateClaimTotalIfPersistent() {
        if (isPersistent()) {
            if (getClaim() instanceof Claim) {
                ((Claim) getClaim()).recalculateTotal();
            }
        }
    }

    // }}

    // {{ Approvals
    @MemberOrder(sequence="1")
	public void approve() {
        changeStatusToApproved();
        recalculateClaimTotalIfPersistent();
    }

    public String disableApprove() {
        return disableApproverActions();
    }

    @MemberOrder(sequence="3")
	public void reject(@Named("Reason")
    final String reason) {
        setComment(reason);
        changeStatusToRejected();
        recalculateClaimTotalIfPersistent();
    }

    public String disableReject(final String reason) {
        return disableApproverActions();
    }

    @MemberOrder(sequence="2")
	public void query(@Named("Reason")
    final String reason) {
        setComment(reason);
        changeStatusToQueried();
        recalculateClaimTotalIfPersistent();
    }

    public String disableQuery(final String reason) {
        return disableApproverActions();
    }

    private String disableApproverActions() {
        if (isNewIncomplete()) {
            return CANNOT_APPROVE_AN_INCOMPLETE_ITEM;
        }
        return getClaim().disableApproverActionsOnAllItems();
    }

    public static final String CANNOT_APPROVE_AN_INCOMPLETE_ITEM = "Cannot approve an incomplete item";

    @Hidden
    public Money requestedOrApprovedAmount() {
        if (isRejected() || isQueried()) {
            return new Money(0, getClaim().currencyCode());
        }
        return getAmount();
    }

    // }}

    // {{ Find similar items
    @MemberOrder(sequence="4")
	public List findSimilarExpenseItems() {
        return claimRepository.findExpenseItemsLike(this);
    }

    // }}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy