View Javadoc
1   /*
2    * Copyright 2008 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.sys.service.impl;
17  
18  import java.math.BigDecimal;
19  import java.sql.Date;
20  import java.util.ArrayList;
21  import java.util.List;
22  
23  import org.apache.commons.lang.StringUtils;
24  import org.kuali.ole.fp.businessobject.SalesTax;
25  import org.kuali.ole.sys.businessobject.TaxDetail;
26  import org.kuali.ole.sys.businessobject.TaxRegion;
27  import org.kuali.ole.sys.service.TaxRegionService;
28  import org.kuali.ole.sys.service.TaxService;
29  import org.kuali.rice.core.api.util.type.KualiDecimal;
30  import org.kuali.rice.coreservice.framework.parameter.ParameterService;
31  import org.kuali.rice.krad.util.ObjectUtils;
32  import org.springframework.transaction.annotation.Transactional;
33  
34  @Transactional
35  public class TaxServiceImpl implements TaxService {
36  
37      protected static final String POSTAL_CODE_DIGITS_PASSED_TO_SALES_TAX_REGION_SERVICE = "POSTAL_CODE_DIGITS_PASSED_TO_SALES_TAX_REGION_SERVICE";
38      
39      protected TaxRegionService taxRegionService;
40      protected ParameterService parameterService;
41      
42      /**
43       * @see org.kuali.ole.sys.service.TaxService#getSalesTaxDetails(java.lang.String, java.lang.String,
44       *      org.kuali.rice.core.api.util.type.KualiDecimal)
45       */
46      @Override
47      public List<TaxDetail> getSalesTaxDetails(Date dateOfTransaction, String postalCode, KualiDecimal amount) {
48          List<TaxDetail> salesTaxDetails = new ArrayList<TaxDetail>();
49  
50          if (StringUtils.isNotEmpty(postalCode)) {
51              List<TaxRegion> salesTaxRegions = taxRegionService.getSalesTaxRegions(postalCode);
52              TaxDetail newTaxDetail = null;
53              for (TaxRegion taxRegion : salesTaxRegions) {
54                  if (taxRegion.isActive()) {
55                      newTaxDetail = populateTaxDetail(taxRegion, dateOfTransaction, amount);
56                      salesTaxDetails.add(newTaxDetail);
57                  }
58              }
59          }
60  
61          return salesTaxDetails;
62      }
63  
64      /**
65       * @see org.kuali.ole.sys.service.TaxService#getUseTaxDetails(java.lang.String, java.lang.String,
66       *      org.kuali.rice.core.api.util.type.KualiDecimal)
67       */
68      @Override
69      public List<TaxDetail> getUseTaxDetails(Date dateOfTransaction, String postalCode, KualiDecimal amount) {
70          List<TaxDetail> useTaxDetails = new ArrayList<TaxDetail>();
71  
72          if (StringUtils.isNotEmpty(postalCode)) {
73              //  strip digits from the postal code before passing it to the sales tax regions 
74              // if the parameters indicate to do so.
75              postalCode = truncatePostalCodeForSalesTaxRegionService(postalCode);
76              
77              for (TaxRegion taxRegion : taxRegionService.getUseTaxRegions(postalCode)) {
78                  useTaxDetails.add(populateTaxDetail(taxRegion, dateOfTransaction, amount));
79              }
80          }
81  
82          return useTaxDetails;
83      }
84  
85      /**
86       * @see org.kuali.ole.sys.service.TaxService#getTotalSalesTaxAmount(java.lang.String, java.lang.String,
87       *      org.kuali.rice.core.api.util.type.KualiDecimal)
88       */
89      @Override
90      public KualiDecimal getTotalSalesTaxAmount(Date dateOfTransaction, String postalCode, KualiDecimal amount) {
91          KualiDecimal totalSalesTaxAmount = KualiDecimal.ZERO;
92  
93          if (StringUtils.isNotEmpty(postalCode)) {
94  
95              //  strip digits from the postal code before passing it to the sales tax regions 
96              // if the parameters indicate to do so.
97              postalCode = truncatePostalCodeForSalesTaxRegionService(postalCode);
98              
99              List<TaxDetail> salesTaxDetails = getSalesTaxDetails(dateOfTransaction, postalCode, amount);
100             KualiDecimal newTaxAmount = KualiDecimal.ZERO;
101             for (TaxDetail taxDetail : salesTaxDetails) {
102                 newTaxAmount = taxDetail.getTaxAmount();
103                 totalSalesTaxAmount = totalSalesTaxAmount.add(newTaxAmount);
104             }
105         }
106 
107         return totalSalesTaxAmount;
108     }
109 
110     /**
111      * This method returns a preTax amount
112      * 
113      * @param dateOfTransaction
114      * @param postalCode
115      * @param amountWithTax
116      * @return
117      */
118 
119     @Override
120     public KualiDecimal getPretaxAmount(Date dateOfTransaction, String postalCode, KualiDecimal amountWithTax) {
121         BigDecimal totalTaxRate = BigDecimal.ZERO;
122 
123         // there is not tax amount
124         if (StringUtils.isEmpty(postalCode))
125             return amountWithTax;
126 
127         //  strip digits from the postal code before passing it to the sales tax regions 
128         // if the parameters indicate to do so.
129         postalCode = truncatePostalCodeForSalesTaxRegionService(postalCode);
130         
131         List<TaxRegion> salesTaxRegions = taxRegionService.getSalesTaxRegions(postalCode);
132         if (salesTaxRegions.size() == 0)
133             return amountWithTax;
134 
135         for (TaxRegion taxRegion : salesTaxRegions) {
136             if (ObjectUtils.isNotNull((taxRegion.getEffectiveTaxRegionRate(dateOfTransaction))))
137                 totalTaxRate = totalTaxRate.add(taxRegion.getEffectiveTaxRegionRate(dateOfTransaction).getTaxRate());
138         }
139 
140         KualiDecimal divisor = new KualiDecimal(totalTaxRate.add(BigDecimal.ONE));
141         KualiDecimal pretaxAmount = amountWithTax.divide(divisor);
142 
143         return pretaxAmount;
144     }
145 
146     /**
147      * This method returns a populated Tax Detail BO based on the Tax Region BO and amount
148      * 
149      * @param taxRegion
150      * @param amount
151      * @return
152      */
153     protected TaxDetail populateTaxDetail(TaxRegion taxRegion, Date dateOfTransaction, KualiDecimal amount) {
154         TaxDetail taxDetail = new TaxDetail();
155         taxDetail.setAccountNumber(taxRegion.getAccountNumber());
156         taxDetail.setChartOfAccountsCode(taxRegion.getChartOfAccountsCode());
157         taxDetail.setFinancialObjectCode(taxRegion.getFinancialObjectCode());
158         taxDetail.setRateCode(taxRegion.getTaxRegionCode());
159         taxDetail.setRateName(taxRegion.getTaxRegionName());
160         taxDetail.setTypeCode(taxRegion.getTaxRegionTypeCode());
161         if (ObjectUtils.isNotNull((taxRegion.getEffectiveTaxRegionRate(dateOfTransaction)))) {
162             taxDetail.setTaxRate(taxRegion.getEffectiveTaxRegionRate(dateOfTransaction).getTaxRate());
163             if (amount != null) {
164                 taxDetail.setTaxAmount(new KualiDecimal((amount.bigDecimalValue().multiply(taxDetail.getTaxRate())).setScale(KualiDecimal.SCALE, KualiDecimal.ROUND_BEHAVIOR)));
165             }
166         }
167         return taxDetail;
168     }
169 
170     protected String truncatePostalCodeForSalesTaxRegionService(String postalCode) {
171         Integer digitsToUse = postalCodeDigitsToUse();
172         if (digitsToUse != null) {
173             return postalCode.substring(0, digitsToUse.intValue());
174         } else {
175             return postalCode; // unchanged
176         }
177     }
178     
179     protected Integer postalCodeDigitsToUse() {
180         String digits = parameterService.getParameterValueAsString(SalesTax.class,
181                 POSTAL_CODE_DIGITS_PASSED_TO_SALES_TAX_REGION_SERVICE);
182         if (StringUtils.isBlank(digits)) { return null; }
183         Integer digitsToUse;
184         try {
185             digitsToUse = new Integer(digits);
186         }
187         catch (NumberFormatException ex) {
188             throw new RuntimeException("The value returned for Parameter " + POSTAL_CODE_DIGITS_PASSED_TO_SALES_TAX_REGION_SERVICE + " was non-numeric and cannot be processed.", ex);
189         }
190         return digitsToUse;
191     }
192     
193     public void setTaxRegionService(TaxRegionService taxRegionService) {
194         this.taxRegionService = taxRegionService;
195     }
196 
197     public void setParameterService(ParameterService parameterService) {
198         this.parameterService = parameterService;
199     }
200 }