001    /*
002     * Copyright 2011 The Kuali Foundation.
003     * 
004     * Licensed under the Educational Community License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     * 
008     * http://www.opensource.org/licenses/ecl2.php
009     * 
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package org.kuali.kfs.module.cam.document.validation.impl;
017    
018    import java.util.ArrayList;
019    import java.util.HashMap;
020    import java.util.List;
021    import java.util.Map;
022    
023    import org.apache.commons.lang.StringUtils;
024    import org.kuali.kfs.coa.businessobject.Account;
025    import org.kuali.kfs.coa.businessobject.ObjectCode;
026    import org.kuali.kfs.coa.businessobject.OffsetDefinition;
027    import org.kuali.kfs.coa.businessobject.Organization;
028    import org.kuali.kfs.coa.service.ObjectCodeService;
029    import org.kuali.kfs.coa.service.OffsetDefinitionService;
030    import org.kuali.kfs.fp.document.TransferOfFundsDocument;
031    import org.kuali.kfs.module.cam.CamsConstants;
032    import org.kuali.kfs.module.cam.CamsKeyConstants;
033    import org.kuali.kfs.module.cam.CamsPropertyConstants;
034    import org.kuali.kfs.module.cam.businessobject.Asset;
035    import org.kuali.kfs.module.cam.businessobject.AssetGlobal;
036    import org.kuali.kfs.module.cam.businessobject.AssetObjectCode;
037    import org.kuali.kfs.module.cam.businessobject.AssetPayment;
038    import org.kuali.kfs.module.cam.document.AssetTransferDocument;
039    import org.kuali.kfs.module.cam.document.service.AssetLocationService;
040    import org.kuali.kfs.module.cam.document.service.AssetObjectCodeService;
041    import org.kuali.kfs.module.cam.document.service.AssetPaymentService;
042    import org.kuali.kfs.module.cam.document.service.AssetService;
043    import org.kuali.kfs.module.cam.document.service.AssetTransferService;
044    import org.kuali.kfs.module.cam.document.service.AssetLocationService.LocationField;
045    import org.kuali.kfs.module.cam.service.AssetLockService;
046    import org.kuali.kfs.sys.KFSConstants;
047    import org.kuali.kfs.sys.context.SpringContext;
048    import org.kuali.kfs.sys.document.authorization.FinancialSystemTransactionalDocumentAuthorizerBase;
049    import org.kuali.kfs.sys.document.validation.impl.GeneralLedgerPostingDocumentRuleBase;
050    import org.kuali.kfs.sys.service.GeneralLedgerPendingEntryService;
051    import org.kuali.kfs.sys.service.UniversityDateService;
052    import org.kuali.rice.kim.bo.Person;
053    import org.kuali.rice.kim.service.PersonService;
054    import org.kuali.rice.kns.document.Document;
055    import org.kuali.rice.kns.exception.ValidationException;
056    import org.kuali.rice.kns.service.DocumentHelperService;
057    import org.kuali.rice.kns.service.ParameterService;
058    import org.kuali.rice.kns.util.GlobalVariables;
059    import org.kuali.rice.kns.util.ObjectUtils;
060    import org.kuali.rice.kns.util.TypedArrayList;
061    
062    public class AssetTransferDocumentRule extends GeneralLedgerPostingDocumentRuleBase {
063        protected static final Map<LocationField, String> LOCATION_FIELD_MAP = new HashMap<LocationField, String>();
064        static {
065            LOCATION_FIELD_MAP.put(LocationField.CAMPUS_CODE, CamsPropertyConstants.AssetTransferDocument.CAMPUS_CODE);
066            LOCATION_FIELD_MAP.put(LocationField.BUILDING_CODE, CamsPropertyConstants.AssetTransferDocument.BUILDING_CODE);
067            LOCATION_FIELD_MAP.put(LocationField.ROOM_NUMBER, CamsPropertyConstants.AssetTransferDocument.BUILDING_ROOM_NUMBER);
068            LOCATION_FIELD_MAP.put(LocationField.SUB_ROOM_NUMBER, CamsPropertyConstants.AssetTransferDocument.BUILDING_SUB_ROOM_NUMBER);
069            LOCATION_FIELD_MAP.put(LocationField.STREET_ADDRESS, CamsPropertyConstants.AssetTransferDocument.OFF_CAMPUS_ADDRESS);
070            LOCATION_FIELD_MAP.put(LocationField.CITY_NAME, CamsPropertyConstants.AssetTransferDocument.OFF_CAMPUS_CITY);
071            LOCATION_FIELD_MAP.put(LocationField.STATE_CODE, CamsPropertyConstants.AssetTransferDocument.OFF_CAMPUS_STATE_CODE);
072            LOCATION_FIELD_MAP.put(LocationField.ZIP_CODE, CamsPropertyConstants.AssetTransferDocument.OFF_CAMPUS_ZIP);
073            LOCATION_FIELD_MAP.put(LocationField.COUNTRY_CODE, CamsPropertyConstants.AssetGlobalDetail.OFF_CAMPUS_COUNTRY_CODE);
074            LOCATION_FIELD_MAP.put(LocationField.CONTACT_NAME, CamsPropertyConstants.AssetTransferDocument.OFF_CAMPUS_CONTACT_NAME);
075        }
076    
077        protected UniversityDateService universityDateService;
078        protected AssetPaymentService assetPaymentService;
079        protected AssetService assetService;
080        protected ObjectCodeService objectCodeService;
081        protected AssetLockService assetLockService;
082    
083        /**
084         * @see org.kuali.rice.kns.rules.DocumentRuleBase#processCustomSaveDocumentBusinessRules(org.kuali.rice.kns.document.Document)
085         */
086        @Override
087        protected boolean processCustomSaveDocumentBusinessRules(Document document) {
088            AssetTransferDocument assetTransferDocument = (AssetTransferDocument) document;
089            Asset asset = assetTransferDocument.getAsset();
090            boolean valid = checkReferencesExist(assetTransferDocument);
091            assetTransferDocument.clearGlPostables();
092            if (valid && (valid &= validateAssetObjectCodeDefn(assetTransferDocument, asset))) {
093                SpringContext.getBean(AssetTransferService.class).createGLPostables(assetTransferDocument);
094                if (!SpringContext.getBean(GeneralLedgerPendingEntryService.class).generateGeneralLedgerPendingEntries(assetTransferDocument)) {
095                    throw new ValidationException("General Ledger GLPE generation failed");
096                }
097            }
098    
099            return valid;
100        }
101    
102        /**
103         * Retrieve asset number need to be locked.
104         * 
105         * @param document
106         * @return
107         */
108        protected List<Long> retrieveAssetNumberForLocking(Document document) {
109            AssetTransferDocument assetTransferDocument = (AssetTransferDocument) document;
110            List<Long> assetNumbers = new ArrayList<Long>();
111            if (assetTransferDocument.getAsset().getCapitalAssetNumber() != null) {
112                assetNumbers.add(assetTransferDocument.getAsset().getCapitalAssetNumber());
113            }
114            return assetNumbers;
115        }
116    
117        protected boolean validateAssetObjectCodeDefn(AssetTransferDocument assetTransferDocument, Asset asset) {
118    
119            if ( !isNonCapitalAsset(asset) && StringUtils.isNotBlank(assetTransferDocument.getOrganizationOwnerChartOfAccountsCode()) && StringUtils.isNotBlank(assetTransferDocument.getOrganizationOwnerAccountNumber())) {
120                boolean valid = true;
121                List<AssetPayment> assetPayments = asset.getAssetPayments();
122                ObjectCodeService objectCodeService = (ObjectCodeService) SpringContext.getBean(ObjectCodeService.class);
123                for (AssetPayment assetPayment : assetPayments) {
124                    if (SpringContext.getBean(AssetPaymentService.class).isPaymentEligibleForGLPosting(assetPayment) && !assetPayment.getAccountChargeAmount().isZero()) {
125                        // validate for transfer source
126    
127                        ObjectCode objectCode = objectCodeService.getByPrimaryIdForCurrentYear(assetPayment.getChartOfAccountsCode(), assetPayment.getFinancialObjectCode());
128    
129                        AssetObjectCode originAssetObjectCode = SpringContext.getBean(AssetObjectCodeService.class).findAssetObjectCode(asset.getOrganizationOwnerChartOfAccountsCode(), objectCode.getFinancialObjectSubTypeCode());
130                        if (valid &= validateAssetObjectCode(originAssetObjectCode, asset.getOrganizationOwnerChartOfAccountsCode(), objectCode.getFinancialObjectSubTypeCode())) {
131                            // validate object codes used to generate Capitalization/Accumulated Depreciation/Offset GL Postings.
132                            valid &= validateFinancialObjectCodes(asset, assetPayment, originAssetObjectCode);
133                        }
134                        // validate for transfer target
135                        AssetObjectCode targetAssetObjectCode = SpringContext.getBean(AssetObjectCodeService.class).findAssetObjectCode(assetTransferDocument.getOrganizationOwnerChartOfAccountsCode(), objectCode.getFinancialObjectSubTypeCode());
136                        if (valid &= validateAssetObjectCode(targetAssetObjectCode, assetTransferDocument.getOrganizationOwnerChartOfAccountsCode(), objectCode.getFinancialObjectSubTypeCode())) {
137                            // validate object codes used to generate Capitalization/Accumulated Depreciation/Offset GL Postings.
138                            valid &= validateFinancialObjectCodes(asset, assetPayment, targetAssetObjectCode);
139                        }
140                    }
141                }
142                return valid;
143            }
144            else {
145                return true;
146            }
147    
148        }
149    
150        /**
151         * Asset Object Code must exist as an active status.
152         * 
153         * @param asset
154         * @param assetPayment
155         * @return
156         */
157        protected boolean validateAssetObjectCode(AssetObjectCode assetObjectCode, String chartOfAccountsCode, String finObjectSubTypeCode) {
158            boolean valid = true;
159            if (ObjectUtils.isNull(assetObjectCode)) {
160                putError(CamsConstants.DOCUMENT_NUMBER_PATH, CamsKeyConstants.GLPosting.ERROR_ASSET_OBJECT_CODE_NOT_FOUND, new String[] { chartOfAccountsCode, finObjectSubTypeCode });
161                valid &= false;
162            }// check Asset Object Code active
163            else if (!assetObjectCode.isActive()) {
164                putError(CamsConstants.DOCUMENT_NUMBER_PATH, CamsKeyConstants.GLPosting.ERROR_ASSET_OBJECT_CODE_INACTIVE, new String[] { chartOfAccountsCode, finObjectSubTypeCode });
165                valid = false;
166            }
167    
168            return valid;
169        }
170    
171        /**
172         * Check Financial Object Code for GLPE.
173         * 
174         * @param asset
175         * @param assetPayment
176         * @return
177         */
178        protected boolean validateFinancialObjectCodes(Asset asset, AssetPayment assetPayment, AssetObjectCode assetObjectCode) {
179            AssetPaymentService assetPaymentService = getAssetPaymentService();
180            boolean valid = true;
181    
182            if (assetPaymentService.isPaymentEligibleForCapitalizationGLPosting(assetPayment)) {
183                // check for capitalization financial object code existing.
184                assetObjectCode.refreshReferenceObject(CamsPropertyConstants.AssetObjectCode.CAPITALIZATION_FINANCIAL_OBJECT);
185                valid &= validateFinObjectCodeForGLPosting(asset.getOrganizationOwnerChartOfAccountsCode(), assetObjectCode.getCapitalizationFinancialObjectCode(), assetObjectCode.getCapitalizationFinancialObject(), CamsConstants.GLPostingObjectCodeType.CAPITALIZATION);
186            }
187            if (assetPaymentService.isPaymentEligibleForAccumDeprGLPosting(assetPayment)) {
188                // check for accumulate depreciation financial Object Code existing
189                assetObjectCode.refreshReferenceObject(CamsPropertyConstants.AssetObjectCode.ACCUMULATED_DEPRECIATION_FINANCIAL_OBJECT);
190                valid &= validateFinObjectCodeForGLPosting(asset.getOrganizationOwnerChartOfAccountsCode(), assetObjectCode.getAccumulatedDepreciationFinancialObjectCode(), assetObjectCode.getAccumulatedDepreciationFinancialObject(), CamsConstants.GLPostingObjectCodeType.ACCUMMULATE_DEPRECIATION);
191            }
192            if (assetPaymentService.isPaymentEligibleForOffsetGLPosting(assetPayment)) {
193                // check for offset financial object code existing.
194                OffsetDefinition offsetDefinition = SpringContext.getBean(OffsetDefinitionService.class).getByPrimaryId(getUniversityDateService().getCurrentFiscalYear(), assetObjectCode.getChartOfAccountsCode(), CamsConstants.AssetTransfer.DOCUMENT_TYPE_CODE, CamsConstants.Postable.GL_BALANCE_TYPE_CODE_AC);
195                valid &= validateFinObjectCodeForGLPosting(asset.getOrganizationOwnerChartOfAccountsCode(), offsetDefinition.getFinancialObjectCode(), offsetDefinition.getFinancialObject(), CamsConstants.GLPostingObjectCodeType.OFFSET_AMOUNT);
196            }
197            return valid;
198        }
199    
200        /**
201         * check existence and active status for given financial Object Code BO.
202         * 
203         * @param chartCode
204         * @param finObjectCode
205         * @param finObject
206         * @return
207         */
208        protected boolean validateFinObjectCodeForGLPosting(String chartOfAccountsCode, String finObjectCode, ObjectCode finObject, String glPostingType) {
209            boolean valid = true;
210            // not defined in Asset Object Code table
211            if (StringUtils.isBlank(finObjectCode)) {
212                putError(CamsConstants.DOCUMENT_NUMBER_PATH, CamsKeyConstants.GLPosting.ERROR_OBJECT_CODE_FROM_ASSET_OBJECT_CODE_NOT_FOUND, new String[] { glPostingType, chartOfAccountsCode });
213                valid = false;
214            }
215            // check Object Code existing
216            else if (ObjectUtils.isNull(finObject)) {
217                putError(CamsConstants.DOCUMENT_NUMBER_PATH, CamsKeyConstants.GLPosting.ERROR_OBJECT_CODE_FROM_ASSET_OBJECT_CODE_INVALID, new String[] { glPostingType, finObjectCode, chartOfAccountsCode });
218                valid = false;
219            }
220            // check Object Code active
221            else if (!finObject.isActive()) {
222                putError(CamsConstants.DOCUMENT_NUMBER_PATH, CamsKeyConstants.GLPosting.ERROR_OBJECT_CODE_FROM_ASSET_OBJECT_CODE_INACTIVE, new String[] { glPostingType, finObjectCode, chartOfAccountsCode });
223                valid = false;
224            }
225            return valid;
226        }
227    
228        /**
229         * @see org.kuali.rice.kns.rules.DocumentRuleBase#processCustomRouteDocumentBusinessRules(org.kuali.rice.kns.document.Document)
230         */
231        @Override
232        protected boolean processCustomRouteDocumentBusinessRules(Document document) {
233            if (!super.processCustomRouteDocumentBusinessRules(document) || GlobalVariables.getMessageMap().hasErrors())
234                return false;
235    
236            Asset asset = ((AssetTransferDocument)document).getAsset();
237            boolean valid = true;
238            if (SpringContext.getBean(AssetService.class).isAssetRetired(asset)) {
239                valid &= false;
240                GlobalVariables.getMessageMap().putError(CamsConstants.DOC_HEADER_PATH, CamsKeyConstants.Transfer.ERROR_ASSET_RETIRED_NOTRANSFER, asset.getCapitalAssetNumber().toString(), asset.getRetirementReason().getRetirementReasonName());
241            }
242    
243            if (valid) {
244                valid &= applyRules(document);
245            }
246    
247            // only generate error message if asset is locked by other document without stop saving
248            valid &= !this.getAssetLockService().isAssetLocked(retrieveAssetNumberForLocking(document), CamsConstants.DocumentTypeName.ASSET_TRANSFER, document.getDocumentNumber());
249    
250            return valid;
251        }
252    
253        /**
254         * This method applies business rules
255         * 
256         * @param document Transfer Document
257         * @return true if all rules are pass
258         */
259        protected boolean applyRules(Document document) {
260            boolean valid = true;
261            // check if selected account has plant fund accounts
262            AssetTransferDocument assetTransferDocument = (AssetTransferDocument) document;
263    
264            // validate if asset status = N or D
265            String inventoryStatusCode = assetTransferDocument.getAsset().getInventoryStatus().getInventoryStatusCode();
266            if (inventoryStatusCode != null && !(StringUtils.equalsIgnoreCase(inventoryStatusCode, CamsConstants.InventoryStatusCode.NON_CAPITAL_ASSET_ACTIVE) || StringUtils.equalsIgnoreCase(inventoryStatusCode, CamsConstants.InventoryStatusCode.NON_CAPITAL_ASSET_ACTIVE_2003))) {
267                valid &= validateOwnerAccount(assetTransferDocument);
268            }
269    
270            // validate if location info is available, campus or off-campus
271            valid &= validateLocation(assetTransferDocument);
272            if (assetTransferDocument.isInterdepartmentalSalesIndicator()) {
273                if (StringUtils.isBlank(assetTransferDocument.getTransferOfFundsFinancialDocumentNumber())) {
274                    putError(CamsPropertyConstants.AssetTransferDocument.TRANSFER_FUND_FINANCIAL_DOC_NUM, CamsKeyConstants.Transfer.ERROR_TRFR_FDOC_REQUIRED);
275                    valid &= false;
276                }
277            }
278    
279            valid &= validatePaymentObjectCodes(assetTransferDocument);
280    
281            return valid;
282        }
283    
284    
285        /**
286         * This method validates location information provided by the user
287         * 
288         * @param assetTransferDocument Transfer Document
289         * @return true is location information is valid for the asset type
290         */
291        protected boolean validateLocation(AssetTransferDocument assetTransferDocument) {
292            GlobalVariables.getMessageMap().addToErrorPath(CamsConstants.DOCUMENT_PATH);
293            Asset asset = assetTransferDocument.getAsset();
294            asset.refreshReferenceObject(CamsPropertyConstants.Asset.CAPITAL_ASSET_TYPE);
295            boolean isCapitalAsset = this.getAssetService().isCapitalAsset(asset);
296            boolean valid = SpringContext.getBean(AssetLocationService.class).validateLocation(LOCATION_FIELD_MAP, assetTransferDocument, isCapitalAsset, asset.getCapitalAssetType());
297            GlobalVariables.getMessageMap().removeFromErrorPath(CamsConstants.DOCUMENT_PATH);
298            return valid;
299        }
300    
301    
302        /**
303         * This method checks if reference objects exist in the database or not
304         * 
305         * @param assetTransferDocument Transfer document
306         * @return true if all objects exists in db
307         */
308        protected boolean checkReferencesExist(AssetTransferDocument assetTransferDocument) {
309            boolean valid = true;
310    
311            assetTransferDocument.refreshReferenceObject(CamsPropertyConstants.AssetTransferDocument.ASSET);
312            // If asset is loaned, ask a confirmation question
313            if (this.getAssetService().isAssetLoaned(assetTransferDocument.getAsset())) {
314                putError(CamsPropertyConstants.AssetTransferDocument.ASSET + "." + CamsPropertyConstants.AssetTransferDocument.CAPITAL_ASSET_NUMBER, CamsKeyConstants.Transfer.ERROR_TRFR_LOANED);
315                valid &= false;
316            }
317    
318            if (StringUtils.isNotBlank(assetTransferDocument.getOrganizationOwnerChartOfAccountsCode())) {
319                assetTransferDocument.refreshReferenceObject(CamsPropertyConstants.AssetTransferDocument.ORGANIZATION_OWNER_CHART_OF_ACCOUNTS);
320                if (ObjectUtils.isNull(assetTransferDocument.getOrganizationOwnerChartOfAccounts())) {
321                    putError(CamsPropertyConstants.AssetTransferDocument.ORGANIZATION_OWNER_CHART_OF_ACCOUNTS_CODE, CamsKeyConstants.Transfer.ERROR_OWNER_CHART_CODE_INVALID, assetTransferDocument.getOrganizationOwnerChartOfAccountsCode());
322                    valid &= false;
323                }
324            }
325    
326            if (StringUtils.isNotBlank(assetTransferDocument.getOrganizationOwnerAccountNumber())) {
327                assetTransferDocument.refreshReferenceObject(CamsPropertyConstants.AssetTransferDocument.ORGANIZATION_OWNER_ACCOUNT);
328                if (ObjectUtils.isNull(assetTransferDocument.getOrganizationOwnerAccount())) {
329                    putError(CamsPropertyConstants.AssetTransferDocument.ORGANIZATION_OWNER_ACCOUNT_NUMBER, CamsKeyConstants.Transfer.ERROR_OWNER_ACCT_INVALID, assetTransferDocument.getOrganizationOwnerAccountNumber(), assetTransferDocument.getOrganizationOwnerChartOfAccountsCode());
330                    valid &= false;
331                }
332            }
333            if (StringUtils.isNotBlank(assetTransferDocument.getTransferOfFundsFinancialDocumentNumber())) {
334                TransferOfFundsDocument transferOfFundsFinancialDocument = assetTransferDocument.getTransferOfFundsFinancialDocument();
335                if (ObjectUtils.isNull(transferOfFundsFinancialDocument) || !KFSConstants.DocumentStatusCodes.APPROVED.equals(transferOfFundsFinancialDocument.getDocumentHeader().getFinancialDocumentStatusCode())) {
336                    putError(CamsPropertyConstants.AssetTransferDocument.TRANSFER_FUND_FINANCIAL_DOC_NUM, CamsKeyConstants.Transfer.ERROR_TRFR_FDOC_INVALID);
337                    valid &= false;
338                }
339            }
340            if (StringUtils.isNotBlank(assetTransferDocument.getCampusCode())) {
341                // assetTransferDocument.refreshReferenceObject(CamsPropertyConstants.AssetTransferDocument.CAMPUS);
342                if (ObjectUtils.isNull(assetTransferDocument.getCampus())) {
343                    putError(CamsPropertyConstants.AssetTransferDocument.CAMPUS_CODE, CamsKeyConstants.AssetLocation.ERROR_INVALID_CAMPUS_CODE, assetTransferDocument.getCampusCode());
344                    valid &= false;
345                }
346            }
347            if (StringUtils.isNotBlank(assetTransferDocument.getBuildingCode())) {
348                assetTransferDocument.refreshReferenceObject(CamsPropertyConstants.AssetTransferDocument.BUILDING);
349                if (ObjectUtils.isNull(assetTransferDocument.getBuilding())) {
350                    putError(CamsPropertyConstants.AssetTransferDocument.BUILDING_CODE, CamsKeyConstants.AssetLocation.ERROR_INVALID_BUILDING_CODE, assetTransferDocument.getBuildingCode(), assetTransferDocument.getCampusCode());
351                    valid &= false;
352                }
353            }
354            if (StringUtils.isNotBlank(assetTransferDocument.getBuildingRoomNumber())) {
355                assetTransferDocument.refreshReferenceObject(CamsPropertyConstants.AssetTransferDocument.BUILDING_ROOM);
356                if (ObjectUtils.isNull(assetTransferDocument.getBuildingRoom())) {
357                    putError(CamsPropertyConstants.AssetTransferDocument.BUILDING_ROOM_NUMBER, CamsKeyConstants.AssetLocation.ERROR_INVALID_ROOM_NUMBER, assetTransferDocument.getBuildingCode(), assetTransferDocument.getBuildingRoomNumber(), assetTransferDocument.getCampusCode());
358                    valid &= false;
359                }
360            }
361            if (StringUtils.isNotBlank(assetTransferDocument.getAssetRepresentative().getPrincipalName())) {
362                PersonService personService = SpringContext.getBean(org.kuali.rice.kim.service.PersonService.class);
363                Person person = personService.getPersonByPrincipalName(assetTransferDocument.getAssetRepresentative().getPrincipalName());
364                if (person != null) {
365                    assetTransferDocument.setAssetRepresentative(person);
366                    assetTransferDocument.setRepresentativeUniversalIdentifier(person.getPrincipalId());
367                }
368                else {
369                    putError(CamsPropertyConstants.AssetTransferDocument.REP_USER_AUTH_ID, CamsKeyConstants.Transfer.ERROR_INVALID_USER_AUTH_ID, assetTransferDocument.getAssetRepresentative().getPrincipalName());
370                    valid &= false;
371                }
372            }
373            return valid;
374        }
375    
376    
377        /**
378         * This method validates the new owner organization and account provided
379         * 
380         * @param assetTransferDocument
381         * @return
382         */
383        protected boolean validateOwnerAccount(AssetTransferDocument assetTransferDocument) {
384            boolean valid = true;
385    
386            Asset asset = assetTransferDocument.getAsset();
387            String finObjectSubTypeCode = asset.getFinancialObjectSubTypeCode();
388            if (ObjectUtils.isNotNull(asset.getAssetPayments()) && !asset.getAssetPayments().isEmpty()) {
389                AssetPayment firstAssetPayment = asset.getAssetPayments().get(0);
390                firstAssetPayment.refreshReferenceObject(CamsPropertyConstants.AssetPayment.FINANCIAL_OBJECT);
391                ObjectCodeService objectCodeService = (ObjectCodeService) SpringContext.getBean(ObjectCodeService.class);
392    
393                ObjectCode objectCode = objectCodeService.getByPrimaryIdForCurrentYear(firstAssetPayment.getChartOfAccountsCode(),firstAssetPayment.getFinancialObjectCode());
394                finObjectSubTypeCode = objectCode.getFinancialObjectSubTypeCode();
395            }
396            boolean assetMovable = getAssetService().isAssetMovableCheckByPayment(finObjectSubTypeCode);
397    
398            FinancialSystemTransactionalDocumentAuthorizerBase documentAuthorizer = (FinancialSystemTransactionalDocumentAuthorizerBase) SpringContext.getBean(DocumentHelperService.class).getDocumentAuthorizer(assetTransferDocument);
399            boolean isAuthorizedTransferMovable = documentAuthorizer.isAuthorized(assetTransferDocument, CamsConstants.CAM_MODULE_CODE, CamsConstants.PermissionNames.TRANSFER_NON_MOVABLE_ASSETS, GlobalVariables.getUserSession().getPerson().getPrincipalId());
400            
401            // KFSMI-6169 - Not check permission for Transfer Non-Movable Assets when user approve the doc.
402            if (!assetTransferDocument.getDocumentHeader().getWorkflowDocument().getRouteHeader().isApproveRequested()){
403                if (!assetMovable && !isAuthorizedTransferMovable) {
404                    GlobalVariables.getMessageMap().putErrorForSectionId(CamsPropertyConstants.COMMON_ERROR_SECTION_ID, CamsKeyConstants.Transfer.ERROR_INVALID_USER_GROUP_FOR_TRANSFER_NONMOVABLE_ASSET, asset.getCapitalAssetNumber().toString());
405                    valid &= false;
406                }
407            }
408    
409            // check if account is valid
410            Account organizationOwnerAccount = assetTransferDocument.getOrganizationOwnerAccount();
411            if (ObjectUtils.isNotNull(organizationOwnerAccount) && (organizationOwnerAccount.isExpired())) {
412                putError(CamsPropertyConstants.AssetTransferDocument.ORGANIZATION_OWNER_ACCOUNT_NUMBER, CamsKeyConstants.Transfer.ERROR_OWNER_ACCT_INVALID, assetTransferDocument.getOrganizationOwnerChartOfAccountsCode(), assetTransferDocument.getOrganizationOwnerAccountNumber());
413                valid &= false;
414            }
415            else if (getAssetService().isCapitalAsset(asset) && !asset.getAssetPayments().isEmpty()) {
416                // for a capital asset, check if plant account is defined
417                Organization ownerOrg = organizationOwnerAccount.getOrganization();
418                Account campusPlantAccount = ownerOrg.getCampusPlantAccount();
419                Account organizationPlantAccount = ownerOrg.getOrganizationPlantAccount();
420    
421                if (assetMovable && ObjectUtils.isNull(organizationPlantAccount)) {
422                    putError(CamsPropertyConstants.AssetTransferDocument.ORGANIZATION_OWNER_ACCOUNT_NUMBER, CamsKeyConstants.Transfer.ERROR_ORG_PLANT_FUND_UNKNOWN);
423                    valid &= false;
424                }
425                if (!assetMovable && ObjectUtils.isNull(campusPlantAccount)) {
426                    putError(CamsPropertyConstants.AssetTransferDocument.ORGANIZATION_OWNER_ACCOUNT_NUMBER, CamsKeyConstants.Transfer.ERROR_CAMPUS_PLANT_FUND_UNKNOWN);
427                    valid &= false;
428                }
429            }
430            return valid;
431        }
432    
433        /**
434         * checks that all the asset payments to be transfer has a valid object code in the new Chart of account code and current fiscal
435         * year
436         * 
437         * @param assetTransferDocument
438         * @return
439         */
440        protected boolean validatePaymentObjectCodes(AssetTransferDocument assetTransferDocument) {
441            boolean valid = true;
442            List<AssetPayment> assetPayments = assetTransferDocument.getAsset().getAssetPayments();
443    
444            String chartOfAccountsCode = assetTransferDocument.getOrganizationOwnerChartOfAccountsCode();
445            Integer fiscalYear = getUniversityDateService().getCurrentUniversityDate().getUniversityFiscalYear();
446    
447            for (AssetPayment assetPayment : assetPayments) {
448                if (!CamsConstants.AssetPayment.TRANSFER_PAYMENT_CODE_Y.equals(assetPayment.getTransferPaymentCode())) {
449                    if (this.getObjectCodeService().getByPrimaryId(fiscalYear, chartOfAccountsCode, assetPayment.getFinancialObjectCode()) == null) {
450                        putError(CamsPropertyConstants.AssetTransferDocument.ORGANIZATION_OWNER_CHART_OF_ACCOUNTS_CODE, CamsKeyConstants.Transfer.ERROR_PAYMENT_OBJECT_CODE_NOT_FOUND, new String[] { assetPayment.getFinancialObjectCode(), fiscalYear.toString() });
451                        valid = false;
452                    }
453                }
454            }
455            return valid;
456        }
457    
458        /**
459         * Convenience method to append the path prefix
460         */
461        public TypedArrayList putError(String propertyName, String errorKey, String... errorParameters) {
462            return GlobalVariables.getMessageMap().putError(CamsConstants.DOCUMENT_PATH + "." + propertyName, errorKey, errorParameters);
463        }
464    
465        private boolean isNonCapitalAsset(Asset asset) {
466            boolean isNonCapitalAsset = false;
467            
468            List<String> capitalAssetAquisitionTypeCodes = new ArrayList<String>();
469            
470            capitalAssetAquisitionTypeCodes.addAll(SpringContext.getBean(ParameterService.class).getParameterValues(AssetGlobal.class, CamsConstants.AssetGlobal.CAPITAL_OBJECT_ACQUISITION_CODE_PARAM));
471            capitalAssetAquisitionTypeCodes.addAll(SpringContext.getBean(ParameterService.class).getParameterValues(AssetGlobal.class, CamsConstants.AssetGlobal.NON_NEW_ACQUISITION_GROUP_PARAM));
472            capitalAssetAquisitionTypeCodes.addAll(SpringContext.getBean(ParameterService.class).getParameterValues(AssetGlobal.class, CamsConstants.AssetGlobal.NEW_ACQUISITION_CODE_PARAM));
473            capitalAssetAquisitionTypeCodes.addAll(SpringContext.getBean(ParameterService.class).getParameterValues(Asset.class, CamsConstants.AssetGlobal.FABRICATED_ACQUISITION_CODE));
474            capitalAssetAquisitionTypeCodes.addAll(SpringContext.getBean(ParameterService.class).getParameterValues(AssetGlobal.class, CamsConstants.AssetGlobal.PRE_TAGGING_ACQUISITION_CODE));
475            
476            if( ObjectUtils.isNotNull(asset.getAcquisitionTypeCode()) &&
477                    capitalAssetAquisitionTypeCodes.contains(asset.getAcquisitionTypeCode()) ) isNonCapitalAsset = false;
478            else isNonCapitalAsset = true;
479            
480            return isNonCapitalAsset;
481        }
482        
483        public UniversityDateService getUniversityDateService() {
484            if (this.universityDateService == null) {
485                this.universityDateService = SpringContext.getBean(UniversityDateService.class);
486            }
487            return universityDateService;
488        }
489    
490        public void setUniversityDateService(UniversityDateService universityDateService) {
491            this.universityDateService = universityDateService;
492        }
493    
494        public AssetPaymentService getAssetPaymentService() {
495            if (this.assetPaymentService == null) {
496                this.assetPaymentService = SpringContext.getBean(AssetPaymentService.class);
497    
498            }
499            return assetPaymentService;
500        }
501    
502        public void setAssetPaymentService(AssetPaymentService assetPaymentService) {
503            this.assetPaymentService = assetPaymentService;
504        }
505    
506        public AssetService getAssetService() {
507            if (this.assetService == null) {
508                this.assetService = SpringContext.getBean(AssetService.class);
509            }
510            return assetService;
511        }
512    
513        public AssetLockService getAssetLockService() {
514            if (this.assetLockService == null) {
515                this.assetLockService = SpringContext.getBean(AssetLockService.class);
516            }
517            return assetLockService;
518        }
519    
520    
521        public void setAssetService(AssetService assetService) {
522            this.assetService = assetService;
523        }
524    
525        public ObjectCodeService getObjectCodeService() {
526            if (this.objectCodeService == null) {
527                this.objectCodeService = SpringContext.getBean(ObjectCodeService.class);
528            }
529            return objectCodeService;
530        }
531    
532        public void setObjectCodeService(ObjectCodeService objectCodeService) {
533            this.objectCodeService = objectCodeService;
534        }
535    }