001/* 002 * Copyright 2008 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 */ 016package org.kuali.ole.module.purap.util; 017 018import org.apache.commons.lang.StringUtils; 019import org.kuali.ole.module.purap.PurapConstants; 020import org.kuali.ole.module.purap.PurapPropertyConstants; 021import org.kuali.ole.module.purap.businessobject.*; 022import org.kuali.ole.module.purap.document.PurchaseOrderDocument; 023import org.kuali.ole.module.purap.document.service.PurapService; 024import org.kuali.ole.sys.OLEConstants; 025import org.kuali.ole.sys.context.SpringContext; 026import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader; 027import org.kuali.rice.kew.api.document.DocumentStatus; 028import org.kuali.rice.kew.api.exception.WorkflowException; 029import org.kuali.rice.kim.api.KimConstants; 030import org.kuali.rice.kim.api.services.IdentityManagementService; 031import org.kuali.rice.kns.service.DataDictionaryService; 032import org.kuali.rice.krad.datadictionary.exception.UnknownDocumentTypeException; 033import org.kuali.rice.krad.document.Document; 034import org.kuali.rice.krad.service.DocumentService; 035import org.kuali.rice.krad.service.KRADServiceLocatorInternal; 036import org.kuali.rice.krad.util.GlobalVariables; 037import org.kuali.rice.krad.util.ObjectUtils; 038import org.springframework.transaction.PlatformTransactionManager; 039import org.springframework.transaction.TransactionStatus; 040import org.springframework.transaction.support.TransactionCallback; 041import org.springframework.transaction.support.TransactionTemplate; 042 043import java.util.*; 044 045public class PurApRelatedViews { 046 private String documentNumber; 047 private Integer accountsPayablePurchasingDocumentLinkIdentifier; 048 049 private transient List<RequisitionView> relatedRequisitionViews; 050 private transient List<PurchaseOrderView> relatedPurchaseOrderViews; 051 private transient List<PaymentRequestView> relatedPaymentRequestViews; 052 private transient List<PaymentRequestView> paymentHistoryPaymentRequestViews; 053 private transient List<CreditMemoView> relatedCreditMemoViews; 054 private transient List<CreditMemoView> paymentHistoryCreditMemoViews; 055 private transient List<InvoiceView> relatedInvoiceViews; 056 private transient List<InvoiceView> paymentHistoryInvoiceViews; 057 private transient List<LineItemReceivingView> relatedLineItemReceivingViews; 058 private transient List<CorrectionReceivingView> relatedCorrectionReceivingViews; 059 private transient List<BulkReceivingView> relatedBulkReceivingViews; 060 private transient List<PurchaseOrderViewGroup> groupedRelatedPurchaseOrderViews; 061 private transient List<ReceivingViewGroup> groupedRelatedReceivingViews; 062 private transient List<ElectronicInvoiceRejectView> relatedRejectViews; 063 064 public PurApRelatedViews(String documentNumber, Integer accountsPayablePurchasingDocumentLinkIdentifier) { 065 super(); 066 this.documentNumber = documentNumber; 067 this.accountsPayablePurchasingDocumentLinkIdentifier = accountsPayablePurchasingDocumentLinkIdentifier; 068 } 069 070 /** 071 * Reset all related view lists to null. 072 */ 073 public void resetRelatedViews() { 074 relatedRequisitionViews = null; 075 relatedPurchaseOrderViews = null; 076 relatedPaymentRequestViews = null; 077 paymentHistoryPaymentRequestViews = null; 078 relatedInvoiceViews = null; 079 paymentHistoryInvoiceViews = null; 080 relatedCreditMemoViews = null; 081 paymentHistoryCreditMemoViews = null; 082 relatedLineItemReceivingViews = null; 083 relatedCorrectionReceivingViews = null; 084 relatedBulkReceivingViews = null; 085 groupedRelatedPurchaseOrderViews = null; 086 groupedRelatedReceivingViews = null; 087 relatedRejectViews = null; 088 } 089 090 private static PlatformTransactionManager transactionManager; 091 092 public static PlatformTransactionManager getTransactionManager() { 093 if (transactionManager == null) { 094 transactionManager = GlobalResourceLoader.getService("transactionManager"); 095 } 096 return transactionManager; 097 } 098 099 public List updateRelatedView(final Class<?> clazz, List<? extends AbstractRelatedView> relatedList, final boolean removeCurrentDocument) { 100 if (relatedList == null) { 101 TransactionTemplate template = new TransactionTemplate(getTransactionManager()); 102 relatedList = template.execute(new TransactionCallback<List<? extends AbstractRelatedView>>() { 103 @Override 104 public List<? extends AbstractRelatedView> doInTransaction(TransactionStatus status) { 105 List<? extends AbstractRelatedView> relatedList = SpringContext.getBean(PurapService.class).getRelatedViews(clazz, accountsPayablePurchasingDocumentLinkIdentifier); 106 if (removeCurrentDocument) { 107 for (AbstractRelatedView view : relatedList) { 108 //KFSMI-4576 Mask/Unmask purapDocumentIdentifier field value 109 maskPONumberIfUnapproved(view); 110 if (documentNumber.equals(view.getDocumentNumber())) { 111 relatedList.remove(view); 112 break; 113 } 114 } 115 } 116 return relatedList; 117 } 118 }); 119 } 120 121 return relatedList; 122 } 123 124 /** 125 * masks the po number if the po is unappoved yet. If the document status is not FINAL then 126 * check for permission for purapDocumentIdentifier field. If NOT permitted to view the value 127 * then mask the value with * and setting this value in poNumberMasked property. 128 * 129 * @param view 130 */ 131 protected void maskPONumberIfUnapproved(AbstractRelatedView view) { 132 Document document = findDocument(view.getDocumentNumber()); 133 134 String poIDstr = ""; 135 136 if (ObjectUtils.isNotNull(view.getPurapDocumentIdentifier())) { 137 poIDstr = view.getPurapDocumentIdentifier().toString(); 138 } 139 140 if (PurapConstants.PurapDocTypeCodes.PO_DOCUMENT.equals(document.getDocumentHeader().getWorkflowDocument().getDocumentTypeName())) { 141 if ((document != null) && (document.getDocumentHeader().getWorkflowDocument() != null)) { 142 if (!document.getDocumentHeader().getWorkflowDocument().getStatus().equals(DocumentStatus.FINAL)) { 143 144 String principalId = GlobalVariables.getUserSession().getPrincipalId(); 145 146 String namespaceCode = OLEConstants.ParameterNamespaces.KNS; 147 String permissionTemplateName = KimConstants.PermissionTemplateNames.FULL_UNMASK_FIELD; 148 149 Map<String, String> roleQualifiers = new HashMap<String, String>(); 150 151 Map<String, String> permissionDetails = new HashMap<String, String>(); 152 permissionDetails.put(KimConstants.AttributeConstants.COMPONENT_NAME, PurchaseOrderDocument.class.getSimpleName()); 153 permissionDetails.put(KimConstants.AttributeConstants.PROPERTY_NAME, PurapPropertyConstants.PURAP_DOC_ID); 154 155 IdentityManagementService identityManagementService = SpringContext.getBean(IdentityManagementService.class); 156 Boolean isAuthorized = identityManagementService.isAuthorizedByTemplateName(principalId, namespaceCode, permissionTemplateName, permissionDetails, roleQualifiers); 157 if (!isAuthorized) { 158 //not authorized to see... so mask the po number string 159 poIDstr = ""; 160 int strLength = SpringContext.getBean(DataDictionaryService.class).getAttributeMaxLength(PurApGenericAttributes.class.getName(), PurapPropertyConstants.PURAP_DOC_ID); 161 for (int i = 0; i < strLength; i++) { 162 poIDstr = poIDstr.concat("*"); 163 } 164 } 165 } 166 } 167 } 168 169 view.setPoNumberMasked(poIDstr); 170 } 171 172 /** 173 * This method finds the document for the given document header id 174 * 175 * @param documentHeaderId 176 * @return document The document in the workflow that matches the document header id. 177 */ 178 protected Document findDocument(String documentHeaderId) { 179 Document document = null; 180 181 try { 182 document = SpringContext.getBean(DocumentService.class).getByDocumentHeaderId(documentHeaderId); 183 } catch (WorkflowException ex) { 184 } catch (UnknownDocumentTypeException ex) { 185 // don't blow up just because a document type is not installed (but don't return it either) 186 } 187 188 return document; 189 } 190 191 /** 192 * @see org.kuali.ole.module.purap.document.PurchasingAccountsPayableDocument#getRelatedRequisitionViews() 193 */ 194 public List<RequisitionView> getRelatedRequisitionViews() { 195 relatedRequisitionViews = updateRelatedView(RequisitionView.class, relatedRequisitionViews, true); 196 return relatedRequisitionViews; 197 } 198 199 public List<ElectronicInvoiceRejectView> getRelatedRejectViews() { 200 relatedRejectViews = updateRelatedView(ElectronicInvoiceRejectView.class, relatedRejectViews, true); 201 return relatedRejectViews; 202 } 203 204 /** 205 * Obtains a list of related PurchaseOrderViews, first ordered by POIDs descending, then by document numbers descending; 206 * thus POs with newer POIDs will be in the front, and within the same POID, the current PO will be in the front. 207 * 208 * @return A list of <PurchaseOrderView> with newer POs in the front. 209 */ 210 public List<PurchaseOrderView> getRelatedPurchaseOrderViews() { 211 if (relatedPurchaseOrderViews != null) { 212 return relatedPurchaseOrderViews; 213 } 214 215 // Obtain a list which is sorted by workflow document ID descending. 216 relatedPurchaseOrderViews = updateRelatedView(PurchaseOrderView.class, relatedPurchaseOrderViews, true); 217 218 // Sort the list. 219 Collections.sort(relatedPurchaseOrderViews, 220 new Comparator<PurchaseOrderView>() { 221 @Override 222 public int compare(PurchaseOrderView v1, PurchaseOrderView v2) { 223 if ((v1 != null) && (v2 != null) && 224 (v1.getPurapDocumentIdentifier() != null) && 225 (v2.getPurapDocumentIdentifier() != null)) { 226 // sort by POID descending 227 int compare = -v1.getPurapDocumentIdentifier().compareTo(v2.getPurapDocumentIdentifier()); 228 // if POIDs are the same, sort by document number descending; usually current PO has biggest documentNumber 229 if (compare == 0) { 230 compare = v1.getPurchaseOrderCurrentIndicator() ? -1 : 231 v2.getPurchaseOrderCurrentIndicator() ? 1 : 232 -v1.getCreateDate().compareTo(v2.getCreateDate()); 233 } 234 return compare; 235 } 236 return 0; 237 } 238 } 239 ); 240 241 return relatedPurchaseOrderViews; 242 } 243 244 /** 245 * Groups related PurchaseOrderViews by POIDs descending, and within each group order POs by document numbers descending; 246 * thus groups of newer POIDs will be in the front, and within each group, more current POs will be in the front. 247 * 248 * @return A list of <PurchaseOrderViewGroup> with newer POs in the front. 249 * @see org.kuali.ole.module.purap.util.PurApRelatedViews.getRelatedPurchaseOrderViews 250 * @see org.kuali.ole.module.purap.businessobject.PurchaseOrderView 251 */ 252 public List<PurchaseOrderViewGroup> getGroupedRelatedPurchaseOrderViews() { 253 if (groupedRelatedPurchaseOrderViews != null) { 254 return groupedRelatedPurchaseOrderViews; 255 } 256 257 /* 258 * This extra layer of grouping is necessary in order to display the notes for a group of 259 * related POChange documents (which should have identical POID) after that group, 260 * and before any other related groups which may result from PO splitting (with different POIDs). 261 * With direct use of relatedPurchaseOrderViews, location of the end of the group is problematic. 262 */ 263 groupedRelatedPurchaseOrderViews = new ArrayList<PurchaseOrderViewGroup>(); 264 PurchaseOrderViewGroup group = new PurchaseOrderViewGroup(); 265 int previousPOID = 0; 266 relatedPurchaseOrderViews = getRelatedPurchaseOrderViews(); 267 for (PurchaseOrderView view : relatedPurchaseOrderViews) { 268 if (previousPOID == 0) { 269 previousPOID = view.getPurapDocumentIdentifier(); 270 271 } 272 if (view.getPurapDocumentIdentifier() == previousPOID) { 273 group.getViews().add(view); 274 } else { 275 groupedRelatedPurchaseOrderViews.add(group); 276 group = new PurchaseOrderViewGroup(); 277 group.getViews().add(view); 278 previousPOID = view.getPurapDocumentIdentifier(); 279 } 280 if (relatedPurchaseOrderViews.size() == relatedPurchaseOrderViews.indexOf(view) + 1) { 281 groupedRelatedPurchaseOrderViews.add(group); 282 } 283 } 284 285 return groupedRelatedPurchaseOrderViews; 286 } 287 288 /** 289 * @see org.kuali.ole.module.purap.document.PurchasingAccountsPayableDocument#getRelatedPaymentRequestViews() 290 */ 291 public List<PaymentRequestView> getRelatedPaymentRequestViews() { 292 relatedPaymentRequestViews = updateRelatedView(PaymentRequestView.class, relatedPaymentRequestViews, true); 293 return relatedPaymentRequestViews; 294 } 295 296 /** 297 * @see org.kuali.ole.module.purap.document.PurchasingAccountsPayableDocument#getRelatedCreditMemoViews() 298 */ 299 public List<CreditMemoView> getRelatedCreditMemoViews() { 300 relatedCreditMemoViews = updateRelatedView(CreditMemoView.class, relatedCreditMemoViews, true); 301 return relatedCreditMemoViews; 302 } 303 304 305 /** 306 * @see org.kuali.ole.module.purap.document.PurchasingAccountsPayableDocument#getRelatedPaymentRequestViews() 307 */ 308 public List<InvoiceView> getRelatedInvoiceViews() { 309 relatedInvoiceViews = updateRelatedView(InvoiceView.class, relatedInvoiceViews, true); 310 return relatedInvoiceViews; 311 } 312 313 /** 314 * Gets the Payment History Payment Request Views for this document. 315 * 316 * @return the list of Payment History Payment Request Views. 317 */ 318 public List<PaymentRequestView> getPaymentHistoryPaymentRequestViews() { 319 if(paymentHistoryPaymentRequestViews==null){ 320 paymentHistoryPaymentRequestViews = updateRelatedView(PaymentRequestView.class, paymentHistoryPaymentRequestViews, false); 321 } 322 return paymentHistoryPaymentRequestViews; 323 } 324 325 /** 326 * Gets the Payment History Credit Memo Views for this document. 327 * 328 * @return the list of Payment History Credit Memo Views. 329 */ 330 public List<CreditMemoView> getPaymentHistoryCreditMemoViews() { 331 if(paymentHistoryCreditMemoViews==null){ 332 paymentHistoryCreditMemoViews = updateRelatedView(CreditMemoView.class, paymentHistoryCreditMemoViews, false); 333 } 334 return paymentHistoryCreditMemoViews; 335 } 336 337 /** 338 * Gets the Payment History Invoice Views for this document. 339 * 340 * @return the list of Payment History Invoice Views. 341 */ 342 public List<InvoiceView> getPaymentHistoryInvoiceViews() { 343 paymentHistoryInvoiceViews = updateRelatedView(InvoiceView.class, paymentHistoryInvoiceViews, false); 344 return paymentHistoryInvoiceViews; 345 } 346 347 /** 348 * @see org.kuali.ole.module.purap.document.PurchasingAccountsPayableDocument#getRelatedRequisitionViews() 349 */ 350 public List<LineItemReceivingView> getRelatedLineItemReceivingViews() { 351 if(relatedLineItemReceivingViews==null){ 352 relatedLineItemReceivingViews = updateRelatedView(LineItemReceivingView.class, relatedLineItemReceivingViews, true); 353 } 354 return relatedLineItemReceivingViews; 355 } 356 357 /** 358 * @see org.kuali.ole.module.purap.document.PurchasingAccountsPayableDocument#getRelatedRequisitionViews() 359 */ 360 public List<CorrectionReceivingView> getRelatedCorrectionReceivingViews() { 361 if(relatedCorrectionReceivingViews == null){ 362 relatedCorrectionReceivingViews = updateRelatedView(CorrectionReceivingView.class, relatedCorrectionReceivingViews, true); 363 } 364 return relatedCorrectionReceivingViews; 365 } 366 367 public List<BulkReceivingView> getRelatedBulkReceivingViews() { 368 relatedBulkReceivingViews = updateRelatedView(BulkReceivingView.class, relatedBulkReceivingViews, true); 369 return relatedBulkReceivingViews; 370 } 371 372 /** 373 * Groups related LineItemReceivingView and its CorrectionReceivingViews, with more recent receiving groups in the front; 374 * and within each group, with more recent corrections in the front. 375 * 376 * @return A list of ReceivingCorrectionViewGroups. 377 */ 378 public List<ReceivingViewGroup> getGroupedRelatedReceivingViews() { 379 if (groupedRelatedReceivingViews != null) { 380 return groupedRelatedReceivingViews; 381 } 382 383 groupedRelatedReceivingViews = new ArrayList<ReceivingViewGroup>(); 384 PurapService purapService = SpringContext.getBean(PurapService.class); 385 List<LineItemReceivingView> liviews = purapService.getRelatedViews(LineItemReceivingView.class, accountsPayablePurchasingDocumentLinkIdentifier); 386 List<CorrectionReceivingView> crviews = purapService.getRelatedViews(CorrectionReceivingView.class, accountsPayablePurchasingDocumentLinkIdentifier); 387 388 // both LineItemReceivingViews and CorrectionReceivingViews are already in order with most recent first, so no need to sort 389 for (LineItemReceivingView liview : liviews) { 390 ReceivingViewGroup group = new ReceivingViewGroup(); 391 group.lineItemView = liview; // could be current document 392 for (CorrectionReceivingView crview : crviews) { 393 if (StringUtils.equals(crview.getLineItemReceivingDocumentNumber(), liview.getDocumentNumber()) && 394 !documentNumber.equals(crview.getDocumentNumber())) {// exclude current document 395 group.addCorrectionView(crview); 396 } 397 } 398 groupedRelatedReceivingViews.add(group); 399 } 400 401 return groupedRelatedReceivingViews; 402 } 403 404 /** 405 * A container for a List<PurchaseOrderView>, to be used by a nested c:forEach tag 406 * in relatedPurchaseOrderDocumentsDetail.tag. 407 */ 408 public class PurchaseOrderViewGroup { 409 protected List<PurchaseOrderView> views = new ArrayList<PurchaseOrderView>(); 410 411 protected PurchaseOrderViewGroup() { 412 } 413 414 public List<PurchaseOrderView> getViews() { 415 return views; 416 } 417 } 418 419 /** 420 * A container for a LineItemReceivingView and a list of its associated CorrectionReceivingViews. 421 */ 422 public class ReceivingViewGroup { 423 protected LineItemReceivingView lineItemView; 424 protected List<CorrectionReceivingView> correctionViews = new ArrayList<CorrectionReceivingView>(); 425 426 protected ReceivingViewGroup() { 427 } 428 429 public LineItemReceivingView getLineItemView() { 430 return lineItemView; 431 } 432 433 public List<CorrectionReceivingView> getCorrectionViews() { 434 return correctionViews; 435 } 436 437 public void addCorrectionView(CorrectionReceivingView correctionView) { 438 correctionViews.add(correctionView); 439 } 440 441 public boolean getIsLineItemViewCurrentDocument() { 442 return (lineItemView != null && documentNumber.equals(lineItemView.getDocumentNumber())); 443 } 444 } 445 446}