/* * Copyright (c) 2005-2011 Grameen Foundation USA * All rights reserved. * * 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. * * See also http://www.apache.org/licenses/LICENSE-2.0.html for an * explanation of the license and how it is applied. */ package org.mifos.customers.office.business; import org.apache.commons.lang.StringUtils; import org.mifos.application.holiday.business.HolidayBO; import org.mifos.customers.office.exceptions.OfficeException; import org.mifos.customers.office.exceptions.OfficeValidationException; import org.mifos.customers.office.util.helpers.OfficeConstants; import org.mifos.customers.office.util.helpers.OfficeLevel; import org.mifos.customers.office.util.helpers.OfficeStatus; import org.mifos.customers.office.util.helpers.OperationMode; import org.mifos.dto.domain.AddressDto; import org.mifos.dto.domain.CustomFieldDto; import org.mifos.dto.domain.OfficeHierarchyDto; import org.mifos.dto.domain.OfficeUpdateRequest; import org.mifos.framework.business.AbstractBusinessObject; import org.mifos.framework.business.util.Address; import org.mifos.framework.util.helpers.Constants; import org.mifos.security.util.UserContext; import java.util.*; public class OfficeBO extends AbstractBusinessObject implements Comparable<OfficeBO> { private Short officeId; private final Short operationMode; @SuppressWarnings("unused") // see .hbm.xml file private Integer maxChildCount = 0; private String officeName; private String shortName; private String globalOfficeNum; private String searchId; private OfficeLevelEntity level; private OfficeBO parentOffice; private OfficeStatusEntity status; private OfficeAddressEntity address; private Set<OfficeCustomFieldEntity> customFields; private Set<OfficeBO> children; private Set<HolidayBO> holidays = new HashSet<HolidayBO>(); public static List<OfficeHierarchyDto> convertToBranchOnlyHierarchyWithParentsOfficeHierarchy(List<OfficeBO> branchParents) { List<OfficeHierarchyDto> hierarchy = new ArrayList<OfficeHierarchyDto>(); for (OfficeBO officeBO : branchParents) { List<OfficeHierarchyDto> children = new ArrayList<OfficeHierarchyDto>(); Set<OfficeBO> branchOnlyChildren = officeBO.getBranchOnlyChildren(); if (branchOnlyChildren != null && !branchOnlyChildren.isEmpty()) { children = convertToBranchOnlyHierarchyWithParentsOfficeHierarchy(new ArrayList<OfficeBO>(branchOnlyChildren)); } OfficeHierarchyDto officeHierarchy = new OfficeHierarchyDto(officeBO.getOfficeId(), officeBO.getOfficeName(), officeBO.getSearchId(), officeBO.isActive(), children); hierarchy.add(officeHierarchy); } return hierarchy; } /** * default constructor for hibernate usuage */ public OfficeBO() { this(null, null, null, null); status = new OfficeStatusEntity(OfficeStatus.ACTIVE); address = new OfficeAddressEntity(); } /** * minimal legal constructor * * @param officeId */ public OfficeBO(Short officeId, final String name, final String shortName, String globalOfficeNum, OfficeBO parentOffice, OfficeLevel officeLevel, String searchId, OfficeStatus status) { this(name, shortName, globalOfficeNum, parentOffice, officeLevel, searchId, status, 0); this.officeId = officeId; } /** * minimal legal constructor */ public OfficeBO(final String name, final String shortName, String globalOfficeNum, OfficeBO parentOffice, OfficeLevel officeLevel, String searchId, OfficeStatus status, int createdBy) { this.officeName = name; this.shortName = shortName; this.globalOfficeNum = globalOfficeNum; this.searchId = searchId; this.parentOffice = parentOffice; this.level = new OfficeLevelEntity(officeLevel); this.operationMode = OperationMode.REMOTE_SERVER.getValue(); this.status = new OfficeStatusEntity(status); setCreateDetails(createdBy); } /** * For tests. Does not require that the names in question actually exist in the database. */ public static OfficeBO makeForTest(final UserContext userContext, final OfficeLevel level, final OfficeBO parentOffice, final String searchId, final List<CustomFieldDto> customFields, final String officeName, final String shortName, final Address address, final OperationMode operationMode, final OfficeStatus status) throws OfficeException { return new OfficeBO(userContext, null, level, parentOffice, searchId, customFields, officeName, shortName, address, operationMode, status); } public static OfficeBO makeForTest(final UserContext userContext, final Short officeId, final String officeName, final String shortName) throws OfficeException { return new OfficeBO(userContext, officeId, OfficeLevel.AREAOFFICE, null, null, null, officeName, shortName, null, OperationMode.LOCAL_SERVER, OfficeStatus.ACTIVE); } /** * Construct an object without validating it against the database. */ private OfficeBO(final UserContext userContext, final Short officeId, final OfficeLevel level, final OfficeBO parentOffice, final String searchId, final List<CustomFieldDto> customFields, final String officeName, final String shortName, final Address address, final OperationMode operationMode, final OfficeStatus status) throws OfficeValidationException { super(userContext); verifyFieldsNoDatabase(level, operationMode); setCreateDetails(); this.operationMode = operationMode.getValue(); this.searchId = searchId; this.officeId = officeId; this.level = new OfficeLevelEntity(level); this.status = new OfficeStatusEntity(status); this.parentOffice = parentOffice; if (parentOffice != null && parentOffice.getHolidays() != null) { this.setHolidays(new HashSet<HolidayBO>(parentOffice.getHolidays())); } this.officeName = officeName; this.shortName = shortName; if (address != null) { this.address = new OfficeAddressEntity(this, address); } this.customFields = new HashSet<OfficeCustomFieldEntity>(); } /** * @throws OfficeValidationException Thrown when there's a validation error */ public OfficeBO(final UserContext userContext, final OfficeLevel level, final OfficeBO parentOffice, final List<CustomFieldDto> customFields, final String officeName, final String shortName, final Address address, final OperationMode operationMode) throws OfficeValidationException { this(userContext, null, level, parentOffice, null, customFields, officeName, shortName, address, operationMode, OfficeStatus.ACTIVE); verifyFields(officeName, shortName, parentOffice); } public OfficeBO(final Short officeId, final String officeName, final Integer maxChildCount, final Short operationMode) { super(); this.officeId = officeId; this.officeName = officeName; this.maxChildCount = maxChildCount; this.operationMode = operationMode; } @Override public void setCreatedDate(final Date createdDate) { this.createdDate = createdDate; } public String getGlobalOfficeNum() { return globalOfficeNum; } public OfficeLevel getOfficeLevel() { return OfficeLevel.getOfficeLevel(level.getId()); } public OfficeStatus getOfficeStatus() throws OfficeException { return OfficeStatus.getOfficeStatus(status.getId()); } public OfficeStatusEntity getStatus() { return this.status; } public OfficeLevelEntity getLevel() { return this.level; } public String getOfficeName() { return officeName; } public void setOfficeName(final String officeName) { this.officeName = officeName; } public Short getOfficeId() { return officeId; } public OperationMode getMode() { return OperationMode.fromInt(operationMode); } public OfficeBO getParentOffice() { return parentOffice; } void setParentOffice(final OfficeBO parentOffice) { this.parentOffice = parentOffice; } public String getSearchId() { return searchId; } public String getShortName() { return shortName; } void setShortName(final String shortName) { this.shortName = shortName; } @Override public void setUpdatedDate(final Date updatedDate) { this.updatedDate = updatedDate; } public OfficeAddressEntity getAddress() { return address; } public Set<OfficeCustomFieldEntity> getCustomFields() { return customFields; } public void setCustomFields(final Set<OfficeCustomFieldEntity> customFields) { if (customFields != null) { this.customFields = customFields; } } public void setAddress(final OfficeAddressEntity address) { this.address = address; } public void setChildren(final Set<OfficeBO> children) { this.children = children; } public void setHolidays(final Set<HolidayBO> holidays) { this.holidays = holidays; } public void setGlobalOfficeNum(final String globalOfficeNum) { this.globalOfficeNum = globalOfficeNum; } void setLevel(final OfficeLevelEntity level) { this.level = level; } public void setSearchId(final String searchId) { this.searchId = searchId; } void setStatus(final OfficeStatusEntity status) { this.status = status; } public Set<OfficeBO> getChildren() { if (children == null) { children = new HashSet<OfficeBO>(); } return children; } public Set<HolidayBO> getHolidays() { return holidays; } private void removeChild(final OfficeBO office) { Set<OfficeBO> childerns = null; if (getChildren().size() > 0) { childerns = getChildren(); childerns.remove(office); } setChildren(childerns); } private void addChild(final OfficeBO office) { Set<OfficeBO> childerns = getChildren(); office.setParentOffice(this); childerns.add(office); setChildren(childerns); } // Changed this method signature so that it throws the PersistenceExcpetion // instead of wrapping in an OfficeExcpetion. The idea being that we are // seperating validation exceptions from PersistenceExceptions, which should // ultimately be runtime errors because they occurr, most likely, from // configuration/binding problems which are exceptions that we shouldn't // be catching. private void verifyFields(final String officeName, final String shortName, final OfficeBO parentOffice) throws OfficeValidationException { if (StringUtils.isBlank(officeName)) { throw new OfficeValidationException(OfficeConstants.ERRORMANDATORYFIELD, new Object[]{OfficeConstants.OFFICE_NAME}); } if (StringUtils.isBlank(shortName)) { throw new OfficeValidationException(OfficeConstants.ERRORMANDATORYFIELD, new Object[]{OfficeConstants.OFFICESHORTNAME}); } if (parentOffice == null) { throw new OfficeValidationException(OfficeConstants.ERRORMANDATORYFIELD, new Object[]{OfficeConstants.PARENTOFFICE}); } } private void verifyFieldsNoDatabase(final OfficeLevel level, final OperationMode operationMode) throws OfficeValidationException { if (level == null) { throw new OfficeValidationException(OfficeConstants.ERRORMANDATORYFIELD, new Object[]{OfficeConstants.OFFICELEVEL}); } if (operationMode == null) { throw new OfficeValidationException(OfficeConstants.ERRORMANDATORYFIELD, new Object[]{OfficeConstants.OFFICEOPERATIONMODE}); } } public boolean isActive() { return OfficeStatus.ACTIVE.getValue().equals(this.status.getId()); } public boolean isInActive() { return OfficeStatus.INACTIVE.getValue().equals(this.status.getId()); } public void update(UserContext userContext, OfficeUpdateRequest officeUpdateRequest, OfficeBO newParentOffice) throws OfficeException { updateDetails(userContext); OfficeStatus officeStatus = OfficeStatus.getOfficeStatus(officeUpdateRequest.getNewStatus()); OfficeLevel officeLevel = OfficeLevel.getOfficeLevel(officeUpdateRequest.getNewlevel()); Address address = null; AddressDto dto = officeUpdateRequest.getAddress(); if (dto != null) { address = new Address(dto.getLine1(), dto.getLine2(), dto.getLine3(), dto.getCity(), dto.getState(), dto.getCountry(), dto.getZip(), dto.getPhoneNumber()); } update(officeUpdateRequest.getOfficeName(), officeUpdateRequest.getShortName(), officeStatus, officeLevel, newParentOffice, address, new ArrayList<CustomFieldDto>()); } public void update(final String newName, final String newShortName, final OfficeStatus newStatus, final OfficeLevel newLevel, final OfficeBO newParent, final Address address, final List<CustomFieldDto> customFileds) throws OfficeException { this.officeName = newName; this.shortName = newShortName; if (isDifferentOfficeLevel(newLevel)) { if (!canUpdateLevel(newLevel)) { throw new OfficeException(OfficeConstants.ERROR_INVALID_LEVEL); } this.level = new OfficeLevelEntity(newLevel); } if (isNotHeadOffice()) { updateParent(newParent); } this.status = new OfficeStatusEntity(newStatus); updateAddress(address); } private boolean isNotHeadOffice() { return !isHeadOffice(); } private boolean isHeadOffice() { return this.getOfficeLevel().equals(OfficeLevel.HEADOFFICE); } private void updateParent(final OfficeBO newParent) throws OfficeException { if (newParent != null) { if (this.getParentOffice() != null) { if (!this.getParentOffice().getOfficeId().equals(newParent.getOfficeId())) { OfficeBO oldParent = this.getParentOffice(); if (this.getOfficeLevel().getValue().shortValue() < newParent.getOfficeLevel().getValue().shortValue()) { throw new OfficeException(OfficeConstants.ERROR_INVALID_PARENT); } OfficeBO oldParent1 = getIfChildPresent(newParent, oldParent); if (oldParent1 == null) { oldParent1 = oldParent; } oldParent1.removeChild(this); OfficeBO newParent1 = getIfChildPresent(oldParent, newParent); if (newParent1 == null) { newParent1 = newParent; } newParent1.addChild(this); newParent1.updateSearchId(newParent1.getSearchId()); oldParent1.updateSearchId(oldParent1.getSearchId()); } } } } private void updateSearchId(final String searchId) { this.setSearchId(searchId); int i = 1; if (this.getChildren() != null) { Iterator<OfficeBO> iter = this.getChildren().iterator(); while (iter.hasNext()) { OfficeBO element = iter.next(); element.updateSearchId(this.getSearchId() + i + "."); i++; } } } private boolean canUpdateLevel(final OfficeLevel level) { if (this.getOfficeLevel().getValue() > level.getValue()) { return true; } for (OfficeBO office : this.children) { if (office.getLevel().getId() <= level.getValue()) { return false; } } return true; } private void updateAddress(final Address address) { if (this.address != null && address != null) { this.address.setAddress(address); } else if (this.address == null && address != null) { this.address = new OfficeAddressEntity(this, address); } } public Set<OfficeBO> getBranchOnlyChildren() { Set<OfficeBO> offices = new HashSet<OfficeBO>(); for (OfficeBO office : getChildren()) { if (office.getOfficeLevel().equals(OfficeLevel.BRANCHOFFICE)) { offices.add(office); } } return offices; } /* FIXME: we also need to implement hashCode() */ @Override public boolean equals(final Object o) { return officeId.equals(((OfficeBO) o).getOfficeId()); } @Override public int compareTo(final OfficeBO o) { return officeId.compareTo(o.getOfficeId()); } public OfficeBO getIfChildPresent(final OfficeBO parent, final OfficeBO child) { for (OfficeBO childl : parent.getChildren()) { if (childl.getOfficeId().equals(child.getOfficeId())) { return childl; } return getIfChildPresent(childl, child); } return null; } public boolean isParent(final OfficeBO child) { boolean isParent = false; for (OfficeBO children : getChildren()) { if (children.equals(child)) { return true; } isParent = children.isParent(child); if (isParent) { return true; } } return isParent; } public void addHoliday(HolidayBO holiday) { getHolidays().add(holiday); } public boolean hasChildWithAnyOf(List<Short> officeIds) { boolean childFound = false; for (OfficeBO child : getChildren()) { if (officeIds.contains(child.getOfficeId())) { childFound = true; return childFound; } childFound = child.hasChildWithAnyOf(officeIds); } return childFound; } public void validateVersion(Integer previousVersionNum) throws OfficeException { if (!this.versionNo.equals(previousVersionNum)) { throw new OfficeException(Constants.ERROR_VERSION_MISMATCH); } } public boolean isNameDifferent(String newOfficeName) { return !this.officeName.equalsIgnoreCase(newOfficeName); } public boolean isShortNameDifferent(String newShortName) { return !this.shortName.equalsIgnoreCase(newShortName); } private boolean isDifferentOfficeLevel(OfficeLevel newLevel) { return !this.level.getLevel().equals(newLevel); } public boolean isStatusDifferent(OfficeStatus newStatus) { return !newStatus.getValue().equals(this.status.getId()); } public boolean isDifferentParentOffice(OfficeBO newParentOffice) { return !newParentOffice.equals(this.parentOffice); } public boolean isNotBranch() { return !isBranch(); } public boolean isBranch() { return OfficeLevel.BRANCHOFFICE.getValue().equals(this.level.getId()); } public boolean isDifferent(OfficeBO newOffice) { return !this.officeId.equals(newOffice.getOfficeId()); } @Deprecated public void setOfficeId(Short officeId) { this.officeId = officeId; } }