001: /*
002: * Copyright 2006-2007 The Kuali Foundation.
003: *
004: * Licensed under the Educational Community License, Version 1.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/ecl1.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.module.financial.service.impl;
017:
018: import java.math.BigDecimal;
019: import java.util.ArrayList;
020: import java.util.Arrays;
021: import java.util.Collection;
022: import java.util.HashMap;
023: import java.util.Iterator;
024: import java.util.List;
025: import java.util.Map;
026:
027: import org.apache.commons.lang.StringUtils;
028: import org.kuali.core.bo.user.PersonTaxId;
029: import org.kuali.core.bo.user.UniversalUser;
030: import org.kuali.core.bo.user.UserId;
031: import org.kuali.core.exceptions.InfrastructureException;
032: import org.kuali.core.exceptions.UserNotFoundException;
033: import org.kuali.core.service.BusinessObjectService;
034: import org.kuali.core.service.MaintenanceDocumentService;
035: import org.kuali.core.service.UniversalUserService;
036: import org.kuali.core.util.ErrorMap;
037: import org.kuali.core.util.GlobalVariables;
038: import org.kuali.core.util.KualiDecimal;
039: import org.kuali.kfs.KFSConstants;
040: import org.kuali.kfs.KFSKeyConstants;
041: import org.kuali.kfs.bo.AccountingLine;
042: import org.kuali.kfs.bo.SourceAccountingLine;
043: import org.kuali.kfs.service.ParameterService;
044: import org.kuali.module.financial.bo.DisbursementVoucherNonResidentAlienTax;
045: import org.kuali.module.financial.bo.Payee;
046: import org.kuali.module.financial.document.DisbursementVoucherDocument;
047: import org.kuali.module.financial.rules.DisbursementVoucherDocumentRule;
048: import org.kuali.module.financial.rules.DisbursementVoucherRuleConstants;
049: import org.kuali.module.financial.service.DisbursementVoucherTaxService;
050:
051: /**
052: * This is the default implementation of the DisbursementVoucherExtractService interface.
053: * This class handles queries and validation on tax id numbers.
054: */
055: public class DisbursementVoucherTaxServiceImpl implements
056: DisbursementVoucherTaxService, DisbursementVoucherRuleConstants {
057: private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger
058: .getLogger(DisbursementVoucherTaxServiceImpl.class);
059:
060: private ParameterService parameterService;
061: private BusinessObjectService businessObjectService;
062: private MaintenanceDocumentService maintenanceDocumentService;
063: private UniversalUserService universalUserService;
064:
065: /**
066: * This method retrieves the universal id of the individual or business entity who matches the tax id number and type
067: * code given.
068: *
069: * @param taxIDNumber The tax identification number of the user being retrieved.
070: * @param taxPayerTypeCode The tax payer type code of the user being retrieved. See the TAX_TYPE_* constants defined in
071: * DisbursementVoucherRuleConstants for examples of valid tax type codes.
072: * @return The universal id of the individual who matches the tax id and type code given. Null if no matching user is found.
073: *
074: * @see org.kuali.module.financial.service.DisbursementVoucherTaxService#getEmployeeNumber(java.lang.String, java.lang.String)
075: */
076: public String getUniversalId(String taxIDNumber,
077: String taxPayerTypeCode) {
078: if (TAX_TYPE_FEIN.equals(taxPayerTypeCode)) {
079: return null;
080: }
081:
082: String universalId = null;
083: UserId userId = (UserId) new PersonTaxId(taxIDNumber);
084: UniversalUser universalUser = null;
085:
086: try {
087: universalUser = universalUserService
088: .getUniversalUser(userId);
089: } catch (UserNotFoundException e) {
090: }
091:
092: if (universalUser != null) {
093: universalId = universalUser.getPersonUniversalIdentifier();
094: }
095: return universalId;
096: }
097:
098: /**
099: * This method retrieves the payee identification code for the payee found who has a matching tax id and tax payer type
100: * code.
101: *
102: * @param taxIDNumber The tax id number used to retrieve the associated payee.
103: * @param taxPayerTypeCode The tax payer type code used to retrieve the associated payee. See the TAX_TYPE_* constants defined in
104: * DisbursementVoucherRuleConstants for examples of valid tax type codes.
105: * @return The id of the payee found matching the tax id and type code provided. Null if no matching payee is found.
106: *
107: * @see org.kuali.module.financial.service.DisbursementVoucherTaxService#getPayeeNumber(java.lang.String, java.lang.String)
108: */
109: public String getPayeeId(String taxIDNumber, String taxPayerTypeCode) {
110: String payeeId = null;
111:
112: Map taxIDCrit = new HashMap();
113: taxIDCrit.put("taxIdNumber", taxIDNumber);
114: taxIDCrit.put("taxpayerTypeCode", taxPayerTypeCode);
115: Collection<Payee> foundPayees = businessObjectService
116: .findMatching(Payee.class, taxIDCrit);
117:
118: if (!foundPayees.isEmpty()) {
119: Payee payee = (Payee) foundPayees.iterator().next();
120: payeeId = payee.getPayeeIdNumber();
121: }
122:
123: return payeeId;
124: }
125:
126: /**
127: * This method is not currently implemented. This method will be implemented once the EPIC vendor system in integrated
128: * into Kuali. Until then, this method will always return null and should not be used.
129: *
130: * @param taxIDNumber The tax id number used to retrieve the associated vendor.
131: * @param taxPayerTypeCode The tax payer type code used to retrieve the associated vendor.
132: * @return Always returns null.
133: *
134: * @see org.kuali.module.financial.service.DisbursementVoucherTaxService#getVendorNumber(java.lang.String, java.lang.String)
135: * @deprecated This method is not currently implemented and should not be called until it is fully implemented.
136: */
137: public String getVendorId(String taxIDNumber,
138: String taxPayerTypeCode) {
139: String vendorId = null;
140: // TODO: implement once EPIC is integrated
141: return vendorId;
142: }
143:
144: /**
145: * This method retrieves the pending payee id based on the tax id and payer type code provided.
146: *
147: * @param taxIDNumber The tax id number used to retrieve the matching pending payee.
148: * @param taxPayerTypeCode The tax payer type code used to retrieve the matching pending payee.
149: * @return The id of the pending payee matching the values given or null if no matching payee is found.
150: *
151: * @see org.kuali.module.financial.service.DisbursementVoucherTaxService#getPendingPayeeNumber(java.lang.String, java.lang.String)
152: * @see org.kuali.core.service.MaintenanceDocumentService#getPendingObjects(Class)
153: */
154: public String getPendingPayeeId(String taxIDNumber,
155: String taxPayerTypeCode) {
156: String pendingPayeeId = null;
157:
158: List<Payee> pendingPayees = maintenanceDocumentService
159: .getPendingObjects(Payee.class);
160:
161: for (Payee pendingPayee : pendingPayees) {
162: if (taxIDNumber.equals(pendingPayee.getTaxIdNumber())
163: && taxPayerTypeCode.equals(pendingPayee
164: .getTaxpayerTypeCode())) {
165: pendingPayeeId = pendingPayee.getPayeeIdNumber();
166: }
167: }
168:
169: return pendingPayeeId;
170: }
171:
172: /**
173: * This method generates non-resident alien (NRA) tax lines for the given disbursement voucher.
174: *
175: * The NRA tax lines consist of three possible sets of tax lines:
176: * - Gross up tax lines
177: * - Federal tax lines
178: * - State tax lines
179: *
180: * Gross up tax lines are generated if the income tax gross up code is set on the DisbursementVoucherNonResidentAlienTax
181: * attribute of the disbursement voucher.
182: *
183: * Federal tax lines are generated if the federal tax rate in the DisbursementVoucherNonResidentAlienTax attribute is
184: * other than zero.
185: *
186: * State tax lines are generated if the state tax rate in the DisbursementVoucherNonResidentAlienTax attribute is
187: * other than zero.
188: *
189: * @param document The disbursement voucher the NRA tax lines will be added to.
190: *
191: * @see org.kuali.module.financial.service.DisbursementVoucherTaxService#generateNRATaxLines(org.kuali.module.financial.document.DisbursementVoucherDocument)
192: */
193: private void generateNRATaxLines(
194: DisbursementVoucherDocument document) {
195: // retrieve first accounting line for tax line attributes
196: AccountingLine line1 = document.getSourceAccountingLine(0);
197:
198: List taxLineNumbers = new ArrayList();
199:
200: // generate gross up
201: if (document.getDvNonResidentAlienTax()
202: .isIncomeTaxGrossUpCode()) {
203: AccountingLine grossLine = null;
204: try {
205: grossLine = (SourceAccountingLine) document
206: .getSourceAccountingLineClass().newInstance();
207: } catch (IllegalAccessException e) {
208: throw new InfrastructureException(
209: "unable to access sourceAccountingLineClass", e);
210: } catch (InstantiationException e) {
211: throw new InfrastructureException(
212: "unable to instantiate sourceAccountingLineClass",
213: e);
214: }
215:
216: grossLine.setDocumentNumber(document.getDocumentNumber());
217: grossLine.setSequenceNumber(document
218: .getNextSourceLineNumber());
219: grossLine.setChartOfAccountsCode(line1
220: .getChartOfAccountsCode());
221: grossLine.setAccountNumber(line1.getAccountNumber());
222: grossLine.setFinancialObjectCode(line1
223: .getFinancialObjectCode());
224:
225: // calculate gross up amount and set as line amount
226: BigDecimal federalTaxPercent = document
227: .getDvNonResidentAlienTax()
228: .getFederalIncomeTaxPercent().bigDecimalValue();
229: BigDecimal stateTaxPercent = document
230: .getDvNonResidentAlienTax()
231: .getStateIncomeTaxPercent().bigDecimalValue();
232: BigDecimal documentAmount = document
233: .getDisbVchrCheckTotalAmount().bigDecimalValue();
234:
235: KualiDecimal grossAmount1 = new KualiDecimal(
236: (documentAmount.multiply(federalTaxPercent).divide(
237: new BigDecimal(100).subtract(
238: federalTaxPercent).subtract(
239: stateTaxPercent), 5,
240: BigDecimal.ROUND_HALF_UP)));
241: KualiDecimal grossAmount2 = new KualiDecimal(
242: (documentAmount.multiply(stateTaxPercent).divide(
243: new BigDecimal(100).subtract(
244: federalTaxPercent).subtract(
245: stateTaxPercent), 5,
246: BigDecimal.ROUND_HALF_UP)));
247: grossLine.setAmount(grossAmount1.add(grossAmount2));
248:
249: // put line number in line number list, and update next line property in document
250: taxLineNumbers.add(grossLine.getSequenceNumber());
251: document.setNextSourceLineNumber(new Integer(document
252: .getNextSourceLineNumber().intValue() + 1));
253:
254: // add to source accounting lines
255: grossLine.refresh();
256: document.getSourceAccountingLines().add(grossLine);
257:
258: // update check total, is added because line amount is negative, so this will take check amount down
259: document.setDisbVchrCheckTotalAmount(document
260: .getDisbVchrCheckTotalAmount().add(
261: grossLine.getAmount()));
262: }
263:
264: KualiDecimal taxableAmount = document
265: .getDisbVchrCheckTotalAmount();
266:
267: // generate federal tax line
268: if (!(KualiDecimal.ZERO.equals(document
269: .getDvNonResidentAlienTax()
270: .getFederalIncomeTaxPercent()))) {
271: String federalTaxChart = parameterService
272: .getParameterValue(
273: DisbursementVoucherDocument.class,
274: DisbursementVoucherRuleConstants.FEDERAL_TAX_PARM_PREFIX
275: + DisbursementVoucherRuleConstants.TAX_PARM_CHART_SUFFIX);
276: String federalTaxAccount = parameterService
277: .getParameterValue(
278: DisbursementVoucherDocument.class,
279: DisbursementVoucherRuleConstants.FEDERAL_TAX_PARM_PREFIX
280: + DisbursementVoucherRuleConstants.TAX_PARM_ACCOUNT_SUFFIX);
281: String federalTaxObjectCode = parameterService
282: .getParameterValue(
283: DisbursementVoucherDocument.class,
284: DisbursementVoucherRuleConstants.FEDERAL_TAX_PARM_PREFIX
285: + DisbursementVoucherRuleConstants.TAX_PARM_OBJECT_BY_INCOME_CLASS_SUFFIX,
286: document.getDvNonResidentAlienTax()
287: .getIncomeClassCode());
288: if (StringUtils.isBlank(federalTaxChart)
289: || StringUtils.isBlank(federalTaxAccount)
290: || StringUtils.isBlank(federalTaxObjectCode)) {
291: LOG.error("Unable to retrieve federal tax parameters.");
292: throw new RuntimeException(
293: "Unable to retrieve federal tax parameters.");
294: }
295:
296: AccountingLine federalTaxLine = generateTaxAccountingLine(
297: document, federalTaxChart, federalTaxAccount,
298: federalTaxObjectCode, document
299: .getDvNonResidentAlienTax()
300: .getFederalIncomeTaxPercent(),
301: taxableAmount);
302:
303: // put line number in line number list, and update next line property in document
304: taxLineNumbers.add(federalTaxLine.getSequenceNumber());
305: document.setNextSourceLineNumber(new Integer(document
306: .getNextSourceLineNumber().intValue() + 1));
307:
308: // add to source accounting lines
309: federalTaxLine.refresh();
310: document.getSourceAccountingLines().add(federalTaxLine);
311:
312: // update check total, is added because line amount is negative, so this will take check amount down
313: document.setDisbVchrCheckTotalAmount(document
314: .getDisbVchrCheckTotalAmount().add(
315: federalTaxLine.getAmount()));
316: }
317:
318: // generate state tax line
319: if (!(KualiDecimal.ZERO.equals(document
320: .getDvNonResidentAlienTax().getStateIncomeTaxPercent()))) {
321: String stateTaxChart = parameterService
322: .getParameterValue(
323: DisbursementVoucherDocument.class,
324: DisbursementVoucherRuleConstants.STATE_TAX_PARM_PREFIX
325: + DisbursementVoucherRuleConstants.TAX_PARM_CHART_SUFFIX);
326: String stateTaxAccount = parameterService
327: .getParameterValue(
328: DisbursementVoucherDocument.class,
329: DisbursementVoucherRuleConstants.STATE_TAX_PARM_PREFIX
330: + DisbursementVoucherRuleConstants.TAX_PARM_ACCOUNT_SUFFIX);
331: String stateTaxObjectCode = parameterService
332: .getParameterValues(
333: DisbursementVoucherDocument.class,
334: DisbursementVoucherRuleConstants.STATE_TAX_PARM_PREFIX
335: + DisbursementVoucherRuleConstants.TAX_PARM_OBJECT_BY_INCOME_CLASS_SUFFIX,
336: document.getDvNonResidentAlienTax()
337: .getIncomeClassCode()).get(0);
338:
339: if (StringUtils.isBlank(stateTaxChart)
340: || StringUtils.isBlank(stateTaxAccount)
341: || StringUtils.isBlank(stateTaxObjectCode)) {
342: LOG.error("Unable to retrieve state tax parameters.");
343: throw new RuntimeException(
344: "Unable to retrieve state tax parameters.");
345: }
346:
347: AccountingLine stateTaxLine = generateTaxAccountingLine(
348: document, stateTaxChart, stateTaxAccount,
349: stateTaxObjectCode, document
350: .getDvNonResidentAlienTax()
351: .getStateIncomeTaxPercent(), taxableAmount);
352:
353: // put line number in line number list, and update next line property in document
354: taxLineNumbers.add(stateTaxLine.getSequenceNumber());
355: document.setNextSourceLineNumber(new Integer(document
356: .getNextSourceLineNumber().intValue() + 1));
357:
358: // add to source accounting lines
359: stateTaxLine.refresh();
360: document.getSourceAccountingLines().add(stateTaxLine);
361:
362: // update check total, is added because line amount is negative, so this will take check amount down
363: document.setDisbVchrCheckTotalAmount(document
364: .getDisbVchrCheckTotalAmount().add(
365: stateTaxLine.getAmount()));
366: }
367:
368: // update line number field
369: document.getDvNonResidentAlienTax()
370: .setFinancialDocumentAccountingLineText(
371: StringUtils
372: .join(taxLineNumbers.iterator(), ","));
373: }
374:
375: /**
376: * Generates an accounting line for the chart, account, object code & tax percentage values given.
377: *
378: * @param document The disbursement voucher the tax will be applied to.
379: * @param chart The chart code to be assigned to the accounting line generated.
380: * @param account The account code to be assigned to the accounting line generated.
381: * @param objectCode The object code used on the accounting line generated.
382: * @param taxPercent The tax rate to be used to calculate the tax amount.
383: * @param taxableAmount The total amount that is taxable. This amount is used in conjunction with the tax percent
384: * to calculate the amount for the accounting lined being generated.
385: * @return A fully populated AccountingLine instance representing the amount of tax that will be applied to the
386: * disbursement voucher provided.
387: */
388: private AccountingLine generateTaxAccountingLine(
389: DisbursementVoucherDocument document, String chart,
390: String account, String objectCode, KualiDecimal taxPercent,
391: KualiDecimal taxableAmount) {
392: AccountingLine taxLine = null;
393: try {
394: taxLine = (SourceAccountingLine) document
395: .getSourceAccountingLineClass().newInstance();
396: } catch (IllegalAccessException e) {
397: throw new InfrastructureException(
398: "unable to access sourceAccountingLineClass", e);
399: } catch (InstantiationException e) {
400: throw new InfrastructureException(
401: "unable to instantiate sourceAccountingLineClass",
402: e);
403: }
404:
405: taxLine.setDocumentNumber(document.getDocumentNumber());
406: taxLine.setSequenceNumber(document.getNextSourceLineNumber());
407: taxLine.setChartOfAccountsCode(chart);
408: taxLine.setAccountNumber(account);
409: taxLine.setFinancialObjectCode(objectCode);
410:
411: // calculate tax amount and set as line amount
412: BigDecimal amount = taxableAmount.bigDecimalValue();
413: BigDecimal tax = taxPercent.bigDecimalValue();
414: BigDecimal taxDecimal = tax.divide(new BigDecimal(100), 5,
415: BigDecimal.ROUND_HALF_UP);
416: KualiDecimal taxAmount = new KualiDecimal(amount
417: .multiply(taxDecimal));
418: taxLine.setAmount(taxAmount.negated());
419:
420: return taxLine;
421: }
422:
423: /**
424: * This method validates the non-resident alien (NRA) tax information for the document and if the information validates,
425: * the NRA tax lines are generated.
426: *
427: * @param document The disbursement voucher document the NRA tax information will be validated and the subsequent
428: * tax lines generated for.
429: *
430: * @see org.kuali.module.financial.service.DisbursementVoucherTaxService#processNonResidentAlienTax(org.kuali.module.financial.document.DisbursementVoucherDocument,
431: * java.util.List)
432: */
433: public void processNonResidentAlienTax(
434: DisbursementVoucherDocument document) {
435: if (validateNRATaxInformation(document)) {
436: generateNRATaxLines(document);
437: }
438: }
439:
440: /**
441: * Removes non-resident alien (NRA) tax lines from the document's accounting lines and updates the check total.
442: *
443: * @param document The disbursement voucher the NRA tax lines will be removed from.
444: */
445: public void clearNRATaxLines(DisbursementVoucherDocument document) {
446: ArrayList<SourceAccountingLine> taxLines = new ArrayList<SourceAccountingLine>();
447: KualiDecimal taxTotal = new KualiDecimal(0);
448:
449: DisbursementVoucherNonResidentAlienTax dvnrat = document
450: .getDvNonResidentAlienTax();
451: if (dvnrat != null) {
452: List<Integer> previousTaxLineNumbers = getNRATaxLineNumbers(dvnrat
453: .getFinancialDocumentAccountingLineText());
454:
455: // get tax lines out of source lines
456: boolean previousGrossUp = false;
457: List<SourceAccountingLine> srcLines = document
458: .getSourceAccountingLines();
459: for (SourceAccountingLine line : srcLines) {
460: if (previousTaxLineNumbers.contains(line
461: .getSequenceNumber())) {
462: taxLines.add(line);
463:
464: // check if tax line was a positive amount, in which case we had a gross up
465: if ((new KualiDecimal(0)).compareTo(line
466: .getAmount()) < 0) {
467: previousGrossUp = true;
468: } else {
469: taxTotal = taxTotal.add(line.getAmount().abs());
470: }
471: }
472: }
473:
474: // remove tax lines
475: /*
476: * NOTE: a custom remove method needed to be used here because the .equals() method for
477: * AccountingLineBase does not take amount into account when determining equality.
478: * This lead to the issues described in KULRNE-6201.
479: */
480: Iterator<SourceAccountingLine> saLineIter = document
481: .getSourceAccountingLines().iterator();
482: while (saLineIter.hasNext()) {
483: SourceAccountingLine saLine = saLineIter.next();
484: for (SourceAccountingLine taxLine : taxLines) {
485: if (saLine.equals(taxLine)) {
486: if (saLine.getAmount().equals(
487: taxLine.getAmount())) {
488: saLineIter.remove();
489: }
490: }
491: }
492: }
493:
494: // update check total if not grossed up
495: if (!previousGrossUp) {
496: document.setDisbVchrCheckTotalAmount(document
497: .getDisbVchrCheckTotalAmount().add(taxTotal));
498: }
499:
500: // clear line string
501: dvnrat.setFinancialDocumentAccountingLineText("");
502: }
503: }
504:
505: /**
506: * This method retrieves the non-resident alien (NRA) tax amount using the disbursement voucher given to calculate the
507: * amount. If the payee is not a non-resident alien or they are and there is no gross up code set, the amount returned
508: * will be zero. If the payee is a non-resident alien and gross up has been set, the amount is calculated by
509: * retrieving all the source accounting lines for the disbursement voucher provided and summing the amounts of all the
510: * lines that are NRA tax lines.
511: *
512: * @param document The disbursement voucher the NRA tax line amount will be calculated for.
513: * @return The NRA tax amount applicable to the given disbursement voucher or zero if the voucher does not have any
514: * NRA tax lines.
515: *
516: * @see org.kuali.module.financial.service.DisbursementVoucherTaxService#getNonResidentAlienTaxAmount(org.kuali.module.financial.document.DisbursementVoucherDocument)
517: */
518: public KualiDecimal getNonResidentAlienTaxAmount(
519: DisbursementVoucherDocument document) {
520: KualiDecimal taxAmount = new KualiDecimal(0);
521:
522: // if not nra payment or gross has been done, no tax amount should have been taken out
523: if (!document.getDvPayeeDetail().isDisbVchrAlienPaymentCode()
524: || (document.getDvPayeeDetail()
525: .isDisbVchrAlienPaymentCode() && document
526: .getDvNonResidentAlienTax()
527: .isIncomeTaxGrossUpCode())) {
528: return taxAmount;
529: }
530:
531: // get tax line numbers
532: List taxLineNumbers = getNRATaxLineNumbers(document
533: .getDvNonResidentAlienTax()
534: .getFinancialDocumentAccountingLineText());
535:
536: for (Iterator iter = document.getSourceAccountingLines()
537: .iterator(); iter.hasNext();) {
538: SourceAccountingLine line = (SourceAccountingLine) iter
539: .next();
540:
541: // check if line is nra tax line
542: if (taxLineNumbers.contains(line.getSequenceNumber())) {
543: taxAmount.add(line.getAmount().negated());
544: }
545: }
546:
547: return taxAmount;
548: }
549:
550: /**
551: * This method performs a series of validation checks to ensure that the disbursement voucher given contains non-resident
552: * alien specific information and non-resident alien tax lines are necessary.
553: *
554: * The following steps are taken to validate the disbursement voucher given:
555: * - Set all percentages (ie. federal, state) to zero if their current value is null.
556: * - Call DisbursementVoucherDocumentRule.validateNonResidentAlienInformation to perform more in-depth validation.
557: * - The payee for the disbursement voucher given is a non-resident alien.
558: * - No reference document exists for the assigned DisbursementVoucherNonResidentAlienTax attribute of the voucher given.
559: * - There is at least one source accounting line to generate the tax line from.
560: * - Both the state and federal tax percentages are greater than zero.
561: * - The total check amount is not negative.
562: * - The total of the accounting lines is not negative.
563: * - The total check amount is equal to the total of the accounting lines.
564: *
565: *
566: * @param document The disbursement voucher document to validate the tax lines for.
567: * @return True if the information associated with non-resident alien tax is correct and valid, false otherwise.
568: *
569: * @see org.kuali.module.financial.service.DisbursementVoucherTaxService#validateNRATaxInformation(org.kuali.module.financial.document.DisbursementVoucherDocument)
570: * @see org.kuali.module.financial.rules.DisbursementVoucherDocumentRule#validateNonResidentAlienInformation(DisbursementVoucherDocument)
571: */
572: private boolean validateNRATaxInformation(
573: DisbursementVoucherDocument document) {
574: ErrorMap errors = GlobalVariables.getErrorMap();
575:
576: // set nulls to 0
577: if (document.getDvNonResidentAlienTax()
578: .getFederalIncomeTaxPercent() == null) {
579: document.getDvNonResidentAlienTax()
580: .setFederalIncomeTaxPercent(new KualiDecimal(0));
581: }
582:
583: if (document.getDvNonResidentAlienTax()
584: .getStateIncomeTaxPercent() == null) {
585: document.getDvNonResidentAlienTax()
586: .setStateIncomeTaxPercent(new KualiDecimal(0));
587: }
588:
589: /* call dv rule to do general nra validation */
590: DisbursementVoucherDocumentRule documentRule = new DisbursementVoucherDocumentRule();
591: documentRule.validateNonResidentAlienInformation(document);
592:
593: if (!GlobalVariables.getErrorMap().isEmpty()) {
594: return false;
595: }
596:
597: /* make sure payee is nra */
598: if (!document.getDvPayeeDetail().isDisbVchrAlienPaymentCode()) {
599: errors.putErrorWithoutFullErrorPath("DVNRATaxErrors",
600: KFSKeyConstants.ERROR_DV_GENERATE_TAX_NOT_NRA);
601: return false;
602: }
603:
604: /* don't generate tax if reference doc is given */
605: if (StringUtils.isNotBlank(document.getDvNonResidentAlienTax()
606: .getReferenceFinancialDocumentNumber())) {
607: errors
608: .putErrorWithoutFullErrorPath(
609: "DVNRATaxErrors",
610: KFSKeyConstants.ERROR_DV_GENERATE_TAX_DOC_REFERENCE);
611: return false;
612: }
613:
614: // check attributes needed to generate lines
615: /* need at least 1 line */
616: if (!(document.getSourceAccountingLines().size() >= 1)) {
617: errors.putErrorWithoutFullErrorPath("DVNRATaxErrors",
618: KFSKeyConstants.ERROR_DV_GENERATE_TAX_NO_SOURCE);
619: return false;
620: }
621:
622: /* make sure both fed and state tax percents are not 0, in which case there is no need to generate lines */
623: if (KualiDecimal.ZERO.equals(document
624: .getDvNonResidentAlienTax()
625: .getFederalIncomeTaxPercent())
626: && KualiDecimal.ZERO.equals(document
627: .getDvNonResidentAlienTax()
628: .getStateIncomeTaxPercent())) {
629: errors.putErrorWithoutFullErrorPath("DVNRATaxErrors",
630: KFSKeyConstants.ERROR_DV_GENERATE_TAX_BOTH_0);
631: return false;
632: }
633:
634: /* check total cannot be negative */
635: if (KFSConstants.ZERO.compareTo(document
636: .getDisbVchrCheckTotalAmount()) == 1) {
637: errors.putErrorWithoutFullErrorPath(
638: "document.disbVchrCheckTotalAmount",
639: KFSKeyConstants.ERROR_NEGATIVE_OR_ZERO_CHECK_TOTAL);
640: return false;
641: }
642:
643: /* total accounting lines cannot be negative */
644: if (KFSConstants.ZERO.compareTo(document.getSourceTotal()) == 1) {
645: errors.putErrorWithoutFullErrorPath(
646: KFSConstants.ACCOUNTING_LINE_ERRORS,
647: KFSKeyConstants.ERROR_NEGATIVE_ACCOUNTING_TOTAL);
648: return false;
649: }
650:
651: /* total of accounting lines must match check total */
652: if (document.getDisbVchrCheckTotalAmount().compareTo(
653: document.getSourceTotal()) != 0) {
654: errors.putErrorWithoutFullErrorPath(
655: KFSConstants.ACCOUNTING_LINE_ERRORS,
656: KFSKeyConstants.ERROR_CHECK_ACCOUNTING_TOTAL);
657: return false;
658: }
659:
660: return true;
661: }
662:
663: /**
664: * Parses the tax line string given and returns a list of line numbers as Integers.
665: *
666: * @param taxLineString The string to be parsed.
667: * @return A collection of line numbers represented as Integers.
668: */
669: public List<Integer> getNRATaxLineNumbers(String taxLineString) {
670: List<Integer> taxLineNumbers = new ArrayList();
671: if (StringUtils.isNotBlank(taxLineString)) {
672: List<String> taxLineNumberStrings = Arrays
673: .asList(StringUtils.split(taxLineString, ","));
674: for (String lineNumber : taxLineNumberStrings) {
675: taxLineNumbers.add(Integer.valueOf(lineNumber));
676: }
677: }
678:
679: return taxLineNumbers;
680: }
681:
682: /**
683: * This method sets the parameterService attribute to the value given.
684: * @param parameterService The ParameterService to be set.
685: */
686: public void setParameterService(ParameterService parameterService) {
687: this .parameterService = parameterService;
688: }
689:
690: /**
691: * Gets the value of the businessObjectService instance.
692: * @return Returns the businessObjectService.
693: */
694: public BusinessObjectService getBusinessObjectService() {
695: return businessObjectService;
696: }
697:
698: /**
699: * This method sets the businessObjectService attribute to the value given.
700: * @param businessObjectService The businessObjectService to set.
701: */
702: public void setBusinessObjectService(
703: BusinessObjectService businessObjectService) {
704: this .businessObjectService = businessObjectService;
705: }
706:
707: /**
708: * Gets the value of the maintenanceDocumentService instance.
709: * @return Returns the maintenanceDocumentService.
710: */
711: public MaintenanceDocumentService getMaintenanceDocumentService() {
712: return maintenanceDocumentService;
713: }
714:
715: /**
716: * This method sets the maintenanceDocumentService attribute to the value given.
717: * @param maintenanceDocumentService The maintenanceDocumentService to set.
718: */
719: public void setMaintenanceDocumentService(
720: MaintenanceDocumentService maintenanceDocumentService) {
721: this .maintenanceDocumentService = maintenanceDocumentService;
722: }
723:
724: /**
725: * Gets the value of the universalUserService instance.
726: * @return Returns the universalUserService.
727: */
728: public UniversalUserService getUniversalUserService() {
729: return universalUserService;
730: }
731:
732: /**
733: * This method sets the universalUserService attribute to the value given.
734: * @param universalUserService The universalUserService to set.
735: */
736: public void setUniversalUserService(
737: UniversalUserService universalUserService) {
738: this.universalUserService = universalUserService;
739: }
740: }
|