com.stagecents.pay.domain.ElementType.java Source code

Java tutorial

Introduction

Here is the source code for com.stagecents.pay.domain.ElementType.java

Source

/**
 * Copyright (c) 2009-2014 Kaaterskil Management, LLC
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package com.stagecents.pay.domain;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;

import org.joda.time.DateTime;
import org.joda.time.Interval;
import org.joda.time.LocalDate;

import com.stagecents.common.DateEffective;
import com.stagecents.common.EffectiveDateInterval;
import com.stagecents.hr.domain.Party;
import com.stagecents.hr.domain.Position;
import com.stagecents.hxt.domain.SummaryHours;
import com.stagecents.hxt.domain.Timecard;
import com.stagecents.pa.domain.Activity;

/**
 * Represents the date effective definitions of the units used to build all
 * earnings, deductions and benefits that users can give to positions and
 * employees. Elements are also used to hold non-payment types of information
 * linked to employee assignments, for example, about assets and other equipment
 * issued to employees for their work.
 * 
 * @author Blair Caple
 */
public class ElementType implements DateEffective {

    public enum Category {
        OSP("Day of Week Premium"), OVT("Overtime Earning"), REG("Regular Earning"), SDF(
                "Shift Differential Premium");
        private String meaning;

        private Category(String meaning) {
            this.meaning = meaning;
        }

        public String getMeaning() {
            return meaning;
        }
    }

    /**
     * Enumeration to provide discriminator values for extended classes.
     */
    public enum Type {
        GENERIC("Other Earning", Category.REG), GTL("Group Term Life", Category.REG), OVERTIME("Overtime",
                Category.OVT), PERF_FEE("Performance Fee", Category.REG), PERF_WAGE("Performance Wage",
                        Category.REG), REG_SALARY("Regular Salary",
                                Category.REG), REG_WAGE("Regular Wage", Category.REG), SHIFT("Shift", Category.SDF);
        private String meaning;
        private Category category;

        private Type(String meaning, Category category) {
            this.meaning = meaning;
            this.category = category;
        }

        public String getMeaning() {
            return meaning;
        }

        public Category getCategory() {
            return category;
        }
    }

    public enum Classification {
        BENEFITS("Employer Benefits", 60, "Employer  Liabilities", true), BONUS("Bonus", 25, "Supplemental",
                true), ER_FED_TAX("Employer Federal Tax", 40, "Employer Tax", true), ER_STATE_TAX(
                        "Employer State Tax", 40, "Employer Tax",
                        true), ER_LOCAL_TAX("Employer Local Tax", 40, "Employer Tax", true), GTL("Group Term Life",
                                30, "Imputed Earnings", true), LABOR_HRS("Labor Hours", 0, "Information",
                                        false), OT_EARNINGS("Overtime Earnings", 15, "Earnings", true), OT_HOURS(
                                                "Overtime Hours", 0, "Information",
                                                false), PENSION("Pension", 25, "Supplemental", true), REG_EARNINGS(
                                                        "Regular Earnings", 15, "Earnings",
                                                        true), REG_HOURS("Regular Hours", 0, "Information",
                                                                false), SHIFT("Shift Pay", 15, "Earnings", true);
        private String name;
        private String type;
        private int priority;
        private boolean costable;

        private Classification(String name, int priority, String category, boolean costable) {
            this.name = name;
            this.priority = priority;
            this.type = category;
            this.costable = costable;
        }

        public String getName() {
            return name;
        }

        public String getType() {
            return type;
        }

        public boolean isCostable() {
            return costable;
        }
    }

    public enum ProcessingType {
        RECURRING, NON_RECURRING
    }

    protected EffectiveDateInterval effectiveDateRange;
    protected Type type;
    protected Classification classification;
    protected ProcessingType processingType;
    protected String name;
    protected String description;
    protected int sequence;

    // Bidirectional one-to-many associations
    protected SortedSet<InputValue> inputValues = new TreeSet<InputValue>(new InputValueComparator());
    protected Set<ElementLink> links = new HashSet<ElementLink>();

    ElementType() {
    }

    public ElementType(String name, String description, Type type, Classification classification,
            ProcessingType processingType, LocalDate startDate, LocalDate endDate) {
        this.name = name;
        this.description = description;
        this.type = type;
        this.classification = classification;
        this.processingType = processingType;
        this.effectiveDateRange = new EffectiveDateInterval(startDate, endDate);
    }

    public EffectiveDateInterval getEffectiveDateRange() {
        return effectiveDateRange;
    }

    public int getSequence() {
        return sequence;
    }

    public SortedSet<InputValue> getInputValues() {
        return inputValues;
    }

    public List<InputValue> getValues(LocalDate effectiveDate) {
        List<InputValue> result = new ArrayList<InputValue>();
        Iterator<InputValue> iter = inputValues.iterator();
        while (iter.hasNext()) {
            InputValue each = iter.next();
            if (each.isEffective(effectiveDate)) {
                result.add(each);
            }
        }
        return result;
    }

    public void addInputValue(InputValue arg) {
        arg.setElementType(this);
        inputValues.add(arg);
    }

    public void removeInputValue(InputValue arg) {
        arg.setElementType(null);
        inputValues.remove(arg);
    }

    public void linkElement(ElementLink arg) {
        arg.setElementType(this);
        links.add(arg);
    }

    public void unlinkElement(ElementLink arg) {
        arg.setElementType(null);
        links.remove(arg);
    }

    public List<Position> getPositions() {
        List<Position> result = new ArrayList<Position>();
        Iterator<ElementLink> iter = links.iterator();
        while (iter.hasNext()) {
            Party party = iter.next().getParty();
            if (party != null && party instanceof Position) {
                result.add((Position) party);
            }
        }
        return result;
    }

    /**
     * Returns the decimal hours from the given time interval, adjusted by any
     * restricted hours specified by the given position and any regular hours
     * already accumulated in the given timecard.
     * 
     * This method does nothing unless extended in a subclass.
     * 
     * @param interval
     *            The time period of the activity, adjusted to a single day.
     * @param activity
     *            The activity from which to compute regular hours.
     * @param timecard
     *            The timecard from which to accumulate prior regular hours.
     * @param position
     *            The position which participates in the given time interval and
     *            which may define restricted or maximum hours.
     */
    public void processHours(Interval interval, Activity activity, Timecard timecard, Position position) {
        // Noop
    }

    /**
     * Returns the total hours from the given time card for this element type
     * prior to the given start date. THe method will return 0 if no prior hours
     * have been recorded for this element type.
     * 
     * @param timecard
     *            The time card from which to sum prior hours.
     * @param start
     *            The cutoff date.
     * @return The total hours recorded on the given time card for this element
     *         type prior to the given start date, or 0 if no prior hours have
     *         been recorded.
     */
    float getPriorHours(Timecard timecard, LocalDate start) {
        float result = 0F;
        Iterator<SummaryHours> iter = timecard.getSummaryHours().iterator();
        while (iter.hasNext()) {
            SummaryHours sh = iter.next();
            if (sh.getDateWorked().isBefore(start)) {
                result += sh.getHours(this);
            }
        }
        return result;
    }

    MultiplierValue getMultiplier(Interval interval) {
        Iterator<InputValue> iter = inputValues.iterator();
        while (iter.hasNext()) {
            InputValue iv = iter.next();
            if (iv instanceof MultiplierValue) {
                MultiplierValue mv = (MultiplierValue) iv;
                if (mv.getEffectiveDateRange() == null || mv.isEffective(interval.getStart())) {
                    return mv;
                }
            }
        }
        return null;
    }

    MinimumCallValue getMinimumCall(Interval interval) {
        Iterator<InputValue> iter = inputValues.iterator();
        while (iter.hasNext()) {
            InputValue iv = iter.next();
            if (iv instanceof MinimumCallValue) {
                MinimumCallValue mcv = (MinimumCallValue) iv;
                if (mcv.getEffectiveDateRange() == null || mcv.isEffective(interval.getStart())) {
                    return mcv;
                }
            }
        }
        return null;
    }

    void updateTimecard(Timecard timecard, Activity activity, Interval timeWorked) {
        LocalDate dateWorked = timeWorked.getStart().toLocalDate();

        SummaryHours sh = timecard.getSummaryHours(dateWorked);
        if (sh == null) {
            int seq = timecard.getSummaryHoursSequence(dateWorked);
            sh = new SummaryHours(timecard, seq, dateWorked);
        }
        sh.updateHours(activity, this, timeWorked);
    }

    @Override
    public boolean isEffective(DateTime effectiveDate) {
        return effectiveDateRange.isEffective(effectiveDate);
    }

    @Override
    public boolean isEffective(LocalDate effectiveDate) {
        return effectiveDateRange.isEffective(effectiveDate);
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((classification == null) ? 0 : classification.hashCode());
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        result = prime * result + ((processingType == null) ? 0 : processingType.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null || !(obj instanceof ElementType)) {
            return false;
        }
        ElementType other = (ElementType) obj;
        if (classification != other.classification) {
            return false;
        }
        if (name == null) {
            if (other.name != null) {
                return false;
            }
        } else if (!name.equals(other.name)) {
            return false;
        }
        if (processingType != other.processingType) {
            return false;
        }
        return true;
    }

    public static class InputValueComparator implements Comparator<InputValue> {

        @Override
        public int compare(InputValue o1, InputValue o2) {
            int s1 = o1.getSequence();
            int s2 = o2.getSequence();
            if (s1 < s2) {
                return -1;
            } else if (s1 == s2) {
                DateTime d1 = o1.getStartDate();
                DateTime d2 = o2.getStartDate();
                return d1.isBefore(d2) ? -1 : (d1.isEqual(d2) ? 0 : 1);
            }
            return 1;
        }
    }
}