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.cab.document.service.impl; 017 018 import java.util.ArrayList; 019 import java.util.HashMap; 020 import java.util.Iterator; 021 import java.util.List; 022 import java.util.Map; 023 024 import org.apache.commons.lang.StringUtils; 025 import org.apache.log4j.Logger; 026 import org.kuali.kfs.integration.purap.CapitalAssetLocation; 027 import org.kuali.kfs.integration.purap.ItemCapitalAsset; 028 import org.kuali.kfs.module.cab.CabConstants; 029 import org.kuali.kfs.module.cab.CabPropertyConstants; 030 import org.kuali.kfs.module.cab.businessobject.GeneralLedgerEntry; 031 import org.kuali.kfs.module.cab.businessobject.Pretag; 032 import org.kuali.kfs.module.cab.businessobject.PretagDetail; 033 import org.kuali.kfs.module.cab.businessobject.PurchasingAccountsPayableDocument; 034 import org.kuali.kfs.module.cab.businessobject.PurchasingAccountsPayableItemAsset; 035 import org.kuali.kfs.module.cab.businessobject.PurchasingAccountsPayableLineAssetAccount; 036 import org.kuali.kfs.module.cab.document.service.PurApInfoService; 037 import org.kuali.kfs.module.cab.document.service.PurApLineDocumentService; 038 import org.kuali.kfs.module.cab.document.service.PurApLineService; 039 import org.kuali.kfs.module.cab.document.web.PurApLineSession; 040 import org.kuali.kfs.module.cam.CamsConstants; 041 import org.kuali.kfs.module.cam.CamsPropertyConstants; 042 import org.kuali.kfs.module.cam.businessobject.Asset; 043 import org.kuali.kfs.module.cam.businessobject.AssetGlobal; 044 import org.kuali.kfs.module.cam.businessobject.AssetGlobalDetail; 045 import org.kuali.kfs.module.cam.businessobject.AssetPaymentAssetDetail; 046 import org.kuali.kfs.module.cam.businessobject.AssetPaymentDetail; 047 import org.kuali.kfs.module.cam.businessobject.AssetType; 048 import org.kuali.kfs.module.cam.businessobject.defaultvalue.NextAssetNumberFinder; 049 import org.kuali.kfs.module.cam.document.AssetPaymentDocument; 050 import org.kuali.kfs.module.cam.document.service.AssetGlobalService; 051 import org.kuali.kfs.module.cam.document.service.AssetService; 052 import org.kuali.kfs.module.purap.PurapPropertyConstants; 053 import org.kuali.kfs.module.purap.businessobject.PurchaseOrderCapitalAssetSystem; 054 import org.kuali.kfs.module.purap.document.PurchaseOrderDocument; 055 import org.kuali.kfs.sys.businessobject.Building; 056 import org.kuali.kfs.sys.businessobject.Room; 057 import org.kuali.kfs.sys.context.SpringContext; 058 import org.kuali.rice.kew.exception.WorkflowException; 059 import org.kuali.rice.kns.bo.Campus; 060 import org.kuali.rice.kns.document.MaintenanceDocument; 061 import org.kuali.rice.kns.service.BusinessObjectService; 062 import org.kuali.rice.kns.service.DocumentService; 063 import org.kuali.rice.kns.service.KualiModuleService; 064 import org.kuali.rice.kns.util.KNSConstants; 065 import org.kuali.rice.kns.util.KualiDecimal; 066 import org.kuali.rice.kns.util.ObjectUtils; 067 068 069 /** 070 * This class provides default implementations of {@link PurApLineService} 071 */ 072 public class PurApLineDocumentServiceImpl implements PurApLineDocumentService { 073 private static final Logger LOG = Logger.getLogger(PurApLineDocumentServiceImpl.class); 074 private BusinessObjectService businessObjectService; 075 private DocumentService documentService; 076 private PurApLineService purApLineService; 077 private PurApInfoService purApInfoService; 078 private AssetGlobalService assetGlobalService; 079 080 public static final String DOCUMENT_DESC_PREFIX = "CAB created for "; 081 082 /** 083 * @see org.kuali.kfs.module.cab.document.service.PurApLineDocumentService#processApplyPayment(PurchasingAccountsPayableItemAsset, 084 * List, PurApLineSession, Integer) 085 */ 086 public String processApplyPayment(PurchasingAccountsPayableItemAsset selectedItem, List<PurchasingAccountsPayableDocument> purApDocs, PurApLineSession purApLineSession, Integer requisitionIdentifer) throws WorkflowException { 087 AssetPaymentDocument newDocument = (AssetPaymentDocument) documentService.getNewDocument(AssetPaymentDocument.class); 088 if (ObjectUtils.isNotNull(selectedItem) && ObjectUtils.isNotNull(selectedItem.getPurchasingAccountsPayableDocument())) { 089 newDocument.getDocumentHeader().setDocumentDescription(DOCUMENT_DESC_PREFIX + selectedItem.getPurchasingAccountsPayableDocument().getDocumentTypeCode() + " " + selectedItem.getDocumentNumber()); 090 } 091 // set assetPaymentDetail list 092 createAssetPaymentDetails(newDocument.getSourceAccountingLines(), selectedItem, newDocument.getDocumentNumber(), requisitionIdentifer); 093 094 // If PurAp user entered capitalAssetNumbers, include them in the Asset Payment Document. 095 if (selectedItem.getPurApItemAssets() != null && !selectedItem.getPurApItemAssets().isEmpty()) { 096 createAssetPaymentAssetDetails(newDocument.getAssetPaymentAssetDetail(), selectedItem, newDocument.getDocumentNumber()); 097 098 } 099 // set origin code in the Asset Payment Document 100 newDocument.setCapitalAssetBuilderOriginIndicator(true); 101 documentService.saveDocument(newDocument); 102 103 postProcessCreatingDocument(selectedItem, purApDocs, purApLineSession, newDocument.getDocumentNumber()); 104 return newDocument.getDocumentNumber(); 105 } 106 107 108 /** 109 * Create AssetPaymentAssetDetail List for assetPaymentDocument. 110 * 111 * @param assetPaymentAssetDetails 112 * @param selectedItem 113 * @param documentNumber 114 */ 115 protected void createAssetPaymentAssetDetails(List assetPaymentAssetDetails, PurchasingAccountsPayableItemAsset selectedItem, String documentNumber) { 116 for (ItemCapitalAsset capitalAssetNumber : selectedItem.getPurApItemAssets()) { 117 // check if capitalAssetNumber is a valid value or not. 118 if (isAssetNumberValid(capitalAssetNumber.getCapitalAssetNumber())) { 119 AssetPaymentAssetDetail assetDetail = new AssetPaymentAssetDetail(); 120 assetDetail.setDocumentNumber(documentNumber); 121 122 assetDetail.setCapitalAssetNumber(capitalAssetNumber.getCapitalAssetNumber()); 123 assetDetail.refreshReferenceObject(CamsPropertyConstants.AssetPaymentAssetDetail.ASSET); 124 125 AssetService assetService = SpringContext.getBean(AssetService.class); 126 Asset candidateAsset = assetDetail.getAsset(); 127 // asset must be an active & not retired. Duplication check is done during feeding asset numbers from PurAp. 128 if (ObjectUtils.isNotNull(candidateAsset) && assetService.isCapitalAsset(candidateAsset) && !assetService.isAssetRetired(candidateAsset)) { 129 assetDetail.setPreviousTotalCostAmount(assetDetail.getAsset().getTotalCostAmount()); 130 assetPaymentAssetDetails.add(assetDetail); 131 } 132 133 } 134 } 135 } 136 137 138 /** 139 * Check the asset table if given capitalAssetNumber is valid or not. 140 * 141 * @param capitalAssetNumber 142 * @return 143 */ 144 protected boolean isAssetNumberValid(Long capitalAssetNumber) { 145 Map pKeys = new HashMap<String, Object>(); 146 147 pKeys.put(CamsPropertyConstants.Asset.CAPITAL_ASSET_NUMBER, capitalAssetNumber); 148 149 Asset asset = (Asset) businessObjectService.findByPrimaryKey(Asset.class, pKeys); 150 151 return ObjectUtils.isNotNull(asset); 152 } 153 154 155 /** 156 * @see org.kuali.kfs.module.cab.document.service.PurApLineService#processCreateAsset(org.kuali.kfs.module.cab.businessobject.PurchasingAccountsPayableItemAsset, 157 * org.kuali.kfs.module.cab.document.web.struts.PurApLineForm) 158 */ 159 public String processCreateAsset(PurchasingAccountsPayableItemAsset selectedItem, List<PurchasingAccountsPayableDocument> purApDocs, PurApLineSession purApLineSession, Integer requisitionIdentifier) throws WorkflowException { 160 // Create new CAMS asset global document 161 MaintenanceDocument newDocument = (MaintenanceDocument) documentService.getNewDocument(CamsConstants.DocumentTypeName.ASSET_ADD_GLOBAL); 162 newDocument.getNewMaintainableObject().setMaintenanceAction(KNSConstants.MAINTENANCE_NEW_ACTION); 163 if (ObjectUtils.isNotNull(selectedItem) && ObjectUtils.isNotNull(selectedItem.getPurchasingAccountsPayableDocument())) { 164 newDocument.getDocumentHeader().setDocumentDescription(DOCUMENT_DESC_PREFIX + selectedItem.getPurchasingAccountsPayableDocument().getDocumentTypeCode() + " " + selectedItem.getDocumentNumber()); 165 } 166 167 // populate pre-tagging entry 168 Integer poId = selectedItem.getPurchasingAccountsPayableDocument().getPurchaseOrderIdentifier(); 169 Pretag preTag = purApLineService.getPreTagLineItem(poId, selectedItem.getItemLineNumber()); 170 171 // create asset global BO instance 172 AssetGlobal assetGlobal = createAssetGlobal(selectedItem, newDocument.getDocumentNumber(), preTag, requisitionIdentifier); 173 174 // save asset global BO to the document 175 newDocument.getNewMaintainableObject().setBusinessObject(assetGlobal); 176 documentService.saveDocument(newDocument); 177 178 postProcessCreatingDocument(selectedItem, purApDocs, purApLineSession, newDocument.getDocumentNumber()); 179 180 // Save for in-active pre-tag detail if it got feed into CAMS 181 if (isItemPretagged(preTag)) { 182 businessObjectService.save(preTag); 183 } 184 return newDocument.getDocumentNumber(); 185 } 186 187 188 /** 189 * Process item line, cab document after creating CAMs document. 190 * 191 * @param selectedItem 192 * @param purApForm 193 * @param purApLineSession 194 * @param documentNumber 195 */ 196 protected void postProcessCreatingDocument(PurchasingAccountsPayableItemAsset selectedItem, List<PurchasingAccountsPayableDocument> purApDocs, PurApLineSession purApLineSession, String documentNumber) { 197 // save CAMS document number in CAB 198 selectedItem.setCapitalAssetManagementDocumentNumber(documentNumber); 199 200 // in-activate item, item account and glEntry(conditionally) 201 inActivateItem(selectedItem); 202 203 // update submit amount in the associated general ledger entries. 204 updateGlEntrySubmitAmount(selectedItem, purApLineSession.getGlEntryUpdateList()); 205 206 // in-activate document if all the associated items are inactive. 207 if (ObjectUtils.isNotNull(selectedItem.getPurchasingAccountsPayableDocument())) { 208 // update document status code as 'Enroute' when all its items are in CAMs. Link reference from item to document should 209 // be set in PurApLineAction.getSelectedLineItem(). 210 conditionalyUpdateDocumentStatusAsEnroute(selectedItem.getPurchasingAccountsPayableDocument()); 211 } 212 213 // persistent to the table 214 purApLineService.processSaveBusinessObjects(purApDocs, purApLineSession); 215 // In-activate general ledger afterwards because we don't maintain the non-persistent relationship from GL to account, so 216 // account need to persistent changes first. 217 List<GeneralLedgerEntry> glEntryUpdatesList = getGlEntryInActivedList(selectedItem); 218 if (glEntryUpdatesList != null && !glEntryUpdatesList.isEmpty()) { 219 businessObjectService.save(glEntryUpdatesList); 220 } 221 } 222 223 224 /** 225 * set doc status as enroute when all its items are in CAMs 226 * 227 * @param selectedDoc 228 */ 229 protected void conditionalyUpdateDocumentStatusAsEnroute(PurchasingAccountsPayableDocument selectedDoc) { 230 for (PurchasingAccountsPayableItemAsset item : selectedDoc.getPurchasingAccountsPayableItemAssets()) { 231 if (item.isActive()) { 232 return; 233 } 234 } 235 236 selectedDoc.setActivityStatusCode(CabConstants.ActivityStatusCode.ENROUTE); 237 } 238 239 240 /** 241 * Update transactionLedgerSubmitAmount in the associated generalLedgerEntry for each item account. 242 * 243 * @param selectedItem 244 */ 245 protected void updateGlEntrySubmitAmount(PurchasingAccountsPayableItemAsset selectedItem, List glEntryList) { 246 GeneralLedgerEntry glEntry = null; 247 for (PurchasingAccountsPayableLineAssetAccount account : selectedItem.getPurchasingAccountsPayableLineAssetAccounts()) { 248 glEntry = account.getGeneralLedgerEntry(); 249 250 if (ObjectUtils.isNotNull(glEntry)) { 251 // Add account amount to GL entry submit amount. 252 if (glEntry.getTransactionLedgerSubmitAmount() != null) { 253 glEntry.setTransactionLedgerSubmitAmount(glEntry.getTransactionLedgerSubmitAmount().add(account.getItemAccountTotalAmount())); 254 } 255 else { 256 glEntry.setTransactionLedgerSubmitAmount(new KualiDecimal(account.getItemAccountTotalAmount().toString())); 257 } 258 } 259 // add to the session for persistence 260 glEntryList.add(glEntry); 261 } 262 } 263 264 265 /** 266 * Build asset details/shared details/unique details lists for new asset global document 267 * 268 * @param selectedItem 269 * @param newDocument 270 * @param assetGlobal 271 */ 272 protected void setAssetGlobalDetails(PurchasingAccountsPayableItemAsset selectedItem, AssetGlobal assetGlobal, Pretag preTag, PurchaseOrderCapitalAssetSystem capitalAssetSystem) { 273 // build assetGlobalDetail list( will be used for creating unique details list at the same time) 274 List<AssetGlobalDetail> assetDetailsList = assetGlobal.getAssetGlobalDetails(); 275 // shared location details list 276 List<AssetGlobalDetail> sharedDetails = assetGlobal.getAssetSharedDetails(); 277 for (int i = 0; i < selectedItem.getAccountsPayableItemQuantity().intValue(); i++) { 278 AssetGlobalDetail assetGlobalDetail = new AssetGlobalDetail(); 279 assetGlobalDetail.setDocumentNumber(assetGlobal.getDocumentNumber()); 280 assetGlobalDetail.setCapitalAssetNumber(NextAssetNumberFinder.getLongValue()); 281 assetDetailsList.add(assetGlobalDetail); 282 // build assetSharedDetails and assetGlobalUniqueDetails list. There two lists will be used to rebuild 283 // assetGlobalDetails list when AssetGlobalMaintainableImpl.prepareForSave() is called during save the document. 284 AssetGlobalDetail sharedDetail = new AssetGlobalDetail(); 285 // added as unique detail 286 sharedDetail.getAssetGlobalUniqueDetails().add(assetGlobalDetail); 287 sharedDetails.add(sharedDetail); 288 } 289 290 // feeding data from pre-tag details into shared location details list and unique detail list 291 if (isItemPretagged(preTag)) { 292 setAssetDetailFromPreTag(preTag, sharedDetails, assetDetailsList); 293 } 294 295 // feeding location data from PurAp into assetGlobalDetail List. 296 if (!isItemFullyPretagged(preTag, assetGlobal) && ObjectUtils.isNotNull(capitalAssetSystem)) { 297 setAssetGlobalDetailFromPurAp(capitalAssetSystem, sharedDetails); 298 } 299 } 300 301 /** 302 * Check if the all new assets get pre-tagged by pre-tagging. 303 * 304 * @param preTag 305 * @param assetGlobal 306 * @return 307 */ 308 protected boolean isItemFullyPretagged(Pretag preTag, AssetGlobal assetGlobal) { 309 if (isItemPretagged(preTag)) { 310 List<PretagDetail> pretagDetails = preTag.getPretagDetails(); 311 int pretagSize = 0; 312 for (PretagDetail pretagDetail : pretagDetails) { 313 if (pretagDetail.isActive()) { 314 pretagSize++; 315 } 316 } 317 return pretagSize >= assetGlobal.getAssetSharedDetails().size(); 318 } 319 return false; 320 } 321 322 323 /** 324 * Set asset global detail location information from PurAp input. In this method, no grouping for shared location because 325 * AssetGlobalMaintainableImpl.processAfterRetrieve() will group the shared location anyway... 326 * 327 * @param capitalAssetSystem 328 * @param assetDetailsList 329 */ 330 protected void setAssetGlobalDetailFromPurAp(PurchaseOrderCapitalAssetSystem capitalAssetSystem, List<AssetGlobalDetail> assetSharedDetail) { 331 List<CapitalAssetLocation> capitalAssetLocations = capitalAssetSystem.getCapitalAssetLocations(); 332 333 if (ObjectUtils.isNotNull(capitalAssetLocations) && !capitalAssetLocations.isEmpty()) { 334 Iterator<CapitalAssetLocation> locationIterator = capitalAssetLocations.iterator(); 335 int locationQuantity = 0; 336 CapitalAssetLocation assetLocation = null; 337 for (AssetGlobalDetail assetDetail : assetSharedDetail) { 338 // if it's already pre-tagged, skip it. 339 if (StringUtils.isNotEmpty(assetDetail.getCampusCode())) { 340 continue; 341 } 342 343 // Each line item can have multiple locations and each location can have a quantity value with it. 344 if (locationQuantity <= 0 && locationIterator.hasNext()) { 345 // when we consume the current location quantity, we need to move to the next PurAp location. 346 assetLocation = locationIterator.next(); 347 // initialize location quantity by PurAp setting 348 if (assetLocation.getItemQuantity() != null) { 349 locationQuantity = assetLocation.getItemQuantity().intValue(); 350 } 351 else { 352 // if Purap not set item quantity, we set it to 1. 353 locationQuantity = 1; 354 } 355 } 356 else if (locationQuantity <= 0 && !locationIterator.hasNext()) { 357 // Consume the current location quantity and no more PurAp locations can be used, stop here. 358 break; 359 } 360 // set PurAp asset location into asset global document 361 setNewAssetByPurApLocation(assetLocation, assetDetail); 362 363 locationQuantity--; 364 } 365 } 366 367 } 368 369 /** 370 * Set asset global detail by PurAp asset location. 371 * 372 * @param assetLocation 373 * @param assetDetail 374 */ 375 protected void setNewAssetByPurApLocation(CapitalAssetLocation assetLocation, AssetGlobalDetail assetDetail) { 376 String campusCode = assetLocation.getCampusCode(); 377 // Set campus code only when it is a valid value. Otherwise, when save document, invalid data will violate data integrity 378 // and block save. 379 if (!StringUtils.isBlank(campusCode) && checkCampusCodeValid(campusCode)) { 380 assetDetail.setCampusCode(campusCode); 381 382 // for on-campus 383 if (!assetLocation.isOffCampusIndicator()) { 384 String buildingCode = assetLocation.getBuildingCode(); 385 // Set building code only when it is a valid value. Otherwise, when save document, invalid data will violate data 386 // integrity and block save. 387 if (!StringUtils.isBlank(buildingCode) && checkBuildingCodeValid(campusCode, buildingCode)) { 388 assetDetail.setBuildingCode(buildingCode); 389 390 String buildingRoomNumber = assetLocation.getBuildingRoomNumber(); 391 // Set building room number only when it is a valid value. Otherwise, when save document, invalid data will 392 // violate data integrity and block save. 393 if (!StringUtils.isBlank(buildingRoomNumber) && checkBuildingRoomNumberValid(campusCode, buildingCode, buildingRoomNumber)) { 394 assetDetail.setBuildingRoomNumber(buildingRoomNumber); 395 } 396 } 397 } 398 else { 399 // off-campus 400 assetDetail.setOffCampusCityName(assetLocation.getCapitalAssetCityName()); 401 assetDetail.setOffCampusAddress(assetLocation.getCapitalAssetLine1Address()); 402 assetDetail.setOffCampusCountryCode(assetLocation.getCapitalAssetCountryCode()); 403 assetDetail.setOffCampusStateCode(assetLocation.getCapitalAssetStateCode()); 404 assetDetail.setOffCampusZipCode(assetLocation.getCapitalAssetPostalCode()); 405 } 406 } 407 } 408 409 410 /** 411 * Check the given buildingCode and campusCode valid. 412 * 413 * @param campusCode 414 * @param buildingCode 415 * @param buildingRoomNumber 416 * @return 417 */ 418 protected boolean checkBuildingRoomNumberValid(String campusCode, String buildingCode, String buildingRoomNumber) { 419 Map<String, Object> pKeys = new HashMap<String, Object>(); 420 pKeys.put(CabPropertyConstants.AssetGlobalDocumentCreate.CAMPUS_CODE, campusCode); 421 pKeys.put(CabPropertyConstants.AssetGlobalDocumentCreate.BUILDING_CODE, buildingCode); 422 pKeys.put(CabPropertyConstants.AssetGlobalDocumentCreate.BUILDING_ROOM_NUMBER, buildingRoomNumber); 423 Room room = (Room) this.getBusinessObjectService().findByPrimaryKey(Room.class, pKeys); 424 return ObjectUtils.isNotNull(room) && room.isActive(); 425 } 426 427 428 /** 429 * Check the given buildingCode and campusCode valid. 430 * 431 * @param buildingCode 432 * @return 433 */ 434 protected boolean checkBuildingCodeValid(String campusCode, String buildingCode) { 435 Map<String, Object> pKeys = new HashMap<String, Object>(); 436 pKeys.put(CabPropertyConstants.AssetGlobalDocumentCreate.CAMPUS_CODE, campusCode); 437 pKeys.put(CabPropertyConstants.AssetGlobalDocumentCreate.BUILDING_CODE, buildingCode); 438 Building building = (Building) this.getBusinessObjectService().findByPrimaryKey(Building.class, pKeys); 439 return ObjectUtils.isNotNull(building) && building.isActive(); 440 } 441 442 443 /** 444 * check the given campus code existing and active status. 445 * 446 * @param campusCode 447 * @return 448 */ 449 protected boolean checkCampusCodeValid(String campusCode) { 450 Map<String, Object> criteria = new HashMap<String, Object>(); 451 criteria.put(CabPropertyConstants.AssetGlobalDocumentCreate.CAMPUS_CODE, campusCode); 452 Campus campus = (Campus) SpringContext.getBean(KualiModuleService.class).getResponsibleModuleService(Campus.class).getExternalizableBusinessObject(Campus.class, criteria); 453 return ObjectUtils.isNotNull(campus) && campus.isActive(); 454 } 455 456 /** 457 * Feeding data into assetGlobalDetail list from preTagDetail 458 * 459 * @param preTag 460 * @param assetDetailsList 461 */ 462 protected void setAssetDetailFromPreTag(Pretag preTag, List<AssetGlobalDetail> assetSharedDetails, List<AssetGlobalDetail> assetUniqueDetails) { 463 Iterator<AssetGlobalDetail> sharedDetailsIterator = assetSharedDetails.iterator(); 464 Iterator<AssetGlobalDetail> uniqueDetailsIterator = assetUniqueDetails.iterator(); 465 for (PretagDetail preTagDetail : preTag.getPretagDetails()) { 466 if (!preTagDetail.isActive()) { 467 continue; 468 } 469 if (sharedDetailsIterator.hasNext()) { 470 // set shared location details 471 AssetGlobalDetail sharedDetail = sharedDetailsIterator.next(); 472 sharedDetail.setBuildingCode(preTagDetail.getBuildingCode()); 473 sharedDetail.setBuildingRoomNumber(preTagDetail.getBuildingRoomNumber()); 474 sharedDetail.setBuildingSubRoomNumber(preTagDetail.getBuildingSubRoomNumber()); 475 sharedDetail.setCampusCode(preTagDetail.getCampusCode()); 476 // In-activate pre-tagging detail, and will be persistent to the DB. 477 preTagDetail.setActive(false); 478 } 479 if (uniqueDetailsIterator.hasNext()) { 480 // set asset unique detail 481 AssetGlobalDetail uniqueDetail = uniqueDetailsIterator.next(); 482 uniqueDetail.setGovernmentTagNumber(preTagDetail.getGovernmentTagNumber()); 483 uniqueDetail.setNationalStockNumber(preTagDetail.getNationalStockNumber()); 484 uniqueDetail.setCampusTagNumber(preTagDetail.getCampusTagNumber()); 485 uniqueDetail.setOrganizationInventoryName(preTag.getOrganizationInventoryName()); 486 uniqueDetail.setSerialNumber(preTagDetail.getSerialNumber()); 487 uniqueDetail.setRepresentativeUniversalIdentifier(preTag.getRepresentativeUniversalIdentifier()); 488 // In-activate pre-tagging detail and will be persistent to the DB. 489 preTagDetail.setActive(false); 490 } 491 } 492 // In-activate preTag if possible. 493 inActivatePreTag(preTag); 494 } 495 496 /** 497 * In-activate preTag if all its preTagDetail entry are inactive. 498 * 499 * @param preTag 500 */ 501 protected void inActivatePreTag(Pretag preTag) { 502 // get the number of inactive pre-tag detail. 503 int inActiveCounter = 0; 504 for (PretagDetail preTagDetail : preTag.getPretagDetails()) { 505 if (!preTagDetail.isActive()) { 506 inActiveCounter++; 507 } 508 } 509 // if the number of inactive preTagDetail is equal or greater than (when quantityInvoiced is decimal) quantityInvoiced, 510 // in-activate the preTag active field. 511 if (preTag.getQuantityInvoiced().isLessEqual(new KualiDecimal(inActiveCounter))) { 512 preTag.setActive(false); 513 } 514 } 515 516 /** 517 * Build asset payment details list for new asset global document. 518 * 519 * @param selectedItem 520 * @param assetGlobal 521 * @param requisitionIdentifier 522 */ 523 protected void createAssetPaymentDetails(List<AssetPaymentDetail> assetPaymentList, PurchasingAccountsPayableItemAsset selectedItem, String documentNumber, Integer requisitionIdentifier) { 524 int seq = 1; 525 526 for (PurchasingAccountsPayableLineAssetAccount account : selectedItem.getPurchasingAccountsPayableLineAssetAccounts()) { 527 GeneralLedgerEntry glEntry = account.getGeneralLedgerEntry(); 528 529 if (ObjectUtils.isNotNull(glEntry)) { 530 AssetPaymentDetail assetPaymentDetail = new AssetPaymentDetail(); 531 // initialize payment detail fields 532 assetPaymentDetail.setDocumentNumber(documentNumber); 533 assetPaymentDetail.setSequenceNumber(Integer.valueOf(seq++)); 534 assetPaymentDetail.setChartOfAccountsCode(glEntry.getChartOfAccountsCode()); 535 assetPaymentDetail.setAccountNumber(replaceFiller(glEntry.getAccountNumber())); 536 assetPaymentDetail.setSubAccountNumber(replaceFiller(glEntry.getSubAccountNumber())); 537 assetPaymentDetail.setFinancialObjectCode(replaceFiller(glEntry.getFinancialObjectCode())); 538 assetPaymentDetail.setFinancialSubObjectCode(replaceFiller(glEntry.getFinancialSubObjectCode())); 539 assetPaymentDetail.setProjectCode(replaceFiller(glEntry.getProjectCode())); 540 assetPaymentDetail.setOrganizationReferenceId(glEntry.getOrganizationReferenceId()); 541 assetPaymentDetail.setPostingYear(glEntry.getUniversityFiscalYear()); 542 assetPaymentDetail.setPostingPeriodCode(glEntry.getUniversityFiscalPeriodCode()); 543 assetPaymentDetail.setExpenditureFinancialSystemOriginationCode(replaceFiller(glEntry.getFinancialSystemOriginationCode())); 544 assetPaymentDetail.setExpenditureFinancialDocumentNumber(glEntry.getDocumentNumber()); 545 assetPaymentDetail.setExpenditureFinancialDocumentTypeCode(replaceFiller(glEntry.getFinancialDocumentTypeCode())); 546 assetPaymentDetail.setExpenditureFinancialDocumentPostedDate(glEntry.getTransactionDate()); 547 assetPaymentDetail.setAmount(account.getItemAccountTotalAmount()); 548 assetPaymentDetail.setPurchaseOrderNumber(replaceFiller(glEntry.getReferenceFinancialDocumentNumber())); 549 assetPaymentDetail.setRequisitionNumber(requisitionIdentifier.toString()); 550 assetPaymentDetail.setTransferPaymentIndicator(false); 551 552 // add to payment list 553 assetPaymentList.add(assetPaymentDetail); 554 } 555 } 556 } 557 558 559 /** 560 * In-activate item, item Account and generalLedgerEntry active indicator. 561 * 562 * @param selectedItem 563 * @param glEntryList 564 */ 565 protected void inActivateItem(PurchasingAccountsPayableItemAsset selectedItem) { 566 // in-active each account. 567 for (PurchasingAccountsPayableLineAssetAccount selectedAccount : selectedItem.getPurchasingAccountsPayableLineAssetAccounts()) { 568 selectedAccount.setActivityStatusCode(CabConstants.ActivityStatusCode.ENROUTE); 569 } 570 // in-activate selected Item 571 selectedItem.setActivityStatusCode(CabConstants.ActivityStatusCode.ENROUTE); 572 } 573 574 /** 575 * Update GL Entry status as "enroute" if all its amount are consumed by submit CAMs document.Return the general ledger entry 576 * changes as a list. 577 * 578 * @param glEntryList 579 * @param selectedAccount 580 * @param glEntry 581 */ 582 protected List<GeneralLedgerEntry> getGlEntryInActivedList(PurchasingAccountsPayableItemAsset selectedItem) { 583 List<GeneralLedgerEntry> glEntryUpdateList = new ArrayList<GeneralLedgerEntry>(); 584 for (PurchasingAccountsPayableLineAssetAccount selectedAccount : selectedItem.getPurchasingAccountsPayableLineAssetAccounts()) { 585 GeneralLedgerEntry glEntry = selectedAccount.getGeneralLedgerEntry(); 586 KualiDecimal relatedAccountAmount = KualiDecimal.ZERO; 587 588 // get persistent account list which should be save before hand 589 glEntry.refreshReferenceObject(CabPropertyConstants.GeneralLedgerEntry.PURAP_LINE_ASSET_ACCOUNTS); 590 // check if all accounts are inactive status 591 for (PurchasingAccountsPayableLineAssetAccount account : glEntry.getPurApLineAssetAccounts()) { 592 if (!account.isActive()) { 593 relatedAccountAmount = relatedAccountAmount.add(account.getItemAccountTotalAmount()); 594 } 595 } 596 597 // if one account shows active, won't in-activate this general ledger entry. 598 if (relatedAccountAmount.compareTo(glEntry.getAmount()) == 0) { 599 glEntry.setActivityStatusCode(CabConstants.ActivityStatusCode.ENROUTE); 600 glEntryUpdateList.add(glEntry); 601 } 602 } 603 return glEntryUpdateList; 604 } 605 606 607 protected String replaceFiller(String val) { 608 return val == null ? "" : val.trim().replaceAll("-", ""); 609 } 610 611 /** 612 * Create AssetGlobal BO and feed data from pre-asset tagging table. 613 * 614 * @param selectedItem 615 * @param newDocument 616 * @param preTag 617 * @return 618 */ 619 protected AssetGlobal createAssetGlobal(PurchasingAccountsPayableItemAsset selectedItem, String documentNumber, Pretag preTag, Integer requisitionIdentifier) { 620 // instantiate AssetGlobal BO 621 AssetGlobal assetGlobal = new AssetGlobal(); 622 assetGlobal.setDocumentNumber(documentNumber); 623 assetGlobal.setCapitalAssetDescription(selectedItem.getAccountsPayableLineItemDescription()); 624 assetGlobal.setConditionCode(CamsConstants.Asset.CONDITION_CODE_E); 625 assetGlobal.setAcquisitionTypeCode(getAssetGlobalService().getNewAcquisitionTypeCode()); 626 assetGlobal.setInventoryStatusCode(CamsConstants.InventoryStatusCode.CAPITAL_ASSET_ACTIVE_IDENTIFIABLE); 627 // set vendor name from Purchase Order Document 628 PurchaseOrderDocument purApdocument = this.getPurApInfoService().getCurrentDocumentForPurchaseOrderIdentifier(selectedItem.getPurchasingAccountsPayableDocument().getPurchaseOrderIdentifier()); 629 if (purApdocument != null) { 630 assetGlobal.setVendorName(purApdocument.getVendorName()); 631 } 632 // set origin code in the Asset Payment Document 633 assetGlobal.setCapitalAssetBuilderOriginIndicator(true); 634 635 PurchaseOrderCapitalAssetSystem capitalAssetSystem = null; 636 // check and set if purAp has new asset information 637 if (selectedItem.getCapitalAssetSystemIdentifier() != null) { 638 capitalAssetSystem = findCapitalAssetSystem(selectedItem.getCapitalAssetSystemIdentifier()); 639 if (ObjectUtils.isNotNull(capitalAssetSystem)) { 640 setAssetGlobalFromPurAp(assetGlobal, capitalAssetSystem); 641 } 642 } 643 // feeding data from pre-asset tagging table into assetGlboal. Here, if there are data overlap in pretag and PurAp, we 644 // respect data in Pretagging. 645 if (isItemPretagged(preTag)) { 646 setAssetGlobalFromPreTag(preTag, assetGlobal); 647 } 648 649 // set asset global detail list 650 setAssetGlobalDetails(selectedItem, assetGlobal, preTag, capitalAssetSystem); 651 652 // Set Organization Inventory Name for each asset unique detail from PO 653 setOrgInventoryNameForAssetDetail(assetGlobal.getAssetGlobalDetails(), purApdocument); 654 655 // build payments list for asset global 656 createAssetPaymentDetails(assetGlobal.getAssetPaymentDetails(), selectedItem, documentNumber, requisitionIdentifier); 657 658 // set total cost 659 setAssetGlobalTotalCost(assetGlobal); 660 // Set Asset Global organization owner account, which is the account that contributed the most dollars. 661 setAssetGlobalOrgOwnerAccount(assetGlobal); 662 663 return assetGlobal; 664 } 665 666 /** 667 * Set organization inventory name for each asset detail by PO Contact name or if empty, by Requestor Name. 668 * 669 * @param assetGlobalDetails 670 * @param purApdocument 671 */ 672 protected void setOrgInventoryNameForAssetDetail(List<AssetGlobalDetail> assetGlobalDetails, PurchaseOrderDocument purApdocument) { 673 if (ObjectUtils.isNotNull(purApdocument)) { 674 String orgInventoryName = purApdocument.getInstitutionContactName(); 675 676 if (StringUtils.isBlank(orgInventoryName)) { 677 orgInventoryName = purApdocument.getRequestorPersonName(); 678 } 679 680 for (AssetGlobalDetail assetGlobalDetail : assetGlobalDetails) { 681 assetGlobalDetail.setOrganizationInventoryName(orgInventoryName); 682 } 683 } 684 } 685 686 687 /** 688 * check if item is pre-tagged already. 689 * 690 * @param preTag 691 * @return 692 */ 693 protected boolean isItemPretagged(Pretag preTag) { 694 return ObjectUtils.isNotNull(preTag) && preTag.isActive() && ObjectUtils.isNotNull(preTag.getPretagDetails()) && !preTag.getPretagDetails().isEmpty(); 695 } 696 697 698 /** 699 * Set asset information from PurAp PurchaseOrderCapitalAssetSystem. 700 * 701 * @param assetGlobal 702 * @param capitalAssetSystem 703 */ 704 protected void setAssetGlobalFromPurAp(AssetGlobal assetGlobal, PurchaseOrderCapitalAssetSystem capitalAssetSystem) { 705 assetGlobal.setManufacturerName(capitalAssetSystem.getCapitalAssetManufacturerName()); 706 assetGlobal.setManufacturerModelNumber(capitalAssetSystem.getCapitalAssetModelDescription()); 707 String capitalAssetTypeCode = capitalAssetSystem.getCapitalAssetTypeCode(); 708 if (!StringUtils.isBlank(capitalAssetTypeCode) && checkCapitalAssetTypeCodeExist(capitalAssetTypeCode)) { 709 assetGlobal.setCapitalAssetTypeCode(capitalAssetSystem.getCapitalAssetTypeCode()); 710 } 711 } 712 713 714 /** 715 * check the given capital asset type code exists in CAM 716 * 717 * @param capitalAssetTypeCode 718 * @return 719 */ 720 protected boolean checkCapitalAssetTypeCodeExist(String capitalAssetTypeCode) { 721 Map<String, Object> pKeys = new HashMap<String, Object>(); 722 pKeys.put(CabPropertyConstants.AssetGlobalDocumentCreate.CAPITAL_ASSET_TYPE_CODE, capitalAssetTypeCode); 723 AssetType assetType = (AssetType) this.getBusinessObjectService().findByPrimaryKey(AssetType.class, pKeys); 724 return ObjectUtils.isNotNull(assetType); 725 } 726 727 728 /** 729 * Get PurAp PurchaseOrderCapitalAssetSystem Object if exists. 730 * 731 * @param capitalAssetSystemIdentifier 732 * @return 733 */ 734 protected PurchaseOrderCapitalAssetSystem findCapitalAssetSystem(Integer capitalAssetSystemIdentifier) { 735 Map pKeys = new HashMap<String, Object>(); 736 737 pKeys.put(PurapPropertyConstants.CAPITAL_ASSET_SYSTEM_IDENTIFIER, capitalAssetSystemIdentifier); 738 return (PurchaseOrderCapitalAssetSystem) businessObjectService.findByPrimaryKey(PurchaseOrderCapitalAssetSystem.class, pKeys); 739 } 740 741 742 /** 743 * Set Asset Global org owner account and chart code. It's assigned by selecting the account that contributed the most dollars 744 * on the payment request. 745 * 746 * @param assetGlobal 747 */ 748 protected void setAssetGlobalOrgOwnerAccount(AssetGlobal assetGlobal) { 749 AssetPaymentDetail maxCostPayment = null; 750 // get the maximum payment cost 751 for (AssetPaymentDetail assetPaymentDetail : assetGlobal.getAssetPaymentDetails()) { 752 if (maxCostPayment == null || assetPaymentDetail.getAmount().isGreaterThan(maxCostPayment.getAmount())) { 753 maxCostPayment = assetPaymentDetail; 754 } 755 } 756 757 if (maxCostPayment != null) { 758 assetGlobal.setOrganizationOwnerAccountNumber(maxCostPayment.getAccountNumber()); 759 assetGlobal.setOrganizationOwnerChartOfAccountsCode(maxCostPayment.getChartOfAccountsCode()); 760 } 761 } 762 763 764 /** 765 * Set Asset Global total cost amount. 766 * 767 * @param assetGlobal 768 */ 769 protected void setAssetGlobalTotalCost(AssetGlobal assetGlobal) { 770 KualiDecimal totalCost = KualiDecimal.ZERO; 771 for (AssetPaymentDetail assetPaymentDetail : assetGlobal.getAssetPaymentDetails()) { 772 totalCost = totalCost.add(assetPaymentDetail.getAmount()); 773 } 774 775 assetGlobal.setTotalCostAmount(totalCost); 776 } 777 778 779 /** 780 * Feeding data from preTag and set into asset global for shared information. PreTag data may override PurAp asset data since 781 * the strategy choose to respect Pretagging 782 * 783 * @param preTag 784 * @param assetGlobal 785 */ 786 protected void setAssetGlobalFromPreTag(Pretag preTag, AssetGlobal assetGlobal) { 787 if (StringUtils.isNotBlank(preTag.getManufacturerName())) { 788 assetGlobal.setManufacturerName(preTag.getManufacturerName()); 789 } 790 if (StringUtils.isNotBlank(preTag.getManufacturerModelNumber())) { 791 assetGlobal.setManufacturerModelNumber(preTag.getManufacturerModelNumber()); 792 } 793 794 if (StringUtils.isNotBlank(preTag.getCapitalAssetTypeCode())) { 795 assetGlobal.setCapitalAssetTypeCode(preTag.getCapitalAssetTypeCode()); 796 } 797 assetGlobal.setOrganizationText(preTag.getOrganizationText()); 798 assetGlobal.setRepresentativeUniversalIdentifier(preTag.getRepresentativeUniversalIdentifier()); 799 if (StringUtils.isNotBlank(preTag.getVendorName())) { 800 assetGlobal.setVendorName(preTag.getVendorName()); 801 } 802 // acquisition type code is set to "P"(Pre-asset tagging) 803 assetGlobal.setAcquisitionTypeCode(CamsConstants.AssetGlobal.PRE_TAGGING_ACQUISITION_TYPE_CODE); 804 } 805 806 /** 807 * Gets the businessObjectService attribute. 808 * 809 * @return Returns the businessObjectService. 810 */ 811 public BusinessObjectService getBusinessObjectService() { 812 return businessObjectService; 813 } 814 815 /** 816 * Sets the businessObjectService attribute value. 817 * 818 * @param businessObjectService The businessObjectService to set. 819 */ 820 public void setBusinessObjectService(BusinessObjectService businessObjectService) { 821 this.businessObjectService = businessObjectService; 822 } 823 824 /** 825 * Gets the documentService attribute. 826 * 827 * @return Returns the documentService. 828 */ 829 public DocumentService getDocumentService() { 830 return documentService; 831 } 832 833 834 /** 835 * Sets the documentService attribute value. 836 * 837 * @param documentService The documentService to set. 838 */ 839 public void setDocumentService(DocumentService documentService) { 840 this.documentService = documentService; 841 } 842 843 /** 844 * Gets the purApLineService attribute. 845 * 846 * @return Returns the purApLineService. 847 */ 848 public PurApLineService getPurApLineService() { 849 return purApLineService; 850 } 851 852 /** 853 * Sets the purApLineService attribute value. 854 * 855 * @param purApLineService The purApLineService to set. 856 */ 857 public void setPurApLineService(PurApLineService purApLineService) { 858 this.purApLineService = purApLineService; 859 } 860 861 862 /** 863 * Gets the purApInfoService attribute. 864 * 865 * @return Returns the purApInfoService. 866 */ 867 public PurApInfoService getPurApInfoService() { 868 return purApInfoService; 869 } 870 871 872 /** 873 * Sets the purApInfoService attribute value. 874 * 875 * @param purApInfoService The purApInfoService to set. 876 */ 877 public void setPurApInfoService(PurApInfoService purApInfoService) { 878 this.purApInfoService = purApInfoService; 879 } 880 881 882 private AssetGlobalService getAssetGlobalService() { 883 return assetGlobalService; 884 } 885 886 887 public void setAssetGlobalService(AssetGlobalService assetGlobalService) { 888 this.assetGlobalService = assetGlobalService; 889 } 890 }