1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.ole.fp.document.service.impl;
17
18 import java.math.BigDecimal;
19 import java.util.ArrayList;
20 import java.util.Arrays;
21 import java.util.Collection;
22 import java.util.HashMap;
23 import java.util.Iterator;
24 import java.util.List;
25 import java.util.Map;
26
27 import org.apache.commons.lang.StringUtils;
28 import org.kuali.ole.fp.businessobject.DisbursementVoucherNonResidentAlienTax;
29 import org.kuali.ole.fp.businessobject.NonResidentAlienTaxPercent;
30 import org.kuali.ole.fp.document.DisbursementVoucherConstants;
31 import org.kuali.ole.fp.document.DisbursementVoucherDocument;
32 import org.kuali.ole.fp.document.service.DisbursementVoucherTaxService;
33 import org.kuali.ole.fp.document.validation.impl.DisbursementVoucherNonResidentAlienInformationValidation;
34 import org.kuali.ole.sys.OLEConstants;
35 import org.kuali.ole.sys.OLEKeyConstants;
36 import org.kuali.ole.sys.OLEPropertyConstants;
37 import org.kuali.ole.sys.businessobject.AccountingLine;
38 import org.kuali.ole.sys.businessobject.SourceAccountingLine;
39 import org.kuali.ole.sys.context.SpringContext;
40 import org.kuali.ole.vnd.businessobject.VendorDetail;
41 import org.kuali.rice.core.api.util.type.KualiDecimal;
42 import org.kuali.rice.coreservice.framework.parameter.ParameterService;
43 import org.kuali.rice.kim.api.identity.Person;
44 import org.kuali.rice.kim.api.identity.PersonService;
45 import org.kuali.rice.krad.bo.PersistableBusinessObject;
46 import org.kuali.rice.krad.service.BusinessObjectService;
47 import org.kuali.rice.krad.service.MaintenanceDocumentService;
48 import org.kuali.rice.krad.util.GlobalVariables;
49 import org.kuali.rice.krad.util.MessageMap;
50
51
52
53
54
55 public class DisbursementVoucherTaxServiceImpl implements DisbursementVoucherTaxService, DisbursementVoucherConstants {
56 private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(DisbursementVoucherTaxServiceImpl.class);
57
58 private ParameterService parameterService;
59 private BusinessObjectService businessObjectService;
60 private MaintenanceDocumentService maintenanceDocumentService;
61
62
63
64
65
66
67
68
69
70
71
72
73 public String getUniversalId(String taxIDNumber, String taxPayerTypeCode) {
74 if (TAX_TYPE_FEIN.equals(taxPayerTypeCode)) {
75 return null;
76 }
77
78 Person person = (Person) SpringContext.getBean(PersonService.class).getPersonByExternalIdentifier(org.kuali.rice.kim.api.KimConstants.PersonExternalIdentifierTypes.TAX, taxIDNumber).get(0);
79
80 String universalId = null;
81 if (person != null) {
82 universalId = person.getPrincipalId();
83 }
84 return universalId;
85 }
86
87
88
89
90
91
92
93
94
95
96
97
98 public String getVendorId(String taxIDNumber, String taxPayerTypeCode) {
99 String vendorId = null;
100
101 Map taxIDCrit = new HashMap();
102 taxIDCrit.put("taxIdNumber", taxIDNumber);
103 taxIDCrit.put("taxpayerTypeCode", taxPayerTypeCode);
104 Collection<VendorDetail> foundPayees = businessObjectService.findMatching(VendorDetail.class, taxIDCrit);
105
106 if (!foundPayees.isEmpty()) {
107 VendorDetail vendor = (VendorDetail) foundPayees.iterator().next();
108 vendorId = vendor.getVendorHeaderGeneratedIdentifier().toString();
109 }
110
111 return vendorId;
112 }
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135 protected void generateNRATaxLines(DisbursementVoucherDocument document) {
136
137 AccountingLine line1 = document.getSourceAccountingLine(0);
138
139 List taxLineNumbers = new ArrayList();
140
141
142 if (document.getDvNonResidentAlienTax().isIncomeTaxGrossUpCode()) {
143 AccountingLine grossLine = null;
144 try {
145 grossLine = (SourceAccountingLine) document.getSourceAccountingLineClass().newInstance();
146 }
147 catch (IllegalAccessException e) {
148 throw new IllegalArgumentException("unable to access sourceAccountingLineClass", e);
149 }
150 catch (InstantiationException e) {
151 throw new IllegalArgumentException("unable to instantiate sourceAccountingLineClass", e);
152 }
153
154 grossLine.setDocumentNumber(document.getDocumentNumber());
155 grossLine.setSequenceNumber(document.getNextSourceLineNumber());
156 grossLine.setChartOfAccountsCode(line1.getChartOfAccountsCode());
157 grossLine.setAccountNumber(line1.getAccountNumber());
158 grossLine.setFinancialObjectCode(line1.getFinancialObjectCode());
159
160
161 BigDecimal federalTaxPercent = document.getDvNonResidentAlienTax().getFederalIncomeTaxPercent().bigDecimalValue();
162 BigDecimal stateTaxPercent = document.getDvNonResidentAlienTax().getStateIncomeTaxPercent().bigDecimalValue();
163 BigDecimal documentAmount = document.getDisbVchrCheckTotalAmount().bigDecimalValue();
164
165 KualiDecimal grossAmount1 = new KualiDecimal((documentAmount.multiply(federalTaxPercent).divide(new BigDecimal(100).subtract(federalTaxPercent).subtract(stateTaxPercent), 5, BigDecimal.ROUND_HALF_UP)));
166 KualiDecimal grossAmount2 = new KualiDecimal((documentAmount.multiply(stateTaxPercent).divide(new BigDecimal(100).subtract(federalTaxPercent).subtract(stateTaxPercent), 5, BigDecimal.ROUND_HALF_UP)));
167 grossLine.setAmount(grossAmount1.add(grossAmount2));
168
169
170 taxLineNumbers.add(grossLine.getSequenceNumber());
171 document.setNextSourceLineNumber(new Integer(document.getNextSourceLineNumber().intValue() + 1));
172
173
174 grossLine.refresh();
175 document.getSourceAccountingLines().add(grossLine);
176
177
178 document.setDisbVchrCheckTotalAmount(document.getDisbVchrCheckTotalAmount().add(grossLine.getAmount()));
179 }
180
181 KualiDecimal taxableAmount = document.getDisbVchrCheckTotalAmount();
182
183
184 if (!(KualiDecimal.ZERO.equals(document.getDvNonResidentAlienTax().getFederalIncomeTaxPercent()))) {
185 String federalTaxChart = parameterService.getParameterValueAsString(DisbursementVoucherDocument.class, DisbursementVoucherConstants.FEDERAL_TAX_PARM_PREFIX + DisbursementVoucherConstants.TAX_PARM_CHART_SUFFIX);
186 String federalTaxAccount = parameterService.getParameterValueAsString(DisbursementVoucherDocument.class, DisbursementVoucherConstants.FEDERAL_TAX_PARM_PREFIX + DisbursementVoucherConstants.TAX_PARM_ACCOUNT_SUFFIX);
187 String federalTaxObjectCode = parameterService.getSubParameterValueAsString(DisbursementVoucherDocument.class, DisbursementVoucherConstants.FEDERAL_TAX_PARM_PREFIX + DisbursementVoucherConstants.TAX_PARM_OBJECT_BY_INCOME_CLASS_SUFFIX, document.getDvNonResidentAlienTax().getIncomeClassCode());
188 if (StringUtils.isBlank(federalTaxChart) || StringUtils.isBlank(federalTaxAccount) || StringUtils.isBlank(federalTaxObjectCode)) {
189 LOG.error("Unable to retrieve federal tax parameters.");
190 throw new RuntimeException("Unable to retrieve federal tax parameters.");
191 }
192
193 AccountingLine federalTaxLine = generateTaxAccountingLine(document, federalTaxChart, federalTaxAccount, federalTaxObjectCode, document.getDvNonResidentAlienTax().getFederalIncomeTaxPercent(), taxableAmount);
194
195
196 taxLineNumbers.add(federalTaxLine.getSequenceNumber());
197 document.setNextSourceLineNumber(new Integer(document.getNextSourceLineNumber().intValue() + 1));
198
199
200 federalTaxLine.refresh();
201 document.getSourceAccountingLines().add(federalTaxLine);
202
203
204 document.setDisbVchrCheckTotalAmount(document.getDisbVchrCheckTotalAmount().add(federalTaxLine.getAmount()));
205 }
206
207
208 if (!(KualiDecimal.ZERO.equals(document.getDvNonResidentAlienTax().getStateIncomeTaxPercent()))) {
209 String stateTaxChart = parameterService.getParameterValueAsString(DisbursementVoucherDocument.class, DisbursementVoucherConstants.STATE_TAX_PARM_PREFIX + DisbursementVoucherConstants.TAX_PARM_CHART_SUFFIX);
210 String stateTaxAccount = parameterService.getParameterValueAsString(DisbursementVoucherDocument.class, DisbursementVoucherConstants.STATE_TAX_PARM_PREFIX + DisbursementVoucherConstants.TAX_PARM_ACCOUNT_SUFFIX);
211 String stateTaxObjectCode = parameterService.getSubParameterValueAsString(DisbursementVoucherDocument.class, DisbursementVoucherConstants.STATE_TAX_PARM_PREFIX + DisbursementVoucherConstants.TAX_PARM_OBJECT_BY_INCOME_CLASS_SUFFIX, document.getDvNonResidentAlienTax().getIncomeClassCode());
212
213 if (StringUtils.isBlank(stateTaxChart) || StringUtils.isBlank(stateTaxAccount) || StringUtils.isBlank(stateTaxObjectCode)) {
214 LOG.error("Unable to retrieve state tax parameters.");
215 throw new RuntimeException("Unable to retrieve state tax parameters.");
216 }
217
218 AccountingLine stateTaxLine = generateTaxAccountingLine(document, stateTaxChart, stateTaxAccount, stateTaxObjectCode, document.getDvNonResidentAlienTax().getStateIncomeTaxPercent(), taxableAmount);
219
220
221 taxLineNumbers.add(stateTaxLine.getSequenceNumber());
222 document.setNextSourceLineNumber(new Integer(document.getNextSourceLineNumber().intValue() + 1));
223
224
225 stateTaxLine.refresh();
226 document.getSourceAccountingLines().add(stateTaxLine);
227
228
229 document.setDisbVchrCheckTotalAmount(document.getDisbVchrCheckTotalAmount().add(stateTaxLine.getAmount()));
230 }
231
232
233 document.getDvNonResidentAlienTax().setFinancialDocumentAccountingLineText(StringUtils.join(taxLineNumbers.iterator(), ","));
234 }
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249 protected AccountingLine generateTaxAccountingLine(DisbursementVoucherDocument document, String chart, String account, String objectCode, KualiDecimal taxPercent, KualiDecimal taxableAmount) {
250 AccountingLine taxLine = null;
251 try {
252 taxLine = (SourceAccountingLine) document.getSourceAccountingLineClass().newInstance();
253 }
254 catch (IllegalAccessException e) {
255 throw new IllegalArgumentException("unable to access sourceAccountingLineClass", e);
256 }
257 catch (InstantiationException e) {
258 throw new IllegalArgumentException("unable to instantiate sourceAccountingLineClass", e);
259 }
260
261 taxLine.setDocumentNumber(document.getDocumentNumber());
262 taxLine.setSequenceNumber(document.getNextSourceLineNumber());
263 taxLine.setChartOfAccountsCode(chart);
264 taxLine.setAccountNumber(account);
265 taxLine.setFinancialObjectCode(objectCode);
266
267
268 BigDecimal amount = taxableAmount.bigDecimalValue();
269 BigDecimal tax = taxPercent.bigDecimalValue();
270 BigDecimal taxDecimal = tax.divide(new BigDecimal(100), 5, BigDecimal.ROUND_HALF_UP);
271 KualiDecimal taxAmount = new KualiDecimal(amount.multiply(taxDecimal).setScale(KualiDecimal.SCALE, KualiDecimal.ROUND_BEHAVIOR));
272 taxLine.setAmount(taxAmount.negated());
273
274 return taxLine;
275 }
276
277
278
279
280
281
282
283
284
285
286
287
288 public void processNonResidentAlienTax(DisbursementVoucherDocument document) {
289 if (validateNRATaxInformation(document)) {
290 generateNRATaxLines(document);
291 }
292 }
293
294
295
296
297
298
299 public void clearNRATaxInfo(DisbursementVoucherDocument document) {
300
301 document.getDvNonResidentAlienTax().setIncomeClassCode(null);
302 document.getDvNonResidentAlienTax().setFederalIncomeTaxPercent(null);
303 document.getDvNonResidentAlienTax().setStateIncomeTaxPercent(null);
304 document.getDvNonResidentAlienTax().setPostalCountryCode(null);
305 document.getDvNonResidentAlienTax().setTaxNQIId(null);
306 document.getDvNonResidentAlienTax().setReferenceFinancialDocumentNumber(null);
307 document.getDvNonResidentAlienTax().setForeignSourceIncomeCode(false);
308 document.getDvNonResidentAlienTax().setIncomeTaxTreatyExemptCode(false);
309 document.getDvNonResidentAlienTax().setTaxOtherExemptIndicator(false);
310 document.getDvNonResidentAlienTax().setIncomeTaxGrossUpCode(false);
311 document.getDvNonResidentAlienTax().setTaxUSAIDPerDiemIndicator(false);
312 document.getDvNonResidentAlienTax().setTaxSpecialW4Amount(null);
313
314 clearNRATaxLines(document);
315
316 }
317
318
319
320
321
322
323 public void clearNRATaxLines(DisbursementVoucherDocument document) {
324 ArrayList<SourceAccountingLine> taxLines = new ArrayList<SourceAccountingLine>();
325 KualiDecimal taxTotal = KualiDecimal.ZERO;
326
327 DisbursementVoucherNonResidentAlienTax dvnrat = document.getDvNonResidentAlienTax();
328 if (dvnrat != null) {
329 List<Integer> previousTaxLineNumbers = getNRATaxLineNumbers(dvnrat.getFinancialDocumentAccountingLineText());
330
331
332 boolean previousGrossUp = false;
333 List<SourceAccountingLine> srcLines = document.getSourceAccountingLines();
334 for (SourceAccountingLine line : srcLines) {
335 if (previousTaxLineNumbers.contains(line.getSequenceNumber())) {
336 taxLines.add(line);
337
338
339 if ((KualiDecimal.ZERO).compareTo(line.getAmount()) < 0) {
340 previousGrossUp = true;
341 }
342 else {
343 taxTotal = taxTotal.add(line.getAmount().abs());
344 }
345 }
346 }
347
348
349
350
351
352
353
354 Iterator<SourceAccountingLine> saLineIter = document.getSourceAccountingLines().iterator();
355 while(saLineIter.hasNext()) {
356 SourceAccountingLine saLine = saLineIter.next();
357 for(SourceAccountingLine taxLine : taxLines) {
358 if(saLine.equals(taxLine)) {
359 if(saLine.getAmount().equals(taxLine.getAmount())) {
360 saLineIter.remove();
361 }
362 }
363 }
364 }
365
366
367 if (!previousGrossUp) {
368 document.setDisbVchrCheckTotalAmount(document.getDisbVchrCheckTotalAmount().add(taxTotal));
369 }
370
371
372 dvnrat.setFinancialDocumentAccountingLineText("");
373 }
374 }
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389 public KualiDecimal getNonResidentAlienTaxAmount(DisbursementVoucherDocument document) {
390 KualiDecimal taxAmount = KualiDecimal.ZERO;
391
392
393 if (!document.getDvPayeeDetail().isDisbVchrAlienPaymentCode() || (document.getDvPayeeDetail().isDisbVchrAlienPaymentCode() && document.getDvNonResidentAlienTax().isIncomeTaxGrossUpCode())) {
394 return taxAmount;
395 }
396
397
398 List taxLineNumbers = getNRATaxLineNumbers(document.getDvNonResidentAlienTax().getFinancialDocumentAccountingLineText());
399
400 for (Iterator iter = document.getSourceAccountingLines().iterator(); iter.hasNext();) {
401 SourceAccountingLine line = (SourceAccountingLine) iter.next();
402
403
404 if (taxLineNumbers.contains(line.getSequenceNumber())) {
405 taxAmount = taxAmount.add(line.getAmount().negated());
406 }
407 }
408
409 return taxAmount;
410 }
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434 protected boolean validateNRATaxInformation(DisbursementVoucherDocument document) {
435 MessageMap errors = GlobalVariables.getMessageMap();
436
437 DisbursementVoucherNonResidentAlienInformationValidation dvNRA = new DisbursementVoucherNonResidentAlienInformationValidation();
438 dvNRA.setAccountingDocumentForValidation(document);
439 dvNRA.setValidationType("GENERATE");
440
441 if(!dvNRA.validate(null)) {
442 return false;
443 }
444
445 if (GlobalVariables.getMessageMap().hasErrors()) {
446 return false;
447 }
448
449
450 if (!document.getDvPayeeDetail().isDisbVchrAlienPaymentCode()) {
451 errors.putErrorWithoutFullErrorPath("DVNRATaxErrors", OLEKeyConstants.ERROR_DV_GENERATE_TAX_NOT_NRA);
452 return false;
453 }
454
455
456 if (StringUtils.isNotBlank(document.getDvNonResidentAlienTax().getReferenceFinancialDocumentNumber())) {
457 errors.putErrorWithoutFullErrorPath("DVNRATaxErrors", OLEKeyConstants.ERROR_DV_GENERATE_TAX_DOC_REFERENCE);
458 return false;
459 }
460
461
462
463 if (!(document.getSourceAccountingLines().size() >= 1)) {
464 errors.putErrorWithoutFullErrorPath("DVNRATaxErrors", OLEKeyConstants.ERROR_DV_GENERATE_TAX_NO_SOURCE);
465 return false;
466 }
467
468
469 if (KualiDecimal.ZERO.equals(document.getDvNonResidentAlienTax().getFederalIncomeTaxPercent()) && KualiDecimal.ZERO.equals(document.getDvNonResidentAlienTax().getStateIncomeTaxPercent())) {
470 errors.putErrorWithoutFullErrorPath("DVNRATaxErrors", OLEKeyConstants.ERROR_DV_GENERATE_TAX_BOTH_0);
471 return false;
472 }
473
474
475 if (KualiDecimal.ZERO.compareTo(document.getDisbVchrCheckTotalAmount()) == 1) {
476 errors.putErrorWithoutFullErrorPath("document.disbVchrCheckTotalAmount", OLEKeyConstants.ERROR_NEGATIVE_OR_ZERO_CHECK_TOTAL);
477 return false;
478 }
479
480
481 if (KualiDecimal.ZERO.compareTo(document.getSourceTotal()) == 1) {
482 errors.putErrorWithoutFullErrorPath(OLEConstants.ACCOUNTING_LINE_ERRORS, OLEKeyConstants.ERROR_NEGATIVE_ACCOUNTING_TOTAL);
483 return false;
484 }
485
486
487 if (document.getDisbVchrCheckTotalAmount().compareTo(document.getSourceTotal()) != 0) {
488 errors.putErrorWithoutFullErrorPath(OLEConstants.ACCOUNTING_LINE_ERRORS, OLEKeyConstants.ERROR_CHECK_ACCOUNTING_TOTAL);
489 return false;
490 }
491
492 return true;
493 }
494
495
496
497
498
499
500
501 public List<Integer> getNRATaxLineNumbers(String taxLineString) {
502 List<Integer> taxLineNumbers = new ArrayList();
503 if (StringUtils.isNotBlank(taxLineString)) {
504 List<String> taxLineNumberStrings = Arrays.asList(StringUtils.split(taxLineString, ","));
505 for (String lineNumber : taxLineNumberStrings) {
506 taxLineNumbers.add(Integer.valueOf(lineNumber));
507 }
508 }
509
510 return taxLineNumbers;
511 }
512
513
514
515
516
517 public void setParameterService(ParameterService parameterService) {
518 this.parameterService = parameterService;
519 }
520
521
522
523
524
525 public BusinessObjectService getBusinessObjectService() {
526 return businessObjectService;
527 }
528
529
530
531
532
533 public void setBusinessObjectService(BusinessObjectService businessObjectService) {
534 this.businessObjectService = businessObjectService;
535 }
536
537
538
539
540
541 public MaintenanceDocumentService getMaintenanceDocumentService() {
542 return maintenanceDocumentService;
543 }
544
545
546
547
548
549 public void setMaintenanceDocumentService(MaintenanceDocumentService maintenanceDocumentService) {
550 this.maintenanceDocumentService = maintenanceDocumentService;
551 }
552 }
553