1 24 package org.ofbiz.accounting.tax; 25 26 import java.math.BigDecimal ; 27 import java.sql.Timestamp ; 28 import java.util.ArrayList ; 29 import java.util.Iterator ; 30 import java.util.List ; 31 import java.util.Map ; 32 import java.util.Set ; 33 34 import javolution.util.FastList; 35 import javolution.util.FastSet; 36 37 import org.ofbiz.base.util.Debug; 38 import org.ofbiz.base.util.UtilDateTime; 39 import org.ofbiz.base.util.UtilMisc; 40 import org.ofbiz.base.util.UtilValidate; 41 import org.ofbiz.base.util.UtilNumber; 42 import org.ofbiz.common.geo.GeoWorker; 43 import org.ofbiz.entity.GenericDelegator; 44 import org.ofbiz.entity.GenericEntityException; 45 import org.ofbiz.entity.GenericValue; 46 import org.ofbiz.entity.condition.EntityCondition; 47 import org.ofbiz.entity.condition.EntityConditionList; 48 import org.ofbiz.entity.condition.EntityExpr; 49 import org.ofbiz.entity.condition.EntityOperator; 50 import org.ofbiz.entity.util.EntityUtil; 51 import org.ofbiz.service.DispatchContext; 52 import org.ofbiz.service.ServiceUtil; 53 54 61 62 public class TaxAuthorityServices { 63 64 public static final String module = TaxAuthorityServices.class.getName(); 65 public static final BigDecimal ZERO_BASE = new BigDecimal ("0.000"); 66 public static final BigDecimal ONE_BASE = new BigDecimal ("1.000"); 67 public static final BigDecimal PERCENT_SCALE = new BigDecimal ("100.000"); 68 69 public static Map rateProductTaxCalcForDisplay(DispatchContext dctx, Map context) { 70 GenericDelegator delegator = dctx.getDelegator(); 71 String productStoreId = (String ) context.get("productStoreId"); 72 String billToPartyId = (String ) context.get("billToPartyId"); 73 String productId = (String ) context.get("productId"); 74 BigDecimal quantity = (BigDecimal ) context.get("quantity"); 75 BigDecimal basePrice = (BigDecimal ) context.get("basePrice"); 76 BigDecimal shippingPrice = (BigDecimal ) context.get("shippingPrice"); 77 78 if (quantity == null) quantity = ONE_BASE; 79 BigDecimal amount = basePrice.multiply(quantity); 80 int salestaxFinalDecimals=UtilNumber.getBigDecimalScale("salestax.final.decimals"); 81 int salestaxCalcDecimals=UtilNumber.getBigDecimalScale("salestax.calc.decimals"); 82 int salestaxRounding=UtilNumber.getBigDecimalRoundingMode("salestax.rounding"); 83 84 BigDecimal taxTotal = ZERO_BASE; 85 BigDecimal taxPercentage = ZERO_BASE; 86 BigDecimal priceWithTax = basePrice; 87 if (shippingPrice != null) priceWithTax = priceWithTax.add(shippingPrice); 88 89 try { 90 GenericValue product = delegator.findByPrimaryKeyCache("Product", UtilMisc.toMap("productId", productId)); 91 GenericValue productStore = delegator.findByPrimaryKeyCache("ProductStore", UtilMisc.toMap("productStoreId", productStoreId)); 92 if (productStore == null) { 93 throw new IllegalArgumentException ("Could not find ProductStore with ID [" + productStoreId + "] for tax calculation"); 94 } 95 96 if ("Y".equals(productStore.getString("showPricesWithVatTax"))) { 97 Set taxAuthoritySet = FastSet.newInstance(); 98 if (productStore.get("vatTaxAuthPartyId") == null) { 99 List taxAuthorityRawList = delegator.findByConditionCache("TaxAuthority", new EntityExpr("taxAuthGeoId", EntityOperator.EQUALS, productStore.get("vatTaxAuthGeoId")), null, null); 100 taxAuthoritySet.addAll(taxAuthorityRawList); 101 } else { 102 GenericValue taxAuthority = delegator.findByPrimaryKeyCache("TaxAuthority", UtilMisc.toMap("taxAuthGeoId", productStore.get("vatTaxAuthGeoId"), "taxAuthPartyId", productStore.get("vatTaxAuthPartyId"))); 103 taxAuthoritySet.add(taxAuthority); 104 } 105 106 if (taxAuthoritySet.size() == 0) { 107 throw new IllegalArgumentException ("Could not find any Tax Authories for store with ID [" + productStoreId + "] for tax calculation; the store settings may need to be corrected."); 108 } 109 110 List taxAdustmentList = getTaxAdjustments(delegator, product, productStore, billToPartyId, taxAuthoritySet, basePrice, amount, shippingPrice); 111 if (taxAdustmentList.size() == 0) { 112 Debug.logWarning("Could not find any Tax Authories Rate Rules for store with ID [" + productStoreId + "], productId [" + productId + "], basePrice [" + basePrice + "], amount [" + amount + "], for tax calculation; the store settings may need to be corrected.", module); 114 } 115 116 Iterator taxAdustmentIter = taxAdustmentList.iterator(); 118 while (taxAdustmentIter.hasNext()) { 119 GenericValue taxAdjustment = (GenericValue) taxAdustmentIter.next(); 120 taxPercentage = taxPercentage.add(taxAdjustment.getBigDecimal("sourcePercentage")); 121 BigDecimal adjAmount = taxAdjustment.getBigDecimal("amount"); 122 taxTotal = taxTotal.add(adjAmount); 123 priceWithTax = priceWithTax.add(adjAmount.divide(quantity,salestaxCalcDecimals,salestaxRounding)); 124 Debug.logInfo("For productId [" + productId + "] added [" + adjAmount.divide(quantity,salestaxCalcDecimals,salestaxRounding) + "] of tax to price for geoId [" + taxAdjustment.getString("taxAuthGeoId") + "], new price is [" + priceWithTax + "]", module); 125 } 126 } 127 } catch (GenericEntityException e) { 128 String errMsg = "Data error getting tax settings: " + e.toString(); 129 Debug.logError(e, errMsg, module); 130 return ServiceUtil.returnError(errMsg); 131 } 132 133 taxTotal.setScale(salestaxFinalDecimals, salestaxRounding); 135 priceWithTax.setScale(salestaxFinalDecimals, salestaxRounding); 136 137 Map result = ServiceUtil.returnSuccess(); 138 result.put("taxTotal", taxTotal); 139 result.put("taxPercentage", taxPercentage); 140 result.put("priceWithTax", priceWithTax); 141 return result; 142 } 143 144 public static Map rateProductTaxCalc(DispatchContext dctx, Map context) { 145 GenericDelegator delegator = dctx.getDelegator(); 146 String productStoreId = (String ) context.get("productStoreId"); 147 String billToPartyId = (String ) context.get("billToPartyId"); 148 List itemProductList = (List ) context.get("itemProductList"); 149 List itemAmountList = (List ) context.get("itemAmountList"); 150 List itemPriceList = (List ) context.get("itemPriceList"); 151 List itemShippingList = (List ) context.get("itemShippingList"); 152 BigDecimal orderShippingAmount = (BigDecimal ) context.get("orderShippingAmount"); 153 GenericValue shippingAddress = (GenericValue) context.get("shippingAddress"); 154 155 Set taxAuthoritySet = FastSet.newInstance(); 157 GenericValue productStore = null; 158 try { 159 Set geoIdSet = FastSet.newInstance(); 160 if (shippingAddress != null) { 161 if (shippingAddress.getString("countryGeoId") != null) { 162 geoIdSet.add(shippingAddress.getString("countryGeoId")); 163 } 164 if (shippingAddress.getString("stateProvinceGeoId") != null) { 165 geoIdSet.add(shippingAddress.getString("stateProvinceGeoId")); 166 } 167 } 168 169 if (geoIdSet.size() == 0) { 170 return ServiceUtil.returnError("The address(es) used for tax calculation did not have State/Province or Country values set, so we cannot determine the taxes to charge."); 171 } 172 173 geoIdSet = GeoWorker.expandGeoRegionDeep(geoIdSet, delegator); 175 176 List taxAuthorityRawList = delegator.findByConditionCache("TaxAuthority", new EntityExpr("taxAuthGeoId", EntityOperator.IN, geoIdSet), null, null); 177 taxAuthoritySet.addAll(taxAuthorityRawList); 178 179 productStore = delegator.findByPrimaryKey("ProductStore", UtilMisc.toMap("productStoreId", productStoreId)); 180 } catch (GenericEntityException e) { 181 String errMsg = "Data error getting tax settings: " + e.toString(); 182 Debug.logError(e, errMsg, module); 183 return ServiceUtil.returnError(errMsg); 184 } 185 186 if (productStore == null) { 187 throw new IllegalArgumentException ("Could not find ProductStore with ID [" + productStoreId + "] for tax calculation"); 188 } 189 190 List orderAdjustments = FastList.newInstance(); 192 List itemAdjustments = FastList.newInstance(); 193 194 for (int i = 0; i < itemProductList.size(); i++) { 196 GenericValue product = (GenericValue) itemProductList.get(i); 197 BigDecimal itemAmount = (BigDecimal ) itemAmountList.get(i); 198 BigDecimal itemPrice = (BigDecimal ) itemPriceList.get(i); 199 BigDecimal shippingAmount = (BigDecimal ) itemShippingList.get(i); 200 List taxList = null; 201 if (shippingAddress != null) { 202 taxList = getTaxAdjustments(delegator, product, productStore, billToPartyId, taxAuthoritySet, itemPrice, itemAmount, shippingAmount); 203 } 204 itemAdjustments.add(taxList); 206 } 207 if (orderShippingAmount.doubleValue() > 0) { 208 List taxList = getTaxAdjustments(delegator, null, productStore, billToPartyId, taxAuthoritySet, ZERO_BASE, ZERO_BASE, orderShippingAmount); 209 orderAdjustments.addAll(taxList); 210 } 211 212 Map result = ServiceUtil.returnSuccess(); 213 result.put("orderAdjustments", orderAdjustments); 214 result.put("itemAdjustments", itemAdjustments); 215 216 return result; 217 } 218 219 private static List getTaxAdjustments(GenericDelegator delegator, GenericValue product, GenericValue productStore, String billToPartyId, Set taxAuthoritySet, BigDecimal itemPrice, BigDecimal itemAmount, BigDecimal shippingAmount) { 220 Timestamp nowTimestamp = UtilDateTime.nowTimestamp(); 221 List adjustments = FastList.newInstance(); 222 223 String payToPartyId = productStore.getString("payToPartyId"); 224 225 EntityCondition storeCond = new EntityExpr("productStoreId", EntityOperator.EQUALS, productStore.get("productStoreId")); 227 228 List taxAuthCondOrList = FastList.newInstance(); 230 taxAuthCondOrList.add(new EntityExpr( 232 new EntityExpr("taxAuthPartyId", EntityOperator.EQUALS, "_NA_"), 233 EntityOperator.AND, 234 new EntityExpr("taxAuthGeoId", EntityOperator.EQUALS, "_NA_"))); 235 236 Iterator taxAuthorityIter = taxAuthoritySet.iterator(); 237 while (taxAuthorityIter.hasNext()) { 238 GenericValue taxAuthority = (GenericValue) taxAuthorityIter.next(); 239 EntityCondition taxAuthCond = new EntityExpr( 240 new EntityExpr("taxAuthPartyId", EntityOperator.EQUALS, taxAuthority.getString("taxAuthPartyId")), 241 EntityOperator.AND, 242 new EntityExpr("taxAuthGeoId", EntityOperator.EQUALS, taxAuthority.getString("taxAuthGeoId"))); 243 taxAuthCondOrList.add(taxAuthCond); 244 } 245 EntityCondition taxAuthoritiesCond = new EntityConditionList(taxAuthCondOrList, EntityOperator.OR); 246 247 try { 248 EntityCondition productCategoryCond = null; 249 if (product != null) { 250 Set productCategoryIdSet = FastSet.newInstance(); 253 List pcmList = delegator.findByAndCache("ProductCategoryMember", UtilMisc.toMap("productId", product.get("productId"))); 254 pcmList = EntityUtil.filterByDate(pcmList, true); 255 Iterator pcmIter = pcmList.iterator(); 256 while (pcmIter.hasNext()) { 257 GenericValue pcm = (GenericValue) pcmIter.next(); 258 productCategoryIdSet.add(pcm.get("productCategoryId")); 259 } 260 261 if (productCategoryIdSet.size() == 0) { 262 productCategoryCond = new EntityExpr("productCategoryId", EntityOperator.EQUALS, null); 263 } else { 264 productCategoryCond = new EntityExpr( 265 new EntityExpr("productCategoryId", EntityOperator.EQUALS, null), 266 EntityOperator.OR, 267 new EntityExpr("productCategoryId", EntityOperator.IN, productCategoryIdSet)); 268 } 269 } else { 270 productCategoryCond = new EntityExpr("productCategoryId", EntityOperator.EQUALS, null); 271 } 272 273 List mainExprs = UtilMisc.toList(storeCond, taxAuthoritiesCond, productCategoryCond); 275 mainExprs.add(new EntityExpr(new EntityExpr("minItemPrice", EntityOperator.EQUALS, null), EntityOperator.OR, new EntityExpr("minItemPrice", EntityOperator.LESS_THAN_EQUAL_TO, itemPrice))); 276 mainExprs.add(new EntityExpr(new EntityExpr("minPurchase", EntityOperator.EQUALS, null), EntityOperator.OR, new EntityExpr("minPurchase", EntityOperator.LESS_THAN_EQUAL_TO, itemAmount))); 277 EntityCondition mainCondition = new EntityConditionList(mainExprs, EntityOperator.AND); 278 279 List orderList = UtilMisc.toList("minItemPrice", "minPurchase", "fromDate"); 281 282 List lookupList = delegator.findByCondition("TaxAuthorityRateProduct", mainCondition, null, orderList); 284 List filteredList = EntityUtil.filterByDate(lookupList, true); 285 286 if (filteredList.size() == 0) { 287 Debug.logWarning("In TaxAuthority Product Rate no records were found for condition:" + mainCondition.toString(), module); 288 return adjustments; 289 } 290 291 Iterator flIt = filteredList.iterator(); 293 while (flIt.hasNext()) { 294 GenericValue taxAuthorityRateProduct = (GenericValue) flIt.next(); 295 296 BigDecimal taxRate = taxAuthorityRateProduct.get("taxPercentage") != null ? taxAuthorityRateProduct.getBigDecimal("taxPercentage") : ZERO_BASE; 297 BigDecimal taxable = ZERO_BASE; 298 299 if (product != null && (product.get("taxable") == null || (product.get("taxable") != null && product.getBoolean("taxable").booleanValue()))) { 300 taxable = taxable.add(itemAmount); 301 } 302 if (taxAuthorityRateProduct != null && (taxAuthorityRateProduct.get("taxShipping") == null || (taxAuthorityRateProduct.get("taxShipping") != null && taxAuthorityRateProduct.getBoolean("taxShipping").booleanValue()))) { 303 taxable = taxable.add(shippingAmount); 304 } 305 306 if (taxable.doubleValue() == 0) { 307 continue; 309 } 310 311 BigDecimal taxAmount = (taxable.multiply(taxRate)).divide(PERCENT_SCALE, 3, BigDecimal.ROUND_CEILING); 313 314 String taxAuthGeoId = taxAuthorityRateProduct.getString("taxAuthGeoId"); 315 String taxAuthPartyId = taxAuthorityRateProduct.getString("taxAuthPartyId"); 316 317 GenericValue taxAuthorityGlAccount = delegator.findByPrimaryKey("TaxAuthorityGlAccount", UtilMisc.toMap("taxAuthPartyId", taxAuthPartyId, "taxAuthGeoId", taxAuthGeoId, "organizationPartyId", payToPartyId)); 319 String taxAuthGlAccountId = null; 320 if (taxAuthorityGlAccount != null) { 321 taxAuthGlAccountId = taxAuthorityGlAccount.getString("glAccountId"); 322 } else { 323 } 325 326 GenericValue adjValue = delegator.makeValue("OrderAdjustment", null); 327 adjValue.set("taxAuthorityRateSeqId", taxAuthorityRateProduct.getString("taxAuthorityRateSeqId")); 328 adjValue.set("amount", taxAmount); 329 adjValue.set("sourcePercentage", taxRate); 330 adjValue.set("orderAdjustmentTypeId", "SALES_TAX"); 331 adjValue.set("primaryGeoId", taxAuthGeoId); 333 adjValue.set("comments", taxAuthorityRateProduct.getString("description")); 334 if (taxAuthPartyId != null) adjValue.set("taxAuthPartyId", taxAuthPartyId); 335 if (taxAuthGlAccountId != null) adjValue.set("overrideGlAccountId", taxAuthGlAccountId); 336 if (taxAuthGeoId != null) adjValue.set("taxAuthGeoId", taxAuthGeoId); 337 338 if (UtilValidate.isNotEmpty(billToPartyId) && taxAuthGeoId != null) { 340 Set billToPartyIdSet = FastSet.newInstance(); 343 billToPartyIdSet.add(billToPartyId); 344 List partyRelationshipList = EntityUtil.filterByDate(delegator.findByAndCache("PartyRelationship", UtilMisc.toMap("partyIdTo", billToPartyId, "partyRelationshipTypeId", "GROUP_ROLLUP")), true); 345 Iterator partyRelationshipIter = partyRelationshipList.iterator(); 346 while (partyRelationshipIter.hasNext()) { 347 GenericValue partyRelationship = (GenericValue) partyRelationshipIter.next(); 348 billToPartyIdSet.add(partyRelationship.get("partyIdFrom")); 349 } 350 351 List ptiConditionList = UtilMisc.toList( 352 new EntityExpr("partyId", EntityOperator.IN, billToPartyIdSet), 353 new EntityExpr("taxAuthGeoId", EntityOperator.EQUALS, taxAuthGeoId), 354 new EntityExpr("taxAuthPartyId", EntityOperator.EQUALS, taxAuthPartyId)); 355 ptiConditionList.add(new EntityExpr("fromDate", EntityOperator.LESS_THAN_EQUAL_TO, nowTimestamp)); 356 ptiConditionList.add(new EntityExpr(new EntityExpr("thruDate", EntityOperator.EQUALS, null), EntityOperator.OR, new EntityExpr("thruDate", EntityOperator.GREATER_THAN, nowTimestamp))); 357 EntityCondition ptiCondition = new EntityConditionList(ptiConditionList, EntityOperator.AND); 358 List partyTaxInfos = delegator.findByCondition("PartyTaxAuthInfo", ptiCondition, null, UtilMisc.toList("-fromDate")); 360 if (partyTaxInfos.size() > 0) { 361 GenericValue partyTaxInfo = (GenericValue) partyTaxInfos.get(0); 362 adjValue.set("customerReferenceId", partyTaxInfo.get("partyTaxId")); 363 if ("Y".equals(partyTaxInfo.getString("isExempt"))) { 364 adjValue.set("amount", new Double (0)); 365 adjValue.set("exemptAmount", taxAmount); 366 } 367 } 368 } else { 369 Debug.logInfo("NOTE: A tax calculation was done without a billToPartyId or taxAuthGeoId, so no tax exemptions or tax IDs considered; billToPartyId=[" + billToPartyId + "] taxAuthGeoId=[" + taxAuthGeoId + "]", module); 370 } 371 372 adjustments.add(adjValue); 373 } 374 } catch (GenericEntityException e) { 375 Debug.logError(e, "Problems looking up tax rates", module); 376 return new ArrayList (); 377 } 378 379 return adjustments; 380 } 381 } 382 | Popular Tags |