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.purap.document.web.struts;
017
018 import java.math.BigDecimal;
019 import java.util.Arrays;
020 import java.util.HashMap;
021 import java.util.List;
022 import java.util.Map;
023
024 import javax.servlet.http.HttpServletRequest;
025
026 import org.apache.commons.lang.StringUtils;
027 import org.kuali.kfs.integration.purap.CapitalAssetLocation;
028 import org.kuali.kfs.module.purap.PurapAuthorizationConstants;
029 import org.kuali.kfs.module.purap.PurapConstants;
030 import org.kuali.kfs.module.purap.PurapWorkflowConstants;
031 import org.kuali.kfs.module.purap.PurapConstants.PaymentRequestStatuses;
032 import org.kuali.kfs.module.purap.PurapConstants.PurchaseOrderStatuses;
033 import org.kuali.kfs.module.purap.businessobject.PaymentRequestView;
034 import org.kuali.kfs.module.purap.businessobject.PurApItem;
035 import org.kuali.kfs.module.purap.businessobject.PurchaseOrderAccount;
036 import org.kuali.kfs.module.purap.businessobject.PurchaseOrderCapitalAssetLocation;
037 import org.kuali.kfs.module.purap.businessobject.PurchaseOrderItem;
038 import org.kuali.kfs.module.purap.businessobject.PurchaseOrderItemCapitalAsset;
039 import org.kuali.kfs.module.purap.businessobject.PurchaseOrderVendorQuote;
040 import org.kuali.kfs.module.purap.businessobject.PurchaseOrderVendorStipulation;
041 import org.kuali.kfs.module.purap.businessobject.RequisitionCapitalAssetLocation;
042 import org.kuali.kfs.module.purap.businessobject.SensitiveData;
043 import org.kuali.kfs.module.purap.businessobject.SensitiveDataAssignment;
044 import org.kuali.kfs.module.purap.document.LineItemReceivingDocument;
045 import org.kuali.kfs.module.purap.document.PaymentRequestDocument;
046 import org.kuali.kfs.module.purap.document.PurchaseOrderAmendmentDocument;
047 import org.kuali.kfs.module.purap.document.PurchaseOrderCloseDocument;
048 import org.kuali.kfs.module.purap.document.PurchaseOrderDocument;
049 import org.kuali.kfs.module.purap.document.PurchaseOrderPaymentHoldDocument;
050 import org.kuali.kfs.module.purap.document.PurchaseOrderRemoveHoldDocument;
051 import org.kuali.kfs.module.purap.document.PurchaseOrderReopenDocument;
052 import org.kuali.kfs.module.purap.document.PurchaseOrderRetransmitDocument;
053 import org.kuali.kfs.module.purap.document.PurchaseOrderSplitDocument;
054 import org.kuali.kfs.module.purap.document.PurchaseOrderVoidDocument;
055 import org.kuali.kfs.module.purap.document.service.PaymentRequestService;
056 import org.kuali.kfs.module.purap.document.service.PurchaseOrderService;
057 import org.kuali.kfs.module.purap.document.service.ReceivingService;
058 import org.kuali.kfs.module.purap.util.PurApItemUtils;
059 import org.kuali.kfs.sys.KFSConstants;
060 import org.kuali.kfs.sys.context.SpringContext;
061 import org.kuali.rice.kns.document.authorization.DocumentAuthorizer;
062 import org.kuali.rice.kns.service.DataDictionaryService;
063 import org.kuali.rice.kns.service.DateTimeService;
064 import org.kuali.rice.kns.service.DocumentHelperService;
065 import org.kuali.rice.kns.util.GlobalVariables;
066 import org.kuali.rice.kns.util.KNSConstants;
067 import org.kuali.rice.kns.util.ObjectUtils;
068 import org.kuali.rice.kns.web.ui.ExtraButton;
069 import org.kuali.rice.kns.web.ui.HeaderField;
070 import org.kuali.rice.kns.workflow.service.KualiWorkflowDocument;
071
072 /**
073 * Struts Action Form for Purchase Order document.
074 */
075 public class PurchaseOrderForm extends PurchasingFormBase {
076
077 protected PurchaseOrderVendorStipulation newPurchaseOrderVendorStipulationLine;
078 protected PurchaseOrderVendorQuote newPurchaseOrderVendorQuote;
079 protected Long awardedVendorNumber;
080
081 // Retransmit.
082 protected String[] retransmitItemsSelected = {};
083 protected String retransmitTransmissionMethod;
084 protected String retransmitFaxNumber;
085 protected String retransmitHeader;
086
087 // Need this for amendment for accounting line only
088 protected Map accountingLineEditingMode;
089
090 protected String splitNoteText;
091
092 // Assign Sensitive Data related fields
093 protected String sensitiveDataAssignmentReason = null; // reason for current assignment of sensitive data to the PO
094 protected SensitiveDataAssignment lastSensitiveDataAssignment = null; // last sensitive data assignment info for the PO
095 protected SensitiveData newSensitiveDataLine = null; // new sensitive data entry to be added to the PO
096 protected List<SensitiveData> sensitiveDatasAssigned = null; // sensitive data entries currently assigned to the PO
097
098 /**
099 * Constructs a PurchaseOrderForm instance and sets up the appropriately casted document.
100 */
101 public PurchaseOrderForm() {
102 super();
103
104 setNewPurchaseOrderVendorStipulationLine(new PurchaseOrderVendorStipulation());
105 setNewPurchaseOrderVendorQuote(new PurchaseOrderVendorQuote());
106 this.accountingLineEditingMode = new HashMap();
107 }
108
109 @Override
110 protected String getDefaultDocumentTypeName() {
111 return "PO";
112 }
113
114 public Map getAccountingLineEditingMode() {
115 return accountingLineEditingMode;
116 }
117
118 public void setAccountingLineEditingMode(Map accountingLineEditingMode) {
119 this.accountingLineEditingMode = accountingLineEditingMode;
120 }
121
122 public Long getAwardedVendorNumber() {
123 return awardedVendorNumber;
124 }
125
126 public void setAwardedVendorNumber(Long awardedVendorNumber) {
127 this.awardedVendorNumber = awardedVendorNumber;
128 }
129
130 public PurchaseOrderVendorStipulation getNewPurchaseOrderVendorStipulationLine() {
131 return newPurchaseOrderVendorStipulationLine;
132 }
133
134 public void setNewPurchaseOrderVendorStipulationLine(PurchaseOrderVendorStipulation newPurchaseOrderVendorStipulationLine) {
135 this.newPurchaseOrderVendorStipulationLine = newPurchaseOrderVendorStipulationLine;
136 }
137
138 public PurchaseOrderVendorQuote getNewPurchaseOrderVendorQuote() {
139 return newPurchaseOrderVendorQuote;
140 }
141
142 public void setNewPurchaseOrderVendorQuote(PurchaseOrderVendorQuote newPurchaseOrderVendorQuote) {
143 this.newPurchaseOrderVendorQuote = newPurchaseOrderVendorQuote;
144 }
145
146 public String[] getRetransmitItemsSelected() {
147 return retransmitItemsSelected;
148 }
149
150 public void setRetransmitItemsSelected(String[] retransmitItemsSelected) {
151 this.retransmitItemsSelected = retransmitItemsSelected;
152 }
153
154 public PurchaseOrderDocument getPurchaseOrderDocument() {
155 return (PurchaseOrderDocument) getDocument();
156 }
157
158 public void setPurchaseOrderDocument(PurchaseOrderDocument purchaseOrderDocument) {
159 setDocument(purchaseOrderDocument);
160 }
161
162 public String getSplitNoteText() {
163 return splitNoteText;
164 }
165
166 public void setSplitNoteText(String splitNoteText) {
167 this.splitNoteText = splitNoteText;
168 }
169
170 public String getSensitiveDataAssignmentReason() {
171 return sensitiveDataAssignmentReason;
172 }
173
174 public void setSensitiveDataAssignmentReason(String sensitiveDataAssignmentReason) {
175 this.sensitiveDataAssignmentReason = sensitiveDataAssignmentReason;
176 }
177
178 public SensitiveDataAssignment getLastSensitiveDataAssignment() {
179 return lastSensitiveDataAssignment;
180 }
181
182 public void setLastSensitiveDataAssignment(SensitiveDataAssignment lastSensitiveDataAssignment) {
183 this.lastSensitiveDataAssignment = lastSensitiveDataAssignment;
184 }
185
186 public SensitiveData getNewSensitiveDataLine() {
187 return newSensitiveDataLine;
188 }
189
190 public void setNewSensitiveDataLine(SensitiveData newSensitiveDataLine) {
191 this.newSensitiveDataLine = newSensitiveDataLine;
192 }
193
194 public List<SensitiveData> getSensitiveDatasAssigned() {
195 return sensitiveDatasAssigned;
196 }
197
198 public void setSensitiveDatasAssigned(List<SensitiveData> poSensitiveData) {
199 this.sensitiveDatasAssigned = poSensitiveData;
200 }
201
202 @Override
203 public Class getCapitalAssetLocationClass() {
204 return PurchaseOrderCapitalAssetLocation.class;
205 }
206
207 @Override
208 public Class getItemCapitalAssetClass() {
209 return PurchaseOrderItemCapitalAsset.class;
210 }
211
212 @Override
213 public CapitalAssetLocation setupNewPurchasingCapitalAssetLocationLine() {
214 CapitalAssetLocation location = new RequisitionCapitalAssetLocation();
215 return location;
216 }
217
218 /**
219 * @see org.kuali.kfs.module.purap.document.web.struts.PurchasingFormBase#setupNewPurchasingItemLine()
220 */
221 @Override
222 public PurApItem setupNewPurchasingItemLine() {
223 return new PurchaseOrderItem();
224 }
225
226 /**
227 * @see org.kuali.kfs.module.purap.document.web.struts.PurchasingFormBase#setupNewPurchasingAccountingLine()
228 */
229 @Override
230 public PurchaseOrderAccount setupNewPurchasingAccountingLine() {
231 return new PurchaseOrderAccount();
232 }
233
234 /**
235 * @see org.kuali.kfs.module.purap.document.web.struts.PurchasingFormBase#setupNewAccountDistributionAccountingLine()
236 */
237 @Override
238 public PurchaseOrderAccount setupNewAccountDistributionAccountingLine() {
239 PurchaseOrderAccount account = setupNewPurchasingAccountingLine();
240 account.setAccountLinePercent(new BigDecimal(100));
241 return account;
242 }
243
244 public boolean isReadOnlyReceivingRequired() {
245
246 PurchaseOrderDocument poDoc = getPurchaseOrderDocument();
247
248 if (poDoc instanceof PurchaseOrderAmendmentDocument){
249 if (!poDoc.isReceivingDocumentRequiredIndicator()){
250 return SpringContext.getBean(PaymentRequestService.class).hasActivePaymentRequestsForPurchaseOrder(poDoc.getPurapDocumentIdentifier());
251 }else{
252 return true;
253 }
254 }
255
256 return false;
257 }
258
259 /**
260 * Returns the new Purchase Order Vendor Stipulation Line and resets it.
261 *
262 * @return the new Purchase Order Vendor Stipulation Line.
263 */
264 public PurchaseOrderVendorStipulation getAndResetNewPurchaseOrderVendorStipulationLine() {
265 PurchaseOrderVendorStipulation aPurchaseOrderVendorStipulationLine = getNewPurchaseOrderVendorStipulationLine();
266 setNewPurchaseOrderVendorStipulationLine(new PurchaseOrderVendorStipulation());
267
268 aPurchaseOrderVendorStipulationLine.setDocumentNumber(getPurchaseOrderDocument().getDocumentNumber());
269 aPurchaseOrderVendorStipulationLine.setVendorStipulationAuthorEmployeeIdentifier(GlobalVariables.getUserSession().getPerson().getPrincipalId());
270 aPurchaseOrderVendorStipulationLine.setVendorStipulationCreateDate(SpringContext.getBean(DateTimeService.class).getCurrentSqlDate());
271
272 return aPurchaseOrderVendorStipulationLine;
273 }
274
275 public String getStatusChange() {
276 if (StringUtils.isNotEmpty(getPurchaseOrderDocument().getStatusChange())){
277 return getPurchaseOrderDocument().getStatusChange();
278 } else {
279 if (StringUtils.equals(getPurchaseOrderDocument().getStatusCode(),PurchaseOrderStatuses.IN_PROCESS)){
280 return PurchaseOrderStatuses.IN_PROCESS;
281 } else if (StringUtils.equals(getPurchaseOrderDocument().getStatusCode(),PurchaseOrderStatuses.WAITING_FOR_DEPARTMENT)){
282 return PurchaseOrderStatuses.WAITING_FOR_DEPARTMENT;
283 }else if (StringUtils.equals(getPurchaseOrderDocument().getStatusCode(),PurchaseOrderStatuses.WAITING_FOR_VENDOR)){
284 return PurchaseOrderStatuses.WAITING_FOR_VENDOR;
285 }else{
286 return null;
287 }
288 }
289 }
290
291 public void setStatusChange(String statusChange) {
292 getPurchaseOrderDocument().setStatusChange(statusChange);
293 }
294
295 /**
296 * @see org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase#shouldMethodToCallParameterBeUsed(java.lang.String, java.lang.String, javax.servlet.http.HttpServletRequest)
297 */
298 @Override
299 public boolean shouldMethodToCallParameterBeUsed(String methodToCallParameterName, String methodToCallParameterValue, HttpServletRequest request) {
300 List<String> methodToCallList = Arrays.asList(new String[]{"printPurchaseOrderPDFOnly", "printingRetransmitPoOnly", "printPoQuoteListOnly"});
301
302 if (KNSConstants.DISPATCH_REQUEST_PARAMETER.equals(methodToCallParameterName) && methodToCallList.contains(methodToCallParameterValue)) {
303 return true;
304 }
305 return super.shouldMethodToCallParameterBeUsed(methodToCallParameterName, methodToCallParameterValue, request);
306 }
307
308 @Override
309 public void populateHeaderFields(KualiWorkflowDocument workflowDocument) {
310 super.populateHeaderFields(workflowDocument);
311 if (ObjectUtils.isNotNull(getPurchaseOrderDocument().getPurapDocumentIdentifier())) {
312 String poIDstr = getPurchaseOrderDocument().getPurapDocumentIdentifier().toString();
313 if (getPurchaseOrderDocument().getNeedWarning()) {
314 poIDstr += " UNAPPROVED";
315 }
316 getDocInfo().add(new HeaderField("DataDictionary.PurchaseOrderDocument.attributes.purapDocumentIdentifier", poIDstr));
317 }
318 else {
319 getDocInfo().add(new HeaderField("DataDictionary.PurchaseOrderDocument.attributes.purapDocumentIdentifier", "Not Available"));
320 }
321 if (ObjectUtils.isNotNull(getPurchaseOrderDocument().getStatus())) {
322 getDocInfo().add(new HeaderField("DataDictionary.PurchaseOrderDocument.attributes.statusCode", ((PurchaseOrderDocument) this.getDocument()).getStatus().getStatusDescription()));
323 }
324 else {
325 getDocInfo().add(new HeaderField("DataDictionary.PurchaseOrderDocument.attributes.statusCode", "Not Available"));
326 }
327 }
328
329 /**
330 * @see org.kuali.kfs.sys.web.struts.KualiAccountingDocumentFormBase#populate(javax.servlet.http.HttpServletRequest)
331 */
332 @Override
333 public void populate(HttpServletRequest request) {
334 PurchaseOrderDocument po = (PurchaseOrderDocument) this.getDocument();
335
336 // call this to make sure it's refreshed from the database if need be since the populate setter doesn't do that
337 po.getDocumentBusinessObject();
338
339 super.populate(request);
340
341 if (ObjectUtils.isNotNull(po.getPurapDocumentIdentifier())) {
342 po.refreshDocumentBusinessObject();
343 }
344
345 for (org.kuali.rice.kns.bo.Note note : (java.util.List<org.kuali.rice.kns.bo.Note>) po.getDocumentBusinessObject().getBoNotes()) {
346 note.refreshReferenceObject("attachment");
347 }
348 }
349
350 /**
351 * Processes validation rules having to do with any payment requests that the given purchase order may have. Specifically,
352 * validates that at least one payment request exists, and makes further checks about the status of such payment requests.
353 *
354 * @param document A PurchaseOrderDocument
355 * @return True if the document passes all the validations.
356 */
357 protected boolean processPaymentRequestRulesForCanClose(PurchaseOrderDocument document) {
358 boolean valid = true;
359 // The PO must have at least one PREQ against it.
360 Integer poDocId = document.getPurapDocumentIdentifier();
361 List<PaymentRequestDocument> pReqs = SpringContext.getBean(PaymentRequestService.class).getPaymentRequestsByPurchaseOrderId(poDocId);
362 if (ObjectUtils.isNotNull(pReqs)) {
363 if (pReqs.size() == 0) {
364 valid = false;
365 }
366 else {
367 boolean checkInProcess = true;
368 boolean hasInProcess = false;
369
370 for (PaymentRequestDocument pReq : pReqs) {
371 // skip exception docs
372 if (pReq.getDocumentHeader().getWorkflowDocument().stateIsException()) {
373 continue;
374 }
375 // TODO NOTE for below, this could/should be changed to look at the first route level after full entry instead of
376 // being tied to AwaitingFiscal (in case full entry is moved)
377 // look for a doc that is currently routing, that will probably be the one that called this close if called from
378 // preq (with close po box)
379 if (StringUtils.equalsIgnoreCase(pReq.getStatusCode(), PaymentRequestStatuses.AWAITING_FISCAL_REVIEW) && !StringUtils.equalsIgnoreCase(pReq.getDocumentHeader().getWorkflowDocument().getCurrentRouteNodeNames(), PurapWorkflowConstants.PaymentRequestDocument.NodeDetailEnum.ACCOUNT_REVIEW.getName())) {
380 // terminate the search since this close doc is probably being called by this doc, a doc should never be In
381 // Process and enroute in any other case
382 checkInProcess = false;
383 break;
384 }
385 if (StringUtils.equalsIgnoreCase(pReq.getStatusCode(), PaymentRequestStatuses.IN_PROCESS)) {
386 hasInProcess = true;
387 }
388 }
389 if (checkInProcess && hasInProcess) {
390 valid = false;
391 }
392 }
393 }
394
395 return valid;
396 }
397
398 /**
399 * Determines whether to display the amend button for the purchase order document. The document status must be open, and the
400 * purchase order must be current and not pending, and the user must be in purchasing group. These are same as the conditions
401 * for displaying the payment hold button. In addition to these conditions, we also have to check that there is no In Process
402 * Payment Requests nor Credit Memos associated with the PO.
403 *
404 * @return boolean true if the amend button can be displayed.
405 */
406 protected boolean canAmend() {
407 boolean can = SpringContext.getBean(PurchaseOrderService.class).isPurchaseOrderOpenForProcessing(getPurchaseOrderDocument());
408
409 // check user authorization
410 if (can) {
411 DocumentAuthorizer documentAuthorizer = SpringContext.getBean(DocumentHelperService.class).getDocumentAuthorizer(getPurchaseOrderDocument());
412 can = documentAuthorizer.canInitiate(KFSConstants.FinancialDocumentTypeCodes.PURCHASE_ORDER_AMENDMENT, GlobalVariables.getUserSession().getPerson());
413 }
414
415 return can;
416 }
417
418 /**
419 * Determines whether to display the void button for the purchase order document. Conditions:
420 * PO is in Pending Print status, or is in Open status and has no PREQs against it;
421 * PO's current indicator is true and pending indicator is false;
422 * and the user is a member of the purchasing group).
423 *
424 * @return boolean true if the void button can be displayed.
425 */
426 protected boolean canVoid() {
427 // check PO status etc
428 boolean can = getPurchaseOrderDocument().isPurchaseOrderCurrentIndicator() && !getPurchaseOrderDocument().isPendingActionIndicator();
429
430 if (can) {
431 boolean pendingPrint = PurchaseOrderStatuses.PENDING_PRINT.equals(getPurchaseOrderDocument().getStatusCode());
432 boolean open = PurchaseOrderStatuses.OPEN.equals(getPurchaseOrderDocument().getStatusCode());
433 boolean errorCxml = PurchaseOrderStatuses.CXML_ERROR.equals(getPurchaseOrderDocument().getStatusCode());
434 boolean errorFax = PurchaseOrderStatuses.FAX_ERROR.equals(getPurchaseOrderDocument().getStatusCode());
435
436 List<PaymentRequestView> preqViews = getPurchaseOrderDocument().getRelatedViews().getRelatedPaymentRequestViews();
437 boolean hasPaymentRequest = preqViews != null && preqViews.size() > 0;
438
439 can = pendingPrint || (open && !hasPaymentRequest) || errorCxml || errorFax;
440 }
441
442 // check user authorization
443 if (can) {
444 DocumentAuthorizer documentAuthorizer = SpringContext.getBean(DocumentHelperService.class).getDocumentAuthorizer(getPurchaseOrderDocument());
445 can = documentAuthorizer.canInitiate(KFSConstants.FinancialDocumentTypeCodes.PURCHASE_ORDER_VOID, GlobalVariables.getUserSession().getPerson());
446 }
447
448 return can;
449 }
450
451 /**
452 * Determines whether to display the close order button to close the purchase order document. Conditions:
453 * PO must be in Open status; must have at least one Payment Request in any status other than "In Process",
454 * and the PO cannot have any Payment Requests in "In Process" status.
455 * This button is available to all faculty/staff.
456 *
457 * @return boolean true if the close order button can be displayed.
458 */
459 protected boolean canClose() {
460 // check PO status etc
461 boolean can = PurchaseOrderStatuses.OPEN.equals(getPurchaseOrderDocument().getStatusCode());
462 can = can && getPurchaseOrderDocument().isPurchaseOrderCurrentIndicator() && !getPurchaseOrderDocument().isPendingActionIndicator();
463 can = can && processPaymentRequestRulesForCanClose(getPurchaseOrderDocument());
464
465 // check user authorization
466 if (can) {
467 DocumentAuthorizer documentAuthorizer = SpringContext.getBean(DocumentHelperService.class).getDocumentAuthorizer(getPurchaseOrderDocument());
468 can = documentAuthorizer.canInitiate(KFSConstants.FinancialDocumentTypeCodes.PURCHASE_ORDER_CLOSE, GlobalVariables.getUserSession().getPerson());
469 }
470
471 return can;
472 }
473
474 /**
475 * Determines whether to display the open order button to reopen the purchase order document.
476 * Conditions: PO status is close, PO is current and not pending, and the user is in purchasing group.
477 *
478 * @return boolean true if the reopen order button can be displayed.
479 */
480 protected boolean canReopen() {
481 // check PO status etc
482 boolean can = PurchaseOrderStatuses.CLOSED.equals(getPurchaseOrderDocument().getStatusCode());
483 can = can && getPurchaseOrderDocument().isPurchaseOrderCurrentIndicator() && !getPurchaseOrderDocument().isPendingActionIndicator();
484
485 // check user authorization
486 if (can) {
487 DocumentAuthorizer documentAuthorizer = SpringContext.getBean(DocumentHelperService.class).getDocumentAuthorizer(getPurchaseOrderDocument());
488 can = documentAuthorizer.canInitiate(KFSConstants.FinancialDocumentTypeCodes.PURCHASE_ORDER_REOPEN, GlobalVariables.getUserSession().getPerson());
489 }
490
491 return can;
492 }
493
494 /**
495 * Determines whether to display the payment hold buttons for the purchase order document.
496 * Conditions: PO status must be open, must be current and not pending, and the user must be in purchasing group.
497 *
498 * @return boolean true if the payment hold button can be displayed.
499 */
500 protected boolean canHoldPayment() {
501 // check PO status etc
502 boolean can = PurchaseOrderStatuses.OPEN.equals(getPurchaseOrderDocument().getStatusCode());
503 can = can && getPurchaseOrderDocument().isPurchaseOrderCurrentIndicator() && !getPurchaseOrderDocument().isPendingActionIndicator();
504
505 // check user authorization
506 if (can) {
507 DocumentAuthorizer documentAuthorizer = SpringContext.getBean(DocumentHelperService.class).getDocumentAuthorizer(getPurchaseOrderDocument());
508 can = documentAuthorizer.canInitiate(KFSConstants.FinancialDocumentTypeCodes.PURCHASE_ORDER_PAYMENT_HOLD, GlobalVariables.getUserSession().getPerson());
509 }
510
511 return can;
512 }
513
514 /**
515 * Determines whether to display the remove hold button for the purchase order document.
516 * Conditions are: PO status must be payment hold, must be current and not pending, and the user must be in purchasing group.
517 *
518 * @return boolean true if the remove hold button can be displayed.
519 */
520 protected boolean canRemoveHold() {
521 // check PO status etc
522 boolean can = PurchaseOrderStatuses.PAYMENT_HOLD.equals(getPurchaseOrderDocument().getStatusCode());
523 can = can && getPurchaseOrderDocument().isPurchaseOrderCurrentIndicator() && !getPurchaseOrderDocument().isPendingActionIndicator();
524
525 // check user authorization
526 if (can) {
527 DocumentAuthorizer documentAuthorizer = SpringContext.getBean(DocumentHelperService.class).getDocumentAuthorizer(getPurchaseOrderDocument());
528 can = documentAuthorizer.canInitiate(KFSConstants.FinancialDocumentTypeCodes.PURCHASE_ORDER_REMOVE_HOLD, GlobalVariables.getUserSession().getPerson());
529 }
530
531 return can;
532 }
533
534 /**
535 * Determines whether to display the retransmit button. Conditions:
536 * PO status must be open, and must be current and not pending, and the last transmit date must not be null.
537 * If the purchase order is an Automated Purchase Order (APO) and does not have any sensitive data set to true,
538 * then any users can see the retransmit button, otherwise, only users in the purchasing group can see it.
539 *
540 * @return boolean true if the retransmit button can be displayed.
541 */
542 protected boolean canRetransmit() {
543 // check PO status etc
544 boolean can = PurchaseOrderStatuses.OPEN.equals(getPurchaseOrderDocument().getStatusCode());
545 can = can && getPurchaseOrderDocument().isPurchaseOrderCurrentIndicator() && !getPurchaseOrderDocument().isPendingActionIndicator();
546 can = can && getPurchaseOrderDocument().getPurchaseOrderLastTransmitTimestamp() != null;
547 can = can && !PurapConstants.RequisitionSources.B2B.equals(getPurchaseOrderDocument().getRequisitionSourceCode());
548 can = can && !editingMode.containsKey(PurapAuthorizationConstants.PurchaseOrderEditMode.DISPLAY_RETRANSMIT_TAB);
549
550 if (!can) {
551 return false;
552 }
553
554 // check user authorization
555 DocumentAuthorizer documentAuthorizer = SpringContext.getBean(DocumentHelperService.class).getDocumentAuthorizer(getPurchaseOrderDocument());
556 if (getPurchaseOrderDocument().getPurchaseOrderAutomaticIndicator()) {
557 // for APO use authorization for PurchaseOrderRetransmitDocument, which is anybody
558 can = documentAuthorizer.canInitiate(KFSConstants.FinancialDocumentTypeCodes.PURCHASE_ORDER_RETRANSMIT, GlobalVariables.getUserSession().getPerson());
559 }
560 else {
561 // for NON_APO use authorization for PurchaseOrderDocument, which is purchasing user
562 can = documentAuthorizer.canInitiate(KFSConstants.FinancialDocumentTypeCodes.PURCHASE_ORDER, GlobalVariables.getUserSession().getPerson());
563 }
564
565 return can;
566 }
567
568 /**
569 * Determines whether to display the button to print the pdf on a retransmit document.
570 * We're currently sharing the same button image as the button for creating a retransmit document but this may change someday.
571 * This button should only appear on Retransmit Document. If it is an Automated Purchase Order (APO)
572 * then any users can see this button, otherwise, only users in the purchasing group can see it.
573 *
574 * @return boolean true if the print retransmit button can be displayed.
575 */
576 protected boolean canPrintRetransmit() {
577 // check PO status etc
578 boolean can = getPurchaseOrderDocument().getDocumentHeader().getWorkflowDocument().getDocumentType().equals(PurapConstants.PurchaseOrderDocTypes.PURCHASE_ORDER_RETRANSMIT_DOCUMENT);
579 can = can && editingMode.containsKey(PurapAuthorizationConstants.PurchaseOrderEditMode.DISPLAY_RETRANSMIT_TAB);
580
581 if (can) {
582 // check user authorization: same as retransmit init, since whoever can init retransmit PO shall be able to print
583 DocumentAuthorizer documentAuthorizer = SpringContext.getBean(DocumentHelperService.class).getDocumentAuthorizer(getPurchaseOrderDocument());
584 if (getPurchaseOrderDocument().getPurchaseOrderAutomaticIndicator()) {
585 // for APO use authorization for PurchaseOrderRetransmitDocument, which is anybody
586 can = documentAuthorizer.canInitiate(KFSConstants.FinancialDocumentTypeCodes.PURCHASE_ORDER_RETRANSMIT, GlobalVariables.getUserSession().getPerson());
587 }
588 else {
589 // for NON_APO use authorization for PurchaseOrderDocument, which is purchasing user
590 can = documentAuthorizer.canInitiate(KFSConstants.FinancialDocumentTypeCodes.PURCHASE_ORDER, GlobalVariables.getUserSession().getPerson());
591 }
592 }
593
594 return can;
595 }
596
597 /**
598 * Determines if a Split PO Document can be created from this purchase order. Conditions:
599 * The parent PO status is either "In Process" or "Awaiting Purchasing Review"; requisition source is not B2B; has at least 2 items,
600 * and PO is not in the process of being split; user must be in purchasing group.
601 *
602 * @return boolean true if the split PO button can be displayed.
603 */
604 protected boolean canSplitPo() {
605 // PO must be in either "In Process" or "Awaiting Purchasing Review"
606 boolean can = PurchaseOrderStatuses.IN_PROCESS.equals(getPurchaseOrderDocument().getStatusCode());
607 can = can && !getPurchaseOrderDocument().getDocumentHeader().getWorkflowDocument().stateIsEnroute();
608 can = can || PurchaseOrderStatuses.AWAIT_PURCHASING_REVIEW.equals(getPurchaseOrderDocument().getStatusCode());
609
610 // can't split a SplitPO Document, according to new specs
611 can = can && !(getPurchaseOrderDocument() instanceof PurchaseOrderSplitDocument);
612
613 // can't initiate another split during the splitting process.
614 can = can && !editingMode.containsKey(PurapAuthorizationConstants.PurchaseOrderEditMode.SPLITTING_ITEM_SELECTION);
615
616 // Requisition Source must not be B2B.
617 can = can && !getPurchaseOrderDocument().getRequisitionSourceCode().equals(PurapConstants.RequisitionSources.B2B);
618
619 // PO must have more than one line item.
620 if (can) {
621 List<PurApItem> items = (List<PurApItem>)getPurchaseOrderDocument().getItems();
622 int itemsBelowTheLine = PurApItemUtils.countBelowTheLineItems(items);
623 can = items.size() - itemsBelowTheLine > 1;
624 }
625
626 // check user authorization
627 if (can) {
628 DocumentAuthorizer documentAuthorizer = SpringContext.getBean(DocumentHelperService.class).getDocumentAuthorizer(getPurchaseOrderDocument());
629 can = documentAuthorizer.canInitiate(KFSConstants.FinancialDocumentTypeCodes.PURCHASE_ORDER_SPLIT, GlobalVariables.getUserSession().getPerson());
630 }
631
632 return can;
633 }
634
635 /**
636 * Determines whether the PO is in a status that signifies it has enough information to generate a Split PO.
637 *
638 * @return True if the PO can continue to be split.
639 */
640 protected boolean canContinuePoSplit() {
641 boolean can = editingMode.containsKey(PurapAuthorizationConstants.PurchaseOrderEditMode.SPLITTING_ITEM_SELECTION);
642
643 // check user authorization
644 if (can) {
645 DocumentAuthorizer documentAuthorizer = SpringContext.getBean(DocumentHelperService.class).getDocumentAuthorizer(getPurchaseOrderDocument());
646 can = documentAuthorizer.canInitiate(KFSConstants.FinancialDocumentTypeCodes.PURCHASE_ORDER_SPLIT, GlobalVariables.getUserSession().getPerson());
647 }
648
649 return can;
650 }
651
652 /**
653 * Determines if a line item receiving document can be created for the purchase order.
654 *
655 * @return boolean true if the receiving document button can be displayed.
656 */
657 protected boolean canCreateReceiving() {
658 // check PO status and item info
659 boolean can = SpringContext.getBean(ReceivingService.class).canCreateLineItemReceivingDocument(getPurchaseOrderDocument());
660
661 // check user authorization
662 if (can) {
663 DocumentAuthorizer documentAuthorizer = SpringContext.getBean(DocumentHelperService.class).getDocumentAuthorizer(getPurchaseOrderDocument());
664 can = documentAuthorizer.canInitiate(KFSConstants.FinancialDocumentTypeCodes.LINE_ITEM_RECEIVING, GlobalVariables.getUserSession().getPerson());
665 }
666
667 return can;
668 }
669
670 /**
671 * Creates a MAP for all the buttons to appear on the Purchase Order Form, and sets the attributes of these buttons.
672 *
673 * @return the button map created.
674 */
675 protected Map<String, ExtraButton> createButtonsMap() {
676 HashMap<String, ExtraButton> result = new HashMap<String, ExtraButton>();
677
678 // Retransmit button
679 ExtraButton retransmitButton = new ExtraButton();
680 retransmitButton.setExtraButtonProperty("methodToCall.retransmitPo");
681 retransmitButton.setExtraButtonSource("${" + KFSConstants.EXTERNALIZABLE_IMAGES_URL_KEY + "}buttonsmall_retransmit.gif");
682 retransmitButton.setExtraButtonAltText("Retransmit");
683
684 // Printing Retransmit button
685 ExtraButton printingRetransmitButton = new ExtraButton();
686 printingRetransmitButton.setExtraButtonProperty("methodToCall.printingRetransmitPo");
687 printingRetransmitButton.setExtraButtonSource("${" + KFSConstants.EXTERNALIZABLE_IMAGES_URL_KEY + "}buttonsmall_retransmit.gif");
688 printingRetransmitButton.setExtraButtonAltText("PrintingRetransmit");
689
690 // Printing Preview button
691 ExtraButton printingPreviewButton = new ExtraButton();
692 printingPreviewButton.setExtraButtonProperty("methodToCall.printingPreviewPo");
693 printingPreviewButton.setExtraButtonSource("${" + KFSConstants.EXTERNALIZABLE_IMAGES_URL_KEY + "}buttonsmall_previewpf.gif");
694 printingPreviewButton.setExtraButtonAltText("PrintingPreview");
695
696 // Print button
697 ExtraButton printButton = new ExtraButton();
698 printButton.setExtraButtonProperty("methodToCall.firstTransmitPrintPo");
699 printButton.setExtraButtonSource("${" + KFSConstants.EXTERNALIZABLE_IMAGES_URL_KEY + "}buttonsmall_print.gif");
700 printButton.setExtraButtonAltText("Print");
701
702 // Reopen PO button
703 ExtraButton reopenButton = new ExtraButton();
704 reopenButton.setExtraButtonProperty("methodToCall.reopenPo");
705 reopenButton.setExtraButtonSource("${" + KFSConstants.EXTERNALIZABLE_IMAGES_URL_KEY + "}buttonsmall_openorder.gif");
706 reopenButton.setExtraButtonAltText("Reopen");
707
708 // Close PO button
709 ExtraButton closeButton = new ExtraButton();
710 closeButton.setExtraButtonProperty("methodToCall.closePo");
711 closeButton.setExtraButtonSource("${" + KFSConstants.EXTERNALIZABLE_IMAGES_URL_KEY + "}buttonsmall_closeorder.gif");
712 closeButton.setExtraButtonAltText("Close PO");
713
714 // Void PO button
715 ExtraButton voidButton = new ExtraButton();
716 voidButton.setExtraButtonProperty("methodToCall.voidPo");
717 voidButton.setExtraButtonSource("${" + KFSConstants.EXTERNALIZABLE_IMAGES_URL_KEY + "}buttonsmall_voidorder.gif");
718 voidButton.setExtraButtonAltText("Void PO");
719
720 // Payment Hold PO button
721 ExtraButton paymentHoldButton = new ExtraButton();
722 paymentHoldButton.setExtraButtonProperty("methodToCall.paymentHoldPo");
723 paymentHoldButton.setExtraButtonSource("${" + KFSConstants.EXTERNALIZABLE_IMAGES_URL_KEY + "}buttonsmall_paymenthold.gif");
724 paymentHoldButton.setExtraButtonAltText("Payment Hold");
725
726 // Amend button
727 ExtraButton amendButton = new ExtraButton();
728 amendButton.setExtraButtonProperty("methodToCall.amendPo");
729 amendButton.setExtraButtonSource("${" + KFSConstants.EXTERNALIZABLE_IMAGES_URL_KEY + "}buttonsmall_amend.gif");
730 amendButton.setExtraButtonAltText("Amend");
731
732 // Remove Hold button
733 ExtraButton removeHoldButton = new ExtraButton();
734 removeHoldButton.setExtraButtonProperty("methodToCall.removeHoldPo");
735 removeHoldButton.setExtraButtonSource("${" + KFSConstants.EXTERNALIZABLE_IMAGES_URL_KEY + "}buttonsmall_removehold.gif");
736 removeHoldButton.setExtraButtonAltText("Remove Hold");
737
738 // Resend PO Cxml button
739 ExtraButton resendPoCxmlButton = new ExtraButton();
740 resendPoCxmlButton.setExtraButtonProperty("methodToCall.resendPoCxml");
741 resendPoCxmlButton.setExtraButtonSource("${" + KFSConstants.EXTERNALIZABLE_IMAGES_URL_KEY + "}buttonsmall_resendpo.gif");
742 resendPoCxmlButton.setExtraButtonAltText("Resend PO CXML");
743
744 // Receiving button
745 ExtraButton receivingButton = new ExtraButton();
746 receivingButton.setExtraButtonProperty("methodToCall.createReceivingLine");
747 receivingButton.setExtraButtonSource("${" + KFSConstants.EXTERNALIZABLE_IMAGES_URL_KEY + "}buttonsmall_receiving.gif");
748 receivingButton.setExtraButtonAltText("Receiving");
749
750 // Split PO button
751 ExtraButton splitPoButton = new ExtraButton();
752 splitPoButton.setExtraButtonProperty("methodToCall.splitPo");
753 splitPoButton.setExtraButtonSource("${" + KFSConstants.EXTERNALIZABLE_IMAGES_URL_KEY + "}buttonsmall_splitorder.gif");
754 splitPoButton.setExtraButtonAltText("Split this PO");
755
756 // Continue button
757 ExtraButton continueButton = new ExtraButton();
758 continueButton.setExtraButtonProperty("methodToCall.continuePurchaseOrderSplit");
759 continueButton.setExtraButtonSource("${" + KFSConstants.RICE_EXTERNALIZABLE_IMAGES_URL_KEY + "}buttonsmall_continue.gif");
760 continueButton.setExtraButtonAltText("Continue");
761
762 // Cancel Split button
763 ExtraButton cancelSplitButton = new ExtraButton();
764 cancelSplitButton.setExtraButtonProperty("methodToCall.cancelPurchaseOrderSplit");
765 cancelSplitButton.setExtraButtonSource("${" + KFSConstants.EXTERNALIZABLE_IMAGES_URL_KEY + "}buttonsmall_cancelsplit.gif");
766 cancelSplitButton.setExtraButtonAltText("Cancel Splitting the PO");
767
768 // Assign Sensitive Data button
769 ExtraButton assignSensitiveDataButton = new ExtraButton();
770 assignSensitiveDataButton.setExtraButtonProperty("methodToCall.assignSensitiveData");
771 assignSensitiveDataButton.setExtraButtonSource("${" + KFSConstants.EXTERNALIZABLE_IMAGES_URL_KEY + "}buttonsmall_sensitivedata.gif ");
772 assignSensitiveDataButton.setExtraButtonAltText("Assign sensitive data to the PO");
773
774 // Submit Sensitive Data Assignment button
775 ExtraButton submitSensitiveDataButton = new ExtraButton();
776 submitSensitiveDataButton.setExtraButtonProperty("methodToCall.submitSensitiveData");
777 submitSensitiveDataButton.setExtraButtonSource("${" + KFSConstants.RICE_EXTERNALIZABLE_IMAGES_URL_KEY + "}buttonsmall_submit.gif");
778 submitSensitiveDataButton.setExtraButtonAltText("Submit sensitive data assignment");
779
780 // Cancel Sensitive Data Assignment button
781 ExtraButton cancelSensitiveDataButton = new ExtraButton();
782 cancelSensitiveDataButton.setExtraButtonProperty("methodToCall.cancelSensitiveData");
783 cancelSensitiveDataButton.setExtraButtonSource("${" + KFSConstants.RICE_EXTERNALIZABLE_IMAGES_URL_KEY + "}buttonsmall_cancel.gif");
784 cancelSensitiveDataButton.setExtraButtonAltText("Cancel sensitive data assignment");
785
786 result.put(retransmitButton.getExtraButtonProperty(), retransmitButton);
787 result.put(printingRetransmitButton.getExtraButtonProperty(), printingRetransmitButton);
788 result.put(printingPreviewButton.getExtraButtonProperty(), printingPreviewButton);
789 result.put(printButton.getExtraButtonProperty(), printButton);
790 result.put(reopenButton.getExtraButtonProperty(), reopenButton);
791 result.put(closeButton.getExtraButtonProperty(), closeButton);
792 result.put(voidButton.getExtraButtonProperty(), voidButton);
793 result.put(paymentHoldButton.getExtraButtonProperty(), paymentHoldButton);
794 result.put(amendButton.getExtraButtonProperty(), amendButton);
795 result.put(removeHoldButton.getExtraButtonProperty(), removeHoldButton);
796 result.put(receivingButton.getExtraButtonProperty(), receivingButton);
797 result.put(splitPoButton.getExtraButtonProperty(), splitPoButton);
798 result.put(continueButton.getExtraButtonProperty(), continueButton);
799 result.put(cancelSplitButton.getExtraButtonProperty(), cancelSplitButton);
800 result.put(assignSensitiveDataButton.getExtraButtonProperty(), assignSensitiveDataButton);
801 result.put(submitSensitiveDataButton.getExtraButtonProperty(), submitSensitiveDataButton);
802 result.put(cancelSensitiveDataButton.getExtraButtonProperty(), cancelSensitiveDataButton);
803 result.put(resendPoCxmlButton.getExtraButtonProperty(), resendPoCxmlButton);
804
805 return result;
806 }
807
808 /**
809 * Override the superclass method to add appropriate buttons for
810 * PurchaseOrderDocument.
811 *
812 * @see org.kuali.rice.kns.web.struts.form.KualiForm#getExtraButtons()
813 */
814 @Override
815 public List<ExtraButton> getExtraButtons() {
816 super.getExtraButtons();
817 Map buttonsMap = createButtonsMap();
818
819 if (getEditingMode().containsKey(PurapAuthorizationConstants.PurchaseOrderEditMode.ASSIGN_SENSITIVE_DATA)) {
820 extraButtons.add((ExtraButton) buttonsMap.get("methodToCall.assignSensitiveData"));
821 if (getPurchaseOrderDocument().getAssigningSensitiveData()) {
822 // no other extra buttons except the following shall appear on "Assign Sensitive Data" page
823 // and these buttons use the same permissions as the "Assign Sensitive Data" button
824 extraButtons.clear();
825 extraButtons.add((ExtraButton) buttonsMap.get("methodToCall.submitSensitiveData"));
826 extraButtons.add((ExtraButton) buttonsMap.get("methodToCall.cancelSensitiveData"));
827 return extraButtons;
828 }
829 }
830
831 if (getEditingMode().containsKey(PurapAuthorizationConstants.PurchaseOrderEditMode.PREVIEW_PRINT_PURCHASE_ORDER)) {
832 extraButtons.add((ExtraButton) buttonsMap.get("methodToCall.printingPreviewPo"));
833 }
834
835 if (getEditingMode().containsKey(PurapAuthorizationConstants.PurchaseOrderEditMode.PRINT_PURCHASE_ORDER)) {
836 extraButtons.add((ExtraButton) buttonsMap.get("methodToCall.firstTransmitPrintPo"));
837 }
838
839 if (getEditingMode().containsKey(PurapAuthorizationConstants.PurchaseOrderEditMode.RESEND_PURCHASE_ORDER)) {
840 extraButtons.add((ExtraButton) buttonsMap.get("methodToCall.resendPoCxml"));
841 }
842
843 if (canRetransmit()) {
844 extraButtons.add((ExtraButton) buttonsMap.get("methodToCall.retransmitPo"));
845 }
846
847 if (canPrintRetransmit()) {
848 extraButtons.add((ExtraButton) buttonsMap.get("methodToCall.printingRetransmitPo"));
849 }
850
851 if (canReopen()) {
852 extraButtons.add((ExtraButton) buttonsMap.get("methodToCall.reopenPo"));
853 }
854
855 if (canClose()) {
856 extraButtons.add((ExtraButton) buttonsMap.get("methodToCall.closePo"));
857 }
858
859 if (canHoldPayment()) {
860 extraButtons.add((ExtraButton) buttonsMap.get("methodToCall.paymentHoldPo"));
861 }
862
863 if (canAmend()) {
864 extraButtons.add((ExtraButton) buttonsMap.get("methodToCall.amendPo"));
865 }
866
867 if (canVoid()) {
868 extraButtons.add((ExtraButton) buttonsMap.get("methodToCall.voidPo"));
869 }
870
871 if (canRemoveHold()) {
872 extraButtons.add((ExtraButton) buttonsMap.get("methodToCall.removeHoldPo"));
873 }
874
875 if (canCreateReceiving()) {
876 extraButtons.add((ExtraButton) buttonsMap.get("methodToCall.createReceivingLine"));
877 }
878
879 if (canSplitPo()) {
880 extraButtons.add((ExtraButton) buttonsMap.get("methodToCall.splitPo"));
881 }
882
883 if (canContinuePoSplit()) {
884 extraButtons.clear();
885 extraButtons.add((ExtraButton) buttonsMap.get("methodToCall.continuePurchaseOrderSplit"));
886 extraButtons.add((ExtraButton) buttonsMap.get("methodToCall.cancelPurchaseOrderSplit"));
887 }
888
889 return extraButtons;
890 }
891
892 }
893