/******************************************************************************* * Copyright (c) 2011 Softberries Krzysztof Grajek. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Softberries Krzysztof Grajek - initial API and implementation ******************************************************************************/ package com.softberries.klerk.calc; import java.math.BigDecimal; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import com.softberries.klerk.dao.to.Document; import com.softberries.klerk.dao.to.DocumentItem; import com.softberries.klerk.dao.to.VatLevelItem; import com.softberries.klerk.gui.editors.SingleDocumentEditor; import com.softberries.klerk.gui.helpers.Messages; import com.softberries.klerk.money.Money; /** * Used to calculate the remaining parts of the document {@link Document} * while editing its items {@link DocumentItem} * @author krzysztof.grajek@softberries.com * */ public class DocumentCalculator { /** * This property is displayed on the {@link SingleDocumentEditor} page as a label */ private static final String TAX_LEVEL = Messages.DocumentCalculator_TaxLevel; /** * This property is displayed on the {@link SingleDocumentEditor} page as a label */ private static final String PRICE_ALL_NET = Messages.DocumentCalculator_NET; /** * This property is displayed on the {@link SingleDocumentEditor} page as a label */ private static final String PRICE_ALL_GROSS = Messages.DocumentCalculator_GROSS; /** * Calculate all remaining {@link Document} and {@link DocumentItem} properties based on * {@code quantity} property * @param di * @param value * @return {@link DocumentItem} object with all fields calculated */ public DocumentItem calculateByQuantity(DocumentItem di, Object value){ if(!isANumber(value.toString())){ return di; } try{ //get new quantity value Money quantity = new Money(new BigDecimal(value.toString()).setScale(2)); di.setQuantity(quantity.getAmount().setScale(2).toPlainString()); //no exception here? get the rest of the values Money priceNet = new Money(new BigDecimal(di.getPriceNetSingle()).setScale(2)); Money taxPercent = new Money(new BigDecimal(di.getTaxValue()).setScale(2)).div(100.00); //calculated Money grossSingleCalc = priceNet.times(taxPercent.getAmount().doubleValue()).plus(priceNet); Money priceNetAllCalc = priceNet.times(quantity.getAmount().doubleValue()); Money priceGrossAllCalc = priceNetAllCalc.times(taxPercent.getAmount().doubleValue()).plus(priceNetAllCalc); Money taxValueAll = priceGrossAllCalc.minus(priceNetAllCalc); di.setPriceNetAll(priceNetAllCalc.getAmount().setScale(2).toPlainString()); di.setPriceGrossSingle(grossSingleCalc.getAmount().setScale(2).toPlainString()); di.setPriceGrossAll(priceGrossAllCalc.getAmount().setScale(2).toPlainString()); di.setPriceTaxAll(taxValueAll.getAmount().setScale(2).toPlainString()); return di; }catch(NumberFormatException nfe){ //ignore it } return di; } /** * Calculate all remaining {@link Document} and {@link DocumentItem} properties based on * {@code basePrice} property * @param di * @param value * @return {@link DocumentItem} object with all fields calculated */ public DocumentItem calculateByBasePrice(DocumentItem di, Object value) { if(!isANumber(value.toString())){ return di; } Money priceNet = new Money(new BigDecimal(value.toString()).setScale(2)); di.setPriceNetSingle(priceNet.getAmount().setScale(2).toPlainString()); //no exception here? get the rest of the values Money quantity = new Money(new BigDecimal(di.getQuantity()).setScale(2)); Money taxPercent = new Money(new BigDecimal(di.getTaxValue()).setScale(2)).div(100.00); //calculated Money grossSingleCalc = priceNet.times(taxPercent.getAmount().doubleValue()).plus(priceNet); Money priceNetAllCalc = priceNet.times(quantity.getAmount().doubleValue()); Money priceGrossAllCalc = priceNetAllCalc.times(taxPercent.getAmount().doubleValue()).plus(priceNetAllCalc); Money taxValueAll = priceGrossAllCalc.minus(priceNetAllCalc); di.setPriceNetAll(priceNetAllCalc.getAmount().setScale(2).toPlainString()); di.setPriceGrossSingle(grossSingleCalc.getAmount().setScale(2).toPlainString()); di.setPriceGrossAll(priceGrossAllCalc.getAmount().setScale(2).toPlainString()); di.setPriceTaxAll(taxValueAll.getAmount().setScale(2).toPlainString()); return di; } /** * Calculate all remaining {@link Document} and {@link DocumentItem} properties based on * {@code priceNetAll} property * @param di * @param value * @return {@link DocumentItem} object with all fields calculated */ public DocumentItem calculateByPriceNetAll(DocumentItem di, Object value) { if(!isANumber(value.toString())){ return di; } Money priceNetAll = new Money(new BigDecimal(value.toString()).setScale(2)); di.setPriceNetAll(priceNetAll.getAmount().setScale(2).toPlainString()); //no exception here? get the rest of the values Money quantity = new Money(new BigDecimal(di.getQuantity()).setScale(2)); Money taxPercent = new Money(new BigDecimal(di.getTaxValue()).setScale(2)).div(100.00); Money priceNet = new Money(new BigDecimal("0")); //$NON-NLS-1$ if(quantity.getAmount().doubleValue() > 0){ priceNet = new Money(new BigDecimal(priceNetAll.getAmount().setScale(2).toPlainString()).setScale(2)).div(quantity.getAmount().doubleValue()); } Money grossSingleCalc = priceNet.times(taxPercent.getAmount().doubleValue()).plus(priceNet); Money priceGrossAllCalc = priceNetAll.times(taxPercent.getAmount().doubleValue()).plus(priceNetAll); Money taxValueAll = priceGrossAllCalc.minus(priceNetAll); di.setPriceGrossSingle(grossSingleCalc.getAmount().setScale(2).toPlainString()); di.setPriceGrossAll(priceGrossAllCalc.getAmount().setScale(2).toPlainString()); di.setPriceTaxAll(taxValueAll.getAmount().setScale(2).toPlainString()); di.setPriceNetSingle(priceNet.getAmount().setScale(2).toPlainString()); return di; } /** * Calculate all remaining {@link Document} and {@link DocumentItem} properties based on * {@code grossAll} property * @param di * @param value * @return {@link DocumentItem} object with all fields calculated */ public DocumentItem calculateByPriceGrossAll(DocumentItem di, Object value) { if(!isANumber(value.toString())){ return di; } Money priceGrossAll = new Money(new BigDecimal(value.toString()).setScale(2)); di.setPriceGrossAll(priceGrossAll.getAmount().setScale(2).toPlainString()); //no exception here? get the rest of the values Money quantity = new Money(new BigDecimal(di.getQuantity()).setScale(2)); Money taxPercent = new Money(new BigDecimal(di.getTaxValue()).setScale(2)).div(100.00); Money grossSingleCalc = new Money(new BigDecimal("0")); //$NON-NLS-1$ if(quantity.getAmount().setScale(2).doubleValue() > 0){ grossSingleCalc = new Money(new BigDecimal(priceGrossAll.getAmount().setScale(2).toPlainString()).setScale(2)).div(quantity.getAmount().setScale(2).doubleValue()); } System.out.println("Gross single: " + grossSingleCalc.getAmount().toPlainString()); //$NON-NLS-1$ Money priceNetSingle = grossSingleCalc.minus(grossSingleCalc.times(taxPercent.getAmount().setScale(2).doubleValue())); System.out.println("Net single: " + priceNetSingle.getAmount().toPlainString()); //$NON-NLS-1$ Money priceNetAllCalc = priceNetSingle.times(quantity.getAmount().doubleValue()); Money taxValueAll = priceGrossAll.minus(priceNetAllCalc); di.setPriceGrossSingle(grossSingleCalc.getAmount().setScale(2).toPlainString()); di.setPriceGrossAll(priceGrossAll.getAmount().setScale(2).toPlainString()); di.setPriceTaxAll(taxValueAll.getAmount().setScale(2).toPlainString()); di.setPriceNetSingle(priceNetSingle.getAmount().setScale(2).toPlainString()); di.setPriceNetAll(priceNetAllCalc.getAmount().setScale(2).toPlainString()); return di; } /** * Calculate all remaining {@link Document} and {@link DocumentItem} properties based on * {@code taxPercent} property * @param di * @param value * @return {@link DocumentItem} object with all fields calculated */ public DocumentItem calculateByTaxPercent(DocumentItem di, Object value) { if(!isANumber(value.toString())){ return di; } Money taxPercentFull = new Money(new BigDecimal(value.toString()).setScale(2)); di.setTaxValue(taxPercentFull.getAmount().setScale(2).toPlainString()); Money taxPercent = new Money(new BigDecimal(di.getTaxValue()).setScale(2)).div(100.00); Money quantity = new Money(new BigDecimal(di.getQuantity()).setScale(2)); Money priceNetSingle = new Money(new BigDecimal(di.getPriceNetSingle()).setScale(2)); Money grossSingleCalc = priceNetSingle.times(taxPercent.getAmount().doubleValue()).plus(priceNetSingle); Money priceNetAllCalc = priceNetSingle.times(quantity.getAmount().doubleValue()); Money priceGrossAllCalc = priceNetAllCalc.times(taxPercent.getAmount().doubleValue()).plus(priceNetAllCalc); Money taxValueAll = priceGrossAllCalc.minus(priceNetAllCalc); di.setPriceNetAll(priceNetAllCalc.getAmount().setScale(2).toPlainString()); di.setPriceGrossSingle(grossSingleCalc.getAmount().setScale(2).toPlainString()); di.setPriceGrossAll(priceGrossAllCalc.getAmount().setScale(2).toPlainString()); di.setPriceTaxAll(taxValueAll.getAmount().setScale(2).toPlainString()); return di; } /** * Calculate all remaining {@link Document} and {@link DocumentItem} properties based on * {@code summaryTaxLevel} property * @param di * @param value * @return {@link DocumentItem} object with all fields calculated */ public List<VatLevelItem> getSummaryTaxLevelItems(List<DocumentItem> items) { Map<String, VatLevelItem> summaryItems = new HashMap<String, VatLevelItem>(); if(items == null || items.size() == 0){ return new ArrayList<VatLevelItem>(); } for(DocumentItem di : items){ Money priceNet = new Money(new BigDecimal(di.getPriceNetAll()).setScale(2)); Money priceGross = new Money(new BigDecimal(di.getPriceGrossAll()).setScale(2)); Money taxLevel = new Money(new BigDecimal(di.getTaxValue()).setScale(2)); Money taxPrice = new Money(new BigDecimal(di.getPriceTaxAll()).setScale(2)); String taxLevelName = TAX_LEVEL + "["+taxLevel.getAmount().setScale(2).toPlainString() + "%]"; //$NON-NLS-1$ //$NON-NLS-2$ VatLevelItem vatItem = summaryItems.get(taxLevelName); System.out.println("TaxLevel: " + taxLevel + ", taxPrice: " + taxPrice); //$NON-NLS-1$ //$NON-NLS-2$ //taxes (divided by tax level) if(vatItem == null){ VatLevelItem item = new VatLevelItem(); item.setVatLevel(taxLevel.getAmount().setScale(2).toPlainString()); item.setNetValue(priceNet.getAmount().setScale(2).toPlainString()); item.setVatValue(taxPrice.getAmount().setScale(2).toPlainString()); item.setGrossValue(priceGross.getAmount().setScale(2).toPlainString()); summaryItems.put(taxLevelName, item); }else{ Money priceNetTemp = new Money(new BigDecimal(vatItem.getNetValue())); Money priceTaxTemp = new Money(new BigDecimal(vatItem.getVatValue())); Money priceGrossTemp = new Money(new BigDecimal(vatItem.getGrossValue())); Money resTax = taxPrice.plus(priceTaxTemp); Money resNet = priceNet.plus(priceNetTemp); Money resGross = priceGross.plus(priceGrossTemp); vatItem.setNetValue(resNet.getAmount().setScale(2).toPlainString()); vatItem.setVatValue(resTax.getAmount().setScale(2).toPlainString()); vatItem.setGrossValue(resGross.getAmount().setScale(2).toPlainString()); summaryItems.remove(taxLevelName); summaryItems.put(taxLevelName, vatItem); } } //prepare results return new ArrayList<VatLevelItem>(summaryItems.values()); } /** * Calculate the net price for the whole {@link Document} * @param items * @return */ public Money getNetPrice(List<DocumentItem> items) { Money result = new Money(new BigDecimal("0.00")); //$NON-NLS-1$ for(DocumentItem di : items){ Money priceNetAll = new Money(new BigDecimal(di.getPriceNetAll()).setScale(2)); result = result.plus(priceNetAll); } return result; } /** * Calculate the gross price for the whole {@link Document} * @param items * @return */ public Money getGrossPrice(List<DocumentItem> items) { Money result = new Money(new BigDecimal("0.00")); //$NON-NLS-1$ for(DocumentItem di : items){ Money priceGrossAll = new Money(new BigDecimal(di.getPriceGrossAll()).setScale(2)); result = result.plus(priceGrossAll); } return result; } /** * Check if the value passed to the calculator is a number * @param items * @return */ private boolean isANumber(String s) { try { BigDecimal a = new BigDecimal(s); return true; } catch (NumberFormatException e) { return false; } } }