/* * The Kuali Financial System, a comprehensive financial management system for higher education. * * Copyright 2005-2014 The Kuali Foundation * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.kuali.kfs.module.purap.document.service; import static org.kuali.kfs.sys.fixture.UserNameFixture.khuntley; import java.sql.Date; import java.util.Calendar; import java.util.HashMap; import java.util.Map; import org.apache.log4j.Logger; import org.kuali.kfs.module.purap.businessobject.PurApItemUseTax; import org.kuali.kfs.module.purap.document.RequisitionDocument; import org.kuali.kfs.module.purap.fixture.RequisitionDocumentFixture; import org.kuali.kfs.module.purap.fixture.TaxFixture; import org.kuali.kfs.sys.ConfigureContext; import org.kuali.kfs.sys.KFSConstants; import org.kuali.kfs.sys.businessobject.TaxRegion; import org.kuali.kfs.sys.context.KualiTestBase; import org.kuali.kfs.sys.context.SpringContext; import org.kuali.kfs.sys.service.impl.KfsParameterConstants; import org.kuali.rice.core.api.datetime.DateTimeService; import org.kuali.rice.core.api.util.type.KualiDecimal; import org.kuali.rice.coreservice.framework.parameter.ParameterService; import org.kuali.rice.coreservice.impl.parameter.ParameterBo; import org.kuali.rice.krad.service.BusinessObjectService; @ConfigureContext(session = khuntley) public class PurapServiceTest extends KualiTestBase { private static final Logger LOG = Logger.getLogger(PurapServiceTest.class); private Date currentDate; private Date compareDate; private int dayOffset = 60; private DateTimeService dateTimeService; private BusinessObjectService businessObjectService; private ParameterService parameterService; private String NAMESPACE = "KFS-PURAP"; private static final String[] TAXABLE_PARM_NMs = { "TAXABLE_DELIVERY_STATES", "TAXABLE_FUND_GROUPS_FOR_NON_TAXABLE_STATES", "TAXABLE_FUND_GROUPS_FOR_TAXABLE_STATES", "TAXABLE_OBJECT_CONSOLIDATIONS_FOR_NON_TAXABLE_STATES", "TAXABLE_OBJECT_CONSOLIDATIONS_FOR_TAXABLE_STATES", "TAXABLE_OBJECT_LEVELS_FOR_NON_TAXABLE_STATES", "TAXABLE_OBJECT_LEVELS_FOR_TAXABLE_STATES", "TAXABLE_SUB_FUND_GROUPS_FOR_NON_TAXABLE_STATES", "TAXABLE_SUB_FUND_GROUPS_FOR_TAXABLE_STATES" }; @Override protected void setUp() throws Exception { super.setUp(); currentDate = SpringContext.getBean(DateTimeService.class).getCurrentSqlDate(); Calendar calendar = SpringContext.getBean(DateTimeService.class).getCurrentCalendar(); calendar.add(Calendar.DATE, dayOffset); compareDate = new Date(calendar.getTimeInMillis()); dateTimeService = SpringContext.getBean(DateTimeService.class); businessObjectService = SpringContext.getBean(BusinessObjectService.class); parameterService = SpringContext.getBean(ParameterService.class); enableParameterConstraints(true); } @Override protected void tearDown() throws Exception { currentDate = null; compareDate = null; super.tearDown(); } public void testIsDateMoreThanANumberOfDaysAway_ManyFewerDays() { int daysAway = dayOffset - 5; assertTrue(SpringContext.getBean(PurapService.class).isDateMoreThanANumberOfDaysAway(compareDate, daysAway)); } public void testIsDateMoreThanANumberOfDaysAway_OneLessDays() { int daysAway = dayOffset - 1; assertTrue(SpringContext.getBean(PurapService.class).isDateMoreThanANumberOfDaysAway(compareDate, daysAway)); } public void testIsDateMoreThanANumberOfDaysAway_SameNumberOfDays() { int daysAway = dayOffset; assertFalse(SpringContext.getBean(PurapService.class).isDateMoreThanANumberOfDaysAway(compareDate, daysAway)); } public void testIsDateMoreThanANumberOfDaysAway_OneMoreDays() { int daysAway = dayOffset + 1; assertFalse(SpringContext.getBean(PurapService.class).isDateMoreThanANumberOfDaysAway(compareDate, daysAway)); } public void testIsDateMoreThanANumberOfDaysAway_ManyMoreDays() { int daysAway = dayOffset + 5; assertFalse(SpringContext.getBean(PurapService.class).isDateMoreThanANumberOfDaysAway(compareDate, daysAway)); } public void testSalesTaxHappyPath() { try { TaxRegion taxRegionPostalCode = TaxFixture.TaxRegionFixture.TAX_REGION_NO_USE_TAX.createTaxRegion(new TaxFixture.TaxRegionRateFixture[] { TaxFixture.TaxRegionRateFixture.TAX_REGION_RATE_05 }, new TaxFixture.TaxRegionPostalCodeFixture[] { TaxFixture.TaxRegionPostalCodeFixture.PO_46202, TaxFixture.TaxRegionPostalCodeFixture.PO_46202_SHORT }, null); businessObjectService.save(taxRegionPostalCode); } catch (Exception e) { // in case the database has the missing data added back in, I do not want this fix to break the test. This will allow the the test // to recover if the data mysteriously gets back to the previous state try { TaxRegion taxRegionPostalCode = TaxFixture.TaxRegionFixture.TAX_REGION_NO_USE_TAX.createTaxRegion(new TaxFixture.TaxRegionRateFixture[] { TaxFixture.TaxRegionRateFixture.TAX_REGION_RATE_05 }, new TaxFixture.TaxRegionPostalCodeFixture[] { TaxFixture.TaxRegionPostalCodeFixture.PO_46202 }, null); businessObjectService.save(taxRegionPostalCode); } catch (Exception e2) { // consume } } RequisitionDocument reqDoc = RequisitionDocumentFixture.REQ_ONLY_REQUIRED_FIELDS.createRequisitionDocumentForTax(TaxFixture.TaxTestCaseFixture.SalesTaxHappyPathTest); SpringContext.getBean(PurapService.class).calculateTax(reqDoc); assertEquals(new KualiDecimal("0.05"), reqDoc.getItem(0).getItemTaxAmount()); assertEquals(new KualiDecimal("1.05"), reqDoc.getItem(0).getTotalAmount()); } public void testUseTaxHappyPath() { TaxRegion taxRegionState = TaxFixture.TaxRegionFixture.TAX_REGION_WITH_USE_TAX.createTaxRegion(new TaxFixture.TaxRegionRateFixture[] { TaxFixture.TaxRegionRateFixture.TAX_REGION_RATE_07 }, null, new TaxFixture.TaxRegionStateFixture[] { TaxFixture.TaxRegionStateFixture.IN }); businessObjectService.save(taxRegionState); RequisitionDocument reqDoc = RequisitionDocumentFixture.REQ_ONLY_REQUIRED_FIELDS.createRequisitionDocumentForTax(TaxFixture.TaxTestCaseFixture.UseTaxHappyPathTest); SpringContext.getBean(PurapService.class).calculateTax(reqDoc); assertNotNull(reqDoc.getItem(0).getUseTaxItems()); assertEquals(1, reqDoc.getItem(0).getUseTaxItems().size()); PurApItemUseTax itemUseTax = reqDoc.getItem(0).getUseTaxItems().get(0); assertEquals(itemUseTax.getAccountNumber(), "6044900"); assertEquals(itemUseTax.getChartOfAccountsCode(), "BA"); assertEquals(itemUseTax.getFinancialObjectCode(), "1500"); assertEquals(itemUseTax.getRateCode(), "USETAX"); assertEquals(itemUseTax.getTaxAmount(), new KualiDecimal("0.07")); } public void testSalesTaxWithItemTypeNotTaxable() { TaxRegion taxRegionPostalCode = TaxFixture.TaxRegionFixture.TAX_REGION_NO_USE_TAX.createTaxRegion(new TaxFixture.TaxRegionRateFixture[] { TaxFixture.TaxRegionRateFixture.TAX_REGION_RATE_05 }, new TaxFixture.TaxRegionPostalCodeFixture[] { TaxFixture.TaxRegionPostalCodeFixture.PO_46202 }, null); businessObjectService.save(taxRegionPostalCode); RequisitionDocument reqDoc = RequisitionDocumentFixture.REQ_ONLY_REQUIRED_FIELDS.createRequisitionDocumentForTax(TaxFixture.TaxTestCaseFixture.SalesTaxItemTypeNotTaxableTest); SpringContext.getBean(PurapService.class).calculateTax(reqDoc); assertNull(reqDoc.getItem(0).getItemTaxAmount()); assertEquals(reqDoc.getItem(0).getTotalAmount(), new KualiDecimal("1.00")); } public void testSalesTaxWithItemTaxFieldNull() { TaxRegion taxRegionPostalCode = TaxFixture.TaxRegionFixture.TAX_REGION_NO_USE_TAX.createTaxRegion(new TaxFixture.TaxRegionRateFixture[] { TaxFixture.TaxRegionRateFixture.TAX_REGION_RATE_05 }, new TaxFixture.TaxRegionPostalCodeFixture[] { TaxFixture.TaxRegionPostalCodeFixture.PO_46202 }, null); businessObjectService.save(taxRegionPostalCode); RequisitionDocument reqDoc = RequisitionDocumentFixture.REQ_ONLY_REQUIRED_FIELDS.createRequisitionDocumentForTax(TaxFixture.TaxTestCaseFixture.SalesTaxItemTaxFieldNullTest); SpringContext.getBean(PurapService.class).calculateTax(reqDoc); assertNotNull(reqDoc.getItem(0).getItemTaxAmount()); assertEquals(new KualiDecimal("100.00"), reqDoc.getItem(0).getItemTaxAmount()); assertEquals(new KualiDecimal("101.00"), reqDoc.getItem(0).getTotalAmount()); } public void testSalesTaxWithCommodityCodeNull() throws Exception { enableParameterConstraints(false); TaxRegion taxRegionPostalCode = TaxFixture.TaxRegionFixture.TAX_REGION_NO_USE_TAX.createTaxRegion(new TaxFixture.TaxRegionRateFixture[] { TaxFixture.TaxRegionRateFixture.TAX_REGION_RATE_05 }, new TaxFixture.TaxRegionPostalCodeFixture[] { TaxFixture.TaxRegionPostalCodeFixture.PO_46202 }, null); businessObjectService.save(taxRegionPostalCode); RequisitionDocument reqDoc = RequisitionDocumentFixture.REQ_ONLY_REQUIRED_FIELDS.createRequisitionDocumentForTax(TaxFixture.TaxTestCaseFixture.SalesTaxCommodityCodeNullTest); SpringContext.getBean(PurapService.class).calculateTax(reqDoc); assertNull(reqDoc.getItem(0).getItemTaxAmount()); assertEquals(new KualiDecimal("1.00"), reqDoc.getItem(0).getTotalAmount()); enableParameterConstraints(true); } public void testSalesTaxWithDeliveryStateNotTaxable() { try { TaxRegion taxRegionPostalCode = TaxFixture.TaxRegionFixture.TAX_REGION_NO_USE_TAX.createTaxRegion(new TaxFixture.TaxRegionRateFixture[] { TaxFixture.TaxRegionRateFixture.TAX_REGION_RATE_05 }, new TaxFixture.TaxRegionPostalCodeFixture[] { TaxFixture.TaxRegionPostalCodeFixture.PO_46202, TaxFixture.TaxRegionPostalCodeFixture.PO_46202_SHORT }, null); businessObjectService.save(taxRegionPostalCode); } catch (Exception e) { // in case the database has the missing data added back in, I do not want this fix to break the test. This will allow the the test // to recover if the data mysteriously gets back to the previous state try { TaxRegion taxRegionPostalCode = TaxFixture.TaxRegionFixture.TAX_REGION_NO_USE_TAX.createTaxRegion(new TaxFixture.TaxRegionRateFixture[] { TaxFixture.TaxRegionRateFixture.TAX_REGION_RATE_05 }, new TaxFixture.TaxRegionPostalCodeFixture[] { TaxFixture.TaxRegionPostalCodeFixture.PO_46202 }, null); businessObjectService.save(taxRegionPostalCode); } catch (Exception e2) { // consume } } boolean isExists = SpringContext.getBean(ParameterService.class).parameterExists(KfsParameterConstants.PURCHASING_DOCUMENT.class, "TAXABLE_DELIVERY_STATES"); RequisitionDocument reqDoc = RequisitionDocumentFixture.REQ_ONLY_REQUIRED_FIELDS.createRequisitionDocumentForTax(TaxFixture.TaxTestCaseFixture.SalesTaxDeliveryStateExemptTest); SpringContext.getBean(PurapService.class).calculateTax(reqDoc); assertEquals(new KualiDecimal("0.05"), reqDoc.getItem(0).getItemTaxAmount()); assertEquals(new KualiDecimal("1.05"), reqDoc.getItem(0).getTotalAmount()); } public void testSalesTaxDeliveryStateExemptWithNonTaxableFund() { TaxRegion taxRegionPostalCode = TaxFixture.TaxRegionFixture.TAX_REGION_NO_USE_TAX.createTaxRegion(new TaxFixture.TaxRegionRateFixture[] { TaxFixture.TaxRegionRateFixture.TAX_REGION_RATE_05 }, new TaxFixture.TaxRegionPostalCodeFixture[] { TaxFixture.TaxRegionPostalCodeFixture.PO_46202 }, null); businessObjectService.save(taxRegionPostalCode); boolean isExists = SpringContext.getBean(ParameterService.class).parameterExists(KfsParameterConstants.PURCHASING_DOCUMENT.class, "TAXABLE_DELIVERY_STATES"); RequisitionDocument reqDoc = RequisitionDocumentFixture.REQ_ONLY_REQUIRED_FIELDS.createRequisitionDocumentForTax(TaxFixture.TaxTestCaseFixture.SalesTaxDeliveryStateExemptWithNonTaxableFundTest); SpringContext.getBean(PurapService.class).calculateTax(reqDoc); assertNull(reqDoc.getItem(0).getItemTaxAmount()); assertEquals(new KualiDecimal("1.00"), reqDoc.getItem(0).getTotalAmount()); } public void testSalesTaxWithAccountNotTaxable() { TaxRegion taxRegionPostalCode = TaxFixture.TaxRegionFixture.TAX_REGION_NO_USE_TAX.createTaxRegion(new TaxFixture.TaxRegionRateFixture[] { TaxFixture.TaxRegionRateFixture.TAX_REGION_RATE_05 }, new TaxFixture.TaxRegionPostalCodeFixture[] { TaxFixture.TaxRegionPostalCodeFixture.PO_46202 }, null); businessObjectService.save(taxRegionPostalCode); RequisitionDocument reqDoc = RequisitionDocumentFixture.REQ_ONLY_REQUIRED_FIELDS.createRequisitionDocumentForTax(TaxFixture.TaxTestCaseFixture.SalesTaxAccountNotTaxableTest); SpringContext.getBean(PurapService.class).calculateTax(reqDoc); assertNull(reqDoc.getItem(0).getItemTaxAmount()); assertEquals(new KualiDecimal("1.00"), reqDoc.getItem(0).getTotalAmount()); } public void testSalesTaxWithObjectCodeNotTaxable() { TaxRegion taxRegionPostalCode = TaxFixture.TaxRegionFixture.TAX_REGION_NO_USE_TAX.createTaxRegion(new TaxFixture.TaxRegionRateFixture[] { TaxFixture.TaxRegionRateFixture.TAX_REGION_RATE_05 }, new TaxFixture.TaxRegionPostalCodeFixture[] { TaxFixture.TaxRegionPostalCodeFixture.PO_46202 }, null); businessObjectService.save(taxRegionPostalCode); RequisitionDocument reqDoc = RequisitionDocumentFixture.REQ_ONLY_REQUIRED_FIELDS.createRequisitionDocumentForTax(TaxFixture.TaxTestCaseFixture.SalesTaxObjectCodeNotTaxableTest); SpringContext.getBean(PurapService.class).calculateTax(reqDoc); assertNull(reqDoc.getItem(0).getItemTaxAmount()); assertEquals(reqDoc.getItem(0).getTotalAmount(), new KualiDecimal("1.00")); } public void testUseTaxItemTypeNotTaxable() { TaxRegion taxRegionPostalCode = TaxFixture.TaxRegionFixture.TAX_REGION_NO_USE_TAX.createTaxRegion(new TaxFixture.TaxRegionRateFixture[] { TaxFixture.TaxRegionRateFixture.TAX_REGION_RATE_05 }, new TaxFixture.TaxRegionPostalCodeFixture[] { TaxFixture.TaxRegionPostalCodeFixture.PO_46202 }, null); businessObjectService.save(taxRegionPostalCode); RequisitionDocument reqDoc = RequisitionDocumentFixture.REQ_ONLY_REQUIRED_FIELDS.createRequisitionDocumentForTax(TaxFixture.TaxTestCaseFixture.UseTaxItemTypeNotTaxableTest); SpringContext.getBean(PurapService.class).calculateTax(reqDoc); assertEquals(reqDoc.getItem(0).getUseTaxItems().size(), 0); } public void testSalesTaxWithSalesTaxParamDisabled() { TaxRegion taxRegionPostalCode = TaxFixture.TaxRegionFixture.TAX_REGION_NO_USE_TAX.createTaxRegion(new TaxFixture.TaxRegionRateFixture[] { TaxFixture.TaxRegionRateFixture.TAX_REGION_RATE_05 }, new TaxFixture.TaxRegionPostalCodeFixture[] { TaxFixture.TaxRegionPostalCodeFixture.PO_46202 }, null); businessObjectService.save(taxRegionPostalCode); RequisitionDocument reqDoc = RequisitionDocumentFixture.REQ_ONLY_REQUIRED_FIELDS.createRequisitionDocumentForTax(TaxFixture.TaxTestCaseFixture.SalesTaxParamDisabledTest); SpringContext.getBean(PurapService.class).calculateTax(reqDoc); assertNull(reqDoc.getItem(0).getItemTaxAmount()); assertEquals(reqDoc.getItem(0).getTotalAmount(), new KualiDecimal("1.00")); } /** * This method ensures that the database entries upon which the test was designed have good values. This * is safe because whatever changes are made for this test are rolled back before the next test. * @param enabled true to set the constraint indicator to Allow; false is Disallow. */ private void enableParameterConstraints(boolean enabled) { // apparently, the database values are not what the test writer originally expected. Force the issue for test (it will be rolled back anyway) for (String taxableParmName : TAXABLE_PARM_NMs) { Map<String, String> fieldValues = new HashMap<String, String>(); fieldValues.put("namespaceCode", NAMESPACE); fieldValues.put("componentCode", "Document"); fieldValues.put("applicationId", KFSConstants.APPLICATION_NAMESPACE_CODE); fieldValues.put("name", taxableParmName); ParameterBo parameter = businessObjectService.findByPrimaryKey(ParameterBo.class, fieldValues); if (enabled) { parameter.setEvaluationOperatorCode("A"); } else { parameter.setEvaluationOperatorCode("D"); } businessObjectService.save(parameter); } } }