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.service.impl;
017    
018    import java.util.ArrayList;
019    import java.util.List;
020    
021    import org.apache.log4j.Logger;
022    import org.kuali.kfs.coa.businessobject.Account;
023    import org.kuali.kfs.coa.businessobject.ObjectCode;
024    import org.kuali.kfs.coa.businessobject.OffsetDefinition;
025    import org.kuali.kfs.coa.service.ObjectCodeService;
026    import org.kuali.kfs.coa.service.OffsetDefinitionService;
027    import org.kuali.kfs.module.cam.CamsConstants;
028    import org.kuali.kfs.module.cam.CamsPropertyConstants;
029    import org.kuali.kfs.module.cam.businessobject.Asset;
030    import org.kuali.kfs.module.cam.businessobject.AssetGlpeSourceDetail;
031    import org.kuali.kfs.module.cam.businessobject.AssetLocation;
032    import org.kuali.kfs.module.cam.businessobject.AssetObjectCode;
033    import org.kuali.kfs.module.cam.businessobject.AssetOrganization;
034    import org.kuali.kfs.module.cam.businessobject.AssetPayment;
035    import org.kuali.kfs.module.cam.document.AssetTransferDocument;
036    import org.kuali.kfs.module.cam.document.service.AssetLocationService;
037    import org.kuali.kfs.module.cam.document.service.AssetObjectCodeService;
038    import org.kuali.kfs.module.cam.document.service.AssetPaymentService;
039    import org.kuali.kfs.module.cam.document.service.AssetService;
040    import org.kuali.kfs.module.cam.document.service.AssetTransferService;
041    import org.kuali.kfs.module.cam.util.ObjectValueUtils;
042    import org.kuali.kfs.sys.context.SpringContext;
043    import org.kuali.kfs.sys.service.UniversityDateService;
044    import org.kuali.rice.kns.bo.PersistableBusinessObject;
045    import org.kuali.rice.kns.service.BusinessObjectService;
046    import org.kuali.rice.kns.service.DateTimeService;
047    import org.kuali.rice.kns.util.DateUtils;
048    import org.kuali.rice.kns.util.ObjectUtils;
049    
050    public class AssetTransferServiceImpl implements AssetTransferService {
051        protected static enum AmountCategory {
052            CAPITALIZATION {
053                public void setParams(AssetGlpeSourceDetail postable, AssetPayment assetPayment, AssetObjectCode assetObjectCode, boolean isSource, OffsetDefinition offsetDefinition) {
054                    postable.setFinancialDocumentLineDescription("" + (isSource ? "Reverse" : "Transfer") + " asset cost");
055                    postable.setAmount(assetPayment.getAccountChargeAmount());
056                    postable.setFinancialObjectCode(assetObjectCode.getCapitalizationFinancialObjectCode());
057                    postable.setObjectCode(assetObjectCode.getCapitalizationFinancialObject());
058                    postable.setCapitalization(true);
059                };
060    
061            },
062            ACCUM_DEPRECIATION {
063                public void setParams(AssetGlpeSourceDetail postable, AssetPayment assetPayment, AssetObjectCode assetObjectCode, boolean isSource, OffsetDefinition offsetDefinition) {
064                    postable.setFinancialDocumentLineDescription("" + (isSource ? "Reverse" : "Transfer") + " accumulated depreciation");
065                    postable.setAmount(assetPayment.getAccumulatedPrimaryDepreciationAmount());
066                    postable.setFinancialObjectCode(assetObjectCode.getAccumulatedDepreciationFinancialObjectCode());
067                    postable.setObjectCode(assetObjectCode.getAccumulatedDepreciationFinancialObject());
068                    postable.setAccumulatedDepreciation(true);
069                };
070    
071            },
072            OFFSET_AMOUNT {
073                public void setParams(AssetGlpeSourceDetail postable, AssetPayment assetPayment, AssetObjectCode assetObjectCode, boolean isSource, OffsetDefinition offsetDefinition) {
074                    postable.setFinancialDocumentLineDescription("" + (isSource ? "Reverse" : "Transfer") + " offset amount");
075                    postable.setAmount(assetPayment.getAccountChargeAmount().subtract(assetPayment.getAccumulatedPrimaryDepreciationAmount()));
076                    postable.setFinancialObjectCode(offsetDefinition.getFinancialObjectCode());
077                    postable.setObjectCode(offsetDefinition.getFinancialObject());
078                    postable.setCapitalizationOffset(true);
079                };
080    
081            };
082            abstract void setParams(AssetGlpeSourceDetail postable, AssetPayment assetPayment, AssetObjectCode assetObjectCode, boolean isSource, OffsetDefinition offsetDefinition);
083        }
084    
085        private static final Logger LOG = Logger.getLogger(AssetTransferServiceImpl.class);
086        private AssetService assetService;
087        private UniversityDateService universityDateService;
088        private BusinessObjectService businessObjectService;
089        private AssetPaymentService assetPaymentService;
090        private AssetObjectCodeService assetObjectCodeService;
091        private DateTimeService dateTimeService;
092        private AssetLocationService assetLocationService;
093    
094    
095        /**
096         * Creates an instance of AssetGlpeSourceDetail depending on the source flag
097         * 
098         * @param universityDateService University Date Service
099         * @param plantAccount Plant account for the organization
100         * @param assetPayment Payment record for which postable is created
101         * @param isSource Indicates if postable is for source organization
102         * @return GL Postable source detail
103         */
104        protected AssetGlpeSourceDetail createAssetGlpePostable(AssetTransferDocument document, Account plantAccount, AssetPayment assetPayment, boolean isSource, AmountCategory amountCategory) {
105            LOG.debug("Start - createAssetGlpePostable (" + document.getDocumentNumber() + "-" + plantAccount.getAccountNumber() + ")");
106            AssetGlpeSourceDetail postable = new AssetGlpeSourceDetail();
107            postable.setSource(isSource);
108            postable.setAccount(plantAccount);
109            postable.setAccountNumber(plantAccount.getAccountNumber());
110            postable.setBalanceTypeCode(CamsConstants.Postable.GL_BALANCE_TYPE_CODE_AC);
111            String organizationOwnerChartOfAccountsCode = null;
112            if (isSource) {
113                organizationOwnerChartOfAccountsCode = document.getAsset().getOrganizationOwnerChartOfAccountsCode();
114                postable.setSubAccountNumber(assetPayment.getSubAccountNumber());
115            }
116            else {
117                organizationOwnerChartOfAccountsCode = document.getOrganizationOwnerChartOfAccountsCode();
118                postable.setSubAccountNumber(null);
119            }
120            ObjectCodeService objectCodeService = (ObjectCodeService) SpringContext.getBean(ObjectCodeService.class);
121            ObjectCode objectCode = objectCodeService.getByPrimaryIdForCurrentYear(assetPayment.getChartOfAccountsCode(), assetPayment.getFinancialObjectCode());
122            postable.setChartOfAccountsCode(organizationOwnerChartOfAccountsCode);
123            postable.setDocumentNumber(document.getDocumentNumber());
124            postable.setFinancialSubObjectCode(assetPayment.getFinancialSubObjectCode());
125            postable.setPostingYear(getUniversityDateService().getCurrentUniversityDate().getUniversityFiscalYear());
126            postable.setProjectCode(assetPayment.getProjectCode());
127            postable.setOrganizationReferenceId(assetPayment.getOrganizationReferenceId());
128    
129            AssetObjectCode assetObjectCode = getAssetObjectCodeService().findAssetObjectCode(organizationOwnerChartOfAccountsCode, objectCode.getFinancialObjectSubTypeCode());
130            OffsetDefinition offsetDefinition = SpringContext.getBean(OffsetDefinitionService.class).getByPrimaryId(getUniversityDateService().getCurrentFiscalYear(), organizationOwnerChartOfAccountsCode, CamsConstants.AssetTransfer.DOCUMENT_TYPE_CODE, CamsConstants.Postable.GL_BALANCE_TYPE_CODE_AC);
131            amountCategory.setParams(postable, assetPayment, assetObjectCode, isSource, offsetDefinition);
132            LOG.debug("End - createAssetGlpePostable(" + document.getDocumentNumber() + "-" + plantAccount.getAccountNumber() + "-" + ")");
133            return postable;
134        }
135    
136        /**
137         * @see org.kuali.kfs.module.cam.document.service.AssetTransferService#createGLPostables(org.kuali.kfs.module.cam.document.AssetTransferDocument)
138         */
139        public void createGLPostables(AssetTransferDocument document) {
140            document.clearGlPostables();
141            // Create GL entries only for capital assets
142            ObjectCodeService objectCodeService = (ObjectCodeService) SpringContext.getBean(ObjectCodeService.class);
143    
144            Asset asset = document.getAsset();
145            if (getAssetService().isCapitalAsset(asset) && !asset.getAssetPayments().isEmpty()) {
146                asset.refreshReferenceObject(CamsPropertyConstants.Asset.ORGANIZATION_OWNER_ACCOUNT);
147                document.refreshReferenceObject(CamsPropertyConstants.AssetTransferDocument.ORGANIZATION_OWNER_ACCOUNT);
148       
149                String finObjectSubTypeCode = asset.getFinancialObjectSubTypeCode();
150                if (finObjectSubTypeCode == null) {
151                    AssetPayment firstAssetPayment = asset.getAssetPayments().get(0);
152                    ObjectCode objectCode = objectCodeService.getByPrimaryIdForCurrentYear(firstAssetPayment.getChartOfAccountsCode(), firstAssetPayment.getFinancialObjectCode());
153                    finObjectSubTypeCode = objectCode.getFinancialObjectSubTypeCode();
154                }
155                boolean movableAsset = getAssetService().isAssetMovableCheckByPayment(finObjectSubTypeCode);
156                if (isGLPostable(document, asset, movableAsset)) {
157                    asset.refreshReferenceObject(CamsPropertyConstants.Asset.ASSET_PAYMENTS);
158                    List<AssetPayment> assetPayments = asset.getAssetPayments();
159                    createSourceGLPostables(document, assetPayments, movableAsset);
160                    createTargetGLPostables(document, assetPayments, movableAsset);
161                }
162            }
163        }
164    
165    
166        /**
167         * Creates new payment records for new organization account
168         * 
169         * @param document Current document
170         * @param persistableObjects Saved objects list
171         * @param originalPayments Original payments for the asset
172         * @param maxSequence Payment sequence number
173         * @return Incremented sequence number
174         */
175        protected Integer createNewPayments(AssetTransferDocument document, List<PersistableBusinessObject> persistableObjects, List<AssetPayment> originalPayments, Integer maxSequence) {
176            Integer maxSequenceNo = maxSequence;
177            for (AssetPayment assetPayment : originalPayments) {
178                if (!CamsConstants.AssetPayment.TRANSFER_PAYMENT_CODE_Y.equals(assetPayment.getTransferPaymentCode())) {
179                    // copy and create new payment
180                    AssetPayment newPayment;
181                    try {
182                        if (maxSequenceNo == null) {
183                            maxSequenceNo = SpringContext.getBean(AssetPaymentService.class).getMaxSequenceNumber(assetPayment.getCapitalAssetNumber());
184                        }
185                        // create new payment info
186                        // newPayment = (AssetPayment) ObjectUtils.deepCopy(assetPayment);
187                        newPayment = new AssetPayment();
188                        ObjectValueUtils.copySimpleProperties(assetPayment, newPayment);
189                        newPayment.setPaymentSequenceNumber(++maxSequenceNo);
190                        newPayment.setAccountNumber(document.getOrganizationOwnerAccountNumber());
191                        newPayment.setChartOfAccountsCode(document.getOrganizationOwnerChartOfAccountsCode());
192                        newPayment.setSubAccountNumber(null);
193                        newPayment.setDocumentNumber(document.getDocumentNumber());
194                        newPayment.setFinancialDocumentTypeCode(CamsConstants.AssetTransfer.DOCUMENT_TYPE_CODE);
195                        newPayment.setFinancialDocumentPostingDate(DateUtils.convertToSqlDate(dateTimeService.getCurrentDate()));
196                        newPayment.setFinancialDocumentPostingYear(getUniversityDateService().getCurrentUniversityDate().getUniversityFiscalYear());
197                        newPayment.setFinancialDocumentPostingPeriodCode(getUniversityDateService().getCurrentUniversityDate().getUniversityFiscalAccountingPeriod());
198                        getAssetPaymentService().adjustPaymentAmounts(newPayment, false, true);
199                        newPayment.setTransferPaymentCode(CamsConstants.AssetPayment.TRANSFER_PAYMENT_CODE_N);
200                        // add new payment
201                        persistableObjects.add(newPayment);
202                    }
203                    catch (Exception e) {
204                        throw new RuntimeException(e);
205                    }
206                }
207            }
208            return maxSequenceNo;
209        }
210    
211    
212        /**
213         * Creates offset payment copying the details from original payments and reversing the amounts
214         * 
215         * @param document Current Document
216         * @param persistableObjects List of update objects
217         * @param originalPayments Original list of payments
218         * @return Incremented sequence number
219         */
220        protected Integer createOffsetPayments(AssetTransferDocument document, List<PersistableBusinessObject> persistableObjects, List<AssetPayment> originalPayments) {
221            Integer maxSequenceNo = null;
222            for (AssetPayment assetPayment : originalPayments) {
223                if (!CamsConstants.AssetPayment.TRANSFER_PAYMENT_CODE_Y.equals(assetPayment.getTransferPaymentCode())) {
224                    // copy and create an offset payment
225                    try {
226                        if (maxSequenceNo == null) {
227                            maxSequenceNo = SpringContext.getBean(AssetPaymentService.class).getMaxSequenceNumber(assetPayment.getCapitalAssetNumber());
228                        }
229                        // AssetPayment offsetPayment = (AssetPayment) ObjectUtils.deepCopy(assetPayment);
230                        AssetPayment offsetPayment = new AssetPayment();
231                        ObjectValueUtils.copySimpleProperties(assetPayment, offsetPayment);
232                        offsetPayment.setDocumentNumber(document.getDocumentNumber());
233                        offsetPayment.setFinancialDocumentTypeCode(CamsConstants.AssetTransfer.DOCUMENT_TYPE_CODE);
234                        offsetPayment.setFinancialDocumentPostingDate(DateUtils.convertToSqlDate(dateTimeService.getCurrentDate()));
235                        offsetPayment.setFinancialDocumentPostingYear(getUniversityDateService().getCurrentUniversityDate().getUniversityFiscalYear());
236                        offsetPayment.setFinancialDocumentPostingPeriodCode(getUniversityDateService().getCurrentUniversityDate().getUniversityFiscalAccountingPeriod());
237                        getAssetPaymentService().adjustPaymentAmounts(offsetPayment, true, true);
238                        offsetPayment.setTransferPaymentCode(CamsConstants.AssetPayment.TRANSFER_PAYMENT_CODE_Y);
239                        offsetPayment.setPaymentSequenceNumber(++maxSequenceNo);
240                        persistableObjects.add(offsetPayment);
241                    }
242                    catch (Exception e) {
243                        throw new RuntimeException(e);
244                    }
245                }
246            }
247            return maxSequenceNo;
248        }
249    
250    
251        /**
252         * Creates GL Postables for the source organization
253         * 
254         * @param universityDateService University Date Service to get the current fiscal year and period
255         * @param assetPayments Payments for which GL entries needs to be created
256         */
257        protected void createSourceGLPostables(AssetTransferDocument document, List<AssetPayment> assetPayments, boolean movableAsset) {
258            Account srcPlantAcct = null;
259            OffsetDefinition offsetDefinition = SpringContext.getBean(OffsetDefinitionService.class).getByPrimaryId(getUniversityDateService().getCurrentFiscalYear(), document.getAsset().getOrganizationOwnerChartOfAccountsCode(), CamsConstants.AssetTransfer.DOCUMENT_TYPE_CODE, CamsConstants.Postable.GL_BALANCE_TYPE_CODE_AC);
260    
261            if (movableAsset) {
262                srcPlantAcct = document.getAsset().getOrganizationOwnerAccount().getOrganization().getOrganizationPlantAccount();
263            }
264            else {
265                srcPlantAcct = document.getAsset().getOrganizationOwnerAccount().getOrganization().getCampusPlantAccount();
266            }
267            ObjectCodeService objectCodeService = (ObjectCodeService) SpringContext.getBean(ObjectCodeService.class);
268    
269            for (AssetPayment assetPayment : assetPayments) {
270                if (getAssetPaymentService().isPaymentEligibleForGLPosting(assetPayment)) {
271                     ObjectCode objectCode = objectCodeService.getByPrimaryIdForCurrentYear(assetPayment.getChartOfAccountsCode(), assetPayment.getFinancialObjectCode());
272                    if (ObjectUtils.isNotNull(objectCode)) {
273                        if (getAssetPaymentService().isPaymentEligibleForCapitalizationGLPosting(assetPayment)) {
274                            document.getSourceAssetGlpeSourceDetails().add(createAssetGlpePostable(document, srcPlantAcct, assetPayment, true, AmountCategory.CAPITALIZATION));
275                        }
276                        if (getAssetPaymentService().isPaymentEligibleForAccumDeprGLPosting(assetPayment)) {
277                            document.getSourceAssetGlpeSourceDetails().add(createAssetGlpePostable(document, srcPlantAcct, assetPayment, true, AmountCategory.ACCUM_DEPRECIATION));
278                        }
279                        if (getAssetPaymentService().isPaymentEligibleForOffsetGLPosting(assetPayment)) {
280                            document.getSourceAssetGlpeSourceDetails().add(createAssetGlpePostable(document, srcPlantAcct, assetPayment, true, AmountCategory.OFFSET_AMOUNT));
281                        }
282                    }
283                }
284            }
285        }
286    
287    
288        /**
289         * Creates target GL Postable for the receiving organization
290         * 
291         * @param universityDateService University Date Service to get the current fiscal year and period
292         * @param assetPayments Payments for which GL entries needs to be created
293         */
294        protected void createTargetGLPostables(AssetTransferDocument document, List<AssetPayment> assetPayments, boolean movableAsset) {
295            Account targetPlantAcct = null;
296    
297            if (movableAsset) {
298                targetPlantAcct = document.getOrganizationOwnerAccount().getOrganization().getOrganizationPlantAccount();
299            }
300            else {
301                targetPlantAcct = document.getOrganizationOwnerAccount().getOrganization().getCampusPlantAccount();
302            }
303            for (AssetPayment assetPayment : assetPayments) {
304                if (getAssetPaymentService().isPaymentEligibleForGLPosting(assetPayment)) {
305                    if (getAssetPaymentService().isPaymentEligibleForCapitalizationGLPosting(assetPayment)) {
306                        document.getTargetAssetGlpeSourceDetails().add(createAssetGlpePostable(document, targetPlantAcct, assetPayment, false, AmountCategory.CAPITALIZATION));
307                    }
308                    if (getAssetPaymentService().isPaymentEligibleForAccumDeprGLPosting(assetPayment)) {
309                        document.getTargetAssetGlpeSourceDetails().add(createAssetGlpePostable(document, targetPlantAcct, assetPayment, false, AmountCategory.ACCUM_DEPRECIATION));
310                    }
311                    if (getAssetPaymentService().isPaymentEligibleForOffsetGLPosting(assetPayment)) {
312                        document.getTargetAssetGlpeSourceDetails().add(createAssetGlpePostable(document, targetPlantAcct, assetPayment, false, AmountCategory.OFFSET_AMOUNT));
313                    }
314                }
315            }
316        }
317    
318    
319        public AssetPaymentService getAssetPaymentService() {
320            return assetPaymentService;
321        }
322    
323    
324        public AssetService getAssetService() {
325            return assetService;
326        }
327    
328    
329        public BusinessObjectService getBusinessObjectService() {
330            return businessObjectService;
331        }
332    
333    
334        public UniversityDateService getUniversityDateService() {
335            return universityDateService;
336        }
337    
338        /**
339         * Checks if it is ready for GL Posting by validating the accounts and plant account numbers
340         * 
341         * @return true if all accounts are valid
342         */
343        protected boolean isGLPostable(AssetTransferDocument document, Asset asset, boolean movableAsset) {
344            boolean isGLPostable = true;
345    
346            Account srcPlantAcct = null;
347    
348            if (ObjectUtils.isNotNull(asset.getOrganizationOwnerAccount())) {
349                if (movableAsset) {
350                    srcPlantAcct = asset.getOrganizationOwnerAccount().getOrganization().getOrganizationPlantAccount();
351                }
352                else {
353                    srcPlantAcct = asset.getOrganizationOwnerAccount().getOrganization().getCampusPlantAccount();
354                }
355            }
356    
357            if (ObjectUtils.isNull(srcPlantAcct)) {
358                isGLPostable &= false;
359            }
360            Account targetPlantAcct = null;
361            if (ObjectUtils.isNotNull(document.getOrganizationOwnerAccount())) {
362                if (movableAsset) {
363                    targetPlantAcct = document.getOrganizationOwnerAccount().getOrganization().getOrganizationPlantAccount();
364                }
365                else {
366                    targetPlantAcct = document.getOrganizationOwnerAccount().getOrganization().getCampusPlantAccount();
367                }
368            }
369            if (ObjectUtils.isNull(targetPlantAcct)) {
370                isGLPostable &= false;
371    
372            }
373            return isGLPostable;
374        }
375    
376    
377        /**
378         * @see org.kuali.kfs.module.cam.document.service.AssetTransferService#saveApprovedChanges(org.kuali.kfs.module.cam.document.AssetTransferDocument)
379         */
380        public void saveApprovedChanges(AssetTransferDocument document) {
381            // save new asset location details to asset table, inventory date
382            List<PersistableBusinessObject> persistableObjects = new ArrayList<PersistableBusinessObject>();
383            Asset saveAsset = new Asset();
384            saveAsset.setCapitalAssetNumber(document.getCapitalAssetNumber());
385            saveAsset = (Asset) getBusinessObjectService().retrieve(saveAsset);
386            saveAssetOwnerData(document, saveAsset);
387            saveLocationChanges(document, saveAsset);
388            saveOrganizationChanges(document, saveAsset);
389    
390            if (getAssetService().isCapitalAsset(saveAsset)) {
391                // for capital assets, create new asset payment records and offset payment records
392                if (ObjectUtils.isNull(saveAsset.getAssetPayments())) {
393                    saveAsset.refreshReferenceObject(CamsPropertyConstants.Asset.ASSET_PAYMENTS);
394                }
395                List<AssetPayment> originalPayments = saveAsset.getAssetPayments();
396                Integer maxSequence = createOffsetPayments(document, persistableObjects, originalPayments);
397                maxSequence = createNewPayments(document, persistableObjects, originalPayments, maxSequence);
398                updateOriginalPayments(persistableObjects, originalPayments);
399            }
400            saveAsset.setTransferOfFundsFinancialDocumentNumber(document.getTransferOfFundsFinancialDocumentNumber());
401            // save asset
402            persistableObjects.add(saveAsset);
403            getBusinessObjectService().save(persistableObjects);
404        }
405    
406    
407        /**
408         * Updates organization data for the asset
409         * 
410         * @param document Current document
411         * @param saveAsset Asset
412         */
413        protected void saveAssetOwnerData(AssetTransferDocument document, Asset saveAsset) {
414            saveAsset.setOrganizationOwnerAccountNumber(document.getOrganizationOwnerAccountNumber());
415            saveAsset.setOrganizationOwnerChartOfAccountsCode(document.getOrganizationOwnerChartOfAccountsCode());
416        }
417    
418        /**
419         * Updates location details to the asset
420         * 
421         * @param document Current document
422         * @param saveAsset Asset
423         */
424        protected void saveLocationChanges(AssetTransferDocument document, Asset saveAsset) {
425            // change inventory date
426            saveAsset.setLastInventoryDate(SpringContext.getBean(DateTimeService.class).getCurrentTimestamp());
427            // save asset location details
428            saveAsset.setCampusCode(document.getCampusCode());
429            saveAsset.setBuildingCode(document.getBuildingCode());
430            saveAsset.setBuildingRoomNumber(document.getBuildingRoomNumber());
431            saveAsset.setBuildingSubRoomNumber(document.getBuildingSubRoomNumber());
432    
433            // save off campus location details
434            AssetLocation offCampusLocation = null;
435            List<AssetLocation> orginalLocations = saveAsset.getAssetLocations();
436            for (AssetLocation assetLocation : orginalLocations) {
437                if (CamsConstants.AssetLocationTypeCode.OFF_CAMPUS.equals(assetLocation.getAssetLocationTypeCode())) {
438                    offCampusLocation = assetLocation;
439                    break;
440                }
441            }
442            if (ObjectUtils.isNull(offCampusLocation)) {
443                offCampusLocation = new AssetLocation();
444                offCampusLocation.setCapitalAssetNumber(saveAsset.getCapitalAssetNumber());
445                offCampusLocation.setAssetLocationTypeCode(CamsConstants.AssetLocationTypeCode.OFF_CAMPUS);
446                saveAsset.getAssetLocations().add(offCampusLocation);
447            }
448            // save details
449            offCampusLocation.setAssetLocationContactName(document.getOffCampusName());
450            offCampusLocation.setAssetLocationState(document.getOffCampusState());
451            offCampusLocation.setPostalZipCode(document.getPostalZipCode());
452            offCampusLocation.setAssetLocationCountryCode(document.getOffCampusCountryCode());
453            offCampusLocation.setAssetLocationStreetAddress(document.getOffCampusAddress());
454            offCampusLocation.setAssetLocationCityName(document.getOffCampusCityName());
455            offCampusLocation.setAssetLocationStateCode(document.getOffCampusStateCode());
456            offCampusLocation.setAssetLocationZipCode(document.getOffCampusZipCode());
457            
458            // remove off Campus Location if it's an empty record. When asset transfer from off to on campus, the off campus location will be removed.
459            if (getAssetLocationService().isOffCampusLocationEmpty(offCampusLocation)) { 
460                saveAsset.getAssetLocations().remove(offCampusLocation); 
461            }
462        }
463    
464    
465        /**
466         * Updates organization changes
467         * 
468         * @param document Current document
469         * @param saveAsset Asset
470         */
471        protected void saveOrganizationChanges(AssetTransferDocument document, Asset saveAsset) {
472            if (ObjectUtils.isNull(saveAsset.getAssetOrganization())) {
473                AssetOrganization assetOrganization = new AssetOrganization();
474                assetOrganization.setCapitalAssetNumber(saveAsset.getCapitalAssetNumber());
475                saveAsset.setAssetOrganization(assetOrganization);
476            }
477    
478            saveAsset.setOrganizationInventoryName(document.getOrganizationInventoryName());
479            saveAsset.setRepresentativeUniversalIdentifier(document.getRepresentativeUniversalIdentifier());
480            saveAsset.getAssetOrganization().setOrganizationTagNumber(document.getOrganizationTagNumber());
481            saveAsset.getAssetOrganization().setOrganizationText(document.getOrganizationText());
482        }
483    
484        public void setAssetPaymentService(AssetPaymentService assetPaymentService) {
485            this.assetPaymentService = assetPaymentService;
486        }
487    
488    
489        public void setAssetService(AssetService assetService) {
490            this.assetService = assetService;
491        }
492    
493    
494        public void setBusinessObjectService(BusinessObjectService businessObjectService) {
495            this.businessObjectService = businessObjectService;
496        }
497    
498        public void setUniversityDateService(UniversityDateService universityDateService) {
499            this.universityDateService = universityDateService;
500        }
501    
502        /**
503         * Updates original payment records
504         * 
505         * @param persistableObjects List of saveable objects
506         * @param originalPayments Original payments list
507         */
508        protected void updateOriginalPayments(List<PersistableBusinessObject> persistableObjects, List<AssetPayment> originalPayments) {
509            for (AssetPayment assetPayment : originalPayments) {
510                if (!CamsConstants.AssetPayment.TRANSFER_PAYMENT_CODE_Y.equals(assetPayment.getTransferPaymentCode())) {
511                    // change payment code
512                    assetPayment.setTransferPaymentCode(CamsConstants.AssetPayment.TRANSFER_PAYMENT_CODE_Y);
513                    persistableObjects.add(assetPayment);
514                }
515            }
516        }
517    
518        public AssetObjectCodeService getAssetObjectCodeService() {
519            return assetObjectCodeService;
520        }
521    
522        public void setAssetObjectCodeService(AssetObjectCodeService assetObjectCodeService) {
523            this.assetObjectCodeService = assetObjectCodeService;
524        }
525    
526        /**
527         * Gets the dateTimeService attribute.
528         * 
529         * @return Returns the dateTimeService.
530         */
531        public DateTimeService getDateTimeService() {
532            return dateTimeService;
533        }
534    
535        /**
536         * Sets the dateTimeService attribute value.
537         * 
538         * @param dateTimeService The dateTimeService to set.
539         */
540        public void setDateTimeService(DateTimeService dateTimeService) {
541            this.dateTimeService = dateTimeService;
542        }
543    
544        /**
545         * Gets the assetLocationService attribute.
546         * 
547         * @return Returns the assetLocationService
548         */
549        public AssetLocationService getAssetLocationService() {
550            return assetLocationService;
551        }
552    
553        /**
554         * Sets the assetLocationService attribute.
555         * 
556         * @param assetLocationService  The assetLocationService to set
557         */
558        public void setAssetLocationService(AssetLocationService assetLocationService) {
559            this.assetLocationService = assetLocationService;
560        }
561    }