1 24 package org.ofbiz.accounting.tax; 25 26 import java.sql.Timestamp ; 27 import java.text.DecimalFormat ; 28 import java.text.ParseException ; 29 import java.util.ArrayList ; 30 import java.util.HashMap ; 31 import java.util.Iterator ; 32 import java.util.List ; 33 import java.util.Map ; 34 import java.util.Set ; 35 36 import javolution.util.FastSet; 37 38 import org.ofbiz.base.util.Debug; 39 import org.ofbiz.base.util.GeneralException; 40 import org.ofbiz.base.util.UtilDateTime; 41 import org.ofbiz.base.util.UtilMisc; 42 import org.ofbiz.base.util.UtilProperties; 43 import org.ofbiz.base.util.UtilValidate; 44 import org.ofbiz.entity.GenericDelegator; 45 import org.ofbiz.entity.GenericEntityException; 46 import org.ofbiz.entity.GenericValue; 47 import org.ofbiz.entity.condition.EntityCondition; 48 import org.ofbiz.entity.condition.EntityConditionList; 49 import org.ofbiz.entity.condition.EntityExpr; 50 import org.ofbiz.entity.condition.EntityOperator; 51 import org.ofbiz.entity.util.EntityUtil; 52 import org.ofbiz.service.DispatchContext; 53 54 62 63 public class SimpleTaxServices { 64 65 public static final String module = SimpleTaxServices.class.getName(); 66 67 68 public static Map nullTaxCalc(DispatchContext dctx, Map context) { 69 return UtilMisc.toMap("orderAdjustments", UtilMisc.toList(null), "itemAdjustments", UtilMisc.toList(null)); 70 } 71 72 73 public static Map simpleTaxCalc(DispatchContext dctx, Map context) { 74 GenericDelegator delegator = dctx.getDelegator(); 75 String productStoreId = (String ) context.get("productStoreId"); 76 String billToPartyId = (String ) context.get("billToPartyId"); 77 List itemProductList = (List ) context.get("itemProductList"); 78 List itemAmountList = (List ) context.get("itemAmountList"); 79 List itemPriceList = (List ) context.get("itemPriceList"); 80 List itemShippingList = (List ) context.get("itemShippingList"); 81 Double orderShippingAmount = (Double ) context.get("orderShippingAmount"); 82 GenericValue shippingAddress = (GenericValue) context.get("shippingAddress"); 83 86 88 String countryCode = null; 89 String stateCode = null; 90 91 if (shippingAddress != null) { 92 countryCode = shippingAddress.getString("countryGeoId"); 93 stateCode = shippingAddress.getString("stateProvinceGeoId"); 94 } 95 96 List orderAdjustments = new ArrayList (); 98 List itemAdjustments = new ArrayList (); 99 100 for (int i = 0; i < itemProductList.size(); i++) { 102 GenericValue product = (GenericValue) itemProductList.get(i); 103 Double itemAmount = (Double ) itemAmountList.get(i); 104 Double itemPrice = (Double ) itemPriceList.get(i); 105 Double shippingAmount = (Double ) itemShippingList.get(i); 106 List taxList = null; 107 if (shippingAddress != null) { 108 taxList = getTaxAmount(delegator, product, productStoreId, billToPartyId, countryCode, stateCode, itemPrice.doubleValue(), itemAmount.doubleValue(), shippingAmount.doubleValue()); 109 } 110 itemAdjustments.add(taxList); 111 } 112 if (orderShippingAmount.doubleValue() > 0) { 113 List taxList = getTaxAmount(delegator, null, productStoreId, billToPartyId, countryCode, stateCode, 0.00, 0.00, orderShippingAmount.doubleValue()); 114 orderAdjustments.addAll(taxList); 115 } 116 117 Map result = UtilMisc.toMap("orderAdjustments", orderAdjustments, "itemAdjustments", itemAdjustments); 118 119 return result; 120 } 121 122 private static List getTaxAmount(GenericDelegator delegator, GenericValue item, String productStoreId, String billToPartyId, String countryCode, String stateCode, double itemPrice, double itemAmount, double shippingAmount) { 123 Timestamp nowTimestamp = UtilDateTime.nowTimestamp(); 124 List adjustments = new ArrayList (); 125 126 EntityCondition storeCond = new EntityExpr("productStoreId", EntityOperator.EQUALS, productStoreId); 128 129 List countryExprs = UtilMisc.toList(new EntityExpr("countryGeoId", EntityOperator.EQUALS, countryCode), new EntityExpr("countryGeoId", EntityOperator.EQUALS, "_NA_")); 131 EntityCondition countryCond = new EntityConditionList(countryExprs, EntityOperator.OR); 132 133 List stateExprs = UtilMisc.toList(new EntityExpr("stateProvinceGeoId", EntityOperator.EQUALS, stateCode), new EntityExpr("stateProvinceGeoId", EntityOperator.EQUALS, "_NA_")); 135 EntityCondition stateCond = new EntityConditionList(stateExprs, EntityOperator.OR); 136 137 List taxCatExprs = UtilMisc.toList(new EntityExpr("taxCategory", EntityOperator.EQUALS, "_NA_")); 139 if (item != null && item.get("taxCategory") != null) { 140 taxCatExprs.add(new EntityExpr("taxCategory", EntityOperator.EQUALS, item.getString("taxCategory"))); 141 } 142 EntityCondition taxCatCond = new EntityConditionList(taxCatExprs, EntityOperator.OR); 143 144 List mainExprs = UtilMisc.toList(storeCond, countryCond, stateCond); 146 if (taxCatExprs.size() > 1) { 147 mainExprs.add(taxCatCond); 148 } else { 149 mainExprs.add(taxCatExprs.get(0)); 150 } 151 EntityCondition mainCondition = new EntityConditionList(mainExprs, EntityOperator.AND); 152 153 List orderList = UtilMisc.toList("minItemPrice", "minPurchase", "fromDate"); 155 156 try { 157 List lookupList = delegator.findByCondition("SimpleSalesTaxLookup", mainCondition, null, orderList); 158 List filteredList = EntityUtil.filterByDate(lookupList); 159 160 if (filteredList.size() == 0) { 161 Debug.logWarning("SimpleTaxCalc: No State/TaxCategory pair found (with or without taxCat).", module); 162 return adjustments; 163 } 164 165 Iterator flIt = filteredList.iterator(); 167 while (flIt.hasNext()) { 168 GenericValue taxLookup = (GenericValue) flIt.next(); 169 double minPrice = taxLookup.get("minItemPrice") != null ? taxLookup.getDouble("minItemPrice").doubleValue() : 0.00; 170 double minAmount = taxLookup.get("minPurchase") != null ? taxLookup.getDouble("minPurchase").doubleValue() : 0.00; 171 172 if (itemPrice >= minPrice && itemAmount >= minAmount) { 174 double taxRate = taxLookup.get("salesTaxPercentage") != null ? taxLookup.getDouble("salesTaxPercentage").doubleValue() : 0; 175 double taxable = 0.00; 176 177 if (item != null && (item.get("taxable") == null || (item.get("taxable") != null && item.getBoolean("taxable").booleanValue()))) { 178 taxable += itemAmount; 179 } 180 if (taxLookup != null && (taxLookup.get("taxShipping") == null || (taxLookup.get("taxShipping") != null && taxLookup.getBoolean("taxShipping").booleanValue()))) { 181 taxable += shippingAmount; 182 } 183 184 String currencyFormat = UtilProperties.getPropertyValue("general.properties", "currency.decimal.format", "##0.00"); 188 DecimalFormat formatter = new DecimalFormat (currencyFormat); 189 double taxTotal = taxable * taxRate; 190 String amountStr = formatter.format(taxTotal); 191 Double taxAmount = null; 192 try { 193 taxAmount = new Double (formatter.parse(amountStr).doubleValue()); 194 } catch (ParseException e) { 195 throw new GeneralException("Problem getting parsed amount from string", e); 196 } 197 198 String primaryGeoId = taxLookup.getString("stateProvinceGeoId"); 199 String secondaryGeoId = taxLookup.getString("countryGeoId"); 200 String taxAuthPartyId = taxLookup.getString("taxAuthPartyId"); 201 String taxAuthGlAccountId = taxLookup.getString("taxAuthGlAccountId"); 202 203 if (primaryGeoId == null || "_NA_".equals(primaryGeoId)) { 205 primaryGeoId = secondaryGeoId; 206 secondaryGeoId = null; 207 } 208 209 Map adjMap = new HashMap (); 210 adjMap.put("amount", taxAmount); 211 adjMap.put("sourcePercentage", new Double (taxRate)); 212 adjMap.put("orderAdjustmentTypeId", "SALES_TAX"); 213 adjMap.put("primaryGeoId", primaryGeoId); 215 if (secondaryGeoId != null) adjMap.put("secondaryGeoId", secondaryGeoId); 216 adjMap.put("comments", taxLookup.getString("description")); 217 if (taxAuthPartyId != null) adjMap.put("taxAuthPartyId", taxAuthPartyId); 218 if (taxAuthGlAccountId != null) adjMap.put("overrideGlAccountId", taxAuthGlAccountId); 219 if (primaryGeoId != null) adjMap.put("taxAuthGeoId", primaryGeoId); 220 221 if (UtilValidate.isNotEmpty(billToPartyId) && primaryGeoId != null) { 223 Set billToPartyIdSet = FastSet.newInstance(); 226 billToPartyIdSet.add(billToPartyId); 227 List partyRelationshipList = EntityUtil.filterByDate(delegator.findByAndCache("PartyRelationship", UtilMisc.toMap("partyIdTo", billToPartyId, "partyRelationshipTypeId", "GROUP_ROLLUP")), true); 228 Iterator partyRelationshipIter = partyRelationshipList.iterator(); 229 while (partyRelationshipIter.hasNext()) { 230 GenericValue partyRelationship = (GenericValue) partyRelationshipIter.next(); 231 billToPartyIdSet.add(partyRelationship.get("partyIdFrom")); 232 } 233 234 List ptiConditionList = UtilMisc.toList( 235 new EntityExpr("partyId", EntityOperator.IN, billToPartyIdSet), 236 new EntityExpr("taxAuthGeoId", EntityOperator.EQUALS, primaryGeoId)); 237 ptiConditionList.add(new EntityExpr("fromDate", EntityOperator.LESS_THAN_EQUAL_TO, nowTimestamp)); 238 ptiConditionList.add(new EntityExpr(new EntityExpr("thruDate", EntityOperator.EQUALS, null), EntityOperator.OR, new EntityExpr("thruDate", EntityOperator.GREATER_THAN, nowTimestamp))); 239 EntityCondition ptiCondition = new EntityConditionList(ptiConditionList, EntityOperator.AND); 240 List partyTaxAuthInfos = delegator.findByCondition("PartyTaxAuthInfo", ptiCondition, null, UtilMisc.toList("-fromDate")); 242 if (partyTaxAuthInfos.size() > 0) { 243 GenericValue partyTaxAuthInfo = (GenericValue) partyTaxAuthInfos.get(0); 244 adjMap.put("customerReferenceId", partyTaxAuthInfo.get("partyTaxId")); 245 if ("Y".equals(partyTaxAuthInfo.getString("isExempt"))) { 246 adjMap.put("amount", new Double (0)); 247 adjMap.put("exemptAmount", taxAmount); 248 } 249 } 250 } else { 251 Debug.logInfo("NOTE: A tax calculation was done without a billToPartyId or primaryGeoId, so no tax exemptions or tax IDs considered; billToPartyId=[" + billToPartyId + "] primaryGeoId=[" + primaryGeoId + "]", module); 252 } 253 254 adjustments.add(delegator.makeValue("OrderAdjustment", adjMap)); 255 } 256 } 257 } catch (GenericEntityException e) { 258 Debug.logError(e, "Problems looking up tax rates", module); 259 return new ArrayList (); 260 } catch (GeneralException e) { 261 Debug.logError(e, "Problems looking up tax rates", module); 262 return new ArrayList (); 263 } 264 265 return adjustments; 266 } 267 } 268 | Popular Tags |