View Javadoc
1   /*
2    * Copyright 2006 The Kuali Foundation
3    * 
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    * http://www.opensource.org/licenses/ecl2.php
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
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   * This is the default implementation of the DisbursementVoucherExtractService interface.
53   * This class handles queries and validation on tax id numbers.
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       * This method retrieves the universal id of the individual or business entity who matches the tax id number and type
64       * code given.
65       * 
66       * @param taxIDNumber The tax identification number of the user being retrieved.
67       * @param taxPayerTypeCode The tax payer type code of the user being retrieved.  See the TAX_TYPE_* constants defined in 
68       *                         DisbursementVoucherRuleConstants for examples of valid tax type codes.
69       * @return The universal id of the individual who matches the tax id and type code given.  Null if no matching user is found.
70       * 
71       * @see org.kuali.ole.fp.document.service.DisbursementVoucherTaxService#getEmployeeNumber(java.lang.String, java.lang.String)
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       * This method retrieves the vendor identification code for the vendor found who has a matching tax id and tax payer type 
89       * code.
90       * 
91       * @param taxIDNumber The tax id number used to retrieve the associated vendor.
92       * @param taxPayerTypeCode The tax payer type code used to retrieve the associated vendor.  See the TAX_TYPE_* constants defined in 
93       *                         DisbursementVoucherRuleConstants for examples of valid tax type codes.
94       * @return The id of the vendor found matching the tax id and type code provided.  Null if no matching vendor is found.
95       * 
96       * @see org.kuali.ole.fp.document.service.DisbursementVoucherTaxService#getPayeeNumber(java.lang.String, java.lang.String)
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      * This method generates non-resident alien (NRA) tax lines for the given disbursement voucher.  
116      * 
117      * The NRA tax lines consist of three possible sets of tax lines: 
118      * - Gross up tax lines
119      * - Federal tax lines
120      * - State tax lines
121      * 
122      * Gross up tax lines are generated if the income tax gross up code is set on the DisbursementVoucherNonResidentAlienTax 
123      * attribute of the disbursement voucher.
124      * 
125      * Federal tax lines are generated if the federal tax rate in the DisbursementVoucherNonResidentAlienTax attribute is
126      * other than zero.
127      * 
128      * State tax lines are generated if the state tax rate in the DisbursementVoucherNonResidentAlienTax attribute is
129      * other than zero.
130      * 
131      * @param document The disbursement voucher the NRA tax lines will be added to.
132      * 
133      * @see org.kuali.ole.fp.document.service.DisbursementVoucherTaxService#generateNRATaxLines(org.kuali.ole.fp.document.DisbursementVoucherDocument)
134      */
135     protected void generateNRATaxLines(DisbursementVoucherDocument document) {
136         // retrieve first accounting line for tax line attributes
137         AccountingLine line1 = document.getSourceAccountingLine(0);
138 
139         List taxLineNumbers = new ArrayList();
140 
141         // generate gross up
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             // calculate gross up amount and set as line amount
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             // put line number in line number list, and update next line property in document
170             taxLineNumbers.add(grossLine.getSequenceNumber());
171             document.setNextSourceLineNumber(new Integer(document.getNextSourceLineNumber().intValue() + 1));
172 
173             // add to source accounting lines
174             grossLine.refresh();
175             document.getSourceAccountingLines().add(grossLine);
176 
177             // update check total, is added because line amount is negative, so this will take check amount down
178             document.setDisbVchrCheckTotalAmount(document.getDisbVchrCheckTotalAmount().add(grossLine.getAmount()));
179         }
180 
181         KualiDecimal taxableAmount = document.getDisbVchrCheckTotalAmount();
182 
183         // generate federal tax line
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             // put line number in line number list, and update next line property in document
196             taxLineNumbers.add(federalTaxLine.getSequenceNumber());
197             document.setNextSourceLineNumber(new Integer(document.getNextSourceLineNumber().intValue() + 1));
198 
199             // add to source accounting lines
200             federalTaxLine.refresh();
201             document.getSourceAccountingLines().add(federalTaxLine);
202 
203             // update check total, is added because line amount is negative, so this will take check amount down
204             document.setDisbVchrCheckTotalAmount(document.getDisbVchrCheckTotalAmount().add(federalTaxLine.getAmount()));
205         }
206 
207         // generate state tax line
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             // put line number in line number list, and update next line property in document
221             taxLineNumbers.add(stateTaxLine.getSequenceNumber());
222             document.setNextSourceLineNumber(new Integer(document.getNextSourceLineNumber().intValue() + 1));
223 
224             // add to source accounting lines
225             stateTaxLine.refresh();
226             document.getSourceAccountingLines().add(stateTaxLine);
227 
228             // update check total, is added because line amount is negative, so this will take check amount down
229             document.setDisbVchrCheckTotalAmount(document.getDisbVchrCheckTotalAmount().add(stateTaxLine.getAmount()));
230         }
231 
232         // update line number field
233         document.getDvNonResidentAlienTax().setFinancialDocumentAccountingLineText(StringUtils.join(taxLineNumbers.iterator(), ","));
234     }
235 
236     /**
237      * Generates an accounting line for the chart, account, object code & tax percentage values given.
238      * 
239      * @param document The disbursement voucher the tax will be applied to.
240      * @param chart The chart code to be assigned to the accounting line generated.
241      * @param account The account code to be assigned to the accounting line generated.
242      * @param objectCode The object code used on the accounting line generated.
243      * @param taxPercent The tax rate to be used to calculate the tax amount.
244      * @param taxableAmount The total amount that is taxable.  This amount is used in conjunction with the tax percent
245      *                      to calculate the amount for the accounting lined being generated.
246      * @return A fully populated AccountingLine instance representing the amount of tax that will be applied to the 
247      *         disbursement voucher provided.
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         // calculate tax amount and set as line amount
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      * This method validates the non-resident alien (NRA) tax information for the document and if the information validates, 
280      * the NRA tax lines are generated. 
281      * 
282      * @param document The disbursement voucher document the NRA tax information will be validated and the subsequent 
283      *                 tax lines generated for.
284      * 
285      * @see org.kuali.ole.fp.document.service.DisbursementVoucherTaxService#processNonResidentAlienTax(org.kuali.ole.fp.document.DisbursementVoucherDocument,
286      *      java.util.List)
287      */
288     public void processNonResidentAlienTax(DisbursementVoucherDocument document) {
289         if (validateNRATaxInformation(document)) {
290             generateNRATaxLines(document);
291         }
292     }
293 
294     /**
295      * Removes non-resident alien (NRA) check boxes and sets information to empty values.
296      * 
297      * @param document The disbursement voucher the NRA tax lines will be removed from.
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      * Removes non-resident alien (NRA) tax lines from the document's accounting lines and updates the check total.
320      * 
321      * @param document The disbursement voucher the NRA tax lines will be removed from.
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             // get tax lines out of source lines
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                     // check if tax line was a positive amount, in which case we had a gross up
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             // remove tax lines
349             /*
350              * NOTE: a custom remove method needed to be used here because the .equals() method for 
351              * AccountingLineBase does not take amount into account when determining equality.  
352              * This lead to the issues described in KULRNE-6201.  
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             // update check total if not grossed up
367             if (!previousGrossUp) {
368                 document.setDisbVchrCheckTotalAmount(document.getDisbVchrCheckTotalAmount().add(taxTotal));
369             }
370 
371             // clear line string
372             dvnrat.setFinancialDocumentAccountingLineText("");
373         }
374     }
375 
376     /**
377      * This method retrieves the non-resident alien (NRA) tax amount using the disbursement voucher given to calculate the 
378      * amount.  If the vendor is not a non-resident alien or they are and there is no gross up code set, the amount returned 
379      * will be zero.  If the vendor is a non-resident alien and gross up has been set, the amount is calculated by 
380      * retrieving all the source accounting lines for the disbursement voucher provided and summing the amounts of all the 
381      * lines that are NRA tax lines.  
382      * 
383      * @param document The disbursement voucher the NRA tax line amount will be calculated for.
384      * @return The NRA tax amount applicable to the given disbursement voucher or zero if the voucher does not have any 
385      *         NRA tax lines.
386      * 
387      * @see org.kuali.ole.fp.document.service.DisbursementVoucherTaxService#getNonResidentAlienTaxAmount(org.kuali.ole.fp.document.DisbursementVoucherDocument)
388      */
389     public KualiDecimal getNonResidentAlienTaxAmount(DisbursementVoucherDocument document) {
390         KualiDecimal taxAmount = KualiDecimal.ZERO;
391 
392         // if not nra payment or gross has been done, no tax amount should have been taken out
393         if (!document.getDvPayeeDetail().isDisbVchrAlienPaymentCode() || (document.getDvPayeeDetail().isDisbVchrAlienPaymentCode() && document.getDvNonResidentAlienTax().isIncomeTaxGrossUpCode())) {
394             return taxAmount;
395         }
396 
397         // get tax line numbers
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             // check if line is nra tax line
404             if (taxLineNumbers.contains(line.getSequenceNumber())) {
405                 taxAmount = taxAmount.add(line.getAmount().negated());
406             }
407         }
408 
409         return taxAmount;
410     }
411 
412     /**
413      * This method performs a series of validation checks to ensure that the disbursement voucher given contains non-resident
414      * alien specific information and non-resident alien tax lines are necessary.  
415      * 
416      * The following steps are taken to validate the disbursement voucher given:
417      * - Set all percentages (ie. federal, state) to zero if their current value is null.
418      * - Call DisbursementVoucherDocumentRule.validateNonResidentAlienInformation to perform more in-depth validation.
419      * - The vendor for the disbursement voucher given is a non-resident alien.
420      * - No reference document exists for the assigned DisbursementVoucherNonResidentAlienTax attribute of the voucher given.
421      * - There is at least one source accounting line to generate the tax line from.
422      * - Both the state and federal tax percentages are greater than zero.
423      * - The total check amount is not negative.
424      * - The total of the accounting lines is not negative.
425      * - The total check amount is equal to the total of the accounting lines.
426      * 
427      * 
428      * @param document The disbursement voucher document to validate the tax lines for.
429      * @return True if the information associated with non-resident alien tax is correct and valid, false otherwise.
430      * 
431      * @see org.kuali.ole.fp.document.service.DisbursementVoucherTaxService#validateNRATaxInformation(org.kuali.ole.fp.document.DisbursementVoucherDocument)
432      * @see org.kuali.ole.fp.document.validation.impl.DisbursementVoucherDocumentRule#validateNonResidentAlienInformation(DisbursementVoucherDocument)
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         /* make sure vendor is nra */
450         if (!document.getDvPayeeDetail().isDisbVchrAlienPaymentCode()) {
451             errors.putErrorWithoutFullErrorPath("DVNRATaxErrors", OLEKeyConstants.ERROR_DV_GENERATE_TAX_NOT_NRA);
452             return false;
453         }
454 
455         /* don't generate tax if reference doc is given */
456         if (StringUtils.isNotBlank(document.getDvNonResidentAlienTax().getReferenceFinancialDocumentNumber())) {
457             errors.putErrorWithoutFullErrorPath("DVNRATaxErrors", OLEKeyConstants.ERROR_DV_GENERATE_TAX_DOC_REFERENCE);
458             return false;
459         }
460 
461         // check attributes needed to generate lines
462         /* need at least 1 line */
463         if (!(document.getSourceAccountingLines().size() >= 1)) {
464             errors.putErrorWithoutFullErrorPath("DVNRATaxErrors", OLEKeyConstants.ERROR_DV_GENERATE_TAX_NO_SOURCE);
465             return false;
466         }
467 
468         /* make sure both fed and state tax percents are not 0, in which case there is no need to generate lines */
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         /* check total cannot be negative */
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         /* total accounting lines cannot be negative */
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         /* total of accounting lines must match check total */
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      * Parses the tax line string given and returns a list of line numbers as Integers.
497      * 
498      * @param taxLineString The string to be parsed.
499      * @return A collection of line numbers represented as Integers.
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      * This method sets the parameterService attribute to the value given.
515      * @param parameterService The ParameterService to be set.
516      */
517     public void setParameterService(ParameterService parameterService) {
518         this.parameterService = parameterService;
519     }
520 
521     /**
522      * Gets the value of the businessObjectService instance.
523      * @return Returns the businessObjectService.
524      */
525     public BusinessObjectService getBusinessObjectService() {
526         return businessObjectService;
527     }
528 
529     /**
530      * This method sets the businessObjectService attribute to the value given.
531      * @param businessObjectService The businessObjectService to set.
532      */
533     public void setBusinessObjectService(BusinessObjectService businessObjectService) {
534         this.businessObjectService = businessObjectService;
535     }
536 
537     /**
538      * Gets the value of the maintenanceDocumentService instance.
539      * @return Returns the maintenanceDocumentService.
540      */
541     public MaintenanceDocumentService getMaintenanceDocumentService() {
542         return maintenanceDocumentService;
543     }
544 
545     /**
546      * This method sets the maintenanceDocumentService attribute to the value given.
547      * @param maintenanceDocumentService The maintenanceDocumentService to set.
548      */
549     public void setMaintenanceDocumentService(MaintenanceDocumentService maintenanceDocumentService) {
550         this.maintenanceDocumentService = maintenanceDocumentService;
551     }
552 }
553