1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.ole.module.purap.document.validation.impl;
17
18 import org.kuali.ole.module.purap.PurapConstants;
19 import org.kuali.ole.module.purap.PurapConstants.ItemFields;
20 import org.kuali.ole.module.purap.PurapKeyConstants;
21 import org.kuali.ole.module.purap.PurapParameterConstants;
22 import org.kuali.ole.module.purap.businessobject.InvoiceItem;
23 import org.kuali.ole.module.purap.businessobject.PurApAccountingLine;
24 import org.kuali.ole.module.purap.businessobject.PurApItem;
25 import org.kuali.ole.module.purap.document.InvoiceDocument;
26 import org.kuali.ole.module.purap.document.service.PurapService;
27 import org.kuali.ole.select.OleSelectConstant;
28 import org.kuali.ole.select.businessobject.OleInvoiceItem;
29 import org.kuali.ole.select.document.OleInvoiceDocument;
30 import org.kuali.ole.sys.OLEConstants;
31 import org.kuali.ole.sys.OLEKeyConstants;
32 import org.kuali.ole.sys.context.SpringContext;
33 import org.kuali.ole.sys.document.validation.GenericValidation;
34 import org.kuali.ole.sys.document.validation.Validation;
35 import org.kuali.ole.sys.document.validation.event.AttributedDocumentEvent;
36 import org.kuali.ole.sys.document.validation.impl.*;
37 import org.kuali.ole.sys.service.impl.OleParameterConstants;
38 import org.kuali.ole.vnd.businessobject.VendorCustomerNumber;
39 import org.kuali.rice.core.api.util.type.KualiDecimal;
40 import org.kuali.rice.coreservice.framework.parameter.ParameterService;
41 import org.kuali.rice.krad.service.KRADServiceLocator;
42 import org.kuali.rice.krad.util.GlobalVariables;
43 import org.kuali.rice.krad.util.KRADConstants;
44 import org.kuali.rice.krad.util.ObjectUtils;
45
46 import java.math.BigDecimal;
47 import java.util.ArrayList;
48 import java.util.HashMap;
49 import java.util.List;
50 import java.util.Map;
51
52 public class InvoiceProcessItemValidation extends GenericValidation {
53
54 private PurapService purapService;
55 private PurApItem itemForValidation;
56 private AttributedDocumentEvent event;
57 private CompositeValidation reviewAccountingLineValidation;
58 private InvoiceDocument invoiceDocument;
59 private PurApAccountingLine invoiceAccountingLine;
60
61 @Override
62 public boolean validate(AttributedDocumentEvent event) {
63 boolean valid = true;
64 this.event = event;
65
66 InvoiceDocument invoiceDocument = (InvoiceDocument) event.getDocument();
67 InvoiceItem invoiceItem = (InvoiceItem) itemForValidation;
68
69 valid &= validateEachItem(invoiceDocument, invoiceItem);
70
71 return valid;
72
73 }
74
75
76
77
78
79
80
81
82 protected boolean validateEachItem(InvoiceDocument invoiceDocument, InvoiceItem item) {
83 boolean valid = true;
84 String identifierString = item.getItemIdentifierString();
85 valid &= validateItem(invoiceDocument, item, identifierString);
86 return valid;
87 }
88
89
90
91
92
93
94
95
96
97
98 public boolean validateItem(InvoiceDocument invoiceDocument, InvoiceItem item, String identifierString) {
99 boolean valid = true;
100
101 if (!purapService.isFullDocumentEntryCompleted(invoiceDocument)) {
102 if (item.getItemType().isLineItemIndicator()) {
103 valid &= validateAboveTheLineItems(item, identifierString, invoiceDocument.isReceivingDocumentRequiredIndicator());
104 valid &= validatePOItem((OleInvoiceItem)item);
105 }
106 valid &= validateItemWithoutAccounts(item, identifierString);
107 }
108
109 valid &= validateProrationType(invoiceDocument);
110 valid &= validateItemAccounts(invoiceDocument, item, identifierString);
111 return valid;
112 }
113
114 private boolean validatePOItem (OleInvoiceItem invoiceItem) {
115 if (invoiceItem.getItemType().isQuantityBasedGeneralLedgerIndicator()) {
116 if(invoiceItem.getPoItemIdentifier() == null ||
117 invoiceItem.getPoItemIdentifier().compareTo(new Integer(0)) == 0) {
118 GlobalVariables.getMessageMap().putError(KRADConstants.GLOBAL_ERRORS, OLEConstants.ITEM_WITHOUT_PO);
119 return false;
120 }
121 }
122 return true;
123
124 }
125
126 protected boolean validateProrationType(InvoiceDocument invoiceDocument) {
127 boolean isValid = true;
128 OleInvoiceDocument document = (OleInvoiceDocument) invoiceDocument;
129 List<OleInvoiceItem> items = document.getItems();
130 boolean additionalItemPresent = false;
131 boolean canProrate = false;
132 KualiDecimal additionalCharge = KualiDecimal.ZERO;
133 KualiDecimal totalAmt = document.getInvoicedItemTotal() != null ?
134 new KualiDecimal(document.getInvoicedItemTotal()) : KualiDecimal.ZERO;
135 for (OleInvoiceItem invoiceItem : items) {
136 if (invoiceItem.getItemType().isAdditionalChargeIndicator() && invoiceItem.getExtendedPrice() != null &&
137 !invoiceItem.getExtendedPrice().isZero()) {
138 additionalCharge = additionalCharge.add(invoiceItem.getExtendedPrice());
139 additionalItemPresent = true;
140 }
141 if (invoiceItem.getItemType().isQuantityBasedGeneralLedgerIndicator() && invoiceItem.getItemUnitPrice().compareTo(BigDecimal.ZERO) != 0 ) {
142 canProrate = true;
143 }
144 }
145 if (additionalItemPresent && ((document.getProrateBy() == null) ||
146 (!document.isProrateDollar() && !document.isProrateManual() && !document.isProrateQty() && !document.isNoProrate()))) {
147 GlobalVariables.getMessageMap().putErrorForSectionId(OleSelectConstant.INVOICE_ADDITIONAL_ITEM_SECTION_ID,
148 OLEKeyConstants.ERROR_REQUIRED, PurapConstants.PRQSDocumentsStrings.PRORATION_TYPE);
149 isValid &= false;
150
151 }
152 if ((totalAmt.isZero() || !canProrate) && document.isProrateDollar() ) {
153 GlobalVariables.getMessageMap().putError(OleSelectConstant.INVOICE_ADDITIONAL_CHARGE_SECTION_ID,
154 OLEKeyConstants.ERROR_PRORATE_DOLLAR_ZERO_ITEM_TOTAL);
155 }
156 if (document.getVendorCustomerNumber() != null && !document.getVendorCustomerNumber().equalsIgnoreCase("")) {
157 Map<String, String> map = new HashMap<String, String>();
158 if (document.getVendorCustomerNumber() != null && !document.getVendorCustomerNumber().equalsIgnoreCase("")) {
159 map.put(OLEConstants.VENDOR_CUSTOMER_NUMBER, document.getVendorCustomerNumber());
160 }
161 if (document.getVendorHeaderGeneratedIdentifier() != null && !document.getVendorHeaderGeneratedIdentifier().toString().equalsIgnoreCase("")) {
162 map.put(OLEConstants.VENDOR_HEADER_IDENTIFIER, document.getVendorHeaderGeneratedIdentifier().toString());
163 }
164 if (document.getVendorDetailAssignedIdentifier() != null && !document.getVendorDetailAssignedIdentifier().toString().equalsIgnoreCase("")) {
165 map.put(OLEConstants.VENDOR_DETAIL_IDENTIFIER, document.getVendorDetailAssignedIdentifier().toString());
166 }
167 List<VendorCustomerNumber> vendorCustomerNumbers = (List<VendorCustomerNumber>) KRADServiceLocator.getBusinessObjectService().findMatching(VendorCustomerNumber.class, map);
168 if (!(vendorCustomerNumbers != null && vendorCustomerNumbers.size() > 0)) {
169 isValid &= false;
170 GlobalVariables.getMessageMap().putError(KRADConstants.GLOBAL_ERRORS, OLEConstants.INVALID_ACQUISITION_NUMBER);
171 }
172 }
173
174
175
176
177
178 return isValid;
179 }
180
181
182
183
184
185
186
187 protected boolean validateAboveTheLineItems(InvoiceItem item, String identifierString, boolean isReceivingDocumentRequiredIndicator) {
188 boolean valid = true;
189
190
191 if (ObjectUtils.isNotNull(item.getItemQuantity())) {
192
193
194
195
196
197 if (!isReceivingDocumentRequiredIndicator) {
198
199
200
201
202 }
203 }
204
205 if (ObjectUtils.isNotNull(item.getExtendedPrice()) && item.getExtendedPrice().isPositive()) {
206
207
208 if (ObjectUtils.isNull(item.getItemQuantity()) || item.getItemQuantity().isZero()) {
209
210
211 valid = false;
212 GlobalVariables.getMessageMap().putError(PurapConstants.ITEM_TAB_ERROR_PROPERTY, PurapKeyConstants.ERROR_ITEM_QUANTITY_REQUIRED, ItemFields.INVOICE_QUANTITY, identifierString, ItemFields.OPEN_QUANTITY);
213 }
214 }
215
216
217 if ((ObjectUtils.isNull(item.getInvoice().getPurapDocumentIdentifier())) || (PurapConstants.InvoiceStatuses.APPDOC_IN_PROCESS.equals(item.getInvoice().getApplicationDocumentStatus()))) {
218
219 if ((item.getItemType().isAmountBasedGeneralLedgerIndicator()) && ((item.getExtendedPrice() != null) && item.getExtendedPrice().isNonZero())) {
220 if (item.getPoOutstandingAmount() == null || item.getPoOutstandingAmount().isZero()) {
221 valid = false;
222 GlobalVariables.getMessageMap().putError(PurapConstants.ITEM_TAB_ERROR_PROPERTY, PurapKeyConstants.ERROR_ITEM_AMOUNT_ALREADY_PAID, identifierString);
223 }
224 }
225 }
226
227 return valid;
228 }
229
230
231
232
233
234
235
236 public boolean validateItemWithoutAccounts(InvoiceItem item, String identifierString) {
237 boolean valid = true;
238 if (ObjectUtils.isNotNull(item.getItemUnitPrice()) && (new KualiDecimal(item.getItemUnitPrice())).isNonZero() && item.isAccountListEmpty()) {
239 valid = false;
240 GlobalVariables.getMessageMap().putError(PurapConstants.ITEM_TAB_ERROR_PROPERTY, PurapKeyConstants.ERROR_ITEM_ACCOUNTING_INCOMPLETE, identifierString);
241 }
242 return valid;
243 }
244
245
246
247
248
249
250
251
252
253
254 public boolean validateItemAccounts(InvoiceDocument invoiceDocument, InvoiceItem item, String identifierString) {
255 boolean valid = true;
256 List<PurApAccountingLine> accountingLines = item.getSourceAccountingLines();
257 KualiDecimal itemTotal = item.getTotalAmount();
258 KualiDecimal accountTotal = KualiDecimal.ZERO;
259 KualiDecimal prorateSurcharge = KualiDecimal.ZERO;
260 OleInvoiceItem invoiceItem = (OleInvoiceItem) item;
261 if (invoiceItem.getItemType().isQuantityBasedGeneralLedgerIndicator() && invoiceItem.getExtendedPrice() != null && invoiceItem.getExtendedPrice().compareTo(KualiDecimal.ZERO) != 0) {
262 if (invoiceItem.getItemSurcharge() != null && invoiceItem.getItemTypeCode().equals("ITEM")) {
263 prorateSurcharge = new KualiDecimal(invoiceItem.getItemSurcharge()).multiply(invoiceItem.getItemQuantity());
264 }
265 itemTotal = itemTotal.subtract(prorateSurcharge);
266 }
267 for (PurApAccountingLine accountingLine : accountingLines) {
268 if (accountingLine.getAmount().isZero()) {
269 if (!canApproveAccountingLinesWithZeroAmount()) {
270 GlobalVariables.getMessageMap().putError(PurapConstants.ITEM_TAB_ERROR_PROPERTY, PurapKeyConstants.ERROR_ITEM_ACCOUNTING_AMOUNT_INVALID, itemForValidation.getItemIdentifierString());
271 valid &= false;
272 }
273 }
274 valid &= reviewAccountingLineValidation(invoiceDocument, accountingLine);
275 accountTotal = accountTotal.add(accountingLine.getAmount());
276 }
277 if (purapService.isFullDocumentEntryCompleted(invoiceDocument)) {
278
279 if (accountTotal.compareTo(itemTotal) != 0) {
280 valid = false;
281 GlobalVariables.getMessageMap().putError(PurapConstants.ITEM_TAB_ERROR_PROPERTY, PurapKeyConstants.ERROR_ITEM_ACCOUNTING_AMOUNT_TOTAL, identifierString);
282 }
283 }
284 return valid;
285 }
286
287 public CompositeValidation getReviewAccountingLineValidation() {
288 return reviewAccountingLineValidation;
289 }
290
291 public void setReviewAccountingLineValidation(CompositeValidation reviewAccountingLineValidation) {
292 this.reviewAccountingLineValidation = reviewAccountingLineValidation;
293 }
294
295 public PurapService getPurapService() {
296 return purapService;
297 }
298
299 public void setPurapService(PurapService purapService) {
300 this.purapService = purapService;
301 }
302
303 public PurApItem getItemForValidation() {
304 return itemForValidation;
305 }
306
307 public void setItemForValidation(PurApItem itemForValidation) {
308 this.itemForValidation = itemForValidation;
309 }
310
311 protected boolean reviewAccountingLineValidation(InvoiceDocument document, PurApAccountingLine accountingLine) {
312 boolean valid = true;
313 List<Validation> gauntlet = new ArrayList<Validation>();
314 this.invoiceDocument = document;
315 this.invoiceAccountingLine = accountingLine;
316
317 createGauntlet(reviewAccountingLineValidation);
318
319 for (Validation validation : gauntlet) {
320 valid &= validation.validate(event);
321 }
322
323 return valid;
324 }
325
326 protected void createGauntlet(CompositeValidation validation) {
327 for (Validation val : validation.getValidations()) {
328 if (val instanceof CompositeValidation) {
329 createGauntlet((CompositeValidation) val);
330 } else if (val instanceof BusinessObjectDataDictionaryValidation) {
331 addParametersToValidation((BusinessObjectDataDictionaryValidation) val);
332 } else if (val instanceof AccountingLineAmountPositiveValidation) {
333
334 } else if (val instanceof AccountingLineDataDictionaryValidation) {
335 addParametersToValidation((AccountingLineDataDictionaryValidation) val);
336 } else if (val instanceof AccountingLineValuesAllowedValidationHutch) {
337 addParametersToValidation((AccountingLineValuesAllowedValidationHutch) val);
338 } else {
339 throw new IllegalStateException("Validations in the InvoiceProcessItemValidation must contain specific instances of validation");
340 }
341 }
342 }
343
344
345
346
347
348
349
350
351 public boolean canApproveAccountingLinesWithZeroAmount() {
352 boolean canApproveLine = false;
353
354
355 String approveZeroAmountLine = SpringContext.getBean(ParameterService.class).getParameterValueAsString(OleParameterConstants.PURCHASING_DOCUMENT.class, PurapParameterConstants.APPROVE_ACCOUNTING_LINES_WITH_ZERO_DOLLAR_AMOUNT_IND);
356
357 if ("Y".equalsIgnoreCase(approveZeroAmountLine)) {
358 return true;
359 }
360
361 return canApproveLine;
362 }
363
364 protected void addParametersToValidation(BusinessObjectDataDictionaryValidation validation) {
365 validation.setBusinessObjectForValidation(this.invoiceAccountingLine);
366 }
367
368 protected void addParametersToValidation(AccountingLineAmountPositiveValidation validation) {
369 validation.setAccountingDocumentForValidation(this.invoiceDocument);
370 validation.setAccountingLineForValidation(this.invoiceAccountingLine);
371 }
372
373 protected void addParametersToValidation(AccountingLineDataDictionaryValidation validation) {
374 validation.setAccountingLineForValidation(this.invoiceAccountingLine);
375 }
376
377 protected void addParametersToValidation(AccountingLineValuesAllowedValidationHutch validation) {
378 validation.setAccountingDocumentForValidation(this.invoiceDocument);
379 validation.setAccountingLineForValidation(this.invoiceAccountingLine);
380 }
381
382
383
384
385
386
387 protected AttributedDocumentEvent getEvent() {
388 return event;
389 }
390
391
392
393
394
395
396 protected void setEvent(AttributedDocumentEvent event) {
397 this.event = event;
398 }
399
400
401
402
403
404
405 protected InvoiceDocument getPreqDocument() {
406 return invoiceDocument;
407 }
408
409
410
411
412
413
414 protected void setPreqDocument(InvoiceDocument invoiceDocument) {
415 this.invoiceDocument = invoiceDocument;
416 }
417
418
419
420
421
422
423 protected PurApAccountingLine getPreqAccountingLine() {
424 return invoiceAccountingLine;
425 }
426
427
428
429
430
431
432 protected void setPreqAccountingLine(PurApAccountingLine invoiceAccountingLine) {
433 this.invoiceAccountingLine = invoiceAccountingLine;
434 }
435
436 }