/* jBilling - The Enterprise Open Source Billing System Copyright (C) 2003-2011 Enterprise jBilling Software Ltd. and Emiliano Conde This file is part of jbilling. jbilling 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. jbilling 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 jbilling. If not, see <http://www.gnu.org/licenses/>. */ package com.sapienter.jbilling.server.process.task; import com.sapienter.jbilling.server.invoice.NewInvoiceDTO; import com.sapienter.jbilling.server.invoice.db.InvoiceLineDTO; import com.sapienter.jbilling.server.item.ItemBL; import com.sapienter.jbilling.server.item.db.ItemDAS; import com.sapienter.jbilling.server.item.db.ItemDTO; import com.sapienter.jbilling.server.item.db.ItemTypeDTO; import com.sapienter.jbilling.server.pluggableTask.InvoiceCompositionTask; import com.sapienter.jbilling.server.pluggableTask.PluggableTask; import com.sapienter.jbilling.server.pluggableTask.TaskException; import com.sapienter.jbilling.server.process.PeriodOfTime; import com.sapienter.jbilling.server.user.contact.db.ContactDAS; import com.sapienter.jbilling.server.user.contact.db.ContactDTO; import com.sapienter.jbilling.server.user.contact.db.ContactFieldDTO; import com.sapienter.jbilling.server.util.Constants; import org.apache.log4j.Logger; import java.math.BigDecimal; import java.util.Set; /** * This plug-in calculates taxes for invoice. * * Plug-in parameters: * * tax_item_id (required) The item that will be added to an invoice with the taxes * * custom_contact_field_id (optional) The id of CCF that if its value is 'true' or 'yes' for a customer, * then the customer is considered exempt. Exempt customers do not get the tax * added to their invoices. * item_exempt_category_id (optional) The id of an item category that, if the item belongs to, it is * exempt from taxes * * @author Alexander Aksenov * @since 30.04.11 */ public class SimpleTaxCompositionTask extends PluggableTask implements InvoiceCompositionTask { private static final Logger LOG = Logger.getLogger(SimpleTaxCompositionTask.class); // plug-in parameters // mandatory parameters protected final static String PARAM_TAX_ITEM_ID = "tax_item_id"; // optional, may be empty protected final static String PARAM_CUSTOM_CONTACT_FIELD_ID = "custom_contact_field_id"; protected final static String PARAM_ITEM_EXEMPT_CATEGORY_ID = "item_exempt_category_id"; @Override public void apply(NewInvoiceDTO invoice, Integer userId) throws TaskException { ItemDTO taxItem; Integer itemExemptCategoryId = null; Integer customContactFieldId = null; try { String paramValue = getParameter(PARAM_TAX_ITEM_ID, ""); if (paramValue == null || "".equals(paramValue.trim())) { throw new TaskException("Tax item id is not defined!"); } taxItem = new ItemDAS().find(new Integer(paramValue)); if (taxItem == null) { throw new TaskException("Tax item not found!"); } paramValue = getParameter(PARAM_ITEM_EXEMPT_CATEGORY_ID, ""); if (paramValue != null && !"".equals(paramValue.trim())) { itemExemptCategoryId = new Integer(paramValue); } paramValue = getParameter(PARAM_CUSTOM_CONTACT_FIELD_ID, ""); if (paramValue != null && !"".equals(paramValue.trim())) { customContactFieldId = new Integer(paramValue); } } catch (NumberFormatException e) { LOG.error("Incorrect plugin configuration", e); throw new TaskException(e); } if (!isTaxCalculationNeeded(userId, customContactFieldId)) { return; } if (taxItem.getPercentage() != null) { // tax calculation as percentage of full cost //calculate total to include result lines invoice.calculateTotal(); BigDecimal invoiceAmountSum = invoice.getTotal(); //remove carried balance from tax calculation //to avoid double taxation LOG.debug("Percentage Price. Carried balance is " + invoice.getCarriedBalance()); if ( null != invoice.getCarriedBalance() ){ invoiceAmountSum = invoiceAmountSum.subtract(invoice.getCarriedBalance()); } LOG.debug("Exempt Category " + itemExemptCategoryId); if (itemExemptCategoryId != null) { // find exemp items and subtract price for (int i = 0; i < invoice.getResultLines().size(); i++) { InvoiceLineDTO invoiceLine = (InvoiceLineDTO) invoice.getResultLines().get(i); ItemDTO item = invoiceLine.getItem(); if (item != null) { Set<ItemTypeDTO> itemTypes = new ItemDAS().find(item.getId()).getItemTypes(); for (ItemTypeDTO itemType : itemTypes) { if (itemType.getId() == itemExemptCategoryId) { LOG.debug("Item " + item.getDescription() + " is Exempt. Category " + itemType.getId()); invoiceAmountSum = invoiceAmountSum.subtract(invoiceLine.getAmount()); break; } } } } } LOG.debug("Calculating tax on = " + invoiceAmountSum); BigDecimal taxValue = invoiceAmountSum.multiply(taxItem.getPercentage()).divide( BigDecimal.valueOf(100L), Constants.BIGDECIMAL_SCALE, Constants.BIGDECIMAL_ROUND ); //if (taxValue.compareTo(BigDecimal.ZERO) > 0) { InvoiceLineDTO invoiceLine = new InvoiceLineDTO(null, "Tax line for percentage tax item " + taxItem.getId(), taxValue, taxValue, BigDecimal.ONE, Constants.INVOICE_LINE_TYPE_TAX, 0, taxItem.getId(), userId, null); invoice.addResultLine(invoiceLine); //} } else { LOG.debug("Flat Price."); ItemBL itemBL = new ItemBL(taxItem); BigDecimal price = itemBL.getPriceByCurrency(taxItem, userId, invoice.getCurrency().getId()); if (price != null && price.compareTo(BigDecimal.ZERO) != 0) { // tax as additional invoiceLine InvoiceLineDTO invoiceLine = new InvoiceLineDTO(null, "Tax line with flat price for tax item " + taxItem.getId(), price, price, BigDecimal.ONE, Constants.INVOICE_LINE_TYPE_TAX, 0, taxItem.getId(), userId, null); invoice.addResultLine(invoiceLine); } } } private boolean isTaxCalculationNeeded(Integer userId, Integer customContactFieldId) { if (customContactFieldId == null) { return true; } ContactDTO contactDto = new ContactDAS().findPrimaryContact(userId); if (contactDto == null) { return true; } for (ContactFieldDTO contactField : contactDto.getFields()) { if (contactField.getType().getId() == customContactFieldId) { String value = contactField.getContent(); if ("yes".equalsIgnoreCase(value) || "true".equalsIgnoreCase(value)) { return false; } } } return true; } @Override public BigDecimal calculatePeriodAmount(BigDecimal fullPrice, PeriodOfTime period) { throw new UnsupportedOperationException("Can't call this method"); } }